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