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

Cache object: 68c48020472f031c50825e6351abbd15


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