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

Cache object: 39e221a745b7aa64dcdc326cc0a29b91


[ 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.