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


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

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

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

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

Cache object: 2d01335a096a87dd490bf566ce3ecf0a


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