The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/nfs/nfs_commonsubs.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1989, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * This code is derived from software contributed to Berkeley by
    6  * Rick Macklem at The University of Guelph.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 4. Neither the name of the University nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD: releng/10.4/sys/fs/nfs/nfs_commonsubs.c 321877 2017-08-01 15:51:16Z trasz $");
   36 
   37 /*
   38  * These functions support the macros and help fiddle mbuf chains for
   39  * the nfs op functions. They do things like create the rpc header and
   40  * copy data between mbuf chains and uio lists.
   41  */
   42 #ifndef APPLEKEXT
   43 #include "opt_inet6.h"
   44 
   45 #include <fs/nfs/nfsport.h>
   46 
   47 #include <security/mac/mac_framework.h>
   48 
   49 /*
   50  * Data items converted to xdr at startup, since they are constant
   51  * This is kinda hokey, but may save a little time doing byte swaps
   52  */
   53 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
   54 
   55 /* And other global data */
   56 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
   57                       NFFIFO, NFNON };
   58 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
   59 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
   60 struct timeval nfsboottime;     /* Copy boottime once, so it never changes */
   61 int nfscl_ticks;
   62 int nfsrv_useacl = 1;
   63 struct nfssockreq nfsrv_nfsuserdsock;
   64 int nfsrv_nfsuserd = 0;
   65 struct nfsreqhead nfsd_reqq;
   66 uid_t nfsrv_defaultuid = UID_NOBODY;
   67 gid_t nfsrv_defaultgid = GID_NOGROUP;
   68 int nfsrv_lease = NFSRV_LEASE;
   69 int ncl_mbuf_mlen = MLEN;
   70 int nfsd_enable_stringtouid = 0;
   71 static int nfs_enable_uidtostring = 0;
   72 NFSNAMEIDMUTEX;
   73 NFSSOCKMUTEX;
   74 extern int nfsrv_lughashsize;
   75 
   76 SYSCTL_DECL(_vfs_nfs);
   77 SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
   78     &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names");
   79 
   80 /*
   81  * This array of structures indicates, for V4:
   82  * retfh - which of 3 types of calling args are used
   83  *      0 - doesn't change cfh or use a sfh
   84  *      1 - replaces cfh with a new one (unless it returns an error status)
   85  *      2 - uses cfh and sfh
   86  * needscfh - if the op wants a cfh and premtime
   87  *      0 - doesn't use a cfh
   88  *      1 - uses a cfh, but doesn't want pre-op attributes
   89  *      2 - uses a cfh and wants pre-op attributes
   90  * savereply - indicates a non-idempotent Op
   91  *      0 - not non-idempotent
   92  *      1 - non-idempotent
   93  * Ops that are ordered via seqid# are handled separately from these
   94  * non-idempotent Ops.
   95  * Define it here, since it is used by both the client and server.
   96  */
   97 struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
   98         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* undef */
   99         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* undef */
  100         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* undef */
  101         { 0, 1, 0, 0, LK_SHARED, 1, 1 },                /* Access */
  102         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* Close */
  103         { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 },             /* Commit */
  104         { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 },             /* Create */
  105         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* Delegpurge */
  106         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* Delegreturn */
  107         { 0, 1, 0, 0, LK_SHARED, 1, 1 },                /* Getattr */
  108         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* GetFH */
  109         { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },             /* Link */
  110         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* Lock */
  111         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* LockT */
  112         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* LockU */
  113         { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Lookup */
  114         { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Lookupp */
  115         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* NVerify */
  116         { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 },             /* Open */
  117         { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* OpenAttr */
  118         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* OpenConfirm */
  119         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* OpenDowngrade */
  120         { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* PutFH */
  121         { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* PutPubFH */
  122         { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* PutRootFH */
  123         { 0, 1, 0, 0, LK_SHARED, 1, 0 },                /* Read */
  124         { 0, 1, 0, 0, LK_SHARED, 1, 1 },                /* Readdir */
  125         { 0, 1, 0, 0, LK_SHARED, 1, 1 },                /* ReadLink */
  126         { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 },             /* Remove */
  127         { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },             /* Rename */
  128         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* Renew */
  129         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* RestoreFH */
  130         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* SaveFH */
  131         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* SecInfo */
  132         { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 },             /* Setattr */
  133         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* SetClientID */
  134         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* SetClientIDConfirm */
  135         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Verify */
  136         { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 },             /* Write */
  137         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* ReleaseLockOwner */
  138         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Backchannel Ctrl */
  139         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Bind Conn to Sess */
  140         { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },             /* Exchange ID */
  141         { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },             /* Create Session */
  142         { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },             /* Destroy Session */
  143         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* Free StateID */
  144         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Get Dir Deleg */
  145         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Get Device Info */
  146         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Get Device List */
  147         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Layout Commit */
  148         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Layout Get */
  149         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* Layout Return */
  150         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Secinfo No name */
  151         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* Sequence */
  152         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Set SSV */
  153         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Test StateID */
  154         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Want Delegation */
  155         { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },             /* Destroy ClientID */
  156         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* Reclaim Complete */
  157 };
  158 #endif  /* !APPLEKEXT */
  159 
  160 static int ncl_mbuf_mhlen = MHLEN;
  161 static int nfsrv_usercnt = 0;
  162 static int nfsrv_dnsnamelen;
  163 static u_char *nfsrv_dnsname = NULL;
  164 static int nfsrv_usermax = 999999999;
  165 struct nfsrv_lughash {
  166         struct mtx              mtx;
  167         struct nfsuserhashhead  lughead;
  168 };
  169 static struct nfsrv_lughash     *nfsuserhash;
  170 static struct nfsrv_lughash     *nfsusernamehash;
  171 static struct nfsrv_lughash     *nfsgrouphash;
  172 static struct nfsrv_lughash     *nfsgroupnamehash;
  173 
  174 /*
  175  * This static array indicates whether or not the RPC generates a large
  176  * reply. This is used by nfs_reply() to decide whether or not an mbuf
  177  * cluster should be allocated. (If a cluster is required by an RPC
  178  * marked 0 in this array, the code will still work, just not quite as
  179  * efficiently.)
  180  */
  181 int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
  182     0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  183     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
  184 
  185 /* local functions */
  186 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
  187 static void nfsv4_wanted(struct nfsv4lock *lp);
  188 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
  189 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
  190     NFSPROC_T *p);
  191 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
  192 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
  193     int *, int *);
  194 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
  195 
  196 
  197 #ifndef APPLE
  198 /*
  199  * copies mbuf chain to the uio scatter/gather list
  200  */
  201 int
  202 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
  203 {
  204         char *mbufcp, *uiocp;
  205         int xfer, left, len;
  206         mbuf_t mp;
  207         long uiosiz, rem;
  208         int error = 0;
  209 
  210         mp = nd->nd_md;
  211         mbufcp = nd->nd_dpos;
  212         len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
  213         rem = NFSM_RNDUP(siz) - siz;
  214         while (siz > 0) {
  215                 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
  216                         error = EBADRPC;
  217                         goto out;
  218                 }
  219                 left = uiop->uio_iov->iov_len;
  220                 uiocp = uiop->uio_iov->iov_base;
  221                 if (left > siz)
  222                         left = siz;
  223                 uiosiz = left;
  224                 while (left > 0) {
  225                         while (len == 0) {
  226                                 mp = mbuf_next(mp);
  227                                 if (mp == NULL) {
  228                                         error = EBADRPC;
  229                                         goto out;
  230                                 }
  231                                 mbufcp = NFSMTOD(mp, caddr_t);
  232                                 len = mbuf_len(mp);
  233                                 KASSERT(len >= 0,
  234                                     ("len %d, corrupted mbuf?", len));
  235                         }
  236                         xfer = (left > len) ? len : left;
  237 #ifdef notdef
  238                         /* Not Yet.. */
  239                         if (uiop->uio_iov->iov_op != NULL)
  240                                 (*(uiop->uio_iov->iov_op))
  241                                 (mbufcp, uiocp, xfer);
  242                         else
  243 #endif
  244                         if (uiop->uio_segflg == UIO_SYSSPACE)
  245                                 NFSBCOPY(mbufcp, uiocp, xfer);
  246                         else
  247                                 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
  248                         left -= xfer;
  249                         len -= xfer;
  250                         mbufcp += xfer;
  251                         uiocp += xfer;
  252                         uiop->uio_offset += xfer;
  253                         uiop->uio_resid -= xfer;
  254                 }
  255                 if (uiop->uio_iov->iov_len <= siz) {
  256                         uiop->uio_iovcnt--;
  257                         uiop->uio_iov++;
  258                 } else {
  259                         uiop->uio_iov->iov_base = (void *)
  260                                 ((char *)uiop->uio_iov->iov_base + uiosiz);
  261                         uiop->uio_iov->iov_len -= uiosiz;
  262                 }
  263                 siz -= uiosiz;
  264         }
  265         nd->nd_dpos = mbufcp;
  266         nd->nd_md = mp;
  267         if (rem > 0) {
  268                 if (len < rem)
  269                         error = nfsm_advance(nd, rem, len);
  270                 else
  271                         nd->nd_dpos += rem;
  272         }
  273 
  274 out:
  275         NFSEXITCODE2(error, nd);
  276         return (error);
  277 }
  278 #endif  /* !APPLE */
  279 
  280 /*
  281  * Help break down an mbuf chain by setting the first siz bytes contiguous
  282  * pointed to by returned val.
  283  * This is used by the macro NFSM_DISSECT for tough
  284  * cases.
  285  */
  286 APPLESTATIC void *
  287 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
  288 {
  289         mbuf_t mp2;
  290         int siz2, xfer;
  291         caddr_t p;
  292         int left;
  293         caddr_t retp;
  294 
  295         retp = NULL;
  296         left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
  297         while (left == 0) {
  298                 nd->nd_md = mbuf_next(nd->nd_md);
  299                 if (nd->nd_md == NULL)
  300                         return (retp);
  301                 left = mbuf_len(nd->nd_md);
  302                 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
  303         }
  304         if (left >= siz) {
  305                 retp = nd->nd_dpos;
  306                 nd->nd_dpos += siz;
  307         } else if (mbuf_next(nd->nd_md) == NULL) {
  308                 return (retp);
  309         } else if (siz > ncl_mbuf_mhlen) {
  310                 panic("nfs S too big");
  311         } else {
  312                 MGET(mp2, MT_DATA, how);
  313                 if (mp2 == NULL)
  314                         return (NULL);
  315                 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
  316                 mbuf_setnext(nd->nd_md, mp2);
  317                 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
  318                 nd->nd_md = mp2;
  319                 retp = p = NFSMTOD(mp2, caddr_t);
  320                 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
  321                 siz2 = siz - left;
  322                 p += left;
  323                 mp2 = mbuf_next(mp2);
  324                 /* Loop around copying up the siz2 bytes */
  325                 while (siz2 > 0) {
  326                         if (mp2 == NULL)
  327                                 return (NULL);
  328                         xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
  329                         if (xfer > 0) {
  330                                 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
  331                                 NFSM_DATAP(mp2, xfer);
  332                                 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
  333                                 p += xfer;
  334                                 siz2 -= xfer;
  335                         }
  336                         if (siz2 > 0)
  337                                 mp2 = mbuf_next(mp2);
  338                 }
  339                 mbuf_setlen(nd->nd_md, siz);
  340                 nd->nd_md = mp2;
  341                 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
  342         }
  343         return (retp);
  344 }
  345 
  346 /*
  347  * Advance the position in the mbuf chain.
  348  * If offs == 0, this is a no-op, but it is simpler to just return from
  349  * here than check for offs > 0 for all calls to nfsm_advance.
  350  * If left == -1, it should be calculated here.
  351  */
  352 APPLESTATIC int
  353 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
  354 {
  355         int error = 0;
  356 
  357         if (offs == 0)
  358                 goto out;
  359         /*
  360          * A negative offs should be considered a serious problem.
  361          */
  362         if (offs < 0)
  363                 panic("nfsrv_advance");
  364 
  365         /*
  366          * If left == -1, calculate it here.
  367          */
  368         if (left == -1)
  369                 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
  370                     nd->nd_dpos;
  371 
  372         /*
  373          * Loop around, advancing over the mbuf data.
  374          */
  375         while (offs > left) {
  376                 offs -= left;
  377                 nd->nd_md = mbuf_next(nd->nd_md);
  378                 if (nd->nd_md == NULL) {
  379                         error = EBADRPC;
  380                         goto out;
  381                 }
  382                 left = mbuf_len(nd->nd_md);
  383                 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
  384         }
  385         nd->nd_dpos += offs;
  386 
  387 out:
  388         NFSEXITCODE(error);
  389         return (error);
  390 }
  391 
  392 /*
  393  * Copy a string into mbuf(s).
  394  * Return the number of bytes output, including XDR overheads.
  395  */
  396 APPLESTATIC int
  397 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
  398 {
  399         mbuf_t m2;
  400         int xfer, left;
  401         mbuf_t m1;
  402         int rem, bytesize;
  403         u_int32_t *tl;
  404         char *cp2;
  405 
  406         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  407         *tl = txdr_unsigned(siz);
  408         rem = NFSM_RNDUP(siz) - siz;
  409         bytesize = NFSX_UNSIGNED + siz + rem;
  410         m2 = nd->nd_mb;
  411         cp2 = nd->nd_bpos;
  412         left = M_TRAILINGSPACE(m2);
  413 
  414         /*
  415          * Loop around copying the string to mbuf(s).
  416          */
  417         while (siz > 0) {
  418                 if (left == 0) {
  419                         if (siz > ncl_mbuf_mlen)
  420                                 NFSMCLGET(m1, M_WAITOK);
  421                         else
  422                                 NFSMGET(m1);
  423                         mbuf_setlen(m1, 0);
  424                         mbuf_setnext(m2, m1);
  425                         m2 = m1;
  426                         cp2 = NFSMTOD(m2, caddr_t);
  427                         left = M_TRAILINGSPACE(m2);
  428                 }
  429                 if (left >= siz)
  430                         xfer = siz;
  431                 else
  432                         xfer = left;
  433                 NFSBCOPY(cp, cp2, xfer);
  434                 cp += xfer;
  435                 mbuf_setlen(m2, mbuf_len(m2) + xfer);
  436                 siz -= xfer;
  437                 left -= xfer;
  438                 if (siz == 0 && rem) {
  439                         if (left < rem)
  440                                 panic("nfsm_strtom");
  441                         NFSBZERO(cp2 + xfer, rem);
  442                         mbuf_setlen(m2, mbuf_len(m2) + rem);
  443                 }
  444         }
  445         nd->nd_mb = m2;
  446         nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
  447         return (bytesize);
  448 }
  449 
  450 /*
  451  * Called once to initialize data structures...
  452  */
  453 APPLESTATIC void
  454 newnfs_init(void)
  455 {
  456         static int nfs_inited = 0;
  457 
  458         if (nfs_inited)
  459                 return;
  460         nfs_inited = 1;
  461 
  462         newnfs_true = txdr_unsigned(TRUE);
  463         newnfs_false = txdr_unsigned(FALSE);
  464         newnfs_xdrneg1 = txdr_unsigned(-1);
  465         nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
  466         if (nfscl_ticks < 1)
  467                 nfscl_ticks = 1;
  468         NFSSETBOOTTIME(nfsboottime);
  469 
  470         /*
  471          * Initialize reply list and start timer
  472          */
  473         TAILQ_INIT(&nfsd_reqq);
  474         NFS_TIMERINIT;
  475 }
  476 
  477 /*
  478  * Put a file handle in an mbuf list.
  479  * If the size argument == 0, just use the default size.
  480  * set_true == 1 if there should be an newnfs_true prepended on the file handle.
  481  * Return the number of bytes output, including XDR overhead.
  482  */
  483 APPLESTATIC int
  484 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
  485 {
  486         u_int32_t *tl;
  487         u_int8_t *cp;
  488         int fullsiz, rem, bytesize = 0;
  489 
  490         if (size == 0)
  491                 size = NFSX_MYFH;
  492         switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
  493         case ND_NFSV2:
  494                 if (size > NFSX_V2FH)
  495                         panic("fh size > NFSX_V2FH for NFSv2");
  496                 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
  497                 NFSBCOPY(fhp, cp, size);
  498                 if (size < NFSX_V2FH)
  499                         NFSBZERO(cp + size, NFSX_V2FH - size);
  500                 bytesize = NFSX_V2FH;
  501                 break;
  502         case ND_NFSV3:
  503         case ND_NFSV4:
  504                 fullsiz = NFSM_RNDUP(size);
  505                 rem = fullsiz - size;
  506                 if (set_true) {
  507                     bytesize = 2 * NFSX_UNSIGNED + fullsiz;
  508                     NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  509                     *tl = newnfs_true;
  510                 } else {
  511                     bytesize = NFSX_UNSIGNED + fullsiz;
  512                 }
  513                 (void) nfsm_strtom(nd, fhp, size);
  514                 break;
  515         };
  516         return (bytesize);
  517 }
  518 
  519 /*
  520  * This function compares two net addresses by family and returns TRUE
  521  * if they are the same host.
  522  * If there is any doubt, return FALSE.
  523  * The AF_INET family is handled as a special case so that address mbufs
  524  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
  525  */
  526 APPLESTATIC int
  527 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
  528 {
  529         struct sockaddr_in *inetaddr;
  530 
  531         switch (family) {
  532         case AF_INET:
  533                 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
  534                 if (inetaddr->sin_family == AF_INET &&
  535                     inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
  536                         return (1);
  537                 break;
  538 #ifdef INET6
  539         case AF_INET6:
  540                 {
  541                 struct sockaddr_in6 *inetaddr6;
  542 
  543                 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
  544                 /* XXX - should test sin6_scope_id ? */
  545                 if (inetaddr6->sin6_family == AF_INET6 &&
  546                     IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
  547                           &haddr->had_inet6))
  548                         return (1);
  549                 }
  550                 break;
  551 #endif
  552         };
  553         return (0);
  554 }
  555 
  556 /*
  557  * Similar to the above, but takes to NFSSOCKADDR_T args.
  558  */
  559 APPLESTATIC int
  560 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
  561 {
  562         struct sockaddr_in *addr1, *addr2;
  563         struct sockaddr *inaddr;
  564 
  565         inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
  566         switch (inaddr->sa_family) {
  567         case AF_INET:
  568                 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
  569                 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
  570                 if (addr2->sin_family == AF_INET &&
  571                     addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
  572                         return (1);
  573                 break;
  574 #ifdef INET6
  575         case AF_INET6:
  576                 {
  577                 struct sockaddr_in6 *inet6addr1, *inet6addr2;
  578 
  579                 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
  580                 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
  581                 /* XXX - should test sin6_scope_id ? */
  582                 if (inet6addr2->sin6_family == AF_INET6 &&
  583                     IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
  584                           &inet6addr2->sin6_addr))
  585                         return (1);
  586                 }
  587                 break;
  588 #endif
  589         };
  590         return (0);
  591 }
  592 
  593 
  594 /*
  595  * Trim the stuff already dissected off the mbuf list.
  596  */
  597 APPLESTATIC void
  598 newnfs_trimleading(nd)
  599         struct nfsrv_descript *nd;
  600 {
  601         mbuf_t m, n;
  602         int offs;
  603 
  604         /*
  605          * First, free up leading mbufs.
  606          */
  607         if (nd->nd_mrep != nd->nd_md) {
  608                 m = nd->nd_mrep;
  609                 while (mbuf_next(m) != nd->nd_md) {
  610                         if (mbuf_next(m) == NULL)
  611                                 panic("nfsm trim leading");
  612                         m = mbuf_next(m);
  613                 }
  614                 mbuf_setnext(m, NULL);
  615                 mbuf_freem(nd->nd_mrep);
  616         }
  617         m = nd->nd_md;
  618 
  619         /*
  620          * Now, adjust this mbuf, based on nd_dpos.
  621          */
  622         offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
  623         if (offs == mbuf_len(m)) {
  624                 n = m;
  625                 m = mbuf_next(m);
  626                 if (m == NULL)
  627                         panic("nfsm trim leading2");
  628                 mbuf_setnext(n, NULL);
  629                 mbuf_freem(n);
  630         } else if (offs > 0) {
  631                 mbuf_setlen(m, mbuf_len(m) - offs);
  632                 NFSM_DATAP(m, offs);
  633         } else if (offs < 0)
  634                 panic("nfsm trimleading offs");
  635         nd->nd_mrep = m;
  636         nd->nd_md = m;
  637         nd->nd_dpos = NFSMTOD(m, caddr_t);
  638 }
  639 
  640 /*
  641  * Trim trailing data off the mbuf list being built.
  642  */
  643 APPLESTATIC void
  644 newnfs_trimtrailing(nd, mb, bpos)
  645         struct nfsrv_descript *nd;
  646         mbuf_t mb;
  647         caddr_t bpos;
  648 {
  649 
  650         if (mbuf_next(mb)) {
  651                 mbuf_freem(mbuf_next(mb));
  652                 mbuf_setnext(mb, NULL);
  653         }
  654         mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
  655         nd->nd_mb = mb;
  656         nd->nd_bpos = bpos;
  657 }
  658 
  659 /*
  660  * Dissect a file handle on the client.
  661  */
  662 APPLESTATIC int
  663 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
  664 {
  665         u_int32_t *tl;
  666         struct nfsfh *nfhp;
  667         int error, len;
  668 
  669         *nfhpp = NULL;
  670         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
  671                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
  672                 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
  673                         len > NFSX_FHMAX) {
  674                         error = EBADRPC;
  675                         goto nfsmout;
  676                 }
  677         } else
  678                 len = NFSX_V2FH;
  679         MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
  680             M_NFSFH, M_WAITOK);
  681         error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
  682         if (error) {
  683                 FREE((caddr_t)nfhp, M_NFSFH);
  684                 goto nfsmout;
  685         }
  686         nfhp->nfh_len = len;
  687         *nfhpp = nfhp;
  688 nfsmout:
  689         NFSEXITCODE2(error, nd);
  690         return (error);
  691 }
  692 
  693 /*
  694  * Break down the nfsv4 acl.
  695  * If the aclp == NULL or won't fit in an acl, just discard the acl info.
  696  */
  697 APPLESTATIC int
  698 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
  699     int *aclsizep, __unused NFSPROC_T *p)
  700 {
  701         u_int32_t *tl;
  702         int i, aclsize;
  703         int acecnt, error = 0, aceerr = 0, acesize;
  704 
  705         *aclerrp = 0;
  706         if (aclp)
  707                 aclp->acl_cnt = 0;
  708         /*
  709          * Parse out the ace entries and expect them to conform to
  710          * what can be supported by R/W/X bits.
  711          */
  712         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
  713         aclsize = NFSX_UNSIGNED;
  714         acecnt = fxdr_unsigned(int, *tl);
  715         if (acecnt > ACL_MAX_ENTRIES)
  716                 aceerr = NFSERR_ATTRNOTSUPP;
  717         if (nfsrv_useacl == 0)
  718                 aceerr = NFSERR_ATTRNOTSUPP;
  719         for (i = 0; i < acecnt; i++) {
  720                 if (aclp && !aceerr)
  721                         error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
  722                             &aceerr, &acesize, p);
  723                 else
  724                         error = nfsrv_skipace(nd, &acesize);
  725                 if (error)
  726                         goto nfsmout;
  727                 aclsize += acesize;
  728         }
  729         if (aclp && !aceerr)
  730                 aclp->acl_cnt = acecnt;
  731         if (aceerr)
  732                 *aclerrp = aceerr;
  733         if (aclsizep)
  734                 *aclsizep = aclsize;
  735 nfsmout:
  736         NFSEXITCODE2(error, nd);
  737         return (error);
  738 }
  739 
  740 /*
  741  * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
  742  */
  743 static int
  744 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
  745 {
  746         u_int32_t *tl;
  747         int error, len = 0;
  748 
  749         NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
  750         len = fxdr_unsigned(int, *(tl + 3));
  751         error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
  752 nfsmout:
  753         *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
  754         NFSEXITCODE2(error, nd);
  755         return (error);
  756 }
  757 
  758 /*
  759  * Get attribute bits from an mbuf list.
  760  * Returns EBADRPC for a parsing error, 0 otherwise.
  761  * If the clearinvalid flag is set, clear the bits not supported.
  762  */
  763 APPLESTATIC int
  764 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
  765     int *retnotsupp)
  766 {
  767         u_int32_t *tl;
  768         int cnt, i, outcnt;
  769         int error = 0;
  770 
  771         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
  772         cnt = fxdr_unsigned(int, *tl);
  773         if (cnt < 0) {
  774                 error = NFSERR_BADXDR;
  775                 goto nfsmout;
  776         }
  777         if (cnt > NFSATTRBIT_MAXWORDS)
  778                 outcnt = NFSATTRBIT_MAXWORDS;
  779         else
  780                 outcnt = cnt;
  781         NFSZERO_ATTRBIT(attrbitp);
  782         if (outcnt > 0) {
  783                 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
  784                 for (i = 0; i < outcnt; i++)
  785                         attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
  786         }
  787         for (i = 0; i < (cnt - outcnt); i++) {
  788                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
  789                 if (retnotsupp != NULL && *tl != 0)
  790                         *retnotsupp = NFSERR_ATTRNOTSUPP;
  791         }
  792         if (cntp)
  793                 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
  794 nfsmout:
  795         NFSEXITCODE2(error, nd);
  796         return (error);
  797 }
  798 
  799 /*
  800  * Get the attributes for V4.
  801  * If the compare flag is true, test for any attribute changes,
  802  * otherwise return the attribute values.
  803  * These attributes cover fields in "struct vattr", "struct statfs",
  804  * "struct nfsfsinfo", the file handle and the lease duration.
  805  * The value of retcmpp is set to 1 if all attributes are the same,
  806  * and 0 otherwise.
  807  * Returns EBADRPC if it can't be parsed, 0 otherwise.
  808  */
  809 APPLESTATIC int
  810 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
  811     struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
  812     struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
  813     struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
  814     u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
  815 {
  816         u_int32_t *tl;
  817         int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
  818         int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
  819         u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
  820         nfsattrbit_t attrbits, retattrbits, checkattrbits;
  821         struct nfsfh *tnfhp;
  822         struct nfsreferral *refp;
  823         u_quad_t tquad;
  824         nfsquad_t tnfsquad;
  825         struct timespec temptime;
  826         uid_t uid;
  827         gid_t gid;
  828         long fid;
  829         u_int32_t freenum = 0, tuint;
  830         u_int64_t uquad = 0, thyp, thyp2;
  831 #ifdef QUOTA
  832         struct dqblk dqb;
  833         uid_t savuid;
  834 #endif
  835         static struct timeval last64fileid;
  836         static size_t count64fileid;
  837         static struct timeval last64mountfileid;
  838         static size_t count64mountfileid;
  839         static struct timeval warninterval = { 60, 0 };
  840 
  841         if (compare) {
  842                 retnotsup = 0;
  843                 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
  844         } else {
  845                 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
  846         }
  847         if (error)
  848                 goto nfsmout;
  849 
  850         if (compare) {
  851                 *retcmpp = retnotsup;
  852         } else {
  853                 /*
  854                  * Just set default values to some of the important ones.
  855                  */
  856                 if (nap != NULL) {
  857                         nap->na_type = VREG;
  858                         nap->na_mode = 0;
  859                         nap->na_rdev = (NFSDEV_T)0;
  860                         nap->na_mtime.tv_sec = 0;
  861                         nap->na_mtime.tv_nsec = 0;
  862                         nap->na_gen = 0;
  863                         nap->na_flags = 0;
  864                         nap->na_blocksize = NFS_FABLKSIZE;
  865                 }
  866                 if (sbp != NULL) {
  867                         sbp->f_bsize = NFS_FABLKSIZE;
  868                         sbp->f_blocks = 0;
  869                         sbp->f_bfree = 0;
  870                         sbp->f_bavail = 0;
  871                         sbp->f_files = 0;
  872                         sbp->f_ffree = 0;
  873                 }
  874                 if (fsp != NULL) {
  875                         fsp->fs_rtmax = 8192;
  876                         fsp->fs_rtpref = 8192;
  877                         fsp->fs_maxname = NFS_MAXNAMLEN;
  878                         fsp->fs_wtmax = 8192;
  879                         fsp->fs_wtpref = 8192;
  880                         fsp->fs_wtmult = NFS_FABLKSIZE;
  881                         fsp->fs_dtpref = 8192;
  882                         fsp->fs_maxfilesize = 0xffffffffffffffffull;
  883                         fsp->fs_timedelta.tv_sec = 0;
  884                         fsp->fs_timedelta.tv_nsec = 1;
  885                         fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
  886                                 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
  887                 }
  888                 if (pc != NULL) {
  889                         pc->pc_linkmax = LINK_MAX;
  890                         pc->pc_namemax = NAME_MAX;
  891                         pc->pc_notrunc = 0;
  892                         pc->pc_chownrestricted = 0;
  893                         pc->pc_caseinsensitive = 0;
  894                         pc->pc_casepreserving = 1;
  895                 }
  896                 if (sfp != NULL) {
  897                         sfp->sf_ffiles = UINT64_MAX;
  898                         sfp->sf_tfiles = UINT64_MAX;
  899                         sfp->sf_afiles = UINT64_MAX;
  900                         sfp->sf_fbytes = UINT64_MAX;
  901                         sfp->sf_tbytes = UINT64_MAX;
  902                         sfp->sf_abytes = UINT64_MAX;
  903                 }
  904         }
  905 
  906         /*
  907          * Loop around getting the attributes.
  908          */
  909         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
  910         attrsize = fxdr_unsigned(int, *tl);
  911         for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
  912             if (attrsum > attrsize) {
  913                 error = NFSERR_BADXDR;
  914                 goto nfsmout;
  915             }
  916             if (NFSISSET_ATTRBIT(&attrbits, bitpos))
  917                 switch (bitpos) {
  918                 case NFSATTRBIT_SUPPORTEDATTRS:
  919                         retnotsup = 0;
  920                         if (compare || nap == NULL)
  921                             error = nfsrv_getattrbits(nd, &retattrbits,
  922                                 &cnt, &retnotsup);
  923                         else
  924                             error = nfsrv_getattrbits(nd, &nap->na_suppattr,
  925                                 &cnt, &retnotsup);
  926                         if (error)
  927                             goto nfsmout;
  928                         if (compare && !(*retcmpp)) {
  929                            NFSSETSUPP_ATTRBIT(&checkattrbits);
  930                            if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
  931                                || retnotsup)
  932                                 *retcmpp = NFSERR_NOTSAME;
  933                         }
  934                         attrsum += cnt;
  935                         break;
  936                 case NFSATTRBIT_TYPE:
  937                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
  938                         if (compare) {
  939                                 if (!(*retcmpp)) {
  940                                     if (nap->na_type != nfsv34tov_type(*tl))
  941                                         *retcmpp = NFSERR_NOTSAME;
  942                                 }
  943                         } else if (nap != NULL) {
  944                                 nap->na_type = nfsv34tov_type(*tl);
  945                         }
  946                         attrsum += NFSX_UNSIGNED;
  947                         break;
  948                 case NFSATTRBIT_FHEXPIRETYPE:
  949                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
  950                         if (compare && !(*retcmpp)) {
  951                                 if (fxdr_unsigned(int, *tl) !=
  952                                         NFSV4FHTYPE_PERSISTENT)
  953                                         *retcmpp = NFSERR_NOTSAME;
  954                         }
  955                         attrsum += NFSX_UNSIGNED;
  956                         break;
  957                 case NFSATTRBIT_CHANGE:
  958                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
  959                         if (compare) {
  960                                 if (!(*retcmpp)) {
  961                                     if (nap->na_filerev != fxdr_hyper(tl))
  962                                         *retcmpp = NFSERR_NOTSAME;
  963                                 }
  964                         } else if (nap != NULL) {
  965                                 nap->na_filerev = fxdr_hyper(tl);
  966                         }
  967                         attrsum += NFSX_HYPER;
  968                         break;
  969                 case NFSATTRBIT_SIZE:
  970                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
  971                         if (compare) {
  972                                 if (!(*retcmpp)) {
  973                                     if (nap->na_size != fxdr_hyper(tl))
  974                                         *retcmpp = NFSERR_NOTSAME;
  975                                 }
  976                         } else if (nap != NULL) {
  977                                 nap->na_size = fxdr_hyper(tl);
  978                         }
  979                         attrsum += NFSX_HYPER;
  980                         break;
  981                 case NFSATTRBIT_LINKSUPPORT:
  982                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
  983                         if (compare) {
  984                                 if (!(*retcmpp)) {
  985                                     if (fsp->fs_properties & NFSV3_FSFLINK) {
  986                                         if (*tl == newnfs_false)
  987                                                 *retcmpp = NFSERR_NOTSAME;
  988                                     } else {
  989                                         if (*tl == newnfs_true)
  990                                                 *retcmpp = NFSERR_NOTSAME;
  991                                     }
  992                                 }
  993                         } else if (fsp != NULL) {
  994                                 if (*tl == newnfs_true)
  995                                         fsp->fs_properties |= NFSV3_FSFLINK;
  996                                 else
  997                                         fsp->fs_properties &= ~NFSV3_FSFLINK;
  998                         }
  999                         attrsum += NFSX_UNSIGNED;
 1000                         break;
 1001                 case NFSATTRBIT_SYMLINKSUPPORT:
 1002                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1003                         if (compare) {
 1004                                 if (!(*retcmpp)) {
 1005                                     if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
 1006                                         if (*tl == newnfs_false)
 1007                                                 *retcmpp = NFSERR_NOTSAME;
 1008                                     } else {
 1009                                         if (*tl == newnfs_true)
 1010                                                 *retcmpp = NFSERR_NOTSAME;
 1011                                     }
 1012                                 }
 1013                         } else if (fsp != NULL) {
 1014                                 if (*tl == newnfs_true)
 1015                                         fsp->fs_properties |= NFSV3_FSFSYMLINK;
 1016                                 else
 1017                                         fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
 1018                         }
 1019                         attrsum += NFSX_UNSIGNED;
 1020                         break;
 1021                 case NFSATTRBIT_NAMEDATTR:
 1022                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1023                         if (compare && !(*retcmpp)) {
 1024                                 if (*tl != newnfs_false)
 1025                                         *retcmpp = NFSERR_NOTSAME;
 1026                         }
 1027                         attrsum += NFSX_UNSIGNED;
 1028                         break;
 1029                 case NFSATTRBIT_FSID:
 1030                         NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 1031                         thyp = fxdr_hyper(tl);
 1032                         tl += 2;
 1033                         thyp2 = fxdr_hyper(tl);
 1034                         if (compare) {
 1035                             if (*retcmpp == 0) {
 1036                                 if (thyp != (u_int64_t)
 1037                                     vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
 1038                                     thyp2 != (u_int64_t)
 1039                                     vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
 1040                                         *retcmpp = NFSERR_NOTSAME;
 1041                             }
 1042                         } else if (nap != NULL) {
 1043                                 nap->na_filesid[0] = thyp;
 1044                                 nap->na_filesid[1] = thyp2;
 1045                         }
 1046                         attrsum += (4 * NFSX_UNSIGNED);
 1047                         break;
 1048                 case NFSATTRBIT_UNIQUEHANDLES:
 1049                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1050                         if (compare && !(*retcmpp)) {
 1051                                 if (*tl != newnfs_true)
 1052                                         *retcmpp = NFSERR_NOTSAME;
 1053                         }
 1054                         attrsum += NFSX_UNSIGNED;
 1055                         break;
 1056                 case NFSATTRBIT_LEASETIME:
 1057                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1058                         if (compare) {
 1059                                 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
 1060                                     !(*retcmpp))
 1061                                         *retcmpp = NFSERR_NOTSAME;
 1062                         } else if (leasep != NULL) {
 1063                                 *leasep = fxdr_unsigned(u_int32_t, *tl);
 1064                         }
 1065                         attrsum += NFSX_UNSIGNED;
 1066                         break;
 1067                 case NFSATTRBIT_RDATTRERROR:
 1068                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1069                         if (compare) {
 1070                                  if (!(*retcmpp))
 1071                                         *retcmpp = NFSERR_INVAL;
 1072                         } else if (rderrp != NULL) {
 1073                                 *rderrp = fxdr_unsigned(u_int32_t, *tl);
 1074                         }
 1075                         attrsum += NFSX_UNSIGNED;
 1076                         break;
 1077                 case NFSATTRBIT_ACL:
 1078                         if (compare) {
 1079                           if (!(*retcmpp)) {
 1080                             if (nfsrv_useacl) {
 1081                                 NFSACL_T *naclp;
 1082 
 1083                                 naclp = acl_alloc(M_WAITOK);
 1084                                 error = nfsrv_dissectacl(nd, naclp, &aceerr,
 1085                                     &cnt, p);
 1086                                 if (error) {
 1087                                     acl_free(naclp);
 1088                                     goto nfsmout;
 1089                                 }
 1090                                 if (aceerr || aclp == NULL ||
 1091                                     nfsrv_compareacl(aclp, naclp))
 1092                                     *retcmpp = NFSERR_NOTSAME;
 1093                                 acl_free(naclp);
 1094                             } else {
 1095                                 error = nfsrv_dissectacl(nd, NULL, &aceerr,
 1096                                     &cnt, p);
 1097                                 *retcmpp = NFSERR_ATTRNOTSUPP;
 1098                             }
 1099                           }
 1100                         } else {
 1101                             if (vp != NULL && aclp != NULL)
 1102                                 error = nfsrv_dissectacl(nd, aclp, &aceerr,
 1103                                     &cnt, p);
 1104                             else
 1105                                 error = nfsrv_dissectacl(nd, NULL, &aceerr,
 1106                                     &cnt, p);
 1107                             if (error)
 1108                                 goto nfsmout;
 1109                         }
 1110                         attrsum += cnt;
 1111                         break;
 1112                 case NFSATTRBIT_ACLSUPPORT:
 1113                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1114                         if (compare && !(*retcmpp)) {
 1115                                 if (nfsrv_useacl) {
 1116                                         if (fxdr_unsigned(u_int32_t, *tl) !=
 1117                                             NFSV4ACE_SUPTYPES)
 1118                                                 *retcmpp = NFSERR_NOTSAME;
 1119                                 } else {
 1120                                         *retcmpp = NFSERR_ATTRNOTSUPP;
 1121                                 }
 1122                         }
 1123                         attrsum += NFSX_UNSIGNED;
 1124                         break;
 1125                 case NFSATTRBIT_ARCHIVE:
 1126                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1127                         if (compare && !(*retcmpp))
 1128                                 *retcmpp = NFSERR_ATTRNOTSUPP;
 1129                         attrsum += NFSX_UNSIGNED;
 1130                         break;
 1131                 case NFSATTRBIT_CANSETTIME:
 1132                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1133                         if (compare) {
 1134                                 if (!(*retcmpp)) {
 1135                                     if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
 1136                                         if (*tl == newnfs_false)
 1137                                                 *retcmpp = NFSERR_NOTSAME;
 1138                                     } else {
 1139                                         if (*tl == newnfs_true)
 1140                                                 *retcmpp = NFSERR_NOTSAME;
 1141                                     }
 1142                                 }
 1143                         } else if (fsp != NULL) {
 1144                                 if (*tl == newnfs_true)
 1145                                         fsp->fs_properties |= NFSV3_FSFCANSETTIME;
 1146                                 else
 1147                                         fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
 1148                         }
 1149                         attrsum += NFSX_UNSIGNED;
 1150                         break;
 1151                 case NFSATTRBIT_CASEINSENSITIVE:
 1152                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1153                         if (compare) {
 1154                                 if (!(*retcmpp)) {
 1155                                     if (*tl != newnfs_false)
 1156                                         *retcmpp = NFSERR_NOTSAME;
 1157                                 }
 1158                         } else if (pc != NULL) {
 1159                                 pc->pc_caseinsensitive =
 1160                                     fxdr_unsigned(u_int32_t, *tl);
 1161                         }
 1162                         attrsum += NFSX_UNSIGNED;
 1163                         break;
 1164                 case NFSATTRBIT_CASEPRESERVING:
 1165                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1166                         if (compare) {
 1167                                 if (!(*retcmpp)) {
 1168                                     if (*tl != newnfs_true)
 1169                                         *retcmpp = NFSERR_NOTSAME;
 1170                                 }
 1171                         } else if (pc != NULL) {
 1172                                 pc->pc_casepreserving =
 1173                                     fxdr_unsigned(u_int32_t, *tl);
 1174                         }
 1175                         attrsum += NFSX_UNSIGNED;
 1176                         break;
 1177                 case NFSATTRBIT_CHOWNRESTRICTED:
 1178                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1179                         if (compare) {
 1180                                 if (!(*retcmpp)) {
 1181                                     if (*tl != newnfs_true)
 1182                                         *retcmpp = NFSERR_NOTSAME;
 1183                                 }
 1184                         } else if (pc != NULL) {
 1185                                 pc->pc_chownrestricted =
 1186                                     fxdr_unsigned(u_int32_t, *tl);
 1187                         }
 1188                         attrsum += NFSX_UNSIGNED;
 1189                         break;
 1190                 case NFSATTRBIT_FILEHANDLE:
 1191                         error = nfsm_getfh(nd, &tnfhp);
 1192                         if (error)
 1193                                 goto nfsmout;
 1194                         tfhsize = tnfhp->nfh_len;
 1195                         if (compare) {
 1196                                 if (!(*retcmpp) &&
 1197                                     !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
 1198                                      fhp, fhsize))
 1199                                         *retcmpp = NFSERR_NOTSAME;
 1200                                 FREE((caddr_t)tnfhp, M_NFSFH);
 1201                         } else if (nfhpp != NULL) {
 1202                                 *nfhpp = tnfhp;
 1203                         } else {
 1204                                 FREE((caddr_t)tnfhp, M_NFSFH);
 1205                         }
 1206                         attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
 1207                         break;
 1208                 case NFSATTRBIT_FILEID:
 1209                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1210                         thyp = fxdr_hyper(tl);
 1211                         if (compare) {
 1212                                 if (!(*retcmpp)) {
 1213                                     if ((u_int64_t)nap->na_fileid != thyp)
 1214                                         *retcmpp = NFSERR_NOTSAME;
 1215                                 }
 1216                         } else if (nap != NULL) {
 1217                                 if (*tl++) {
 1218                                         count64fileid++;
 1219                                         if (ratecheck(&last64fileid, &warninterval)) {
 1220                                                 printf("NFSv4 fileid > 32bits (%zu occurrences)\n",
 1221                                                     count64fileid);
 1222                                                 count64fileid = 0;
 1223                                         }
 1224                                 }
 1225                                 nap->na_fileid = thyp;
 1226                         }
 1227                         attrsum += NFSX_HYPER;
 1228                         break;
 1229                 case NFSATTRBIT_FILESAVAIL:
 1230                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1231                         if (compare) {
 1232                                 if (!(*retcmpp) &&
 1233                                     sfp->sf_afiles != fxdr_hyper(tl))
 1234                                         *retcmpp = NFSERR_NOTSAME;
 1235                         } else if (sfp != NULL) {
 1236                                 sfp->sf_afiles = fxdr_hyper(tl);
 1237                         }
 1238                         attrsum += NFSX_HYPER;
 1239                         break;
 1240                 case NFSATTRBIT_FILESFREE:
 1241                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1242                         if (compare) {
 1243                                 if (!(*retcmpp) &&
 1244                                     sfp->sf_ffiles != fxdr_hyper(tl))
 1245                                         *retcmpp = NFSERR_NOTSAME;
 1246                         } else if (sfp != NULL) {
 1247                                 sfp->sf_ffiles = fxdr_hyper(tl);
 1248                         }
 1249                         attrsum += NFSX_HYPER;
 1250                         break;
 1251                 case NFSATTRBIT_FILESTOTAL:
 1252                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1253                         if (compare) {
 1254                                 if (!(*retcmpp) &&
 1255                                     sfp->sf_tfiles != fxdr_hyper(tl))
 1256                                         *retcmpp = NFSERR_NOTSAME;
 1257                         } else if (sfp != NULL) {
 1258                                 sfp->sf_tfiles = fxdr_hyper(tl);
 1259                         }
 1260                         attrsum += NFSX_HYPER;
 1261                         break;
 1262                 case NFSATTRBIT_FSLOCATIONS:
 1263                         error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
 1264                         if (error)
 1265                                 goto nfsmout;
 1266                         attrsum += l;
 1267                         if (compare && !(*retcmpp)) {
 1268                                 refp = nfsv4root_getreferral(vp, NULL, 0);
 1269                                 if (refp != NULL) {
 1270                                         if (cp == NULL || cp2 == NULL ||
 1271                                             strcmp(cp, "/") ||
 1272                                             strcmp(cp2, refp->nfr_srvlist))
 1273                                                 *retcmpp = NFSERR_NOTSAME;
 1274                                 } else if (m == 0) {
 1275                                         *retcmpp = NFSERR_NOTSAME;
 1276                                 }
 1277                         }
 1278                         if (cp != NULL)
 1279                                 free(cp, M_NFSSTRING);
 1280                         if (cp2 != NULL)
 1281                                 free(cp2, M_NFSSTRING);
 1282                         break;
 1283                 case NFSATTRBIT_HIDDEN:
 1284                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1285                         if (compare && !(*retcmpp))
 1286                                 *retcmpp = NFSERR_ATTRNOTSUPP;
 1287                         attrsum += NFSX_UNSIGNED;
 1288                         break;
 1289                 case NFSATTRBIT_HOMOGENEOUS:
 1290                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1291                         if (compare) {
 1292                                 if (!(*retcmpp)) {
 1293                                     if (fsp->fs_properties &
 1294                                         NFSV3_FSFHOMOGENEOUS) {
 1295                                         if (*tl == newnfs_false)
 1296                                                 *retcmpp = NFSERR_NOTSAME;
 1297                                     } else {
 1298                                         if (*tl == newnfs_true)
 1299                                                 *retcmpp = NFSERR_NOTSAME;
 1300                                     }
 1301                                 }
 1302                         } else if (fsp != NULL) {
 1303                                 if (*tl == newnfs_true)
 1304                                     fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
 1305                                 else
 1306                                     fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
 1307                         }
 1308                         attrsum += NFSX_UNSIGNED;
 1309                         break;
 1310                 case NFSATTRBIT_MAXFILESIZE:
 1311                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1312                         tnfsquad.qval = fxdr_hyper(tl);
 1313                         if (compare) {
 1314                                 if (!(*retcmpp)) {
 1315                                         tquad = NFSRV_MAXFILESIZE;
 1316                                         if (tquad != tnfsquad.qval)
 1317                                                 *retcmpp = NFSERR_NOTSAME;
 1318                                 }
 1319                         } else if (fsp != NULL) {
 1320                                 fsp->fs_maxfilesize = tnfsquad.qval;
 1321                         }
 1322                         attrsum += NFSX_HYPER;
 1323                         break;
 1324                 case NFSATTRBIT_MAXLINK:
 1325                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1326                         if (compare) {
 1327                                 if (!(*retcmpp)) {
 1328                                     if (fxdr_unsigned(int, *tl) != LINK_MAX)
 1329                                         *retcmpp = NFSERR_NOTSAME;
 1330                                 }
 1331                         } else if (pc != NULL) {
 1332                                 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
 1333                         }
 1334                         attrsum += NFSX_UNSIGNED;
 1335                         break;
 1336                 case NFSATTRBIT_MAXNAME:
 1337                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1338                         if (compare) {
 1339                                 if (!(*retcmpp)) {
 1340                                     if (fsp->fs_maxname !=
 1341                                         fxdr_unsigned(u_int32_t, *tl))
 1342                                                 *retcmpp = NFSERR_NOTSAME;
 1343                                 }
 1344                         } else {
 1345                                 tuint = fxdr_unsigned(u_int32_t, *tl);
 1346                                 /*
 1347                                  * Some Linux NFSv4 servers report this
 1348                                  * as 0 or 4billion, so I'll set it to
 1349                                  * NFS_MAXNAMLEN. If a server actually creates
 1350                                  * a name longer than NFS_MAXNAMLEN, it will
 1351                                  * get an error back.
 1352                                  */
 1353                                 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
 1354                                         tuint = NFS_MAXNAMLEN;
 1355                                 if (fsp != NULL)
 1356                                         fsp->fs_maxname = tuint;
 1357                                 if (pc != NULL)
 1358                                         pc->pc_namemax = tuint;
 1359                         }
 1360                         attrsum += NFSX_UNSIGNED;
 1361                         break;
 1362                 case NFSATTRBIT_MAXREAD:
 1363                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1364                         if (compare) {
 1365                                 if (!(*retcmpp)) {
 1366                                     if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
 1367                                         *(tl + 1)) || *tl != 0)
 1368                                         *retcmpp = NFSERR_NOTSAME;
 1369                                 }
 1370                         } else if (fsp != NULL) {
 1371                                 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
 1372                                 fsp->fs_rtpref = fsp->fs_rtmax;
 1373                                 fsp->fs_dtpref = fsp->fs_rtpref;
 1374                         }
 1375                         attrsum += NFSX_HYPER;
 1376                         break;
 1377                 case NFSATTRBIT_MAXWRITE:
 1378                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1379                         if (compare) {
 1380                                 if (!(*retcmpp)) {
 1381                                     if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
 1382                                         *(tl + 1)) || *tl != 0)
 1383                                         *retcmpp = NFSERR_NOTSAME;
 1384                                 }
 1385                         } else if (fsp != NULL) {
 1386                                 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
 1387                                 fsp->fs_wtpref = fsp->fs_wtmax;
 1388                         }
 1389                         attrsum += NFSX_HYPER;
 1390                         break;
 1391                 case NFSATTRBIT_MIMETYPE:
 1392                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1393                         i = fxdr_unsigned(int, *tl);
 1394                         attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
 1395                         error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
 1396                         if (error)
 1397                                 goto nfsmout;
 1398                         if (compare && !(*retcmpp))
 1399                                 *retcmpp = NFSERR_ATTRNOTSUPP;
 1400                         break;
 1401                 case NFSATTRBIT_MODE:
 1402                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1403                         if (compare) {
 1404                                 if (!(*retcmpp)) {
 1405                                     if (nap->na_mode != nfstov_mode(*tl))
 1406                                         *retcmpp = NFSERR_NOTSAME;
 1407                                 }
 1408                         } else if (nap != NULL) {
 1409                                 nap->na_mode = nfstov_mode(*tl);
 1410                         }
 1411                         attrsum += NFSX_UNSIGNED;
 1412                         break;
 1413                 case NFSATTRBIT_NOTRUNC:
 1414                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1415                         if (compare) {
 1416                                 if (!(*retcmpp)) {
 1417                                     if (*tl != newnfs_true)
 1418                                         *retcmpp = NFSERR_NOTSAME;
 1419                                 }
 1420                         } else if (pc != NULL) {
 1421                                 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
 1422                         }
 1423                         attrsum += NFSX_UNSIGNED;
 1424                         break;
 1425                 case NFSATTRBIT_NUMLINKS:
 1426                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1427                         tuint = fxdr_unsigned(u_int32_t, *tl);
 1428                         if (compare) {
 1429                             if (!(*retcmpp)) {
 1430                                 if ((u_int32_t)nap->na_nlink != tuint)
 1431                                         *retcmpp = NFSERR_NOTSAME;
 1432                             }
 1433                         } else if (nap != NULL) {
 1434                                 nap->na_nlink = tuint;
 1435                         }
 1436                         attrsum += NFSX_UNSIGNED;
 1437                         break;
 1438                 case NFSATTRBIT_OWNER:
 1439                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1440                         j = fxdr_unsigned(int, *tl);
 1441                         if (j < 0) {
 1442                                 error = NFSERR_BADXDR;
 1443                                 goto nfsmout;
 1444                         }
 1445                         attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
 1446                         if (j > NFSV4_SMALLSTR)
 1447                                 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
 1448                         else
 1449                                 cp = namestr;
 1450                         error = nfsrv_mtostr(nd, cp, j);
 1451                         if (error) {
 1452                                 if (j > NFSV4_SMALLSTR)
 1453                                         free(cp, M_NFSSTRING);
 1454                                 goto nfsmout;
 1455                         }
 1456                         if (compare) {
 1457                             if (!(*retcmpp)) {
 1458                                 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
 1459                                     nap->na_uid != uid)
 1460                                     *retcmpp = NFSERR_NOTSAME;
 1461                             }
 1462                         } else if (nap != NULL) {
 1463                                 if (nfsv4_strtouid(nd, cp, j, &uid, p))
 1464                                         nap->na_uid = nfsrv_defaultuid;
 1465                                 else
 1466                                         nap->na_uid = uid;
 1467                         }
 1468                         if (j > NFSV4_SMALLSTR)
 1469                                 free(cp, M_NFSSTRING);
 1470                         break;
 1471                 case NFSATTRBIT_OWNERGROUP:
 1472                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1473                         j = fxdr_unsigned(int, *tl);
 1474                         if (j < 0) {
 1475                                 error =  NFSERR_BADXDR;
 1476                                 goto nfsmout;
 1477                         }
 1478                         attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
 1479                         if (j > NFSV4_SMALLSTR)
 1480                                 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
 1481                         else
 1482                                 cp = namestr;
 1483                         error = nfsrv_mtostr(nd, cp, j);
 1484                         if (error) {
 1485                                 if (j > NFSV4_SMALLSTR)
 1486                                         free(cp, M_NFSSTRING);
 1487                                 goto nfsmout;
 1488                         }
 1489                         if (compare) {
 1490                             if (!(*retcmpp)) {
 1491                                 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
 1492                                     nap->na_gid != gid)
 1493                                     *retcmpp = NFSERR_NOTSAME;
 1494                             }
 1495                         } else if (nap != NULL) {
 1496                                 if (nfsv4_strtogid(nd, cp, j, &gid, p))
 1497                                         nap->na_gid = nfsrv_defaultgid;
 1498                                 else
 1499                                         nap->na_gid = gid;
 1500                         }
 1501                         if (j > NFSV4_SMALLSTR)
 1502                                 free(cp, M_NFSSTRING);
 1503                         break;
 1504                 case NFSATTRBIT_QUOTAHARD:
 1505                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1506                         if (sbp != NULL) {
 1507                             if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
 1508                                 freenum = sbp->f_bfree;
 1509                             else
 1510                                 freenum = sbp->f_bavail;
 1511 #ifdef QUOTA
 1512                             /*
 1513                              * ufs_quotactl() insists that the uid argument
 1514                              * equal p_ruid for non-root quota access, so
 1515                              * we'll just make sure that's the case.
 1516                              */
 1517                             savuid = p->p_cred->p_ruid;
 1518                             p->p_cred->p_ruid = cred->cr_uid;
 1519                             if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
 1520                                 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
 1521                                 freenum = min(dqb.dqb_bhardlimit, freenum);
 1522                             p->p_cred->p_ruid = savuid;
 1523 #endif  /* QUOTA */
 1524                             uquad = (u_int64_t)freenum;
 1525                             NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
 1526                         }
 1527                         if (compare && !(*retcmpp)) {
 1528                                 if (uquad != fxdr_hyper(tl))
 1529                                         *retcmpp = NFSERR_NOTSAME;
 1530                         }
 1531                         attrsum += NFSX_HYPER;
 1532                         break;
 1533                 case NFSATTRBIT_QUOTASOFT:
 1534                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1535                         if (sbp != NULL) {
 1536                             if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
 1537                                 freenum = sbp->f_bfree;
 1538                             else
 1539                                 freenum = sbp->f_bavail;
 1540 #ifdef QUOTA
 1541                             /*
 1542                              * ufs_quotactl() insists that the uid argument
 1543                              * equal p_ruid for non-root quota access, so
 1544                              * we'll just make sure that's the case.
 1545                              */
 1546                             savuid = p->p_cred->p_ruid;
 1547                             p->p_cred->p_ruid = cred->cr_uid;
 1548                             if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
 1549                                 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
 1550                                 freenum = min(dqb.dqb_bsoftlimit, freenum);
 1551                             p->p_cred->p_ruid = savuid;
 1552 #endif  /* QUOTA */
 1553                             uquad = (u_int64_t)freenum;
 1554                             NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
 1555                         }
 1556                         if (compare && !(*retcmpp)) {
 1557                                 if (uquad != fxdr_hyper(tl))
 1558                                         *retcmpp = NFSERR_NOTSAME;
 1559                         }
 1560                         attrsum += NFSX_HYPER;
 1561                         break;
 1562                 case NFSATTRBIT_QUOTAUSED:
 1563                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1564                         if (sbp != NULL) {
 1565                             freenum = 0;
 1566 #ifdef QUOTA
 1567                             /*
 1568                              * ufs_quotactl() insists that the uid argument
 1569                              * equal p_ruid for non-root quota access, so
 1570                              * we'll just make sure that's the case.
 1571                              */
 1572                             savuid = p->p_cred->p_ruid;
 1573                             p->p_cred->p_ruid = cred->cr_uid;
 1574                             if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
 1575                                 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
 1576                                 freenum = dqb.dqb_curblocks;
 1577                             p->p_cred->p_ruid = savuid;
 1578 #endif  /* QUOTA */
 1579                             uquad = (u_int64_t)freenum;
 1580                             NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
 1581                         }
 1582                         if (compare && !(*retcmpp)) {
 1583                                 if (uquad != fxdr_hyper(tl))
 1584                                         *retcmpp = NFSERR_NOTSAME;
 1585                         }
 1586                         attrsum += NFSX_HYPER;
 1587                         break;
 1588                 case NFSATTRBIT_RAWDEV:
 1589                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
 1590                         j = fxdr_unsigned(int, *tl++);
 1591                         k = fxdr_unsigned(int, *tl);
 1592                         if (compare) {
 1593                             if (!(*retcmpp)) {
 1594                                 if (nap->na_rdev != NFSMAKEDEV(j, k))
 1595                                         *retcmpp = NFSERR_NOTSAME;
 1596                             }
 1597                         } else if (nap != NULL) {
 1598                                 nap->na_rdev = NFSMAKEDEV(j, k);
 1599                         }
 1600                         attrsum += NFSX_V4SPECDATA;
 1601                         break;
 1602                 case NFSATTRBIT_SPACEAVAIL:
 1603                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1604                         if (compare) {
 1605                                 if (!(*retcmpp) &&
 1606                                     sfp->sf_abytes != fxdr_hyper(tl))
 1607                                         *retcmpp = NFSERR_NOTSAME;
 1608                         } else if (sfp != NULL) {
 1609                                 sfp->sf_abytes = fxdr_hyper(tl);
 1610                         }
 1611                         attrsum += NFSX_HYPER;
 1612                         break;
 1613                 case NFSATTRBIT_SPACEFREE:
 1614                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1615                         if (compare) {
 1616                                 if (!(*retcmpp) &&
 1617                                     sfp->sf_fbytes != fxdr_hyper(tl))
 1618                                         *retcmpp = NFSERR_NOTSAME;
 1619                         } else if (sfp != NULL) {
 1620                                 sfp->sf_fbytes = fxdr_hyper(tl);
 1621                         }
 1622                         attrsum += NFSX_HYPER;
 1623                         break;
 1624                 case NFSATTRBIT_SPACETOTAL:
 1625                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1626                         if (compare) {
 1627                                 if (!(*retcmpp) &&
 1628                                     sfp->sf_tbytes != fxdr_hyper(tl))
 1629                                         *retcmpp = NFSERR_NOTSAME;
 1630                         } else if (sfp != NULL) {
 1631                                 sfp->sf_tbytes = fxdr_hyper(tl);
 1632                         }
 1633                         attrsum += NFSX_HYPER;
 1634                         break;
 1635                 case NFSATTRBIT_SPACEUSED:
 1636                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1637                         thyp = fxdr_hyper(tl);
 1638                         if (compare) {
 1639                             if (!(*retcmpp)) {
 1640                                 if ((u_int64_t)nap->na_bytes != thyp)
 1641                                         *retcmpp = NFSERR_NOTSAME;
 1642                             }
 1643                         } else if (nap != NULL) {
 1644                                 nap->na_bytes = thyp;
 1645                         }
 1646                         attrsum += NFSX_HYPER;
 1647                         break;
 1648                 case NFSATTRBIT_SYSTEM:
 1649                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1650                         if (compare && !(*retcmpp))
 1651                                 *retcmpp = NFSERR_ATTRNOTSUPP;
 1652                         attrsum += NFSX_UNSIGNED;
 1653                         break;
 1654                 case NFSATTRBIT_TIMEACCESS:
 1655                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
 1656                         fxdr_nfsv4time(tl, &temptime);
 1657                         if (compare) {
 1658                             if (!(*retcmpp)) {
 1659                                 if (!NFS_CMPTIME(temptime, nap->na_atime))
 1660                                         *retcmpp = NFSERR_NOTSAME;
 1661                             }
 1662                         } else if (nap != NULL) {
 1663                                 nap->na_atime = temptime;
 1664                         }
 1665                         attrsum += NFSX_V4TIME;
 1666                         break;
 1667                 case NFSATTRBIT_TIMEACCESSSET:
 1668                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1669                         attrsum += NFSX_UNSIGNED;
 1670                         i = fxdr_unsigned(int, *tl);
 1671                         if (i == NFSV4SATTRTIME_TOCLIENT) {
 1672                                 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
 1673                                 attrsum += NFSX_V4TIME;
 1674                         }
 1675                         if (compare && !(*retcmpp))
 1676                                 *retcmpp = NFSERR_INVAL;
 1677                         break;
 1678                 case NFSATTRBIT_TIMEBACKUP:
 1679                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
 1680                         if (compare && !(*retcmpp))
 1681                                 *retcmpp = NFSERR_ATTRNOTSUPP;
 1682                         attrsum += NFSX_V4TIME;
 1683                         break;
 1684                 case NFSATTRBIT_TIMECREATE:
 1685                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
 1686                         if (compare && !(*retcmpp))
 1687                                 *retcmpp = NFSERR_ATTRNOTSUPP;
 1688                         attrsum += NFSX_V4TIME;
 1689                         break;
 1690                 case NFSATTRBIT_TIMEDELTA:
 1691                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
 1692                         if (fsp != NULL) {
 1693                             if (compare) {
 1694                                 if (!(*retcmpp)) {
 1695                                     if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
 1696                                         fxdr_unsigned(u_int32_t, *(tl + 1)) ||
 1697                                         (u_int32_t)fsp->fs_timedelta.tv_nsec !=
 1698                                         (fxdr_unsigned(u_int32_t, *(tl + 2)) %
 1699                                          1000000000) ||
 1700                                         *tl != 0)
 1701                                             *retcmpp = NFSERR_NOTSAME;
 1702                                 }
 1703                             } else {
 1704                                 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
 1705                             }
 1706                         }
 1707                         attrsum += NFSX_V4TIME;
 1708                         break;
 1709                 case NFSATTRBIT_TIMEMETADATA:
 1710                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
 1711                         fxdr_nfsv4time(tl, &temptime);
 1712                         if (compare) {
 1713                             if (!(*retcmpp)) {
 1714                                 if (!NFS_CMPTIME(temptime, nap->na_ctime))
 1715                                         *retcmpp = NFSERR_NOTSAME;
 1716                             }
 1717                         } else if (nap != NULL) {
 1718                                 nap->na_ctime = temptime;
 1719                         }
 1720                         attrsum += NFSX_V4TIME;
 1721                         break;
 1722                 case NFSATTRBIT_TIMEMODIFY:
 1723                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
 1724                         fxdr_nfsv4time(tl, &temptime);
 1725                         if (compare) {
 1726                             if (!(*retcmpp)) {
 1727                                 if (!NFS_CMPTIME(temptime, nap->na_mtime))
 1728                                         *retcmpp = NFSERR_NOTSAME;
 1729                             }
 1730                         } else if (nap != NULL) {
 1731                                 nap->na_mtime = temptime;
 1732                         }
 1733                         attrsum += NFSX_V4TIME;
 1734                         break;
 1735                 case NFSATTRBIT_TIMEMODIFYSET:
 1736                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1737                         attrsum += NFSX_UNSIGNED;
 1738                         i = fxdr_unsigned(int, *tl);
 1739                         if (i == NFSV4SATTRTIME_TOCLIENT) {
 1740                                 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
 1741                                 attrsum += NFSX_V4TIME;
 1742                         }
 1743                         if (compare && !(*retcmpp))
 1744                                 *retcmpp = NFSERR_INVAL;
 1745                         break;
 1746                 case NFSATTRBIT_MOUNTEDONFILEID:
 1747                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1748                         thyp = fxdr_hyper(tl);
 1749                         if (compare) {
 1750                             if (!(*retcmpp)) {
 1751                                 if (*tl++) {
 1752                                         *retcmpp = NFSERR_NOTSAME;
 1753                                 } else {
 1754                                         if (!vp || !nfsrv_atroot(vp, &fid))
 1755                                                 fid = nap->na_fileid;
 1756                                         if ((u_int64_t)fid != thyp)
 1757                                                 *retcmpp = NFSERR_NOTSAME;
 1758                                 }
 1759                             }
 1760                         } else if (nap != NULL) {
 1761                             if (*tl++) {
 1762                                 count64mountfileid++;
 1763                                 if (ratecheck(&last64mountfileid, &warninterval)) {
 1764                                         printf("NFSv4 mounted on fileid > 32bits (%zu occurrences)\n",
 1765                                             count64mountfileid);
 1766                                         count64mountfileid = 0;
 1767                                 }
 1768                             }
 1769                             nap->na_mntonfileno = thyp;
 1770                         }
 1771                         attrsum += NFSX_HYPER;
 1772                         break;
 1773                 case NFSATTRBIT_SUPPATTREXCLCREAT:
 1774                         retnotsup = 0;
 1775                         error = nfsrv_getattrbits(nd, &retattrbits,
 1776                             &cnt, &retnotsup);
 1777                         if (error)
 1778                             goto nfsmout;
 1779                         if (compare && !(*retcmpp)) {
 1780                            NFSSETSUPP_ATTRBIT(&checkattrbits);
 1781                            NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits);
 1782                            NFSCLRBIT_ATTRBIT(&checkattrbits,
 1783                                 NFSATTRBIT_TIMEACCESSSET);
 1784                            if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
 1785                                || retnotsup)
 1786                                 *retcmpp = NFSERR_NOTSAME;
 1787                         }
 1788                         attrsum += cnt;
 1789                         break;
 1790                 default:
 1791                         printf("EEK! nfsv4_loadattr unknown attr=%d\n",
 1792                                 bitpos);
 1793                         if (compare && !(*retcmpp))
 1794                                 *retcmpp = NFSERR_ATTRNOTSUPP;
 1795                         /*
 1796                          * and get out of the loop, since we can't parse
 1797                          * the unknown attrbute data.
 1798                          */
 1799                         bitpos = NFSATTRBIT_MAX;
 1800                         break;
 1801                 };
 1802         }
 1803 
 1804         /*
 1805          * some clients pad the attrlist, so we need to skip over the
 1806          * padding.
 1807          */
 1808         if (attrsum > attrsize) {
 1809                 error = NFSERR_BADXDR;
 1810         } else {
 1811                 attrsize = NFSM_RNDUP(attrsize);
 1812                 if (attrsum < attrsize)
 1813                         error = nfsm_advance(nd, attrsize - attrsum, -1);
 1814         }
 1815 nfsmout:
 1816         NFSEXITCODE2(error, nd);
 1817         return (error);
 1818 }
 1819 
 1820 /*
 1821  * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
 1822  * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
 1823  * The first argument is a pointer to an nfsv4lock structure.
 1824  * The second argument is 1 iff a blocking lock is wanted.
 1825  * If this argument is 0, the call waits until no thread either wants nor
 1826  * holds an exclusive lock.
 1827  * It returns 1 if the lock was acquired, 0 otherwise.
 1828  * If several processes call this function concurrently wanting the exclusive
 1829  * lock, one will get the lock and the rest will return without getting the
 1830  * lock. (If the caller must have the lock, it simply calls this function in a
 1831  *  loop until the function returns 1 to indicate the lock was acquired.)
 1832  * Any usecnt must be decremented by calling nfsv4_relref() before
 1833  * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
 1834  * be called in a loop.
 1835  * The isleptp argument is set to indicate if the call slept, iff not NULL
 1836  * and the mp argument indicates to check for a forced dismount, iff not
 1837  * NULL.
 1838  */
 1839 APPLESTATIC int
 1840 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
 1841     void *mutex, struct mount *mp)
 1842 {
 1843 
 1844         if (isleptp)
 1845                 *isleptp = 0;
 1846         /*
 1847          * If a lock is wanted, loop around until the lock is acquired by
 1848          * someone and then released. If I want the lock, try to acquire it.
 1849          * For a lock to be issued, no lock must be in force and the usecnt
 1850          * must be zero.
 1851          */
 1852         if (iwantlock) {
 1853             if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
 1854                 lp->nfslock_usecnt == 0) {
 1855                 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
 1856                 lp->nfslock_lock |= NFSV4LOCK_LOCK;
 1857                 return (1);
 1858             }
 1859             lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
 1860         }
 1861         while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
 1862                 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
 1863                         lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
 1864                         return (0);
 1865                 }
 1866                 lp->nfslock_lock |= NFSV4LOCK_WANTED;
 1867                 if (isleptp)
 1868                         *isleptp = 1;
 1869                 (void) nfsmsleep(&lp->nfslock_lock, mutex,
 1870                     PZERO - 1, "nfsv4lck", NULL);
 1871                 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
 1872                     lp->nfslock_usecnt == 0) {
 1873                         lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
 1874                         lp->nfslock_lock |= NFSV4LOCK_LOCK;
 1875                         return (1);
 1876                 }
 1877         }
 1878         return (0);
 1879 }
 1880 
 1881 /*
 1882  * Release the lock acquired by nfsv4_lock().
 1883  * The second argument is set to 1 to indicate the nfslock_usecnt should be
 1884  * incremented, as well.
 1885  */
 1886 APPLESTATIC void
 1887 nfsv4_unlock(struct nfsv4lock *lp, int incref)
 1888 {
 1889 
 1890         lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
 1891         if (incref)
 1892                 lp->nfslock_usecnt++;
 1893         nfsv4_wanted(lp);
 1894 }
 1895 
 1896 /*
 1897  * Release a reference cnt.
 1898  */
 1899 APPLESTATIC void
 1900 nfsv4_relref(struct nfsv4lock *lp)
 1901 {
 1902 
 1903         if (lp->nfslock_usecnt <= 0)
 1904                 panic("nfsv4root ref cnt");
 1905         lp->nfslock_usecnt--;
 1906         if (lp->nfslock_usecnt == 0)
 1907                 nfsv4_wanted(lp);
 1908 }
 1909 
 1910 /*
 1911  * Get a reference cnt.
 1912  * This function will wait for any exclusive lock to be released, but will
 1913  * not wait for threads that want the exclusive lock. If priority needs
 1914  * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
 1915  * with the 2nd argument == 0 should be done before calling nfsv4_getref().
 1916  * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
 1917  * return without getting a refcnt for that case.
 1918  */
 1919 APPLESTATIC void
 1920 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
 1921     struct mount *mp)
 1922 {
 1923 
 1924         if (isleptp)
 1925                 *isleptp = 0;
 1926 
 1927         /*
 1928          * Wait for a lock held.
 1929          */
 1930         while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
 1931                 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
 1932                         return;
 1933                 lp->nfslock_lock |= NFSV4LOCK_WANTED;
 1934                 if (isleptp)
 1935                         *isleptp = 1;
 1936                 (void) nfsmsleep(&lp->nfslock_lock, mutex,
 1937                     PZERO - 1, "nfsv4gr", NULL);
 1938         }
 1939         if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
 1940                 return;
 1941 
 1942         lp->nfslock_usecnt++;
 1943 }
 1944 
 1945 /*
 1946  * Get a reference as above, but return failure instead of sleeping if
 1947  * an exclusive lock is held.
 1948  */
 1949 APPLESTATIC int
 1950 nfsv4_getref_nonblock(struct nfsv4lock *lp)
 1951 {
 1952 
 1953         if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
 1954                 return (0);
 1955 
 1956         lp->nfslock_usecnt++;
 1957         return (1);
 1958 }
 1959 
 1960 /*
 1961  * Test for a lock. Return 1 if locked, 0 otherwise.
 1962  */
 1963 APPLESTATIC int
 1964 nfsv4_testlock(struct nfsv4lock *lp)
 1965 {
 1966 
 1967         if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
 1968             lp->nfslock_usecnt == 0)
 1969                 return (0);
 1970         return (1);
 1971 }
 1972 
 1973 /*
 1974  * Wake up anyone sleeping, waiting for this lock.
 1975  */
 1976 static void
 1977 nfsv4_wanted(struct nfsv4lock *lp)
 1978 {
 1979 
 1980         if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
 1981                 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
 1982                 wakeup((caddr_t)&lp->nfslock_lock);
 1983         }
 1984 }
 1985 
 1986 /*
 1987  * Copy a string from an mbuf list into a character array.
 1988  * Return EBADRPC if there is an mbuf error,
 1989  * 0 otherwise.
 1990  */
 1991 APPLESTATIC int
 1992 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
 1993 {
 1994         char *cp;
 1995         int xfer, len;
 1996         mbuf_t mp;
 1997         int rem, error = 0;
 1998 
 1999         mp = nd->nd_md;
 2000         cp = nd->nd_dpos;
 2001         len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
 2002         rem = NFSM_RNDUP(siz) - siz;
 2003         while (siz > 0) {
 2004                 if (len > siz)
 2005                         xfer = siz;
 2006                 else
 2007                         xfer = len;
 2008                 NFSBCOPY(cp, str, xfer);
 2009                 str += xfer;
 2010                 siz -= xfer;
 2011                 if (siz > 0) {
 2012                         mp = mbuf_next(mp);
 2013                         if (mp == NULL) {
 2014                                 error = EBADRPC;
 2015                                 goto out;
 2016                         }
 2017                         cp = NFSMTOD(mp, caddr_t);
 2018                         len = mbuf_len(mp);
 2019                 } else {
 2020                         cp += xfer;
 2021                         len -= xfer;
 2022                 }
 2023         }
 2024         *str = '\0';
 2025         nd->nd_dpos = cp;
 2026         nd->nd_md = mp;
 2027         if (rem > 0) {
 2028                 if (len < rem)
 2029                         error = nfsm_advance(nd, rem, len);
 2030                 else
 2031                         nd->nd_dpos += rem;
 2032         }
 2033 
 2034 out:
 2035         NFSEXITCODE2(error, nd);
 2036         return (error);
 2037 }
 2038 
 2039 /*
 2040  * Fill in the attributes as marked by the bitmap (V4).
 2041  */
 2042 APPLESTATIC int
 2043 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
 2044     NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
 2045     nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
 2046     int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
 2047 {
 2048         int bitpos, retnum = 0;
 2049         u_int32_t *tl;
 2050         int siz, prefixnum, error;
 2051         u_char *cp, namestr[NFSV4_SMALLSTR];
 2052         nfsattrbit_t attrbits, retbits;
 2053         nfsattrbit_t *retbitp = &retbits;
 2054         u_int32_t freenum, *retnump;
 2055         u_int64_t uquad;
 2056         struct statfs fs;
 2057         struct nfsfsinfo fsinf;
 2058         struct timespec temptime;
 2059         NFSACL_T *aclp, *naclp = NULL;
 2060 #ifdef QUOTA
 2061         struct dqblk dqb;
 2062         uid_t savuid;
 2063 #endif
 2064 
 2065         /*
 2066          * First, set the bits that can be filled and get fsinfo.
 2067          */
 2068         NFSSET_ATTRBIT(retbitp, attrbitp);
 2069         /*
 2070          * If both p and cred are NULL, it is a client side setattr call.
 2071          * If both p and cred are not NULL, it is a server side reply call.
 2072          * If p is not NULL and cred is NULL, it is a client side callback
 2073          * reply call.
 2074          */
 2075         if (p == NULL && cred == NULL) {
 2076                 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
 2077                 aclp = saclp;
 2078         } else {
 2079                 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
 2080                 naclp = acl_alloc(M_WAITOK);
 2081                 aclp = naclp;
 2082         }
 2083         nfsvno_getfs(&fsinf, isdgram);
 2084 #ifndef APPLE
 2085         /*
 2086          * Get the VFS_STATFS(), since some attributes need them.
 2087          */
 2088         if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
 2089                 error = VFS_STATFS(mp, &fs);
 2090                 if (error != 0) {
 2091                         if (reterr) {
 2092                                 nd->nd_repstat = NFSERR_ACCES;
 2093                                 return (0);
 2094                         }
 2095                         NFSCLRSTATFS_ATTRBIT(retbitp);
 2096                 }
 2097         }
 2098 #endif
 2099 
 2100         /*
 2101          * And the NFSv4 ACL...
 2102          */
 2103         if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
 2104             (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
 2105                 supports_nfsv4acls == 0))) {
 2106                 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
 2107         }
 2108         if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
 2109                 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
 2110                     supports_nfsv4acls == 0)) {
 2111                         NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
 2112                 } else if (naclp != NULL) {
 2113                         if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
 2114                                 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
 2115                                 if (error == 0)
 2116                                         error = VOP_GETACL(vp, ACL_TYPE_NFS4,
 2117                                             naclp, cred, p);
 2118                                 NFSVOPUNLOCK(vp, 0);
 2119                         } else
 2120                                 error = NFSERR_PERM;
 2121                         if (error != 0) {
 2122                                 if (reterr) {
 2123                                         nd->nd_repstat = NFSERR_ACCES;
 2124                                         return (0);
 2125                                 }
 2126                                 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
 2127                         }
 2128                 }
 2129         }
 2130         /*
 2131          * Put out the attribute bitmap for the ones being filled in
 2132          * and get the field for the number of attributes returned.
 2133          */
 2134         prefixnum = nfsrv_putattrbit(nd, retbitp);
 2135         NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
 2136         prefixnum += NFSX_UNSIGNED;
 2137 
 2138         /*
 2139          * Now, loop around filling in the attributes for each bit set.
 2140          */
 2141         for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
 2142             if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
 2143                 switch (bitpos) {
 2144                 case NFSATTRBIT_SUPPORTEDATTRS:
 2145                         NFSSETSUPP_ATTRBIT(&attrbits);
 2146                         if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
 2147                             && supports_nfsv4acls == 0)) {
 2148                             NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
 2149                             NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
 2150                         }
 2151                         retnum += nfsrv_putattrbit(nd, &attrbits);
 2152                         break;
 2153                 case NFSATTRBIT_TYPE:
 2154                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2155                         *tl = vtonfsv34_type(vap->va_type);
 2156                         retnum += NFSX_UNSIGNED;
 2157                         break;
 2158                 case NFSATTRBIT_FHEXPIRETYPE:
 2159                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2160                         *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
 2161                         retnum += NFSX_UNSIGNED;
 2162                         break;
 2163                 case NFSATTRBIT_CHANGE:
 2164                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2165                         txdr_hyper(vap->va_filerev, tl);
 2166                         retnum += NFSX_HYPER;
 2167                         break;
 2168                 case NFSATTRBIT_SIZE:
 2169                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2170                         txdr_hyper(vap->va_size, tl);
 2171                         retnum += NFSX_HYPER;
 2172                         break;
 2173                 case NFSATTRBIT_LINKSUPPORT:
 2174                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2175                         if (fsinf.fs_properties & NFSV3FSINFO_LINK)
 2176                                 *tl = newnfs_true;
 2177                         else
 2178                                 *tl = newnfs_false;
 2179                         retnum += NFSX_UNSIGNED;
 2180                         break;
 2181                 case NFSATTRBIT_SYMLINKSUPPORT:
 2182                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2183                         if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
 2184                                 *tl = newnfs_true;
 2185                         else
 2186                                 *tl = newnfs_false;
 2187                         retnum += NFSX_UNSIGNED;
 2188                         break;
 2189                 case NFSATTRBIT_NAMEDATTR:
 2190                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2191                         *tl = newnfs_false;
 2192                         retnum += NFSX_UNSIGNED;
 2193                         break;
 2194                 case NFSATTRBIT_FSID:
 2195                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
 2196                         *tl++ = 0;
 2197                         *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
 2198                         *tl++ = 0;
 2199                         *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
 2200                         retnum += NFSX_V4FSID;
 2201                         break;
 2202                 case NFSATTRBIT_UNIQUEHANDLES:
 2203                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2204                         *tl = newnfs_true;
 2205                         retnum += NFSX_UNSIGNED;
 2206                         break;
 2207                 case NFSATTRBIT_LEASETIME:
 2208                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2209                         *tl = txdr_unsigned(nfsrv_lease);
 2210                         retnum += NFSX_UNSIGNED;
 2211                         break;
 2212                 case NFSATTRBIT_RDATTRERROR:
 2213                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2214                         *tl = txdr_unsigned(rderror);
 2215                         retnum += NFSX_UNSIGNED;
 2216                         break;
 2217                 /*
 2218                  * Recommended Attributes. (Only the supported ones.)
 2219                  */
 2220                 case NFSATTRBIT_ACL:
 2221                         retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
 2222                         break;
 2223                 case NFSATTRBIT_ACLSUPPORT:
 2224                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2225                         *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
 2226                         retnum += NFSX_UNSIGNED;
 2227                         break;
 2228                 case NFSATTRBIT_CANSETTIME:
 2229                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2230                         if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
 2231                                 *tl = newnfs_true;
 2232                         else
 2233                                 *tl = newnfs_false;
 2234                         retnum += NFSX_UNSIGNED;
 2235                         break;
 2236                 case NFSATTRBIT_CASEINSENSITIVE:
 2237                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2238                         *tl = newnfs_false;
 2239                         retnum += NFSX_UNSIGNED;
 2240                         break;
 2241                 case NFSATTRBIT_CASEPRESERVING:
 2242                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2243                         *tl = newnfs_true;
 2244                         retnum += NFSX_UNSIGNED;
 2245                         break;
 2246                 case NFSATTRBIT_CHOWNRESTRICTED:
 2247                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2248                         *tl = newnfs_true;
 2249                         retnum += NFSX_UNSIGNED;
 2250                         break;
 2251                 case NFSATTRBIT_FILEHANDLE:
 2252                         retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
 2253                         break;
 2254                 case NFSATTRBIT_FILEID:
 2255                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2256                         *tl++ = 0;
 2257                         *tl = txdr_unsigned(vap->va_fileid);
 2258                         retnum += NFSX_HYPER;
 2259                         break;
 2260                 case NFSATTRBIT_FILESAVAIL:
 2261                         /*
 2262                          * Check quota and use min(quota, f_ffree).
 2263                          */
 2264                         freenum = fs.f_ffree;
 2265 #ifdef QUOTA
 2266                         /*
 2267                          * ufs_quotactl() insists that the uid argument
 2268                          * equal p_ruid for non-root quota access, so
 2269                          * we'll just make sure that's the case.
 2270                          */
 2271                         savuid = p->p_cred->p_ruid;
 2272                         p->p_cred->p_ruid = cred->cr_uid;
 2273                         if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
 2274                             cred->cr_uid, (caddr_t)&dqb))
 2275                             freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
 2276                                 freenum);
 2277                         p->p_cred->p_ruid = savuid;
 2278 #endif  /* QUOTA */
 2279                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2280                         *tl++ = 0;
 2281                         *tl = txdr_unsigned(freenum);
 2282                         retnum += NFSX_HYPER;
 2283                         break;
 2284                 case NFSATTRBIT_FILESFREE:
 2285                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2286                         *tl++ = 0;
 2287                         *tl = txdr_unsigned(fs.f_ffree);
 2288                         retnum += NFSX_HYPER;
 2289                         break;
 2290                 case NFSATTRBIT_FILESTOTAL:
 2291                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2292                         *tl++ = 0;
 2293                         *tl = txdr_unsigned(fs.f_files);
 2294                         retnum += NFSX_HYPER;
 2295                         break;
 2296                 case NFSATTRBIT_FSLOCATIONS:
 2297                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2298                         *tl++ = 0;
 2299                         *tl = 0;
 2300                         retnum += 2 * NFSX_UNSIGNED;
 2301                         break;
 2302                 case NFSATTRBIT_HOMOGENEOUS:
 2303                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2304                         if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
 2305                                 *tl = newnfs_true;
 2306                         else
 2307                                 *tl = newnfs_false;
 2308                         retnum += NFSX_UNSIGNED;
 2309                         break;
 2310                 case NFSATTRBIT_MAXFILESIZE:
 2311                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2312                         uquad = NFSRV_MAXFILESIZE;
 2313                         txdr_hyper(uquad, tl);
 2314                         retnum += NFSX_HYPER;
 2315                         break;
 2316                 case NFSATTRBIT_MAXLINK:
 2317                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2318                         *tl = txdr_unsigned(LINK_MAX);
 2319                         retnum += NFSX_UNSIGNED;
 2320                         break;
 2321                 case NFSATTRBIT_MAXNAME:
 2322                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2323                         *tl = txdr_unsigned(NFS_MAXNAMLEN);
 2324                         retnum += NFSX_UNSIGNED;
 2325                         break;
 2326                 case NFSATTRBIT_MAXREAD:
 2327                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2328                         *tl++ = 0;
 2329                         *tl = txdr_unsigned(fsinf.fs_rtmax);
 2330                         retnum += NFSX_HYPER;
 2331                         break;
 2332                 case NFSATTRBIT_MAXWRITE:
 2333                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2334                         *tl++ = 0;
 2335                         *tl = txdr_unsigned(fsinf.fs_wtmax);
 2336                         retnum += NFSX_HYPER;
 2337                         break;
 2338                 case NFSATTRBIT_MODE:
 2339                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2340                         *tl = vtonfsv34_mode(vap->va_mode);
 2341                         retnum += NFSX_UNSIGNED;
 2342                         break;
 2343                 case NFSATTRBIT_NOTRUNC:
 2344                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2345                         *tl = newnfs_true;
 2346                         retnum += NFSX_UNSIGNED;
 2347                         break;
 2348                 case NFSATTRBIT_NUMLINKS:
 2349                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2350                         *tl = txdr_unsigned(vap->va_nlink);
 2351                         retnum += NFSX_UNSIGNED;
 2352                         break;
 2353                 case NFSATTRBIT_OWNER:
 2354                         cp = namestr;
 2355                         nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
 2356                         retnum += nfsm_strtom(nd, cp, siz);
 2357                         if (cp != namestr)
 2358                                 free(cp, M_NFSSTRING);
 2359                         break;
 2360                 case NFSATTRBIT_OWNERGROUP:
 2361                         cp = namestr;
 2362                         nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
 2363                         retnum += nfsm_strtom(nd, cp, siz);
 2364                         if (cp != namestr)
 2365                                 free(cp, M_NFSSTRING);
 2366                         break;
 2367                 case NFSATTRBIT_QUOTAHARD:
 2368                         if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
 2369                                 freenum = fs.f_bfree;
 2370                         else
 2371                                 freenum = fs.f_bavail;
 2372 #ifdef QUOTA
 2373                         /*
 2374                          * ufs_quotactl() insists that the uid argument
 2375                          * equal p_ruid for non-root quota access, so
 2376                          * we'll just make sure that's the case.
 2377                          */
 2378                         savuid = p->p_cred->p_ruid;
 2379                         p->p_cred->p_ruid = cred->cr_uid;
 2380                         if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
 2381                             cred->cr_uid, (caddr_t)&dqb))
 2382                             freenum = min(dqb.dqb_bhardlimit, freenum);
 2383                         p->p_cred->p_ruid = savuid;
 2384 #endif  /* QUOTA */
 2385                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2386                         uquad = (u_int64_t)freenum;
 2387                         NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
 2388                         txdr_hyper(uquad, tl);
 2389                         retnum += NFSX_HYPER;
 2390                         break;
 2391                 case NFSATTRBIT_QUOTASOFT:
 2392                         if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
 2393                                 freenum = fs.f_bfree;
 2394                         else
 2395                                 freenum = fs.f_bavail;
 2396 #ifdef QUOTA
 2397                         /*
 2398                          * ufs_quotactl() insists that the uid argument
 2399                          * equal p_ruid for non-root quota access, so
 2400                          * we'll just make sure that's the case.
 2401                          */
 2402                         savuid = p->p_cred->p_ruid;
 2403                         p->p_cred->p_ruid = cred->cr_uid;
 2404                         if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
 2405                             cred->cr_uid, (caddr_t)&dqb))
 2406                             freenum = min(dqb.dqb_bsoftlimit, freenum);
 2407                         p->p_cred->p_ruid = savuid;
 2408 #endif  /* QUOTA */
 2409                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2410                         uquad = (u_int64_t)freenum;
 2411                         NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
 2412                         txdr_hyper(uquad, tl);
 2413                         retnum += NFSX_HYPER;
 2414                         break;
 2415                 case NFSATTRBIT_QUOTAUSED:
 2416                         freenum = 0;
 2417 #ifdef QUOTA
 2418                         /*
 2419                          * ufs_quotactl() insists that the uid argument
 2420                          * equal p_ruid for non-root quota access, so
 2421                          * we'll just make sure that's the case.
 2422                          */
 2423                         savuid = p->p_cred->p_ruid;
 2424                         p->p_cred->p_ruid = cred->cr_uid;
 2425                         if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
 2426                             cred->cr_uid, (caddr_t)&dqb))
 2427                             freenum = dqb.dqb_curblocks;
 2428                         p->p_cred->p_ruid = savuid;
 2429 #endif  /* QUOTA */
 2430                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2431                         uquad = (u_int64_t)freenum;
 2432                         NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
 2433                         txdr_hyper(uquad, tl);
 2434                         retnum += NFSX_HYPER;
 2435                         break;
 2436                 case NFSATTRBIT_RAWDEV:
 2437                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
 2438                         *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
 2439                         *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
 2440                         retnum += NFSX_V4SPECDATA;
 2441                         break;
 2442                 case NFSATTRBIT_SPACEAVAIL:
 2443                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2444                         if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
 2445                                 uquad = (u_int64_t)fs.f_bfree;
 2446                         else
 2447                                 uquad = (u_int64_t)fs.f_bavail;
 2448                         uquad *= fs.f_bsize;
 2449                         txdr_hyper(uquad, tl);
 2450                         retnum += NFSX_HYPER;
 2451                         break;
 2452                 case NFSATTRBIT_SPACEFREE:
 2453                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2454                         uquad = (u_int64_t)fs.f_bfree;
 2455                         uquad *= fs.f_bsize;
 2456                         txdr_hyper(uquad, tl);
 2457                         retnum += NFSX_HYPER;
 2458                         break;
 2459                 case NFSATTRBIT_SPACETOTAL:
 2460                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2461                         uquad = (u_int64_t)fs.f_blocks;
 2462                         uquad *= fs.f_bsize;
 2463                         txdr_hyper(uquad, tl);
 2464                         retnum += NFSX_HYPER;
 2465                         break;
 2466                 case NFSATTRBIT_SPACEUSED:
 2467                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2468                         txdr_hyper(vap->va_bytes, tl);
 2469                         retnum += NFSX_HYPER;
 2470                         break;
 2471                 case NFSATTRBIT_TIMEACCESS:
 2472                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
 2473                         txdr_nfsv4time(&vap->va_atime, tl);
 2474                         retnum += NFSX_V4TIME;
 2475                         break;
 2476                 case NFSATTRBIT_TIMEACCESSSET:
 2477                         if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
 2478                                 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
 2479                                 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
 2480                                 txdr_nfsv4time(&vap->va_atime, tl);
 2481                                 retnum += NFSX_V4SETTIME;
 2482                         } else {
 2483                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2484                                 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
 2485                                 retnum += NFSX_UNSIGNED;
 2486                         }
 2487                         break;
 2488                 case NFSATTRBIT_TIMEDELTA:
 2489                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
 2490                         temptime.tv_sec = 0;
 2491                         temptime.tv_nsec = 1000000000 / hz;
 2492                         txdr_nfsv4time(&temptime, tl);
 2493                         retnum += NFSX_V4TIME;
 2494                         break;
 2495                 case NFSATTRBIT_TIMEMETADATA:
 2496                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
 2497                         txdr_nfsv4time(&vap->va_ctime, tl);
 2498                         retnum += NFSX_V4TIME;
 2499                         break;
 2500                 case NFSATTRBIT_TIMEMODIFY:
 2501                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
 2502                         txdr_nfsv4time(&vap->va_mtime, tl);
 2503                         retnum += NFSX_V4TIME;
 2504                         break;
 2505                 case NFSATTRBIT_TIMEMODIFYSET:
 2506                         if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
 2507                                 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
 2508                                 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
 2509                                 txdr_nfsv4time(&vap->va_mtime, tl);
 2510                                 retnum += NFSX_V4SETTIME;
 2511                         } else {
 2512                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2513                                 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
 2514                                 retnum += NFSX_UNSIGNED;
 2515                         }
 2516                         break;
 2517                 case NFSATTRBIT_MOUNTEDONFILEID:
 2518                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2519                         if (at_root != 0)
 2520                                 uquad = mounted_on_fileno;
 2521                         else
 2522                                 uquad = (u_int64_t)vap->va_fileid;
 2523                         txdr_hyper(uquad, tl);
 2524                         retnum += NFSX_HYPER;
 2525                         break;
 2526                 case NFSATTRBIT_SUPPATTREXCLCREAT:
 2527                         NFSSETSUPP_ATTRBIT(&attrbits);
 2528                         NFSCLRNOTSETABLE_ATTRBIT(&attrbits);
 2529                         NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
 2530                         retnum += nfsrv_putattrbit(nd, &attrbits);
 2531                         break;
 2532                 default:
 2533                         printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
 2534                 };
 2535             }
 2536         }
 2537         if (naclp != NULL)
 2538                 acl_free(naclp);
 2539         *retnump = txdr_unsigned(retnum);
 2540         return (retnum + prefixnum);
 2541 }
 2542 
 2543 /*
 2544  * Put the attribute bits onto an mbuf list.
 2545  * Return the number of bytes of output generated.
 2546  */
 2547 APPLESTATIC int
 2548 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
 2549 {
 2550         u_int32_t *tl;
 2551         int cnt, i, bytesize;
 2552 
 2553         for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
 2554                 if (attrbitp->bits[cnt - 1])
 2555                         break;
 2556         bytesize = (cnt + 1) * NFSX_UNSIGNED;
 2557         NFSM_BUILD(tl, u_int32_t *, bytesize);
 2558         *tl++ = txdr_unsigned(cnt);
 2559         for (i = 0; i < cnt; i++)
 2560                 *tl++ = txdr_unsigned(attrbitp->bits[i]);
 2561         return (bytesize);
 2562 }
 2563 
 2564 /*
 2565  * Convert a uid to a string.
 2566  * If the lookup fails, just output the digits.
 2567  * uid - the user id
 2568  * cpp - points to a buffer of size NFSV4_SMALLSTR
 2569  *       (malloc a larger one, as required)
 2570  * retlenp - pointer to length to be returned
 2571  */
 2572 APPLESTATIC void
 2573 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
 2574 {
 2575         int i;
 2576         struct nfsusrgrp *usrp;
 2577         u_char *cp = *cpp;
 2578         uid_t tmp;
 2579         int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
 2580         struct nfsrv_lughash *hp;
 2581 
 2582         cnt = 0;
 2583 tryagain:
 2584         if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
 2585                 /*
 2586                  * Always map nfsrv_defaultuid to "nobody".
 2587                  */
 2588                 if (uid == nfsrv_defaultuid) {
 2589                         i = nfsrv_dnsnamelen + 7;
 2590                         if (i > len) {
 2591                                 if (len > NFSV4_SMALLSTR)
 2592                                         free(cp, M_NFSSTRING);
 2593                                 cp = malloc(i, M_NFSSTRING, M_WAITOK);
 2594                                 *cpp = cp;
 2595                                 len = i;
 2596                                 goto tryagain;
 2597                         }
 2598                         *retlenp = i;
 2599                         NFSBCOPY("nobody@", cp, 7);
 2600                         cp += 7;
 2601                         NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
 2602                         return;
 2603                 }
 2604                 hasampersand = 0;
 2605                 hp = NFSUSERHASH(uid);
 2606                 mtx_lock(&hp->mtx);
 2607                 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
 2608                         if (usrp->lug_uid == uid) {
 2609                                 if (usrp->lug_expiry < NFSD_MONOSEC)
 2610                                         break;
 2611                                 /*
 2612                                  * If the name doesn't already have an '@'
 2613                                  * in it, append @domainname to it.
 2614                                  */
 2615                                 for (i = 0; i < usrp->lug_namelen; i++) {
 2616                                         if (usrp->lug_name[i] == '@') {
 2617                                                 hasampersand = 1;
 2618                                                 break;
 2619                                         }
 2620                                 }
 2621                                 if (hasampersand)
 2622                                         i = usrp->lug_namelen;
 2623                                 else
 2624                                         i = usrp->lug_namelen +
 2625                                             nfsrv_dnsnamelen + 1;
 2626                                 if (i > len) {
 2627                                         mtx_unlock(&hp->mtx);
 2628                                         if (len > NFSV4_SMALLSTR)
 2629                                                 free(cp, M_NFSSTRING);
 2630                                         cp = malloc(i, M_NFSSTRING, M_WAITOK);
 2631                                         *cpp = cp;
 2632                                         len = i;
 2633                                         goto tryagain;
 2634                                 }
 2635                                 *retlenp = i;
 2636                                 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
 2637                                 if (!hasampersand) {
 2638                                         cp += usrp->lug_namelen;
 2639                                         *cp++ = '@';
 2640                                         NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
 2641                                 }
 2642                                 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
 2643                                 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
 2644                                     lug_numhash);
 2645                                 mtx_unlock(&hp->mtx);
 2646                                 return;
 2647                         }
 2648                 }
 2649                 mtx_unlock(&hp->mtx);
 2650                 cnt++;
 2651                 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
 2652                     NULL, p);
 2653                 if (ret == 0 && cnt < 2)
 2654                         goto tryagain;
 2655         }
 2656 
 2657         /*
 2658          * No match, just return a string of digits.
 2659          */
 2660         tmp = uid;
 2661         i = 0;
 2662         while (tmp || i == 0) {
 2663                 tmp /= 10;
 2664                 i++;
 2665         }
 2666         len = (i > len) ? len : i;
 2667         *retlenp = len;
 2668         cp += (len - 1);
 2669         tmp = uid;
 2670         for (i = 0; i < len; i++) {
 2671                 *cp-- = '' + (tmp % 10);
 2672                 tmp /= 10;
 2673         }
 2674         return;
 2675 }
 2676 
 2677 /*
 2678  * Get a credential for the uid with the server's group list.
 2679  * If none is found, just return the credential passed in after
 2680  * logging a warning message.
 2681  */
 2682 struct ucred *
 2683 nfsrv_getgrpscred(struct ucred *oldcred)
 2684 {
 2685         struct nfsusrgrp *usrp;
 2686         struct ucred *newcred;
 2687         int cnt, ret;
 2688         uid_t uid;
 2689         struct nfsrv_lughash *hp;
 2690 
 2691         cnt = 0;
 2692         uid = oldcred->cr_uid;
 2693 tryagain:
 2694         if (nfsrv_dnsnamelen > 0) {
 2695                 hp = NFSUSERHASH(uid);
 2696                 mtx_lock(&hp->mtx);
 2697                 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
 2698                         if (usrp->lug_uid == uid) {
 2699                                 if (usrp->lug_expiry < NFSD_MONOSEC)
 2700                                         break;
 2701                                 if (usrp->lug_cred != NULL) {
 2702                                         newcred = crhold(usrp->lug_cred);
 2703                                         crfree(oldcred);
 2704                                 } else
 2705                                         newcred = oldcred;
 2706                                 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
 2707                                 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
 2708                                     lug_numhash);
 2709                                 mtx_unlock(&hp->mtx);
 2710                                 return (newcred);
 2711                         }
 2712                 }
 2713                 mtx_unlock(&hp->mtx);
 2714                 cnt++;
 2715                 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
 2716                     NULL, curthread);
 2717                 if (ret == 0 && cnt < 2)
 2718                         goto tryagain;
 2719         }
 2720         return (oldcred);
 2721 }
 2722 
 2723 /*
 2724  * Convert a string to a uid.
 2725  * If no conversion is possible return NFSERR_BADOWNER, otherwise
 2726  * return 0.
 2727  * If this is called from a client side mount using AUTH_SYS and the
 2728  * string is made up entirely of digits, just convert the string to
 2729  * a number.
 2730  */
 2731 APPLESTATIC int
 2732 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
 2733     NFSPROC_T *p)
 2734 {
 2735         int i;
 2736         char *cp, *endstr, *str0;
 2737         struct nfsusrgrp *usrp;
 2738         int cnt, ret;
 2739         int error = 0;
 2740         uid_t tuid;
 2741         struct nfsrv_lughash *hp, *hp2;
 2742 
 2743         if (len == 0) {
 2744                 error = NFSERR_BADOWNER;
 2745                 goto out;
 2746         }
 2747         /* If a string of digits and an AUTH_SYS mount, just convert it. */
 2748         str0 = str;
 2749         tuid = (uid_t)strtoul(str0, &endstr, 10);
 2750         if ((endstr - str0) == len) {
 2751                 /* A numeric string. */
 2752                 if ((nd->nd_flag & ND_KERBV) == 0 &&
 2753                     ((nd->nd_flag & ND_NFSCL) != 0 ||
 2754                       nfsd_enable_stringtouid != 0))
 2755                         *uidp = tuid;
 2756                 else
 2757                         error = NFSERR_BADOWNER;
 2758                 goto out;
 2759         }
 2760         /*
 2761          * Look for an '@'.
 2762          */
 2763         cp = strchr(str0, '@');
 2764         if (cp != NULL)
 2765                 i = (int)(cp++ - str0);
 2766         else
 2767                 i = len;
 2768 
 2769         cnt = 0;
 2770 tryagain:
 2771         if (nfsrv_dnsnamelen > 0) {
 2772                 /*
 2773                  * If an '@' is found and the domain name matches, search for
 2774                  * the name with dns stripped off.
 2775                  * Mixed case alpahbetics will match for the domain name, but
 2776                  * all upper case will not.
 2777                  */
 2778                 if (cnt == 0 && i < len && i > 0 &&
 2779                     (len - 1 - i) == nfsrv_dnsnamelen &&
 2780                     !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
 2781                         len -= (nfsrv_dnsnamelen + 1);
 2782                         *(cp - 1) = '\0';
 2783                 }
 2784         
 2785                 /*
 2786                  * Check for the special case of "nobody".
 2787                  */
 2788                 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
 2789                         *uidp = nfsrv_defaultuid;
 2790                         error = 0;
 2791                         goto out;
 2792                 }
 2793         
 2794                 hp = NFSUSERNAMEHASH(str, len);
 2795                 mtx_lock(&hp->mtx);
 2796                 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
 2797                         if (usrp->lug_namelen == len &&
 2798                             !NFSBCMP(usrp->lug_name, str, len)) {
 2799                                 if (usrp->lug_expiry < NFSD_MONOSEC)
 2800                                         break;
 2801                                 hp2 = NFSUSERHASH(usrp->lug_uid);
 2802                                 mtx_lock(&hp2->mtx);
 2803                                 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
 2804                                 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
 2805                                     lug_numhash);
 2806                                 *uidp = usrp->lug_uid;
 2807                                 mtx_unlock(&hp2->mtx);
 2808                                 mtx_unlock(&hp->mtx);
 2809                                 error = 0;
 2810                                 goto out;
 2811                         }
 2812                 }
 2813                 mtx_unlock(&hp->mtx);
 2814                 cnt++;
 2815                 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
 2816                     str, p);
 2817                 if (ret == 0 && cnt < 2)
 2818                         goto tryagain;
 2819         }
 2820         error = NFSERR_BADOWNER;
 2821 
 2822 out:
 2823         NFSEXITCODE(error);
 2824         return (error);
 2825 }
 2826 
 2827 /*
 2828  * Convert a gid to a string.
 2829  * gid - the group id
 2830  * cpp - points to a buffer of size NFSV4_SMALLSTR
 2831  *       (malloc a larger one, as required)
 2832  * retlenp - pointer to length to be returned
 2833  */
 2834 APPLESTATIC void
 2835 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
 2836 {
 2837         int i;
 2838         struct nfsusrgrp *usrp;
 2839         u_char *cp = *cpp;
 2840         gid_t tmp;
 2841         int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
 2842         struct nfsrv_lughash *hp;
 2843 
 2844         cnt = 0;
 2845 tryagain:
 2846         if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
 2847                 /*
 2848                  * Always map nfsrv_defaultgid to "nogroup".
 2849                  */
 2850                 if (gid == nfsrv_defaultgid) {
 2851                         i = nfsrv_dnsnamelen + 8;
 2852                         if (i > len) {
 2853                                 if (len > NFSV4_SMALLSTR)
 2854                                         free(cp, M_NFSSTRING);
 2855                                 cp = malloc(i, M_NFSSTRING, M_WAITOK);
 2856                                 *cpp = cp;
 2857                                 len = i;
 2858                                 goto tryagain;
 2859                         }
 2860                         *retlenp = i;
 2861                         NFSBCOPY("nogroup@", cp, 8);
 2862                         cp += 8;
 2863                         NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
 2864                         return;
 2865                 }
 2866                 hasampersand = 0;
 2867                 hp = NFSGROUPHASH(gid);
 2868                 mtx_lock(&hp->mtx);
 2869                 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
 2870                         if (usrp->lug_gid == gid) {
 2871                                 if (usrp->lug_expiry < NFSD_MONOSEC)
 2872                                         break;
 2873                                 /*
 2874                                  * If the name doesn't already have an '@'
 2875                                  * in it, append @domainname to it.
 2876                                  */
 2877                                 for (i = 0; i < usrp->lug_namelen; i++) {
 2878                                         if (usrp->lug_name[i] == '@') {
 2879                                                 hasampersand = 1;
 2880                                                 break;
 2881                                         }
 2882                                 }
 2883                                 if (hasampersand)
 2884                                         i = usrp->lug_namelen;
 2885                                 else
 2886                                         i = usrp->lug_namelen +
 2887                                             nfsrv_dnsnamelen + 1;
 2888                                 if (i > len) {
 2889                                         mtx_unlock(&hp->mtx);
 2890                                         if (len > NFSV4_SMALLSTR)
 2891                                                 free(cp, M_NFSSTRING);
 2892                                         cp = malloc(i, M_NFSSTRING, M_WAITOK);
 2893                                         *cpp = cp;
 2894                                         len = i;
 2895                                         goto tryagain;
 2896                                 }
 2897                                 *retlenp = i;
 2898                                 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
 2899                                 if (!hasampersand) {
 2900                                         cp += usrp->lug_namelen;
 2901                                         *cp++ = '@';
 2902                                         NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
 2903                                 }
 2904                                 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
 2905                                 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
 2906                                     lug_numhash);
 2907                                 mtx_unlock(&hp->mtx);
 2908                                 return;
 2909                         }
 2910                 }
 2911                 mtx_unlock(&hp->mtx);
 2912                 cnt++;
 2913                 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
 2914                     NULL, p);
 2915                 if (ret == 0 && cnt < 2)
 2916                         goto tryagain;
 2917         }
 2918 
 2919         /*
 2920          * No match, just return a string of digits.
 2921          */
 2922         tmp = gid;
 2923         i = 0;
 2924         while (tmp || i == 0) {
 2925                 tmp /= 10;
 2926                 i++;
 2927         }
 2928         len = (i > len) ? len : i;
 2929         *retlenp = len;
 2930         cp += (len - 1);
 2931         tmp = gid;
 2932         for (i = 0; i < len; i++) {
 2933                 *cp-- = '' + (tmp % 10);
 2934                 tmp /= 10;
 2935         }
 2936         return;
 2937 }
 2938 
 2939 /*
 2940  * Convert a string to a gid.
 2941  * If no conversion is possible return NFSERR_BADOWNER, otherwise
 2942  * return 0.
 2943  * If this is called from a client side mount using AUTH_SYS and the
 2944  * string is made up entirely of digits, just convert the string to
 2945  * a number.
 2946  */
 2947 APPLESTATIC int
 2948 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
 2949     NFSPROC_T *p)
 2950 {
 2951         int i;
 2952         char *cp, *endstr, *str0;
 2953         struct nfsusrgrp *usrp;
 2954         int cnt, ret;
 2955         int error = 0;
 2956         gid_t tgid;
 2957         struct nfsrv_lughash *hp, *hp2;
 2958 
 2959         if (len == 0) {
 2960                 error =  NFSERR_BADOWNER;
 2961                 goto out;
 2962         }
 2963         /* If a string of digits and an AUTH_SYS mount, just convert it. */
 2964         str0 = str;
 2965         tgid = (gid_t)strtoul(str0, &endstr, 10);
 2966         if ((endstr - str0) == len) {
 2967                 /* A numeric string. */
 2968                 if ((nd->nd_flag & ND_KERBV) == 0 &&
 2969                     ((nd->nd_flag & ND_NFSCL) != 0 ||
 2970                       nfsd_enable_stringtouid != 0))
 2971                         *gidp = tgid;
 2972                 else
 2973                         error = NFSERR_BADOWNER;
 2974                 goto out;
 2975         }
 2976         /*
 2977          * Look for an '@'.
 2978          */
 2979         cp = strchr(str0, '@');
 2980         if (cp != NULL)
 2981                 i = (int)(cp++ - str0);
 2982         else
 2983                 i = len;
 2984 
 2985         cnt = 0;
 2986 tryagain:
 2987         if (nfsrv_dnsnamelen > 0) {
 2988                 /*
 2989                  * If an '@' is found and the dns name matches, search for the
 2990                  * name with the dns stripped off.
 2991                  */
 2992                 if (cnt == 0 && i < len && i > 0 &&
 2993                     (len - 1 - i) == nfsrv_dnsnamelen &&
 2994                     !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
 2995                         len -= (nfsrv_dnsnamelen + 1);
 2996                         *(cp - 1) = '\0';
 2997                 }
 2998         
 2999                 /*
 3000                  * Check for the special case of "nogroup".
 3001                  */
 3002                 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
 3003                         *gidp = nfsrv_defaultgid;
 3004                         error = 0;
 3005                         goto out;
 3006                 }
 3007         
 3008                 hp = NFSGROUPNAMEHASH(str, len);
 3009                 mtx_lock(&hp->mtx);
 3010                 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
 3011                         if (usrp->lug_namelen == len &&
 3012                             !NFSBCMP(usrp->lug_name, str, len)) {
 3013                                 if (usrp->lug_expiry < NFSD_MONOSEC)
 3014                                         break;
 3015                                 hp2 = NFSGROUPHASH(usrp->lug_gid);
 3016                                 mtx_lock(&hp2->mtx);
 3017                                 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
 3018                                 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
 3019                                     lug_numhash);
 3020                                 *gidp = usrp->lug_gid;
 3021                                 mtx_unlock(&hp2->mtx);
 3022                                 mtx_unlock(&hp->mtx);
 3023                                 error = 0;
 3024                                 goto out;
 3025                         }
 3026                 }
 3027                 mtx_unlock(&hp->mtx);
 3028                 cnt++;
 3029                 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
 3030                     str, p);
 3031                 if (ret == 0 && cnt < 2)
 3032                         goto tryagain;
 3033         }
 3034         error = NFSERR_BADOWNER;
 3035 
 3036 out:
 3037         NFSEXITCODE(error);
 3038         return (error);
 3039 }
 3040 
 3041 /*
 3042  * Cmp len chars, allowing mixed case in the first argument to match lower
 3043  * case in the second, but not if the first argument is all upper case.
 3044  * Return 0 for a match, 1 otherwise.
 3045  */
 3046 static int
 3047 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
 3048 {
 3049         int i;
 3050         u_char tmp;
 3051         int fndlower = 0;
 3052 
 3053         for (i = 0; i < len; i++) {
 3054                 if (*cp >= 'A' && *cp <= 'Z') {
 3055                         tmp = *cp++ + ('a' - 'A');
 3056                 } else {
 3057                         tmp = *cp++;
 3058                         if (tmp >= 'a' && tmp <= 'z')
 3059                                 fndlower = 1;
 3060                 }
 3061                 if (tmp != *cp2++)
 3062                         return (1);
 3063         }
 3064         if (fndlower)
 3065                 return (0);
 3066         else
 3067                 return (1);
 3068 }
 3069 
 3070 /*
 3071  * Set the port for the nfsuserd.
 3072  */
 3073 APPLESTATIC int
 3074 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
 3075 {
 3076         struct nfssockreq *rp;
 3077         struct sockaddr_in *ad;
 3078         int error;
 3079 
 3080         NFSLOCKNAMEID();
 3081         if (nfsrv_nfsuserd) {
 3082                 NFSUNLOCKNAMEID();
 3083                 error = EPERM;
 3084                 goto out;
 3085         }
 3086         nfsrv_nfsuserd = 1;
 3087         NFSUNLOCKNAMEID();
 3088         /*
 3089          * Set up the socket record and connect.
 3090          */
 3091         rp = &nfsrv_nfsuserdsock;
 3092         rp->nr_client = NULL;
 3093         rp->nr_sotype = SOCK_DGRAM;
 3094         rp->nr_soproto = IPPROTO_UDP;
 3095         rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
 3096         rp->nr_cred = NULL;
 3097         NFSSOCKADDRALLOC(rp->nr_nam);
 3098         NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
 3099         ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
 3100         ad->sin_family = AF_INET;
 3101         ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001);     /* 127.0.0.1 */
 3102         ad->sin_port = port;
 3103         rp->nr_prog = RPCPROG_NFSUSERD;
 3104         rp->nr_vers = RPCNFSUSERD_VERS;
 3105         error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
 3106         if (error) {
 3107                 NFSSOCKADDRFREE(rp->nr_nam);
 3108                 nfsrv_nfsuserd = 0;
 3109         }
 3110 out:
 3111         NFSEXITCODE(error);
 3112         return (error);
 3113 }
 3114 
 3115 /*
 3116  * Delete the nfsuserd port.
 3117  */
 3118 APPLESTATIC void
 3119 nfsrv_nfsuserddelport(void)
 3120 {
 3121 
 3122         NFSLOCKNAMEID();
 3123         if (nfsrv_nfsuserd == 0) {
 3124                 NFSUNLOCKNAMEID();
 3125                 return;
 3126         }
 3127         nfsrv_nfsuserd = 0;
 3128         NFSUNLOCKNAMEID();
 3129         newnfs_disconnect(&nfsrv_nfsuserdsock);
 3130         NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
 3131 }
 3132 
 3133 /*
 3134  * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
 3135  * name<-->id cache.
 3136  * Returns 0 upon success, non-zero otherwise.
 3137  */
 3138 static int
 3139 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
 3140 {
 3141         u_int32_t *tl;
 3142         struct nfsrv_descript *nd;
 3143         int len;
 3144         struct nfsrv_descript nfsd;
 3145         struct ucred *cred;
 3146         int error;
 3147 
 3148         NFSLOCKNAMEID();
 3149         if (nfsrv_nfsuserd == 0) {
 3150                 NFSUNLOCKNAMEID();
 3151                 error = EPERM;
 3152                 goto out;
 3153         }
 3154         NFSUNLOCKNAMEID();
 3155         nd = &nfsd;
 3156         cred = newnfs_getcred();
 3157         nd->nd_flag = ND_GSSINITREPLY;
 3158         nfsrvd_rephead(nd);
 3159 
 3160         nd->nd_procnum = procnum;
 3161         if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
 3162                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3163                 if (procnum == RPCNFSUSERD_GETUID)
 3164                         *tl = txdr_unsigned(uid);
 3165                 else
 3166                         *tl = txdr_unsigned(gid);
 3167         } else {
 3168                 len = strlen(name);
 3169                 (void) nfsm_strtom(nd, name, len);
 3170         }
 3171         error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
 3172                 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
 3173         NFSFREECRED(cred);
 3174         if (!error) {
 3175                 mbuf_freem(nd->nd_mrep);
 3176                 error = nd->nd_repstat;
 3177         }
 3178 out:
 3179         NFSEXITCODE(error);
 3180         return (error);
 3181 }
 3182 
 3183 /*
 3184  * This function is called from the nfssvc(2) system call, to update the
 3185  * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
 3186  */
 3187 APPLESTATIC int
 3188 nfssvc_idname(struct nfsd_idargs *nidp)
 3189 {
 3190         struct nfsusrgrp *nusrp, *usrp, *newusrp;
 3191         struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
 3192         int i, group_locked, groupname_locked, user_locked, username_locked;
 3193         int error = 0;
 3194         u_char *cp;
 3195         gid_t *grps;
 3196         struct ucred *cr;
 3197         static int onethread = 0;
 3198         static time_t lasttime = 0;
 3199 
 3200         if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
 3201                 error = EINVAL;
 3202                 goto out;
 3203         }
 3204         if (nidp->nid_flag & NFSID_INITIALIZE) {
 3205                 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
 3206                 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
 3207                     nidp->nid_namelen);
 3208                 if (error != 0) {
 3209                         free(cp, M_NFSSTRING);
 3210                         goto out;
 3211                 }
 3212                 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
 3213                         /*
 3214                          * Free up all the old stuff and reinitialize hash
 3215                          * lists.  All mutexes for both lists must be locked,
 3216                          * with the user/group name ones before the uid/gid
 3217                          * ones, to avoid a LOR.
 3218                          */
 3219                         for (i = 0; i < nfsrv_lughashsize; i++)
 3220                                 mtx_lock(&nfsusernamehash[i].mtx);
 3221                         for (i = 0; i < nfsrv_lughashsize; i++)
 3222                                 mtx_lock(&nfsuserhash[i].mtx);
 3223                         for (i = 0; i < nfsrv_lughashsize; i++)
 3224                                 TAILQ_FOREACH_SAFE(usrp,
 3225                                     &nfsuserhash[i].lughead, lug_numhash, nusrp)
 3226                                         nfsrv_removeuser(usrp, 1);
 3227                         for (i = 0; i < nfsrv_lughashsize; i++)
 3228                                 mtx_unlock(&nfsuserhash[i].mtx);
 3229                         for (i = 0; i < nfsrv_lughashsize; i++)
 3230                                 mtx_unlock(&nfsusernamehash[i].mtx);
 3231                         for (i = 0; i < nfsrv_lughashsize; i++)
 3232                                 mtx_lock(&nfsgroupnamehash[i].mtx);
 3233                         for (i = 0; i < nfsrv_lughashsize; i++)
 3234                                 mtx_lock(&nfsgrouphash[i].mtx);
 3235                         for (i = 0; i < nfsrv_lughashsize; i++)
 3236                                 TAILQ_FOREACH_SAFE(usrp,
 3237                                     &nfsgrouphash[i].lughead, lug_numhash,
 3238                                     nusrp)
 3239                                         nfsrv_removeuser(usrp, 0);
 3240                         for (i = 0; i < nfsrv_lughashsize; i++)
 3241                                 mtx_unlock(&nfsgrouphash[i].mtx);
 3242                         for (i = 0; i < nfsrv_lughashsize; i++)
 3243                                 mtx_unlock(&nfsgroupnamehash[i].mtx);
 3244                         free(nfsrv_dnsname, M_NFSSTRING);
 3245                         nfsrv_dnsname = NULL;
 3246                 }
 3247                 if (nfsuserhash == NULL) {
 3248                         /* Allocate the hash tables. */
 3249                         nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
 3250                             nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
 3251                             M_ZERO);
 3252                         for (i = 0; i < nfsrv_lughashsize; i++)
 3253                                 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
 3254                                     NULL, MTX_DEF | MTX_DUPOK);
 3255                         nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
 3256                             nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
 3257                             M_ZERO);
 3258                         for (i = 0; i < nfsrv_lughashsize; i++)
 3259                                 mtx_init(&nfsusernamehash[i].mtx,
 3260                                     "nfsusrhash", NULL, MTX_DEF |
 3261                                     MTX_DUPOK);
 3262                         nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
 3263                             nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
 3264                             M_ZERO);
 3265                         for (i = 0; i < nfsrv_lughashsize; i++)
 3266                                 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
 3267                                     NULL, MTX_DEF | MTX_DUPOK);
 3268                         nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
 3269                             nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
 3270                             M_ZERO);
 3271                         for (i = 0; i < nfsrv_lughashsize; i++)
 3272                             mtx_init(&nfsgroupnamehash[i].mtx,
 3273                             "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
 3274                 }
 3275                 /* (Re)initialize the list heads. */
 3276                 for (i = 0; i < nfsrv_lughashsize; i++)
 3277                         TAILQ_INIT(&nfsuserhash[i].lughead);
 3278                 for (i = 0; i < nfsrv_lughashsize; i++)
 3279                         TAILQ_INIT(&nfsusernamehash[i].lughead);
 3280                 for (i = 0; i < nfsrv_lughashsize; i++)
 3281                         TAILQ_INIT(&nfsgrouphash[i].lughead);
 3282                 for (i = 0; i < nfsrv_lughashsize; i++)
 3283                         TAILQ_INIT(&nfsgroupnamehash[i].lughead);
 3284 
 3285                 /*
 3286                  * Put name in "DNS" string.
 3287                  */
 3288                 nfsrv_dnsname = cp;
 3289                 nfsrv_defaultuid = nidp->nid_uid;
 3290                 nfsrv_defaultgid = nidp->nid_gid;
 3291                 nfsrv_usercnt = 0;
 3292                 nfsrv_usermax = nidp->nid_usermax;
 3293                 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
 3294                 goto out;
 3295         }
 3296 
 3297         /*
 3298          * malloc the new one now, so any potential sleep occurs before
 3299          * manipulation of the lists.
 3300          */
 3301         newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
 3302             M_NFSUSERGROUP, M_WAITOK | M_ZERO);
 3303         error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
 3304             nidp->nid_namelen);
 3305         if (error == 0 && nidp->nid_ngroup > 0 &&
 3306             (nidp->nid_flag & NFSID_ADDUID) != 0) {
 3307                 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
 3308                     M_WAITOK);
 3309                 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
 3310                     sizeof(gid_t) * nidp->nid_ngroup);
 3311                 if (error == 0) {
 3312                         /*
 3313                          * Create a credential just like svc_getcred(),
 3314                          * but using the group list provided.
 3315                          */
 3316                         cr = crget();
 3317                         cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
 3318                         crsetgroups(cr, nidp->nid_ngroup, grps);
 3319                         cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
 3320                         cr->cr_prison = &prison0;
 3321                         prison_hold(cr->cr_prison);
 3322 #ifdef MAC
 3323                         mac_cred_associate_nfsd(cr);
 3324 #endif
 3325                         newusrp->lug_cred = cr;
 3326                 }
 3327                 free(grps, M_TEMP);
 3328         }
 3329         if (error) {
 3330                 free(newusrp, M_NFSUSERGROUP);
 3331                 goto out;
 3332         }
 3333         newusrp->lug_namelen = nidp->nid_namelen;
 3334 
 3335         /*
 3336          * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
 3337          * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
 3338          * The flags user_locked, username_locked, group_locked and
 3339          * groupname_locked are set to indicate all of those hash lists are
 3340          * locked. hp_name != NULL  and hp_idnum != NULL indicates that
 3341          * the respective one mutex is locked.
 3342          */
 3343         user_locked = username_locked = group_locked = groupname_locked = 0;
 3344         hp_name = hp_idnum = NULL;
 3345 
 3346         /*
 3347          * Delete old entries, as required.
 3348          */
 3349         if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
 3350                 /* Must lock all username hash lists first, to avoid a LOR. */
 3351                 for (i = 0; i < nfsrv_lughashsize; i++)
 3352                         mtx_lock(&nfsusernamehash[i].mtx);
 3353                 username_locked = 1;
 3354                 hp_idnum = NFSUSERHASH(nidp->nid_uid);
 3355                 mtx_lock(&hp_idnum->mtx);
 3356                 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
 3357                     nusrp) {
 3358                         if (usrp->lug_uid == nidp->nid_uid)
 3359                                 nfsrv_removeuser(usrp, 1);
 3360                 }
 3361         } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
 3362                 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
 3363                     newusrp->lug_namelen);
 3364                 mtx_lock(&hp_name->mtx);
 3365                 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
 3366                     nusrp) {
 3367                         if (usrp->lug_namelen == newusrp->lug_namelen &&
 3368                             !NFSBCMP(usrp->lug_name, newusrp->lug_name,
 3369                             usrp->lug_namelen)) {
 3370                                 thp = NFSUSERHASH(usrp->lug_uid);
 3371                                 mtx_lock(&thp->mtx);
 3372                                 nfsrv_removeuser(usrp, 1);
 3373                                 mtx_unlock(&thp->mtx);
 3374                         }
 3375                 }
 3376                 hp_idnum = NFSUSERHASH(nidp->nid_uid);
 3377                 mtx_lock(&hp_idnum->mtx);
 3378         } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
 3379                 /* Must lock all groupname hash lists first, to avoid a LOR. */
 3380                 for (i = 0; i < nfsrv_lughashsize; i++)
 3381                         mtx_lock(&nfsgroupnamehash[i].mtx);
 3382                 groupname_locked = 1;
 3383                 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
 3384                 mtx_lock(&hp_idnum->mtx);
 3385                 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
 3386                     nusrp) {
 3387                         if (usrp->lug_gid == nidp->nid_gid)
 3388                                 nfsrv_removeuser(usrp, 0);
 3389                 }
 3390         } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
 3391                 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
 3392                     newusrp->lug_namelen);
 3393                 mtx_lock(&hp_name->mtx);
 3394                 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
 3395                     nusrp) {
 3396                         if (usrp->lug_namelen == newusrp->lug_namelen &&
 3397                             !NFSBCMP(usrp->lug_name, newusrp->lug_name,
 3398                             usrp->lug_namelen)) {
 3399                                 thp = NFSGROUPHASH(usrp->lug_gid);
 3400                                 mtx_lock(&thp->mtx);
 3401                                 nfsrv_removeuser(usrp, 0);
 3402                                 mtx_unlock(&thp->mtx);
 3403                         }
 3404                 }
 3405                 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
 3406                 mtx_lock(&hp_idnum->mtx);
 3407         }
 3408 
 3409         /*
 3410          * Now, we can add the new one.
 3411          */
 3412         if (nidp->nid_usertimeout)
 3413                 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
 3414         else
 3415                 newusrp->lug_expiry = NFSD_MONOSEC + 5;
 3416         if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
 3417                 newusrp->lug_uid = nidp->nid_uid;
 3418                 thp = NFSUSERHASH(newusrp->lug_uid);
 3419                 mtx_assert(&thp->mtx, MA_OWNED);
 3420                 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
 3421                 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
 3422                 mtx_assert(&thp->mtx, MA_OWNED);
 3423                 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
 3424                 atomic_add_int(&nfsrv_usercnt, 1);
 3425         } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
 3426                 newusrp->lug_gid = nidp->nid_gid;
 3427                 thp = NFSGROUPHASH(newusrp->lug_gid);
 3428                 mtx_assert(&thp->mtx, MA_OWNED);
 3429                 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
 3430                 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
 3431                 mtx_assert(&thp->mtx, MA_OWNED);
 3432                 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
 3433                 atomic_add_int(&nfsrv_usercnt, 1);
 3434         } else {
 3435                 if (newusrp->lug_cred != NULL)
 3436                         crfree(newusrp->lug_cred);
 3437                 free(newusrp, M_NFSUSERGROUP);
 3438         }
 3439 
 3440         /*
 3441          * Once per second, allow one thread to trim the cache.
 3442          */
 3443         if (lasttime < NFSD_MONOSEC &&
 3444             atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
 3445                 /*
 3446                  * First, unlock the single mutexes, so that all entries
 3447                  * can be locked and any LOR is avoided.
 3448                  */
 3449                 if (hp_name != NULL) {
 3450                         mtx_unlock(&hp_name->mtx);
 3451                         hp_name = NULL;
 3452                 }
 3453                 if (hp_idnum != NULL) {
 3454                         mtx_unlock(&hp_idnum->mtx);
 3455                         hp_idnum = NULL;
 3456                 }
 3457 
 3458                 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
 3459                     NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
 3460                         if (username_locked == 0) {
 3461                                 for (i = 0; i < nfsrv_lughashsize; i++)
 3462                                         mtx_lock(&nfsusernamehash[i].mtx);
 3463                                 username_locked = 1;
 3464                         }
 3465                         KASSERT(user_locked == 0,
 3466                             ("nfssvc_idname: user_locked"));
 3467                         for (i = 0; i < nfsrv_lughashsize; i++)
 3468                                 mtx_lock(&nfsuserhash[i].mtx);
 3469                         user_locked = 1;
 3470                         for (i = 0; i < nfsrv_lughashsize; i++) {
 3471                                 TAILQ_FOREACH_SAFE(usrp,
 3472                                     &nfsuserhash[i].lughead, lug_numhash,
 3473                                     nusrp)
 3474                                         if (usrp->lug_expiry < NFSD_MONOSEC)
 3475                                                 nfsrv_removeuser(usrp, 1);
 3476                         }
 3477                         for (i = 0; i < nfsrv_lughashsize; i++) {
 3478                                 /*
 3479                                  * Trim the cache using an approximate LRU
 3480                                  * algorithm.  This code deletes the least
 3481                                  * recently used entry on each hash list.
 3482                                  */
 3483                                 if (nfsrv_usercnt <= nfsrv_usermax)
 3484                                         break;
 3485                                 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
 3486                                 if (usrp != NULL)
 3487                                         nfsrv_removeuser(usrp, 1);
 3488                         }
 3489                 } else {
 3490                         if (groupname_locked == 0) {
 3491                                 for (i = 0; i < nfsrv_lughashsize; i++)
 3492                                         mtx_lock(&nfsgroupnamehash[i].mtx);
 3493                                 groupname_locked = 1;
 3494                         }
 3495                         KASSERT(group_locked == 0,
 3496                             ("nfssvc_idname: group_locked"));
 3497                         for (i = 0; i < nfsrv_lughashsize; i++)
 3498                                 mtx_lock(&nfsgrouphash[i].mtx);
 3499                         group_locked = 1;
 3500                         for (i = 0; i < nfsrv_lughashsize; i++) {
 3501                                 TAILQ_FOREACH_SAFE(usrp,
 3502                                     &nfsgrouphash[i].lughead, lug_numhash,
 3503                                     nusrp)
 3504                                         if (usrp->lug_expiry < NFSD_MONOSEC)
 3505                                                 nfsrv_removeuser(usrp, 0);
 3506                         }
 3507                         for (i = 0; i < nfsrv_lughashsize; i++) {
 3508                                 /*
 3509                                  * Trim the cache using an approximate LRU
 3510                                  * algorithm.  This code deletes the least
 3511                                  * recently user entry on each hash list.
 3512                                  */
 3513                                 if (nfsrv_usercnt <= nfsrv_usermax)
 3514                                         break;
 3515                                 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
 3516                                 if (usrp != NULL)
 3517                                         nfsrv_removeuser(usrp, 0);
 3518                         }
 3519                 }
 3520                 lasttime = NFSD_MONOSEC;
 3521                 atomic_store_rel_int(&onethread, 0);
 3522         }
 3523 
 3524         /* Now, unlock all locked mutexes. */
 3525         if (hp_idnum != NULL)
 3526                 mtx_unlock(&hp_idnum->mtx);
 3527         if (hp_name != NULL)
 3528                 mtx_unlock(&hp_name->mtx);
 3529         if (user_locked != 0)
 3530                 for (i = 0; i < nfsrv_lughashsize; i++)
 3531                         mtx_unlock(&nfsuserhash[i].mtx);
 3532         if (username_locked != 0)
 3533                 for (i = 0; i < nfsrv_lughashsize; i++)
 3534                         mtx_unlock(&nfsusernamehash[i].mtx);
 3535         if (group_locked != 0)
 3536                 for (i = 0; i < nfsrv_lughashsize; i++)
 3537                         mtx_unlock(&nfsgrouphash[i].mtx);
 3538         if (groupname_locked != 0)
 3539                 for (i = 0; i < nfsrv_lughashsize; i++)
 3540                         mtx_unlock(&nfsgroupnamehash[i].mtx);
 3541 out:
 3542         NFSEXITCODE(error);
 3543         return (error);
 3544 }
 3545 
 3546 /*
 3547  * Remove a user/group name element.
 3548  */
 3549 static void
 3550 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
 3551 {
 3552         struct nfsrv_lughash *hp;
 3553 
 3554         if (isuser != 0) {
 3555                 hp = NFSUSERHASH(usrp->lug_uid);
 3556                 mtx_assert(&hp->mtx, MA_OWNED);
 3557                 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
 3558                 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
 3559                 mtx_assert(&hp->mtx, MA_OWNED);
 3560                 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
 3561         } else {
 3562                 hp = NFSGROUPHASH(usrp->lug_gid);
 3563                 mtx_assert(&hp->mtx, MA_OWNED);
 3564                 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
 3565                 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
 3566                 mtx_assert(&hp->mtx, MA_OWNED);
 3567                 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
 3568         }
 3569         atomic_add_int(&nfsrv_usercnt, -1);
 3570         if (usrp->lug_cred != NULL)
 3571                 crfree(usrp->lug_cred);
 3572         free(usrp, M_NFSUSERGROUP);
 3573 }
 3574 
 3575 /*
 3576  * Free up all the allocations related to the name<-->id cache.
 3577  * This function should only be called when the nfsuserd daemon isn't
 3578  * running, since it doesn't do any locking.
 3579  * This function is meant to be used when the nfscommon module is unloaded.
 3580  */
 3581 APPLESTATIC void
 3582 nfsrv_cleanusergroup(void)
 3583 {
 3584         struct nfsrv_lughash *hp, *hp2;
 3585         struct nfsusrgrp *nusrp, *usrp;
 3586         int i;
 3587 
 3588         if (nfsuserhash == NULL)
 3589                 return;
 3590 
 3591         for (i = 0; i < nfsrv_lughashsize; i++) {
 3592                 hp = &nfsuserhash[i];
 3593                 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
 3594                         TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
 3595                         hp2 = NFSUSERNAMEHASH(usrp->lug_name,
 3596                             usrp->lug_namelen);
 3597                         TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
 3598                         if (usrp->lug_cred != NULL)
 3599                                 crfree(usrp->lug_cred);
 3600                         free(usrp, M_NFSUSERGROUP);
 3601                 }
 3602                 hp = &nfsgrouphash[i];
 3603                 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
 3604                         TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
 3605                         hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
 3606                             usrp->lug_namelen);
 3607                         TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
 3608                         if (usrp->lug_cred != NULL)
 3609                                 crfree(usrp->lug_cred);
 3610                         free(usrp, M_NFSUSERGROUP);
 3611                 }
 3612                 mtx_destroy(&nfsuserhash[i].mtx);
 3613                 mtx_destroy(&nfsusernamehash[i].mtx);
 3614                 mtx_destroy(&nfsgroupnamehash[i].mtx);
 3615                 mtx_destroy(&nfsgrouphash[i].mtx);
 3616         }
 3617         free(nfsuserhash, M_NFSUSERGROUP);
 3618         free(nfsusernamehash, M_NFSUSERGROUP);
 3619         free(nfsgrouphash, M_NFSUSERGROUP);
 3620         free(nfsgroupnamehash, M_NFSUSERGROUP);
 3621         free(nfsrv_dnsname, M_NFSSTRING);
 3622 }
 3623 
 3624 /*
 3625  * This function scans a byte string and checks for UTF-8 compliance.
 3626  * It returns 0 if it conforms and NFSERR_INVAL if not.
 3627  */
 3628 APPLESTATIC int
 3629 nfsrv_checkutf8(u_int8_t *cp, int len)
 3630 {
 3631         u_int32_t val = 0x0;
 3632         int cnt = 0, gotd = 0, shift = 0;
 3633         u_int8_t byte;
 3634         static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
 3635         int error = 0;
 3636 
 3637         /*
 3638          * Here are what the variables are used for:
 3639          * val - the calculated value of a multibyte char, used to check
 3640          *       that it was coded with the correct range
 3641          * cnt - the number of 10xxxxxx bytes to follow
 3642          * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
 3643          * shift - lower order bits of range (ie. "val >> shift" should
 3644          *       not be 0, in other words, dividing by the lower bound
 3645          *       of the range should get a non-zero value)
 3646          * byte - used to calculate cnt
 3647          */
 3648         while (len > 0) {
 3649                 if (cnt > 0) {
 3650                         /* This handles the 10xxxxxx bytes */
 3651                         if ((*cp & 0xc0) != 0x80 ||
 3652                             (gotd && (*cp & 0x20))) {
 3653                                 error = NFSERR_INVAL;
 3654                                 goto out;
 3655                         }
 3656                         gotd = 0;
 3657                         val <<= 6;
 3658                         val |= (*cp & 0x3f);
 3659                         cnt--;
 3660                         if (cnt == 0 && (val >> shift) == 0x0) {
 3661                                 error = NFSERR_INVAL;
 3662                                 goto out;
 3663                         }
 3664                 } else if (*cp & 0x80) {
 3665                         /* first byte of multi byte char */
 3666                         byte = *cp;
 3667                         while ((byte & 0x40) && cnt < 6) {
 3668                                 cnt++;
 3669                                 byte <<= 1;
 3670                         }
 3671                         if (cnt == 0 || cnt == 6) {
 3672                                 error = NFSERR_INVAL;
 3673                                 goto out;
 3674                         }
 3675                         val = (*cp & (0x3f >> cnt));
 3676                         shift = utf8_shift[cnt - 1];
 3677                         if (cnt == 2 && val == 0xd)
 3678                                 /* Check for the 0xd800-0xdfff case */
 3679                                 gotd = 1;
 3680                 }
 3681                 cp++;
 3682                 len--;
 3683         }
 3684         if (cnt > 0)
 3685                 error = NFSERR_INVAL;
 3686 
 3687 out:
 3688         NFSEXITCODE(error);
 3689         return (error);
 3690 }
 3691 
 3692 /*
 3693  * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
 3694  * strings, one with the root path in it and the other with the list of
 3695  * locations. The list is in the same format as is found in nfr_refs.
 3696  * It is a "," separated list of entries, where each of them is of the
 3697  * form <server>:<rootpath>. For example
 3698  * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
 3699  * The nilp argument is set to 1 for the special case of a null fs_root
 3700  * and an empty server list.
 3701  * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
 3702  * number of xdr bytes parsed in sump.
 3703  */
 3704 static int
 3705 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
 3706     int *sump, int *nilp)
 3707 {
 3708         u_int32_t *tl;
 3709         u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
 3710         int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
 3711         struct list {
 3712                 SLIST_ENTRY(list) next;
 3713                 int len;
 3714                 u_char host[1];
 3715         } *lsp, *nlsp;
 3716         SLIST_HEAD(, list) head;
 3717 
 3718         *fsrootp = NULL;
 3719         *srvp = NULL;
 3720         *nilp = 0;
 3721 
 3722         /*
 3723          * Get the fs_root path and check for the special case of null path
 3724          * and 0 length server list.
 3725          */
 3726         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3727         len = fxdr_unsigned(int, *tl);
 3728         if (len < 0 || len > 10240) {
 3729                 error = NFSERR_BADXDR;
 3730                 goto nfsmout;
 3731         }
 3732         if (len == 0) {
 3733                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3734                 if (*tl != 0) {
 3735                         error = NFSERR_BADXDR;
 3736                         goto nfsmout;
 3737                 }
 3738                 *nilp = 1;
 3739                 *sump = 2 * NFSX_UNSIGNED;
 3740                 error = 0;
 3741                 goto nfsmout;
 3742         }
 3743         cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
 3744         error = nfsrv_mtostr(nd, cp, len);
 3745         if (!error) {
 3746                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3747                 cnt = fxdr_unsigned(int, *tl);
 3748                 if (cnt <= 0)
 3749                         error = NFSERR_BADXDR;
 3750         }
 3751         if (error)
 3752                 goto nfsmout;
 3753 
 3754         /*
 3755          * Now, loop through the location list and make up the srvlist.
 3756          */
 3757         xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
 3758         cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
 3759         slen = 1024;
 3760         siz = 0;
 3761         for (i = 0; i < cnt; i++) {
 3762                 SLIST_INIT(&head);
 3763                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3764                 nsrv = fxdr_unsigned(int, *tl);
 3765                 if (nsrv <= 0) {
 3766                         error = NFSERR_BADXDR;
 3767                         goto nfsmout;
 3768                 }
 3769 
 3770                 /*
 3771                  * Handle the first server by putting it in the srvstr.
 3772                  */
 3773                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3774                 len = fxdr_unsigned(int, *tl);
 3775                 if (len <= 0 || len > 1024) {
 3776                         error = NFSERR_BADXDR;
 3777                         goto nfsmout;
 3778                 }
 3779                 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
 3780                 if (cp3 != cp2) {
 3781                         *cp3++ = ',';
 3782                         siz++;
 3783                 }
 3784                 error = nfsrv_mtostr(nd, cp3, len);
 3785                 if (error)
 3786                         goto nfsmout;
 3787                 cp3 += len;
 3788                 *cp3++ = ':';
 3789                 siz += (len + 1);
 3790                 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
 3791                 for (j = 1; j < nsrv; j++) {
 3792                         /*
 3793                          * Yuck, put them in an slist and process them later.
 3794                          */
 3795                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3796                         len = fxdr_unsigned(int, *tl);
 3797                         if (len <= 0 || len > 1024) {
 3798                                 error = NFSERR_BADXDR;
 3799                                 goto nfsmout;
 3800                         }
 3801                         lsp = (struct list *)malloc(sizeof (struct list)
 3802                             + len, M_TEMP, M_WAITOK);
 3803                         error = nfsrv_mtostr(nd, lsp->host, len);
 3804                         if (error)
 3805                                 goto nfsmout;
 3806                         xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
 3807                         lsp->len = len;
 3808                         SLIST_INSERT_HEAD(&head, lsp, next);
 3809                 }
 3810 
 3811                 /*
 3812                  * Finally, we can get the path.
 3813                  */
 3814                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3815                 len = fxdr_unsigned(int, *tl);
 3816                 if (len <= 0 || len > 1024) {
 3817                         error = NFSERR_BADXDR;
 3818                         goto nfsmout;
 3819                 }
 3820                 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
 3821                 error = nfsrv_mtostr(nd, cp3, len);
 3822                 if (error)
 3823                         goto nfsmout;
 3824                 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
 3825                 str = cp3;
 3826                 stringlen = len;
 3827                 cp3 += len;
 3828                 siz += len;
 3829                 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
 3830                         nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
 3831                             &cp2, &cp3, &slen);
 3832                         *cp3++ = ',';
 3833                         NFSBCOPY(lsp->host, cp3, lsp->len);
 3834                         cp3 += lsp->len;
 3835                         *cp3++ = ':';
 3836                         NFSBCOPY(str, cp3, stringlen);
 3837                         cp3 += stringlen;
 3838                         *cp3 = '\0';
 3839                         siz += (lsp->len + stringlen + 2);
 3840                         free((caddr_t)lsp, M_TEMP);
 3841                 }
 3842         }
 3843         *fsrootp = cp;
 3844         *srvp = cp2;
 3845         *sump = xdrsum;
 3846         NFSEXITCODE2(0, nd);
 3847         return (0);
 3848 nfsmout:
 3849         if (cp != NULL)
 3850                 free(cp, M_NFSSTRING);
 3851         if (cp2 != NULL)
 3852                 free(cp2, M_NFSSTRING);
 3853         NFSEXITCODE2(error, nd);
 3854         return (error);
 3855 }
 3856 
 3857 /*
 3858  * Make the malloc'd space large enough. This is a pain, but the xdr
 3859  * doesn't set an upper bound on the side, so...
 3860  */
 3861 static void
 3862 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
 3863 {
 3864         u_char *cp;
 3865         int i;
 3866 
 3867         if (siz <= *slenp)
 3868                 return;
 3869         cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
 3870         NFSBCOPY(*cpp, cp, *slenp);
 3871         free(*cpp, M_NFSSTRING);
 3872         i = *cpp2 - *cpp;
 3873         *cpp = cp;
 3874         *cpp2 = cp + i;
 3875         *slenp = siz + 1024;
 3876 }
 3877 
 3878 /*
 3879  * Initialize the reply header data structures.
 3880  */
 3881 APPLESTATIC void
 3882 nfsrvd_rephead(struct nfsrv_descript *nd)
 3883 {
 3884         mbuf_t mreq;
 3885 
 3886         /*
 3887          * If this is a big reply, use a cluster.
 3888          */
 3889         if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
 3890             nfs_bigreply[nd->nd_procnum]) {
 3891                 NFSMCLGET(mreq, M_WAITOK);
 3892                 nd->nd_mreq = mreq;
 3893                 nd->nd_mb = mreq;
 3894         } else {
 3895                 NFSMGET(mreq);
 3896                 nd->nd_mreq = mreq;
 3897                 nd->nd_mb = mreq;
 3898         }
 3899         nd->nd_bpos = NFSMTOD(mreq, caddr_t);
 3900         mbuf_setlen(mreq, 0);
 3901 
 3902         if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
 3903                 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
 3904 }
 3905 
 3906 /*
 3907  * Lock a socket against others.
 3908  * Currently used to serialize connect/disconnect attempts.
 3909  */
 3910 int
 3911 newnfs_sndlock(int *flagp)
 3912 {
 3913         struct timespec ts;
 3914 
 3915         NFSLOCKSOCK();
 3916         while (*flagp & NFSR_SNDLOCK) {
 3917                 *flagp |= NFSR_WANTSND;
 3918                 ts.tv_sec = 0;
 3919                 ts.tv_nsec = 0;
 3920                 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
 3921                     PZERO - 1, "nfsndlck", &ts);
 3922         }
 3923         *flagp |= NFSR_SNDLOCK;
 3924         NFSUNLOCKSOCK();
 3925         return (0);
 3926 }
 3927 
 3928 /*
 3929  * Unlock the stream socket for others.
 3930  */
 3931 void
 3932 newnfs_sndunlock(int *flagp)
 3933 {
 3934 
 3935         NFSLOCKSOCK();
 3936         if ((*flagp & NFSR_SNDLOCK) == 0)
 3937                 panic("nfs sndunlock");
 3938         *flagp &= ~NFSR_SNDLOCK;
 3939         if (*flagp & NFSR_WANTSND) {
 3940                 *flagp &= ~NFSR_WANTSND;
 3941                 wakeup((caddr_t)flagp);
 3942         }
 3943         NFSUNLOCKSOCK();
 3944 }
 3945 
 3946 APPLESTATIC int
 3947 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
 3948     int *isudp)
 3949 {
 3950         struct sockaddr_in *sad;
 3951         struct sockaddr_in6 *sad6;
 3952         struct in_addr saddr;
 3953         uint32_t portnum, *tl;
 3954         int af = 0, i, j, k;
 3955         char addr[64], protocol[5], *cp;
 3956         int cantparse = 0, error = 0;
 3957         uint16_t portv;
 3958 
 3959         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3960         i = fxdr_unsigned(int, *tl);
 3961         if (i >= 3 && i <= 4) {
 3962                 error = nfsrv_mtostr(nd, protocol, i);
 3963                 if (error)
 3964                         goto nfsmout;
 3965                 if (strcmp(protocol, "tcp") == 0) {
 3966                         af = AF_INET;
 3967                         *isudp = 0;
 3968                 } else if (strcmp(protocol, "udp") == 0) {
 3969                         af = AF_INET;
 3970                         *isudp = 1;
 3971                 } else if (strcmp(protocol, "tcp6") == 0) {
 3972                         af = AF_INET6;
 3973                         *isudp = 0;
 3974                 } else if (strcmp(protocol, "udp6") == 0) {
 3975                         af = AF_INET6;
 3976                         *isudp = 1;
 3977                 } else
 3978                         cantparse = 1;
 3979         } else {
 3980                 cantparse = 1;
 3981                 if (i > 0) {
 3982                         error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
 3983                         if (error)
 3984                                 goto nfsmout;
 3985                 }
 3986         }
 3987         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3988         i = fxdr_unsigned(int, *tl);
 3989         if (i < 0) {
 3990                 error = NFSERR_BADXDR;
 3991                 goto nfsmout;
 3992         } else if (cantparse == 0 && i >= 11 && i < 64) {
 3993                 /*
 3994                  * The shortest address is 11chars and the longest is < 64.
 3995                  */
 3996                 error = nfsrv_mtostr(nd, addr, i);
 3997                 if (error)
 3998                         goto nfsmout;
 3999 
 4000                 /* Find the port# at the end and extract that. */
 4001                 i = strlen(addr);
 4002                 k = 0;
 4003                 cp = &addr[i - 1];
 4004                 /* Count back two '.'s from end to get port# field. */
 4005                 for (j = 0; j < i; j++) {
 4006                         if (*cp == '.') {
 4007                                 k++;
 4008                                 if (k == 2)
 4009                                         break;
 4010                         }
 4011                         cp--;
 4012                 }
 4013                 if (k == 2) {
 4014                         /*
 4015                          * The NFSv4 port# is appended as .N.N, where N is
 4016                          * a decimal # in the range 0-255, just like an inet4
 4017                          * address. Cheat and use inet_aton(), which will
 4018                          * return a Class A address and then shift the high
 4019                          * order 8bits over to convert it to the port#.
 4020                          */
 4021                         *cp++ = '\0';
 4022                         if (inet_aton(cp, &saddr) == 1) {
 4023                                 portnum = ntohl(saddr.s_addr);
 4024                                 portv = (uint16_t)((portnum >> 16) |
 4025                                     (portnum & 0xff));
 4026                         } else
 4027                                 cantparse = 1;
 4028                 } else
 4029                         cantparse = 1;
 4030                 if (cantparse == 0) {
 4031                         if (af == AF_INET) {
 4032                                 sad = (struct sockaddr_in *)sa;
 4033                                 if (inet_pton(af, addr, &sad->sin_addr) == 1) {
 4034                                         sad->sin_len = sizeof(*sad);
 4035                                         sad->sin_family = AF_INET;
 4036                                         sad->sin_port = htons(portv);
 4037                                         return (0);
 4038                                 }
 4039                         } else {
 4040                                 sad6 = (struct sockaddr_in6 *)sa;
 4041                                 if (inet_pton(af, addr, &sad6->sin6_addr)
 4042                                     == 1) {
 4043                                         sad6->sin6_len = sizeof(*sad6);
 4044                                         sad6->sin6_family = AF_INET6;
 4045                                         sad6->sin6_port = htons(portv);
 4046                                         return (0);
 4047                                 }
 4048                         }
 4049                 }
 4050         } else {
 4051                 if (i > 0) {
 4052                         error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
 4053                         if (error)
 4054                                 goto nfsmout;
 4055                 }
 4056         }
 4057         error = EPERM;
 4058 nfsmout:
 4059         return (error);
 4060 }
 4061 
 4062 /*
 4063  * Handle an NFSv4.1 Sequence request for the session.
 4064  * If reply != NULL, use it to return the cached reply, as required.
 4065  * The client gets a cached reply via this call for callbacks, however the
 4066  * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
 4067  */
 4068 int
 4069 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
 4070     struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
 4071 {
 4072         int error;
 4073 
 4074         error = 0;
 4075         if (reply != NULL)
 4076                 *reply = NULL;
 4077         if (slotid > maxslot)
 4078                 return (NFSERR_BADSLOT);
 4079         if (seqid == slots[slotid].nfssl_seq) {
 4080                 /* A retry. */
 4081                 if (slots[slotid].nfssl_inprog != 0)
 4082                         error = NFSERR_DELAY;
 4083                 else if (slots[slotid].nfssl_reply != NULL) {
 4084                         if (reply != NULL) {
 4085                                 *reply = slots[slotid].nfssl_reply;
 4086                                 slots[slotid].nfssl_reply = NULL;
 4087                         }
 4088                         slots[slotid].nfssl_inprog = 1;
 4089                         error = NFSERR_REPLYFROMCACHE;
 4090                 } else
 4091                         /* No reply cached, so just do it. */
 4092                         slots[slotid].nfssl_inprog = 1;
 4093         } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
 4094                 if (slots[slotid].nfssl_reply != NULL)
 4095                         m_freem(slots[slotid].nfssl_reply);
 4096                 slots[slotid].nfssl_reply = NULL;
 4097                 slots[slotid].nfssl_inprog = 1;
 4098                 slots[slotid].nfssl_seq++;
 4099         } else
 4100                 error = NFSERR_SEQMISORDERED;
 4101         return (error);
 4102 }
 4103 
 4104 /*
 4105  * Cache this reply for the slot.
 4106  * Use the "rep" argument to return the cached reply if repstat is set to
 4107  * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
 4108  */
 4109 void
 4110 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
 4111    struct mbuf **rep)
 4112 {
 4113 
 4114         if (repstat == NFSERR_REPLYFROMCACHE) {
 4115                 *rep = slots[slotid].nfssl_reply;
 4116                 slots[slotid].nfssl_reply = NULL;
 4117         } else {
 4118                 if (slots[slotid].nfssl_reply != NULL)
 4119                         m_freem(slots[slotid].nfssl_reply);
 4120                 slots[slotid].nfssl_reply = *rep;
 4121         }
 4122         slots[slotid].nfssl_inprog = 0;
 4123 }
 4124 
 4125 /*
 4126  * Generate the xdr for an NFSv4.1 Sequence Operation.
 4127  */
 4128 APPLESTATIC void
 4129 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
 4130     struct nfsclsession *sep, int dont_replycache)
 4131 {
 4132         uint32_t *tl, slotseq = 0;
 4133         int error, maxslot, slotpos;
 4134         uint8_t sessionid[NFSX_V4SESSIONID];
 4135 
 4136         error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
 4137             sessionid);
 4138 
 4139         /* Build the Sequence arguments. */
 4140         NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
 4141         nd->nd_sequence = tl;
 4142         bcopy(sessionid, tl, NFSX_V4SESSIONID);
 4143         tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
 4144         nd->nd_slotseq = tl;
 4145         if (error == 0) {
 4146                 *tl++ = txdr_unsigned(slotseq);
 4147                 *tl++ = txdr_unsigned(slotpos);
 4148                 *tl++ = txdr_unsigned(maxslot);
 4149                 if (dont_replycache == 0)
 4150                         *tl = newnfs_true;
 4151                 else
 4152                         *tl = newnfs_false;
 4153         } else {
 4154                 /*
 4155                  * There are two errors and the rest of the session can
 4156                  * just be zeros.
 4157                  * NFSERR_BADSESSION: This bad session should just generate
 4158                  *    the same error again when the RPC is retried.
 4159                  * ESTALE: A forced dismount is in progress and will cause the
 4160                  *    RPC to fail later.
 4161                  */
 4162                 *tl++ = 0;
 4163                 *tl++ = 0;
 4164                 *tl++ = 0;
 4165                 *tl = 0;
 4166         }
 4167         nd->nd_flag |= ND_HASSEQUENCE;
 4168 }
 4169 
 4170 int
 4171 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
 4172     int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
 4173 {
 4174         int i, maxslot, slotpos;
 4175         uint64_t bitval;
 4176 
 4177         /* Find an unused slot. */
 4178         slotpos = -1;
 4179         maxslot = -1;
 4180         mtx_lock(&sep->nfsess_mtx);
 4181         do {
 4182                 if (nmp != NULL && sep->nfsess_defunct != 0) {
 4183                         /* Just return the bad session. */
 4184                         bcopy(sep->nfsess_sessionid, sessionid,
 4185                             NFSX_V4SESSIONID);
 4186                         mtx_unlock(&sep->nfsess_mtx);
 4187                         return (NFSERR_BADSESSION);
 4188                 }
 4189                 bitval = 1;
 4190                 for (i = 0; i < sep->nfsess_foreslots; i++) {
 4191                         if ((bitval & sep->nfsess_slots) == 0) {
 4192                                 slotpos = i;
 4193                                 sep->nfsess_slots |= bitval;
 4194                                 sep->nfsess_slotseq[i]++;
 4195                                 *slotseqp = sep->nfsess_slotseq[i];
 4196                                 break;
 4197                         }
 4198                         bitval <<= 1;
 4199                 }
 4200                 if (slotpos == -1) {
 4201                         /*
 4202                          * If a forced dismount is in progress, just return.
 4203                          * This RPC attempt will fail when it calls
 4204                          * newnfs_request().
 4205                          */
 4206                         if (nmp != NULL &&
 4207                             (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF)
 4208                             != 0) {
 4209                                 mtx_unlock(&sep->nfsess_mtx);
 4210                                 return (ESTALE);
 4211                         }
 4212                         /* Wake up once/sec, to check for a forced dismount. */
 4213                         (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
 4214                             PZERO, "nfsclseq", hz);
 4215                 }
 4216         } while (slotpos == -1);
 4217         /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
 4218         bitval = 1;
 4219         for (i = 0; i < 64; i++) {
 4220                 if ((bitval & sep->nfsess_slots) != 0)
 4221                         maxslot = i;
 4222                 bitval <<= 1;
 4223         }
 4224         bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
 4225         mtx_unlock(&sep->nfsess_mtx);
 4226         *slotposp = slotpos;
 4227         *maxslotp = maxslot;
 4228         return (0);
 4229 }
 4230 
 4231 /*
 4232  * Free a session slot.
 4233  */
 4234 APPLESTATIC void
 4235 nfsv4_freeslot(struct nfsclsession *sep, int slot)
 4236 {
 4237         uint64_t bitval;
 4238 
 4239         bitval = 1;
 4240         if (slot > 0)
 4241                 bitval <<= slot;
 4242         mtx_lock(&sep->nfsess_mtx);
 4243         if ((bitval & sep->nfsess_slots) == 0)
 4244                 printf("freeing free slot!!\n");
 4245         sep->nfsess_slots &= ~bitval;
 4246         wakeup(&sep->nfsess_slots);
 4247         mtx_unlock(&sep->nfsess_mtx);
 4248 }
 4249 

Cache object: 1039a853f20ddc5fdf2400d243ec39b0


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.