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


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

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

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

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

Cache object: e63c0dff40370005b3f6e00f3cb9cbd2


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