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