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