xref: /freebsd/sys/fs/nfs/nfs_commonsubs.c (revision 830940567b49bb0c08dfaed40418999e76616909)
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 #ifdef NFS4_ACL_EXTATTR_NAME
654 	if (aclp)
655 		aclp->acl_cnt = 0;
656 #endif
657 	/*
658 	 * Parse out the ace entries and expect them to conform to
659 	 * what can be supported by R/W/X bits.
660 	 */
661 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
662 	aclsize = NFSX_UNSIGNED;
663 	acecnt = fxdr_unsigned(int, *tl);
664 #ifdef NFS4_ACL_EXTATTR_NAME
665 	if (acecnt > ACL_MAX_ENTRIES)
666 		aceerr = 1;
667 #endif
668 	if (nfsrv_useacl == 0)
669 		aceerr = 1;
670 	for (i = 0; i < acecnt; i++) {
671 #ifdef NFS4_ACL_EXTATTR_NAME
672 		if (aclp && !aceerr)
673 			error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
674 			    &aceerr, &acesize, p);
675 		else
676 #endif
677 			error = nfsrv_skipace(nd, &acesize);
678 		if (error)
679 			return (error);
680 		aclsize += acesize;
681 	}
682 #ifdef NFS4_ACL_EXTATTR_NAME
683 	if (aclp && !aceerr)
684 		aclp->acl_cnt = acecnt;
685 #endif
686 	if (aceerr)
687 		*aclerrp = aceerr;
688 	if (aclsizep)
689 		*aclsizep = aclsize;
690 nfsmout:
691 	return (error);
692 }
693 
694 /*
695  * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
696  */
697 static int
698 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
699 {
700 	u_int32_t *tl;
701 	int error, len = 0;
702 
703 	NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
704 	len = fxdr_unsigned(int, *(tl + 3));
705 	error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
706 nfsmout:
707 	*acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
708 	return (error);
709 }
710 
711 /*
712  * Get attribute bits from an mbuf list.
713  * Returns EBADRPC for a parsing error, 0 otherwise.
714  * If the clearinvalid flag is set, clear the bits not supported.
715  */
716 APPLESTATIC int
717 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
718     int *retnotsupp)
719 {
720 	u_int32_t *tl;
721 	int cnt, i, outcnt;
722 	int error = 0;
723 
724 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
725 	cnt = fxdr_unsigned(int, *tl);
726 	if (cnt < 0)
727 		return (NFSERR_BADXDR);
728 	if (cnt > NFSATTRBIT_MAXWORDS) {
729 		outcnt = NFSATTRBIT_MAXWORDS;
730 		if (retnotsupp)
731 			*retnotsupp = NFSERR_ATTRNOTSUPP;
732 	} else {
733 		outcnt = cnt;
734 	}
735 	NFSZERO_ATTRBIT(attrbitp);
736 	if (outcnt > 0) {
737 		NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
738 		for (i = 0; i < outcnt; i++)
739 			attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
740 	}
741 	if (cnt > outcnt)
742 		error = nfsm_advance(nd, (cnt - outcnt) * NFSX_UNSIGNED, -1);
743 	if (cntp)
744 		*cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
745 nfsmout:
746 	return (error);
747 }
748 
749 /*
750  * Get the attributes for V4.
751  * If the compare flag is true, test for any attribute changes,
752  * otherwise return the attribute values.
753  * These attributes cover fields in "struct vattr", "struct statfs",
754  * "struct nfsfsinfo", the file handle and the lease duration.
755  * The value of retcmpp is set to 1 if all attributes are the same,
756  * and 0 otherwise.
757  * Returns EBADRPC if it can't be parsed, 0 otherwise.
758  */
759 APPLESTATIC int
760 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
761     struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
762     struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
763     struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
764     u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
765 {
766 	u_int32_t *tl;
767 	int i = 0, j, k, l, m, bitpos, attrsum = 0;
768 	int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
769 	u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
770 	nfsattrbit_t attrbits, retattrbits, checkattrbits;
771 	struct nfsfh *tnfhp;
772 	struct nfsreferral *refp;
773 	u_quad_t tquad;
774 	nfsquad_t tnfsquad;
775 	struct timespec temptime;
776 	uid_t uid;
777 	gid_t gid;
778 	long fid;
779 	u_int32_t freenum = 0, tuint;
780 	u_int64_t uquad = 0, thyp, thyp2;
781 #ifdef QUOTA
782 	struct dqblk dqb;
783 	uid_t savuid;
784 #endif
785 
786 	if (compare) {
787 		retnotsup = 0;
788 		error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
789 	} else {
790 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
791 	}
792 	if (error)
793 		return (error);
794 
795 	if (compare) {
796 		*retcmpp = retnotsup;
797 	} else {
798 		/*
799 		 * Just set default values to some of the important ones.
800 		 */
801 		if (nap != NULL) {
802 			nap->na_type = VREG;
803 			nap->na_mode = 0;
804 			nap->na_rdev = (NFSDEV_T)0;
805 			nap->na_mtime.tv_sec = 0;
806 			nap->na_mtime.tv_nsec = 0;
807 			nap->na_gen = 0;
808 			nap->na_flags = 0;
809 			nap->na_blocksize = NFS_FABLKSIZE;
810 		}
811 		if (sbp != NULL) {
812 			sbp->f_bsize = NFS_FABLKSIZE;
813 			sbp->f_blocks = 0;
814 			sbp->f_bfree = 0;
815 			sbp->f_bavail = 0;
816 			sbp->f_files = 0;
817 			sbp->f_ffree = 0;
818 		}
819 		if (fsp != NULL) {
820 			fsp->fs_rtmax = 8192;
821 			fsp->fs_rtpref = 8192;
822 			fsp->fs_maxname = NFS_MAXNAMLEN;
823 			fsp->fs_wtmax = 8192;
824 			fsp->fs_wtpref = 8192;
825 			fsp->fs_wtmult = NFS_FABLKSIZE;
826 			fsp->fs_dtpref = 8192;
827 			fsp->fs_maxfilesize = 0xffffffffffffffffull;
828 			fsp->fs_timedelta.tv_sec = 0;
829 			fsp->fs_timedelta.tv_nsec = 1;
830 			fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
831 				NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
832 		}
833 		if (pc != NULL) {
834 			pc->pc_linkmax = LINK_MAX;
835 			pc->pc_namemax = NAME_MAX;
836 			pc->pc_notrunc = 0;
837 			pc->pc_chownrestricted = 0;
838 			pc->pc_caseinsensitive = 0;
839 			pc->pc_casepreserving = 1;
840 		}
841 	}
842 
843 	/*
844 	 * Loop around getting the attributes.
845 	 */
846 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
847 	attrsize = fxdr_unsigned(int, *tl);
848 	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
849 	    if (attrsum > attrsize) {
850 		error = NFSERR_BADXDR;
851 		goto nfsmout;
852 	    }
853 	    if (NFSISSET_ATTRBIT(&attrbits, bitpos))
854 		switch (bitpos) {
855 		case NFSATTRBIT_SUPPORTEDATTRS:
856 			retnotsup = 0;
857 			if (compare || nap == NULL)
858 			    error = nfsrv_getattrbits(nd, &retattrbits,
859 				&cnt, &retnotsup);
860 			else
861 			    error = nfsrv_getattrbits(nd, &nap->na_suppattr,
862 				&cnt, &retnotsup);
863 			if (error)
864 			    return (error);
865 			if (compare && !(*retcmpp)) {
866 			   NFSSETSUPP_ATTRBIT(&checkattrbits);
867 			   if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
868 			       || retnotsup)
869 				*retcmpp = NFSERR_NOTSAME;
870 			}
871 			attrsum += cnt;
872 			break;
873 		case NFSATTRBIT_TYPE:
874 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
875 			if (compare) {
876 				if (!(*retcmpp)) {
877 				    if (nap->na_type != nfsv34tov_type(*tl))
878 					*retcmpp = NFSERR_NOTSAME;
879 				}
880 			} else if (nap != NULL) {
881 				nap->na_type = nfsv34tov_type(*tl);
882 			}
883 			attrsum += NFSX_UNSIGNED;
884 			break;
885 		case NFSATTRBIT_FHEXPIRETYPE:
886 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
887 			if (compare && !(*retcmpp)) {
888 				if (fxdr_unsigned(int, *tl) !=
889 					NFSV4FHTYPE_PERSISTENT)
890 					*retcmpp = NFSERR_NOTSAME;
891 			}
892 			attrsum += NFSX_UNSIGNED;
893 			break;
894 		case NFSATTRBIT_CHANGE:
895 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
896 			if (compare) {
897 				if (!(*retcmpp)) {
898 				    if (nap->na_filerev != fxdr_hyper(tl))
899 					*retcmpp = NFSERR_NOTSAME;
900 				}
901 			} else if (nap != NULL) {
902 				nap->na_filerev = fxdr_hyper(tl);
903 			}
904 			attrsum += NFSX_HYPER;
905 			break;
906 		case NFSATTRBIT_SIZE:
907 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
908 			if (compare) {
909 				if (!(*retcmpp)) {
910 				    if (nap->na_size != fxdr_hyper(tl))
911 					*retcmpp = NFSERR_NOTSAME;
912 				}
913 			} else if (nap != NULL) {
914 				nap->na_size = fxdr_hyper(tl);
915 			}
916 			attrsum += NFSX_HYPER;
917 			break;
918 		case NFSATTRBIT_LINKSUPPORT:
919 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
920 			if (compare) {
921 				if (!(*retcmpp)) {
922 				    if (fsp->fs_properties & NFSV3_FSFLINK) {
923 					if (*tl == newnfs_false)
924 						*retcmpp = NFSERR_NOTSAME;
925 				    } else {
926 					if (*tl == newnfs_true)
927 						*retcmpp = NFSERR_NOTSAME;
928 				    }
929 				}
930 			} else if (fsp != NULL) {
931 				if (*tl == newnfs_true)
932 					fsp->fs_properties |= NFSV3_FSFLINK;
933 				else
934 					fsp->fs_properties &= ~NFSV3_FSFLINK;
935 			}
936 			attrsum += NFSX_UNSIGNED;
937 			break;
938 		case NFSATTRBIT_SYMLINKSUPPORT:
939 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
940 			if (compare) {
941 				if (!(*retcmpp)) {
942 				    if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
943 					if (*tl == newnfs_false)
944 						*retcmpp = NFSERR_NOTSAME;
945 				    } else {
946 					if (*tl == newnfs_true)
947 						*retcmpp = NFSERR_NOTSAME;
948 				    }
949 				}
950 			} else if (fsp != NULL) {
951 				if (*tl == newnfs_true)
952 					fsp->fs_properties |= NFSV3_FSFSYMLINK;
953 				else
954 					fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
955 			}
956 			attrsum += NFSX_UNSIGNED;
957 			break;
958 		case NFSATTRBIT_NAMEDATTR:
959 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
960 			if (compare && !(*retcmpp)) {
961 				if (*tl != newnfs_false)
962 					*retcmpp = NFSERR_NOTSAME;
963 			}
964 			attrsum += NFSX_UNSIGNED;
965 			break;
966 		case NFSATTRBIT_FSID:
967 			NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
968 			thyp = fxdr_hyper(tl);
969 			tl += 2;
970 			thyp2 = fxdr_hyper(tl);
971 			if (compare) {
972 			    if (*retcmpp == 0) {
973 				if (thyp != (u_int64_t)
974 				    vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
975 				    thyp2 != (u_int64_t)
976 				    vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
977 					*retcmpp = NFSERR_NOTSAME;
978 			    }
979 			} else if (nap != NULL) {
980 				nap->na_filesid[0] = thyp;
981 				nap->na_filesid[1] = thyp2;
982 			}
983 			attrsum += (4 * NFSX_UNSIGNED);
984 			break;
985 		case NFSATTRBIT_UNIQUEHANDLES:
986 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
987 			if (compare && !(*retcmpp)) {
988 				if (*tl != newnfs_true)
989 					*retcmpp = NFSERR_NOTSAME;
990 			}
991 			attrsum += NFSX_UNSIGNED;
992 			break;
993 		case NFSATTRBIT_LEASETIME:
994 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
995 			if (compare) {
996 				if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
997 				    !(*retcmpp))
998 					*retcmpp = NFSERR_NOTSAME;
999 			} else if (leasep != NULL) {
1000 				*leasep = fxdr_unsigned(u_int32_t, *tl);
1001 			}
1002 			attrsum += NFSX_UNSIGNED;
1003 			break;
1004 		case NFSATTRBIT_RDATTRERROR:
1005 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1006 			if (compare) {
1007 				 if (!(*retcmpp))
1008 					*retcmpp = NFSERR_INVAL;
1009 			} else if (rderrp != NULL) {
1010 				*rderrp = fxdr_unsigned(u_int32_t, *tl);
1011 			}
1012 			attrsum += NFSX_UNSIGNED;
1013 			break;
1014 		case NFSATTRBIT_ACL:
1015 			if (compare) {
1016 			  if (!(*retcmpp)) {
1017 #ifdef NFS4_ACL_EXTATTR_NAME
1018 			    if (nfsrv_useacl) {
1019 				NFSACL_T *naclp;
1020 
1021 				naclp = acl_alloc(M_WAITOK);
1022 				error = nfsrv_dissectacl(nd, naclp, &aceerr,
1023 				    &cnt, p);
1024 				if (error) {
1025 				    acl_free(naclp);
1026 				    return (error);
1027 				}
1028 				if (aceerr || nfsrv_compareacl(aclp, naclp))
1029 				    *retcmpp = NFSERR_NOTSAME;
1030 				acl_free(naclp);
1031 			    } else
1032 #endif
1033 			    {
1034 				error = nfsrv_dissectacl(nd, NULL, &aceerr,
1035 				    &cnt, p);
1036 				*retcmpp = NFSERR_ATTRNOTSUPP;
1037 			    }
1038 			  }
1039 			} else {
1040 			    if (vp != NULL && aclp != NULL)
1041 				error = nfsrv_dissectacl(nd, aclp, &aceerr,
1042 				    &cnt, p);
1043 			    else
1044 				error = nfsrv_dissectacl(nd, NULL, &aceerr,
1045 				    &cnt, p);
1046 			    if (error)
1047 				return (error);
1048 			}
1049 			attrsum += cnt;
1050 			break;
1051 		case NFSATTRBIT_ACLSUPPORT:
1052 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1053 			if (compare && !(*retcmpp)) {
1054 				if (nfsrv_useacl) {
1055 					if (fxdr_unsigned(u_int32_t, *tl) !=
1056 					    NFSV4ACE_SUPTYPES)
1057 						*retcmpp = NFSERR_NOTSAME;
1058 				} else {
1059 					*retcmpp = NFSERR_ATTRNOTSUPP;
1060 				}
1061 			}
1062 			attrsum += NFSX_UNSIGNED;
1063 			break;
1064 		case NFSATTRBIT_ARCHIVE:
1065 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1066 			if (compare && !(*retcmpp))
1067 				*retcmpp = NFSERR_ATTRNOTSUPP;
1068 			attrsum += NFSX_UNSIGNED;
1069 			break;
1070 		case NFSATTRBIT_CANSETTIME:
1071 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1072 			if (compare) {
1073 				if (!(*retcmpp)) {
1074 				    if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1075 					if (*tl == newnfs_false)
1076 						*retcmpp = NFSERR_NOTSAME;
1077 				    } else {
1078 					if (*tl == newnfs_true)
1079 						*retcmpp = NFSERR_NOTSAME;
1080 				    }
1081 				}
1082 			} else if (fsp != NULL) {
1083 				if (*tl == newnfs_true)
1084 					fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1085 				else
1086 					fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1087 			}
1088 			attrsum += NFSX_UNSIGNED;
1089 			break;
1090 		case NFSATTRBIT_CASEINSENSITIVE:
1091 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1092 			if (compare) {
1093 				if (!(*retcmpp)) {
1094 				    if (*tl != newnfs_false)
1095 					*retcmpp = NFSERR_NOTSAME;
1096 				}
1097 			} else if (pc != NULL) {
1098 				pc->pc_caseinsensitive =
1099 				    fxdr_unsigned(u_int32_t, *tl);
1100 			}
1101 			attrsum += NFSX_UNSIGNED;
1102 			break;
1103 		case NFSATTRBIT_CASEPRESERVING:
1104 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1105 			if (compare) {
1106 				if (!(*retcmpp)) {
1107 				    if (*tl != newnfs_true)
1108 					*retcmpp = NFSERR_NOTSAME;
1109 				}
1110 			} else if (pc != NULL) {
1111 				pc->pc_casepreserving =
1112 				    fxdr_unsigned(u_int32_t, *tl);
1113 			}
1114 			attrsum += NFSX_UNSIGNED;
1115 			break;
1116 		case NFSATTRBIT_CHOWNRESTRICTED:
1117 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1118 			if (compare) {
1119 				if (!(*retcmpp)) {
1120 				    if (*tl != newnfs_true)
1121 					*retcmpp = NFSERR_NOTSAME;
1122 				}
1123 			} else if (pc != NULL) {
1124 				pc->pc_chownrestricted =
1125 				    fxdr_unsigned(u_int32_t, *tl);
1126 			}
1127 			attrsum += NFSX_UNSIGNED;
1128 			break;
1129 		case NFSATTRBIT_FILEHANDLE:
1130 			error = nfsm_getfh(nd, &tnfhp);
1131 			if (error)
1132 				return (error);
1133 			tfhsize = tnfhp->nfh_len;
1134 			if (compare) {
1135 				if (!(*retcmpp) &&
1136 				    !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1137 				     fhp, fhsize))
1138 					*retcmpp = NFSERR_NOTSAME;
1139 				FREE((caddr_t)tnfhp, M_NFSFH);
1140 			} else if (nfhpp != NULL) {
1141 				*nfhpp = tnfhp;
1142 			} else {
1143 				FREE((caddr_t)tnfhp, M_NFSFH);
1144 			}
1145 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1146 			break;
1147 		case NFSATTRBIT_FILEID:
1148 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1149 			thyp = fxdr_hyper(tl);
1150 			if (compare) {
1151 				if (!(*retcmpp)) {
1152 				    if ((u_int64_t)nap->na_fileid != thyp)
1153 					*retcmpp = NFSERR_NOTSAME;
1154 				}
1155 			} else if (nap != NULL) {
1156 				if (*tl++)
1157 					printf("NFSv4 fileid > 32bits\n");
1158 				nap->na_fileid = thyp;
1159 			}
1160 			attrsum += NFSX_HYPER;
1161 			break;
1162 		case NFSATTRBIT_FILESAVAIL:
1163 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1164 			if (compare) {
1165 				if (!(*retcmpp) &&
1166 				    sfp->sf_afiles != fxdr_hyper(tl))
1167 					*retcmpp = NFSERR_NOTSAME;
1168 			} else if (sfp != NULL) {
1169 				sfp->sf_afiles = fxdr_hyper(tl);
1170 			}
1171 			attrsum += NFSX_HYPER;
1172 			break;
1173 		case NFSATTRBIT_FILESFREE:
1174 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1175 			if (compare) {
1176 				if (!(*retcmpp) &&
1177 				    sfp->sf_ffiles != fxdr_hyper(tl))
1178 					*retcmpp = NFSERR_NOTSAME;
1179 			} else if (sfp != NULL) {
1180 				sfp->sf_ffiles = fxdr_hyper(tl);
1181 			}
1182 			attrsum += NFSX_HYPER;
1183 			break;
1184 		case NFSATTRBIT_FILESTOTAL:
1185 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1186 			if (compare) {
1187 				if (!(*retcmpp) &&
1188 				    sfp->sf_tfiles != fxdr_hyper(tl))
1189 					*retcmpp = NFSERR_NOTSAME;
1190 			} else if (sfp != NULL) {
1191 				sfp->sf_tfiles = fxdr_hyper(tl);
1192 			}
1193 			attrsum += NFSX_HYPER;
1194 			break;
1195 		case NFSATTRBIT_FSLOCATIONS:
1196 			error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1197 			if (error)
1198 				return (error);
1199 			attrsum += l;
1200 			if (compare && !(*retcmpp)) {
1201 				refp = nfsv4root_getreferral(vp, NULL, 0);
1202 				if (refp != NULL) {
1203 					if (cp == NULL || cp2 == NULL ||
1204 					    strcmp(cp, "/") ||
1205 					    strcmp(cp2, refp->nfr_srvlist))
1206 						*retcmpp = NFSERR_NOTSAME;
1207 				} else if (m == 0) {
1208 					*retcmpp = NFSERR_NOTSAME;
1209 				}
1210 			}
1211 			if (cp != NULL)
1212 				free(cp, M_NFSSTRING);
1213 			if (cp2 != NULL)
1214 				free(cp2, M_NFSSTRING);
1215 			break;
1216 		case NFSATTRBIT_HIDDEN:
1217 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1218 			if (compare && !(*retcmpp))
1219 				*retcmpp = NFSERR_ATTRNOTSUPP;
1220 			attrsum += NFSX_UNSIGNED;
1221 			break;
1222 		case NFSATTRBIT_HOMOGENEOUS:
1223 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1224 			if (compare) {
1225 				if (!(*retcmpp)) {
1226 				    if (fsp->fs_properties &
1227 					NFSV3_FSFHOMOGENEOUS) {
1228 					if (*tl == newnfs_false)
1229 						*retcmpp = NFSERR_NOTSAME;
1230 				    } else {
1231 					if (*tl == newnfs_true)
1232 						*retcmpp = NFSERR_NOTSAME;
1233 				    }
1234 				}
1235 			} else if (fsp != NULL) {
1236 				if (*tl == newnfs_true)
1237 				    fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1238 				else
1239 				    fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1240 			}
1241 			attrsum += NFSX_UNSIGNED;
1242 			break;
1243 		case NFSATTRBIT_MAXFILESIZE:
1244 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1245 			tnfsquad.qval = fxdr_hyper(tl);
1246 			if (compare) {
1247 				if (!(*retcmpp)) {
1248 					tquad = NFSRV_MAXFILESIZE;
1249 					if (tquad != tnfsquad.qval)
1250 						*retcmpp = NFSERR_NOTSAME;
1251 				}
1252 			} else if (fsp != NULL) {
1253 				fsp->fs_maxfilesize = tnfsquad.qval;
1254 			}
1255 			attrsum += NFSX_HYPER;
1256 			break;
1257 		case NFSATTRBIT_MAXLINK:
1258 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1259 			if (compare) {
1260 				if (!(*retcmpp)) {
1261 				    if (fxdr_unsigned(int, *tl) != LINK_MAX)
1262 					*retcmpp = NFSERR_NOTSAME;
1263 				}
1264 			} else if (pc != NULL) {
1265 				pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1266 			}
1267 			attrsum += NFSX_UNSIGNED;
1268 			break;
1269 		case NFSATTRBIT_MAXNAME:
1270 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1271 			if (compare) {
1272 				if (!(*retcmpp)) {
1273 				    if (fsp->fs_maxname !=
1274 					fxdr_unsigned(u_int32_t, *tl))
1275 						*retcmpp = NFSERR_NOTSAME;
1276 				}
1277 			} else {
1278 				tuint = fxdr_unsigned(u_int32_t, *tl);
1279 				/*
1280 				 * Some Linux NFSv4 servers report this
1281 				 * as 0 or 4billion, so I'll set it to
1282 				 * NFS_MAXNAMLEN. If a server actually creates
1283 				 * a name longer than NFS_MAXNAMLEN, it will
1284 				 * get an error back.
1285 				 */
1286 				if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1287 					tuint = NFS_MAXNAMLEN;
1288 				if (fsp != NULL)
1289 					fsp->fs_maxname = tuint;
1290 				if (pc != NULL)
1291 					pc->pc_namemax = tuint;
1292 			}
1293 			attrsum += NFSX_UNSIGNED;
1294 			break;
1295 		case NFSATTRBIT_MAXREAD:
1296 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1297 			if (compare) {
1298 				if (!(*retcmpp)) {
1299 				    if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1300 					*(tl + 1)) || *tl != 0)
1301 					*retcmpp = NFSERR_NOTSAME;
1302 				}
1303 			} else if (fsp != NULL) {
1304 				fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1305 				fsp->fs_rtpref = fsp->fs_rtmax;
1306 				fsp->fs_dtpref = fsp->fs_rtpref;
1307 			}
1308 			attrsum += NFSX_HYPER;
1309 			break;
1310 		case NFSATTRBIT_MAXWRITE:
1311 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1312 			if (compare) {
1313 				if (!(*retcmpp)) {
1314 				    if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1315 					*(tl + 1)) || *tl != 0)
1316 					*retcmpp = NFSERR_NOTSAME;
1317 				}
1318 			} else if (fsp != NULL) {
1319 				fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1320 				fsp->fs_wtpref = fsp->fs_wtmax;
1321 			}
1322 			attrsum += NFSX_HYPER;
1323 			break;
1324 		case NFSATTRBIT_MIMETYPE:
1325 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1326 			i = fxdr_unsigned(int, *tl);
1327 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1328 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1329 			if (error)
1330 				goto nfsmout;
1331 			if (compare && !(*retcmpp))
1332 				*retcmpp = NFSERR_ATTRNOTSUPP;
1333 			break;
1334 		case NFSATTRBIT_MODE:
1335 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1336 			if (compare) {
1337 				if (!(*retcmpp)) {
1338 				    if (nap->na_mode != nfstov_mode(*tl))
1339 					*retcmpp = NFSERR_NOTSAME;
1340 				}
1341 			} else if (nap != NULL) {
1342 				nap->na_mode = nfstov_mode(*tl);
1343 			}
1344 			attrsum += NFSX_UNSIGNED;
1345 			break;
1346 		case NFSATTRBIT_NOTRUNC:
1347 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1348 			if (compare) {
1349 				if (!(*retcmpp)) {
1350 				    if (*tl != newnfs_true)
1351 					*retcmpp = NFSERR_NOTSAME;
1352 				}
1353 			} else if (pc != NULL) {
1354 				pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1355 			}
1356 			attrsum += NFSX_UNSIGNED;
1357 			break;
1358 		case NFSATTRBIT_NUMLINKS:
1359 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1360 			tuint = fxdr_unsigned(u_int32_t, *tl);
1361 			if (compare) {
1362 			    if (!(*retcmpp)) {
1363 				if ((u_int32_t)nap->na_nlink != tuint)
1364 					*retcmpp = NFSERR_NOTSAME;
1365 			    }
1366 			} else if (nap != NULL) {
1367 				nap->na_nlink = tuint;
1368 			}
1369 			attrsum += NFSX_UNSIGNED;
1370 			break;
1371 		case NFSATTRBIT_OWNER:
1372 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1373 			j = fxdr_unsigned(int, *tl);
1374 			if (j < 0)
1375 				return (NFSERR_BADXDR);
1376 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1377 			if (j > NFSV4_SMALLSTR)
1378 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1379 			else
1380 				cp = namestr;
1381 			error = nfsrv_mtostr(nd, cp, j);
1382 			if (error) {
1383 				if (j > NFSV4_SMALLSTR)
1384 					free(cp, M_NFSSTRING);
1385 				return (error);
1386 			}
1387 			if (compare) {
1388 			    if (!(*retcmpp)) {
1389 				if (nfsv4_strtouid(cp, j, &uid, p) ||
1390 				    nap->na_uid != uid)
1391 				    *retcmpp = NFSERR_NOTSAME;
1392 			    }
1393 			} else if (nap != NULL) {
1394 				if (nfsv4_strtouid(cp, j, &uid, p))
1395 					nap->na_uid = nfsrv_defaultuid;
1396 				else
1397 					nap->na_uid = uid;
1398 			}
1399 			if (j > NFSV4_SMALLSTR)
1400 				free(cp, M_NFSSTRING);
1401 			break;
1402 		case NFSATTRBIT_OWNERGROUP:
1403 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1404 			j = fxdr_unsigned(int, *tl);
1405 			if (j < 0)
1406 				return (NFSERR_BADXDR);
1407 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1408 			if (j > NFSV4_SMALLSTR)
1409 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1410 			else
1411 				cp = namestr;
1412 			error = nfsrv_mtostr(nd, cp, j);
1413 			if (error) {
1414 				if (j > NFSV4_SMALLSTR)
1415 					free(cp, M_NFSSTRING);
1416 				return (error);
1417 			}
1418 			if (compare) {
1419 			    if (!(*retcmpp)) {
1420 				if (nfsv4_strtogid(cp, j, &gid, p) ||
1421 				    nap->na_gid != gid)
1422 				    *retcmpp = NFSERR_NOTSAME;
1423 			    }
1424 			} else if (nap != NULL) {
1425 				if (nfsv4_strtogid(cp, j, &gid, p))
1426 					nap->na_gid = nfsrv_defaultgid;
1427 				else
1428 					nap->na_gid = gid;
1429 			}
1430 			if (j > NFSV4_SMALLSTR)
1431 				free(cp, M_NFSSTRING);
1432 			break;
1433 		case NFSATTRBIT_QUOTAHARD:
1434 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1435 			if (sbp != NULL) {
1436 			    if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1437 				freenum = sbp->f_bfree;
1438 			    else
1439 				freenum = sbp->f_bavail;
1440 #ifdef QUOTA
1441 			    /*
1442 			     * ufs_quotactl() insists that the uid argument
1443 			     * equal p_ruid for non-root quota access, so
1444 			     * we'll just make sure that's the case.
1445 			     */
1446 			    savuid = p->p_cred->p_ruid;
1447 			    p->p_cred->p_ruid = cred->cr_uid;
1448 			    if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1449 				USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1450 				freenum = min(dqb.dqb_bhardlimit, freenum);
1451 			    p->p_cred->p_ruid = savuid;
1452 #endif	/* QUOTA */
1453 			    uquad = (u_int64_t)freenum;
1454 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1455 			}
1456 			if (compare && !(*retcmpp)) {
1457 				if (uquad != fxdr_hyper(tl))
1458 					*retcmpp = NFSERR_NOTSAME;
1459 			}
1460 			attrsum += NFSX_HYPER;
1461 			break;
1462 		case NFSATTRBIT_QUOTASOFT:
1463 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1464 			if (sbp != NULL) {
1465 			    if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1466 				freenum = sbp->f_bfree;
1467 			    else
1468 				freenum = sbp->f_bavail;
1469 #ifdef QUOTA
1470 			    /*
1471 			     * ufs_quotactl() insists that the uid argument
1472 			     * equal p_ruid for non-root quota access, so
1473 			     * we'll just make sure that's the case.
1474 			     */
1475 			    savuid = p->p_cred->p_ruid;
1476 			    p->p_cred->p_ruid = cred->cr_uid;
1477 			    if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1478 				USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1479 				freenum = min(dqb.dqb_bsoftlimit, freenum);
1480 			    p->p_cred->p_ruid = savuid;
1481 #endif	/* QUOTA */
1482 			    uquad = (u_int64_t)freenum;
1483 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1484 			}
1485 			if (compare && !(*retcmpp)) {
1486 				if (uquad != fxdr_hyper(tl))
1487 					*retcmpp = NFSERR_NOTSAME;
1488 			}
1489 			attrsum += NFSX_HYPER;
1490 			break;
1491 		case NFSATTRBIT_QUOTAUSED:
1492 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1493 			if (sbp != NULL) {
1494 			    freenum = 0;
1495 #ifdef QUOTA
1496 			    /*
1497 			     * ufs_quotactl() insists that the uid argument
1498 			     * equal p_ruid for non-root quota access, so
1499 			     * we'll just make sure that's the case.
1500 			     */
1501 			    savuid = p->p_cred->p_ruid;
1502 			    p->p_cred->p_ruid = cred->cr_uid;
1503 			    if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1504 				USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1505 				freenum = dqb.dqb_curblocks;
1506 			    p->p_cred->p_ruid = savuid;
1507 #endif	/* QUOTA */
1508 			    uquad = (u_int64_t)freenum;
1509 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1510 			}
1511 			if (compare && !(*retcmpp)) {
1512 				if (uquad != fxdr_hyper(tl))
1513 					*retcmpp = NFSERR_NOTSAME;
1514 			}
1515 			attrsum += NFSX_HYPER;
1516 			break;
1517 		case NFSATTRBIT_RAWDEV:
1518 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1519 			j = fxdr_unsigned(int, *tl++);
1520 			k = fxdr_unsigned(int, *tl);
1521 			if (compare) {
1522 			    if (!(*retcmpp)) {
1523 				if (nap->na_rdev != NFSMAKEDEV(j, k))
1524 					*retcmpp = NFSERR_NOTSAME;
1525 			    }
1526 			} else if (nap != NULL) {
1527 				nap->na_rdev = NFSMAKEDEV(j, k);
1528 			}
1529 			attrsum += NFSX_V4SPECDATA;
1530 			break;
1531 		case NFSATTRBIT_SPACEAVAIL:
1532 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1533 			if (compare) {
1534 				if (!(*retcmpp) &&
1535 				    sfp->sf_abytes != fxdr_hyper(tl))
1536 					*retcmpp = NFSERR_NOTSAME;
1537 			} else if (sfp != NULL) {
1538 				sfp->sf_abytes = fxdr_hyper(tl);
1539 			}
1540 			attrsum += NFSX_HYPER;
1541 			break;
1542 		case NFSATTRBIT_SPACEFREE:
1543 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1544 			if (compare) {
1545 				if (!(*retcmpp) &&
1546 				    sfp->sf_fbytes != fxdr_hyper(tl))
1547 					*retcmpp = NFSERR_NOTSAME;
1548 			} else if (sfp != NULL) {
1549 				sfp->sf_fbytes = fxdr_hyper(tl);
1550 			}
1551 			attrsum += NFSX_HYPER;
1552 			break;
1553 		case NFSATTRBIT_SPACETOTAL:
1554 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1555 			if (compare) {
1556 				if (!(*retcmpp) &&
1557 				    sfp->sf_tbytes != fxdr_hyper(tl))
1558 					*retcmpp = NFSERR_NOTSAME;
1559 			} else if (sfp != NULL) {
1560 				sfp->sf_tbytes = fxdr_hyper(tl);
1561 			}
1562 			attrsum += NFSX_HYPER;
1563 			break;
1564 		case NFSATTRBIT_SPACEUSED:
1565 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1566 			thyp = fxdr_hyper(tl);
1567 			if (compare) {
1568 			    if (!(*retcmpp)) {
1569 				if ((u_int64_t)nap->na_bytes != thyp)
1570 					*retcmpp = NFSERR_NOTSAME;
1571 			    }
1572 			} else if (nap != NULL) {
1573 				nap->na_bytes = thyp;
1574 			}
1575 			attrsum += NFSX_HYPER;
1576 			break;
1577 		case NFSATTRBIT_SYSTEM:
1578 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1579 			if (compare && !(*retcmpp))
1580 				*retcmpp = NFSERR_ATTRNOTSUPP;
1581 			attrsum += NFSX_UNSIGNED;
1582 			break;
1583 		case NFSATTRBIT_TIMEACCESS:
1584 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1585 			fxdr_nfsv4time(tl, &temptime);
1586 			if (compare) {
1587 			    if (!(*retcmpp)) {
1588 				if (!NFS_CMPTIME(temptime, nap->na_atime))
1589 					*retcmpp = NFSERR_NOTSAME;
1590 			    }
1591 			} else if (nap != NULL) {
1592 				nap->na_atime = temptime;
1593 			}
1594 			attrsum += NFSX_V4TIME;
1595 			break;
1596 		case NFSATTRBIT_TIMEACCESSSET:
1597 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1598 			attrsum += NFSX_UNSIGNED;
1599 			i = fxdr_unsigned(int, *tl);
1600 			if (i == NFSV4SATTRTIME_TOCLIENT) {
1601 				NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1602 				attrsum += NFSX_V4TIME;
1603 			}
1604 			if (compare && !(*retcmpp))
1605 				*retcmpp = NFSERR_INVAL;
1606 			break;
1607 		case NFSATTRBIT_TIMEBACKUP:
1608 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1609 			if (compare && !(*retcmpp))
1610 				*retcmpp = NFSERR_ATTRNOTSUPP;
1611 			attrsum += NFSX_V4TIME;
1612 			break;
1613 		case NFSATTRBIT_TIMECREATE:
1614 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1615 			if (compare && !(*retcmpp))
1616 				*retcmpp = NFSERR_ATTRNOTSUPP;
1617 			attrsum += NFSX_V4TIME;
1618 			break;
1619 		case NFSATTRBIT_TIMEDELTA:
1620 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1621 			if (fsp != NULL) {
1622 			    if (compare) {
1623 				if (!(*retcmpp)) {
1624 				    if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1625 					fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1626 				        (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1627 					(fxdr_unsigned(u_int32_t, *(tl + 2)) %
1628 					 1000000000) ||
1629 					*tl != 0)
1630 					    *retcmpp = NFSERR_NOTSAME;
1631 				}
1632 			    } else {
1633 				fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1634 			    }
1635 			}
1636 			attrsum += NFSX_V4TIME;
1637 			break;
1638 		case NFSATTRBIT_TIMEMETADATA:
1639 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1640 			fxdr_nfsv4time(tl, &temptime);
1641 			if (compare) {
1642 			    if (!(*retcmpp)) {
1643 				if (!NFS_CMPTIME(temptime, nap->na_ctime))
1644 					*retcmpp = NFSERR_NOTSAME;
1645 			    }
1646 			} else if (nap != NULL) {
1647 				nap->na_ctime = temptime;
1648 			}
1649 			attrsum += NFSX_V4TIME;
1650 			break;
1651 		case NFSATTRBIT_TIMEMODIFY:
1652 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1653 			fxdr_nfsv4time(tl, &temptime);
1654 			if (compare) {
1655 			    if (!(*retcmpp)) {
1656 				if (!NFS_CMPTIME(temptime, nap->na_mtime))
1657 					*retcmpp = NFSERR_NOTSAME;
1658 			    }
1659 			} else if (nap != NULL) {
1660 				nap->na_mtime = temptime;
1661 			}
1662 			attrsum += NFSX_V4TIME;
1663 			break;
1664 		case NFSATTRBIT_TIMEMODIFYSET:
1665 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1666 			attrsum += NFSX_UNSIGNED;
1667 			i = fxdr_unsigned(int, *tl);
1668 			if (i == NFSV4SATTRTIME_TOCLIENT) {
1669 				NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1670 				attrsum += NFSX_V4TIME;
1671 			}
1672 			if (compare && !(*retcmpp))
1673 				*retcmpp = NFSERR_INVAL;
1674 			break;
1675 		case NFSATTRBIT_MOUNTEDONFILEID:
1676 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1677 			thyp = fxdr_hyper(tl);
1678 			if (compare) {
1679 			    if (!(*retcmpp)) {
1680 				if (*tl++) {
1681 					*retcmpp = NFSERR_NOTSAME;
1682 				} else {
1683 					if (!vp || !nfsrv_atroot(vp, &fid))
1684 						fid = nap->na_fileid;
1685 					if ((u_int64_t)fid != thyp)
1686 						*retcmpp = NFSERR_NOTSAME;
1687 				}
1688 			    }
1689 			} else if (nap != NULL) {
1690 			    if (*tl++)
1691 				printf("NFSv4 mounted on fileid > 32bits\n");
1692 			    nap->na_mntonfileno = thyp;
1693 			}
1694 			attrsum += NFSX_HYPER;
1695 			break;
1696 		default:
1697 			printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1698 				bitpos);
1699 			if (compare && !(*retcmpp))
1700 				*retcmpp = NFSERR_ATTRNOTSUPP;
1701 			/*
1702 			 * and get out of the loop, since we can't parse
1703 			 * the unknown attrbute data.
1704 			 */
1705 			bitpos = NFSATTRBIT_MAX;
1706 			break;
1707 		};
1708 	}
1709 
1710 	/*
1711 	 * some clients pad the attrlist, so we need to skip over the
1712 	 * padding.
1713 	 */
1714 	if (attrsum > attrsize) {
1715 		error = NFSERR_BADXDR;
1716 	} else {
1717 		attrsize = NFSM_RNDUP(attrsize);
1718 		if (attrsum < attrsize)
1719 			error = nfsm_advance(nd, attrsize - attrsum, -1);
1720 	}
1721 nfsmout:
1722 	return (error);
1723 }
1724 
1725 /*
1726  * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1727  * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1728  * The first argument is a pointer to an nfsv4lock structure.
1729  * The second argument is 1 iff a blocking lock is wanted.
1730  * If this argument is 0, the call waits until no thread either wants nor
1731  * holds an exclusive lock.
1732  * It returns 1 if the lock was acquired, 0 otherwise.
1733  * If several processes call this function concurrently wanting the exclusive
1734  * lock, one will get the lock and the rest will return without getting the
1735  * lock. (If the caller must have the lock, it simply calls this function in a
1736  *  loop until the function returns 1 to indicate the lock was acquired.)
1737  * Any usecnt must be decremented by calling nfsv4_relref() before
1738  * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1739  * be called in a loop.
1740  * The last argument is set to indicate if the call slept, iff not NULL.
1741  */
1742 APPLESTATIC int
1743 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1744     void *mutex)
1745 {
1746 
1747 	if (isleptp)
1748 		*isleptp = 0;
1749 	/*
1750 	 * If a lock is wanted, loop around until the lock is acquired by
1751 	 * someone and then released. If I want the lock, try to acquire it.
1752 	 * For a lock to be issued, no lock must be in force and the usecnt
1753 	 * must be zero.
1754 	 */
1755 	if (iwantlock) {
1756 	    if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1757 		lp->nfslock_usecnt == 0) {
1758 		lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1759 		lp->nfslock_lock |= NFSV4LOCK_LOCK;
1760 		return (1);
1761 	    }
1762 	    lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1763 	}
1764 	while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1765 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
1766 		if (isleptp)
1767 			*isleptp = 1;
1768 		(void) nfsmsleep(&lp->nfslock_lock, mutex,
1769 		    PZERO - 1, "nfsv4lck", NULL);
1770 		if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1771 		    lp->nfslock_usecnt == 0) {
1772 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1773 			lp->nfslock_lock |= NFSV4LOCK_LOCK;
1774 			return (1);
1775 		}
1776 	}
1777 	return (0);
1778 }
1779 
1780 /*
1781  * Release the lock acquired by nfsv4_lock().
1782  * The second argument is set to 1 to indicate the nfslock_usecnt should be
1783  * incremented, as well.
1784  */
1785 APPLESTATIC void
1786 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1787 {
1788 
1789 	lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1790 	if (incref)
1791 		lp->nfslock_usecnt++;
1792 	nfsv4_wanted(lp);
1793 }
1794 
1795 /*
1796  * Release a reference cnt.
1797  */
1798 APPLESTATIC void
1799 nfsv4_relref(struct nfsv4lock *lp)
1800 {
1801 
1802 	if (lp->nfslock_usecnt <= 0)
1803 		panic("nfsv4root ref cnt");
1804 	lp->nfslock_usecnt--;
1805 	if (lp->nfslock_usecnt == 0)
1806 		nfsv4_wanted(lp);
1807 }
1808 
1809 /*
1810  * Get a reference cnt.
1811  * This function will wait for any exclusive lock to be released, but will
1812  * not wait for threads that want the exclusive lock. If priority needs
1813  * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1814  * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1815  */
1816 APPLESTATIC void
1817 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex)
1818 {
1819 
1820 	if (isleptp)
1821 		*isleptp = 0;
1822 
1823 	/*
1824 	 * Wait for a lock held.
1825 	 */
1826 	while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1827 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
1828 		if (isleptp)
1829 			*isleptp = 1;
1830 		(void) nfsmsleep(&lp->nfslock_lock, mutex,
1831 		    PZERO - 1, "nfsv4lck", NULL);
1832 	}
1833 
1834 	lp->nfslock_usecnt++;
1835 }
1836 
1837 /*
1838  * Wake up anyone sleeping, waiting for this lock.
1839  */
1840 static void
1841 nfsv4_wanted(struct nfsv4lock *lp)
1842 {
1843 
1844 	if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1845 		lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1846 		wakeup((caddr_t)&lp->nfslock_lock);
1847 	}
1848 }
1849 
1850 /*
1851  * Copy a string from an mbuf list into a character array.
1852  * Return EBADRPC if there is an mbuf error,
1853  * 0 otherwise.
1854  */
1855 APPLESTATIC int
1856 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1857 {
1858 	char *cp;
1859 	int xfer, len;
1860 	mbuf_t mp;
1861 	int rem, error = 0;
1862 
1863 	mp = nd->nd_md;
1864 	cp = nd->nd_dpos;
1865 	len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1866 	rem = NFSM_RNDUP(siz) - siz;
1867 	while (siz > 0) {
1868 		if (len > siz)
1869 			xfer = siz;
1870 		else
1871 			xfer = len;
1872 		NFSBCOPY(cp, str, xfer);
1873 		str += xfer;
1874 		siz -= xfer;
1875 		if (siz > 0) {
1876 			mp = mbuf_next(mp);
1877 			if (mp == NULL)
1878 				return (EBADRPC);
1879 			cp = NFSMTOD(mp, caddr_t);
1880 			len = mbuf_len(mp);
1881 		} else {
1882 			cp += xfer;
1883 			len -= xfer;
1884 		}
1885 	}
1886 	*str = '\0';
1887 	nd->nd_dpos = cp;
1888 	nd->nd_md = mp;
1889 	if (rem > 0) {
1890 		if (len < rem)
1891 			error = nfsm_advance(nd, rem, len);
1892 		else
1893 			nd->nd_dpos += rem;
1894 	}
1895 	return (error);
1896 }
1897 
1898 /*
1899  * Fill in the attributes as marked by the bitmap (V4).
1900  */
1901 APPLESTATIC int
1902 nfsv4_fillattr(struct nfsrv_descript *nd, vnode_t vp, NFSACL_T *saclp,
1903     struct vattr *vap, fhandle_t *fhp, int rderror, nfsattrbit_t *attrbitp,
1904     struct ucred *cred, NFSPROC_T *p, int isdgram, int reterr)
1905 {
1906 	int bitpos, retnum = 0;
1907 	u_int32_t *tl;
1908 	int siz, prefixnum, error;
1909 	u_char *cp, namestr[NFSV4_SMALLSTR];
1910 	nfsattrbit_t attrbits, retbits;
1911 	nfsattrbit_t *retbitp = &retbits;
1912 	u_int32_t freenum, *retnump;
1913 	u_int64_t uquad;
1914 	long fid;
1915 	struct statfs fs;
1916 	struct nfsfsinfo fsinf;
1917 	struct timespec temptime;
1918 	struct timeval curtime;
1919 	NFSACL_T *aclp, *naclp = NULL;
1920 #ifdef QUOTA
1921 	struct dqblk dqb;
1922 	uid_t savuid;
1923 #endif
1924 
1925 	/*
1926 	 * First, set the bits that can be filled and get fsinfo.
1927 	 */
1928 	NFSSET_ATTRBIT(retbitp, attrbitp);
1929 	/* If p and cred are NULL, it is a client side call */
1930 	if (p == NULL && cred == NULL) {
1931 		NFSCLRNOTSETABLE_ATTRBIT(retbitp);
1932 		aclp = saclp;
1933 	} else {
1934 		NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
1935 #ifdef NFS4_ACL_EXTATTR_NAME
1936 		naclp = acl_alloc(M_WAITOK);
1937 #endif
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 #ifdef NFS4_ACL_EXTATTR_NAME
1962 	    && (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
1963 		!NFSHASNFS4ACL(vnode_mount(vp))))
1964 #endif
1965 	    ) {
1966 		NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
1967 	}
1968 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
1969 #ifdef NFS4_ACL_EXTATTR_NAME
1970 		if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
1971 		    !NFSHASNFS4ACL(vnode_mount(vp)))) {
1972 #endif
1973 			NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
1974 #ifdef NFS4_ACL_EXTATTR_NAME
1975 		} else if (naclp != NULL) {
1976 			NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
1977 			error = VOP_ACCESS(vp, VREAD_ACL, cred, p);
1978 			if (error == 0)
1979 				error = VOP_GETACL(vp, ACL_TYPE_NFS4, naclp,
1980 				    cred, p);
1981 			NFSVOPUNLOCK(vp, 0, p);
1982 			if (error != 0) {
1983 				if (reterr) {
1984 					nd->nd_repstat = NFSERR_ACCES;
1985 					return (0);
1986 				}
1987 				NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
1988 			}
1989 		}
1990 #endif
1991 	}
1992 	/*
1993 	 * Put out the attribute bitmap for the ones being filled in
1994 	 * and get the field for the number of attributes returned.
1995 	 */
1996 	prefixnum = nfsrv_putattrbit(nd, retbitp);
1997 	NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
1998 	prefixnum += NFSX_UNSIGNED;
1999 
2000 	/*
2001 	 * Now, loop around filling in the attributes for each bit set.
2002 	 */
2003 	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2004 	    if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2005 		switch (bitpos) {
2006 		case NFSATTRBIT_SUPPORTEDATTRS:
2007 			NFSSETSUPP_ATTRBIT(&attrbits);
2008 #ifdef NFS4_ACL_EXTATTR_NAME
2009 			if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2010 			    && !NFSHASNFS4ACL(vnode_mount(vp))))
2011 #endif
2012 			{
2013 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2014 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2015 			}
2016 			retnum += nfsrv_putattrbit(nd, &attrbits);
2017 			break;
2018 		case NFSATTRBIT_TYPE:
2019 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2020 			*tl = vtonfsv34_type(vap->va_type);
2021 			retnum += NFSX_UNSIGNED;
2022 			break;
2023 		case NFSATTRBIT_FHEXPIRETYPE:
2024 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2025 			*tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2026 			retnum += NFSX_UNSIGNED;
2027 			break;
2028 		case NFSATTRBIT_CHANGE:
2029 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2030 			txdr_hyper(vap->va_filerev, tl);
2031 			retnum += NFSX_HYPER;
2032 			break;
2033 		case NFSATTRBIT_SIZE:
2034 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2035 			txdr_hyper(vap->va_size, tl);
2036 			retnum += NFSX_HYPER;
2037 			break;
2038 		case NFSATTRBIT_LINKSUPPORT:
2039 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2040 			if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2041 				*tl = newnfs_true;
2042 			else
2043 				*tl = newnfs_false;
2044 			retnum += NFSX_UNSIGNED;
2045 			break;
2046 		case NFSATTRBIT_SYMLINKSUPPORT:
2047 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2048 			if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2049 				*tl = newnfs_true;
2050 			else
2051 				*tl = newnfs_false;
2052 			retnum += NFSX_UNSIGNED;
2053 			break;
2054 		case NFSATTRBIT_NAMEDATTR:
2055 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2056 			*tl = newnfs_false;
2057 			retnum += NFSX_UNSIGNED;
2058 			break;
2059 		case NFSATTRBIT_FSID:
2060 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2061 			*tl++ = 0;
2062 			*tl++=txdr_unsigned(vfs_statfs(vnode_mount(vp))->f_fsid.val[0]);
2063 			*tl++ = 0;
2064 			*tl=txdr_unsigned(vfs_statfs(vnode_mount(vp))->f_fsid.val[1]);
2065 			retnum += NFSX_V4FSID;
2066 			break;
2067 		case NFSATTRBIT_UNIQUEHANDLES:
2068 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2069 			*tl = newnfs_true;
2070 			retnum += NFSX_UNSIGNED;
2071 			break;
2072 		case NFSATTRBIT_LEASETIME:
2073 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2074 			*tl = txdr_unsigned(nfsrv_lease);
2075 			retnum += NFSX_UNSIGNED;
2076 			break;
2077 		case NFSATTRBIT_RDATTRERROR:
2078 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2079 			*tl = txdr_unsigned(rderror);
2080 			retnum += NFSX_UNSIGNED;
2081 			break;
2082 		/*
2083 		 * Recommended Attributes. (Only the supported ones.)
2084 		 */
2085 #ifdef NFS4_ACL_EXTATTR_NAME
2086 		case NFSATTRBIT_ACL:
2087 			retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2088 			break;
2089 		case NFSATTRBIT_ACLSUPPORT:
2090 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2091 			*tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2092 			retnum += NFSX_UNSIGNED;
2093 			break;
2094 #endif
2095 		case NFSATTRBIT_CANSETTIME:
2096 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2097 			if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2098 				*tl = newnfs_true;
2099 			else
2100 				*tl = newnfs_false;
2101 			retnum += NFSX_UNSIGNED;
2102 			break;
2103 		case NFSATTRBIT_CASEINSENSITIVE:
2104 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2105 			*tl = newnfs_false;
2106 			retnum += NFSX_UNSIGNED;
2107 			break;
2108 		case NFSATTRBIT_CASEPRESERVING:
2109 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2110 			*tl = newnfs_true;
2111 			retnum += NFSX_UNSIGNED;
2112 			break;
2113 		case NFSATTRBIT_CHOWNRESTRICTED:
2114 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2115 			*tl = newnfs_true;
2116 			retnum += NFSX_UNSIGNED;
2117 			break;
2118 		case NFSATTRBIT_FILEHANDLE:
2119 			retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2120 			break;
2121 		case NFSATTRBIT_FILEID:
2122 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2123 			*tl++ = 0;
2124 			*tl = txdr_unsigned(vap->va_fileid);
2125 			retnum += NFSX_HYPER;
2126 			break;
2127 		case NFSATTRBIT_FILESAVAIL:
2128 			/*
2129 			 * Check quota and use min(quota, f_ffree).
2130 			 */
2131 			freenum = fs.f_ffree;
2132 #ifdef QUOTA
2133 			/*
2134 			 * ufs_quotactl() insists that the uid argument
2135 			 * equal p_ruid for non-root quota access, so
2136 			 * we'll just make sure that's the case.
2137 			 */
2138 			savuid = p->p_cred->p_ruid;
2139 			p->p_cred->p_ruid = cred->cr_uid;
2140 			if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
2141 			    cred->cr_uid, (caddr_t)&dqb))
2142 			    freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2143 				freenum);
2144 			p->p_cred->p_ruid = savuid;
2145 #endif	/* QUOTA */
2146 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2147 			*tl++ = 0;
2148 			*tl = txdr_unsigned(freenum);
2149 			retnum += NFSX_HYPER;
2150 			break;
2151 		case NFSATTRBIT_FILESFREE:
2152 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2153 			*tl++ = 0;
2154 			*tl = txdr_unsigned(fs.f_ffree);
2155 			retnum += NFSX_HYPER;
2156 			break;
2157 		case NFSATTRBIT_FILESTOTAL:
2158 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2159 			*tl++ = 0;
2160 			*tl = txdr_unsigned(fs.f_files);
2161 			retnum += NFSX_HYPER;
2162 			break;
2163 		case NFSATTRBIT_FSLOCATIONS:
2164 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2165 			*tl++ = 0;
2166 			*tl = 0;
2167 			retnum += 2 * NFSX_UNSIGNED;
2168 			break;
2169 		case NFSATTRBIT_HOMOGENEOUS:
2170 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2171 			if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2172 				*tl = newnfs_true;
2173 			else
2174 				*tl = newnfs_false;
2175 			retnum += NFSX_UNSIGNED;
2176 			break;
2177 		case NFSATTRBIT_MAXFILESIZE:
2178 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2179 			uquad = NFSRV_MAXFILESIZE;
2180 			txdr_hyper(uquad, tl);
2181 			retnum += NFSX_HYPER;
2182 			break;
2183 		case NFSATTRBIT_MAXLINK:
2184 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2185 			*tl = txdr_unsigned(LINK_MAX);
2186 			retnum += NFSX_UNSIGNED;
2187 			break;
2188 		case NFSATTRBIT_MAXNAME:
2189 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2190 			*tl = txdr_unsigned(NFS_MAXNAMLEN);
2191 			retnum += NFSX_UNSIGNED;
2192 			break;
2193 		case NFSATTRBIT_MAXREAD:
2194 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2195 			*tl++ = 0;
2196 			*tl = txdr_unsigned(fsinf.fs_rtmax);
2197 			retnum += NFSX_HYPER;
2198 			break;
2199 		case NFSATTRBIT_MAXWRITE:
2200 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2201 			*tl++ = 0;
2202 			*tl = txdr_unsigned(fsinf.fs_wtmax);
2203 			retnum += NFSX_HYPER;
2204 			break;
2205 		case NFSATTRBIT_MODE:
2206 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2207 			*tl = vtonfsv34_mode(vap->va_mode);
2208 			retnum += NFSX_UNSIGNED;
2209 			break;
2210 		case NFSATTRBIT_NOTRUNC:
2211 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2212 			*tl = newnfs_true;
2213 			retnum += NFSX_UNSIGNED;
2214 			break;
2215 		case NFSATTRBIT_NUMLINKS:
2216 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2217 			*tl = txdr_unsigned(vap->va_nlink);
2218 			retnum += NFSX_UNSIGNED;
2219 			break;
2220 		case NFSATTRBIT_OWNER:
2221 			cp = namestr;
2222 			nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2223 			retnum += nfsm_strtom(nd, cp, siz);
2224 			if (cp != namestr)
2225 				free(cp, M_NFSSTRING);
2226 			break;
2227 		case NFSATTRBIT_OWNERGROUP:
2228 			cp = namestr;
2229 			nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2230 			retnum += nfsm_strtom(nd, cp, siz);
2231 			if (cp != namestr)
2232 				free(cp, M_NFSSTRING);
2233 			break;
2234 		case NFSATTRBIT_QUOTAHARD:
2235 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2236 				freenum = fs.f_bfree;
2237 			else
2238 				freenum = fs.f_bavail;
2239 #ifdef QUOTA
2240 			/*
2241 			 * ufs_quotactl() insists that the uid argument
2242 			 * equal p_ruid for non-root quota access, so
2243 			 * we'll just make sure that's the case.
2244 			 */
2245 			savuid = p->p_cred->p_ruid;
2246 			p->p_cred->p_ruid = cred->cr_uid;
2247 			if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
2248 			    cred->cr_uid, (caddr_t)&dqb))
2249 			    freenum = min(dqb.dqb_bhardlimit, freenum);
2250 			p->p_cred->p_ruid = savuid;
2251 #endif	/* QUOTA */
2252 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2253 			uquad = (u_int64_t)freenum;
2254 			NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2255 			txdr_hyper(uquad, tl);
2256 			retnum += NFSX_HYPER;
2257 			break;
2258 		case NFSATTRBIT_QUOTASOFT:
2259 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2260 				freenum = fs.f_bfree;
2261 			else
2262 				freenum = fs.f_bavail;
2263 #ifdef QUOTA
2264 			/*
2265 			 * ufs_quotactl() insists that the uid argument
2266 			 * equal p_ruid for non-root quota access, so
2267 			 * we'll just make sure that's the case.
2268 			 */
2269 			savuid = p->p_cred->p_ruid;
2270 			p->p_cred->p_ruid = cred->cr_uid;
2271 			if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
2272 			    cred->cr_uid, (caddr_t)&dqb))
2273 			    freenum = min(dqb.dqb_bsoftlimit, freenum);
2274 			p->p_cred->p_ruid = savuid;
2275 #endif	/* QUOTA */
2276 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2277 			uquad = (u_int64_t)freenum;
2278 			NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2279 			txdr_hyper(uquad, tl);
2280 			retnum += NFSX_HYPER;
2281 			break;
2282 		case NFSATTRBIT_QUOTAUSED:
2283 			freenum = 0;
2284 #ifdef QUOTA
2285 			/*
2286 			 * ufs_quotactl() insists that the uid argument
2287 			 * equal p_ruid for non-root quota access, so
2288 			 * we'll just make sure that's the case.
2289 			 */
2290 			savuid = p->p_cred->p_ruid;
2291 			p->p_cred->p_ruid = cred->cr_uid;
2292 			if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA),
2293 			    cred->cr_uid, (caddr_t)&dqb))
2294 			    freenum = dqb.dqb_curblocks;
2295 			p->p_cred->p_ruid = savuid;
2296 #endif	/* QUOTA */
2297 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2298 			uquad = (u_int64_t)freenum;
2299 			NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2300 			txdr_hyper(uquad, tl);
2301 			retnum += NFSX_HYPER;
2302 			break;
2303 		case NFSATTRBIT_RAWDEV:
2304 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2305 			*tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2306 			*tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2307 			retnum += NFSX_V4SPECDATA;
2308 			break;
2309 		case NFSATTRBIT_SPACEAVAIL:
2310 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2311 			if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2312 				uquad = (u_int64_t)fs.f_bfree;
2313 			else
2314 				uquad = (u_int64_t)fs.f_bavail;
2315 			uquad *= fs.f_bsize;
2316 			txdr_hyper(uquad, tl);
2317 			retnum += NFSX_HYPER;
2318 			break;
2319 		case NFSATTRBIT_SPACEFREE:
2320 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2321 			uquad = (u_int64_t)fs.f_bfree;
2322 			uquad *= fs.f_bsize;
2323 			txdr_hyper(uquad, tl);
2324 			retnum += NFSX_HYPER;
2325 			break;
2326 		case NFSATTRBIT_SPACETOTAL:
2327 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2328 			uquad = (u_int64_t)fs.f_blocks;
2329 			uquad *= fs.f_bsize;
2330 			txdr_hyper(uquad, tl);
2331 			retnum += NFSX_HYPER;
2332 			break;
2333 		case NFSATTRBIT_SPACEUSED:
2334 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2335 			txdr_hyper(vap->va_bytes, tl);
2336 			retnum += NFSX_HYPER;
2337 			break;
2338 		case NFSATTRBIT_TIMEACCESS:
2339 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2340 			txdr_nfsv4time(&vap->va_atime, tl);
2341 			retnum += NFSX_V4TIME;
2342 			break;
2343 		case NFSATTRBIT_TIMEACCESSSET:
2344 			NFSGETTIME(&curtime);
2345 			if (vap->va_atime.tv_sec != curtime.tv_sec) {
2346 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2347 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2348 				txdr_nfsv4time(&vap->va_atime, tl);
2349 				retnum += NFSX_V4SETTIME;
2350 			} else {
2351 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2352 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2353 				retnum += NFSX_UNSIGNED;
2354 			}
2355 			break;
2356 		case NFSATTRBIT_TIMEDELTA:
2357 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2358 			temptime.tv_sec = 0;
2359 			temptime.tv_nsec = 1000000000 / hz;
2360 			txdr_nfsv4time(&temptime, tl);
2361 			retnum += NFSX_V4TIME;
2362 			break;
2363 		case NFSATTRBIT_TIMEMETADATA:
2364 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2365 			txdr_nfsv4time(&vap->va_ctime, tl);
2366 			retnum += NFSX_V4TIME;
2367 			break;
2368 		case NFSATTRBIT_TIMEMODIFY:
2369 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2370 			txdr_nfsv4time(&vap->va_mtime, tl);
2371 			retnum += NFSX_V4TIME;
2372 			break;
2373 		case NFSATTRBIT_TIMEMODIFYSET:
2374 			NFSGETTIME(&curtime);
2375 			if (vap->va_mtime.tv_sec != curtime.tv_sec) {
2376 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2377 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2378 				txdr_nfsv4time(&vap->va_mtime, tl);
2379 				retnum += NFSX_V4SETTIME;
2380 			} else {
2381 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2382 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2383 				retnum += NFSX_UNSIGNED;
2384 			}
2385 			break;
2386 		case NFSATTRBIT_MOUNTEDONFILEID:
2387 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2388 			*tl++ = 0;
2389 			if (nfsrv_atroot(vp, &fid))
2390 				*tl = txdr_unsigned(fid);
2391 			else
2392 				*tl = txdr_unsigned(vap->va_fileid);
2393 			retnum += NFSX_HYPER;
2394 			break;
2395 		default:
2396 			printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2397 		};
2398 	    }
2399 	}
2400 #ifdef NFS4_ACL_EXTATTR_NAME
2401 	if (naclp != NULL)
2402 		acl_free(naclp);
2403 #endif
2404 	*retnump = txdr_unsigned(retnum);
2405 	return (retnum + prefixnum);
2406 }
2407 
2408 /*
2409  * Put the attribute bits onto an mbuf list.
2410  * Return the number of bytes of output generated.
2411  */
2412 APPLESTATIC int
2413 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2414 {
2415 	u_int32_t *tl;
2416 	int cnt, i, bytesize;
2417 
2418 	for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2419 		if (attrbitp->bits[cnt - 1])
2420 			break;
2421 	bytesize = (cnt + 1) * NFSX_UNSIGNED;
2422 	NFSM_BUILD(tl, u_int32_t *, bytesize);
2423 	*tl++ = txdr_unsigned(cnt);
2424 	for (i = 0; i < cnt; i++)
2425 		*tl++ = txdr_unsigned(attrbitp->bits[i]);
2426 	return (bytesize);
2427 }
2428 
2429 /*
2430  * Convert a uid to a string.
2431  * If the lookup fails, just output the digits.
2432  * uid - the user id
2433  * cpp - points to a buffer of size NFSV4_SMALLSTR
2434  *       (malloc a larger one, as required)
2435  * retlenp - pointer to length to be returned
2436  */
2437 APPLESTATIC void
2438 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2439 {
2440 	int i;
2441 	struct nfsusrgrp *usrp;
2442 	u_char *cp = *cpp;
2443 	uid_t tmp;
2444 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2445 
2446 	cnt = 0;
2447 tryagain:
2448 	NFSLOCKNAMEID();
2449 	if (nfsrv_dnsname) {
2450 		/*
2451 		 * Always map nfsrv_defaultuid to "nobody".
2452 		 */
2453 		if (uid == nfsrv_defaultuid) {
2454 			i = nfsrv_dnsnamelen + 7;
2455 			if (i > len) {
2456 				NFSUNLOCKNAMEID();
2457 				if (len > NFSV4_SMALLSTR)
2458 					free(cp, M_NFSSTRING);
2459 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
2460 				*cpp = cp;
2461 				len = i;
2462 				goto tryagain;
2463 			}
2464 			*retlenp = i;
2465 			NFSBCOPY("nobody@", cp, 7);
2466 			cp += 7;
2467 			NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2468 			NFSUNLOCKNAMEID();
2469 			return;
2470 		}
2471 		hasampersand = 0;
2472 		LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
2473 			if (usrp->lug_uid == uid) {
2474 				if (usrp->lug_expiry < NFSD_MONOSEC)
2475 					break;
2476 				/*
2477 				 * If the name doesn't already have an '@'
2478 				 * in it, append @domainname to it.
2479 				 */
2480 				for (i = 0; i < usrp->lug_namelen; i++) {
2481 					if (usrp->lug_name[i] == '@') {
2482 						hasampersand = 1;
2483 						break;
2484 					}
2485 				}
2486 				if (hasampersand)
2487 					i = usrp->lug_namelen;
2488 				else
2489 					i = usrp->lug_namelen +
2490 					    nfsrv_dnsnamelen + 1;
2491 				if (i > len) {
2492 					NFSUNLOCKNAMEID();
2493 					if (len > NFSV4_SMALLSTR)
2494 						free(cp, M_NFSSTRING);
2495 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
2496 					*cpp = cp;
2497 					len = i;
2498 					goto tryagain;
2499 				}
2500 				*retlenp = i;
2501 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2502 				if (!hasampersand) {
2503 					cp += usrp->lug_namelen;
2504 					*cp++ = '@';
2505 					NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2506 				}
2507 				TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2508 				TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2509 				NFSUNLOCKNAMEID();
2510 				return;
2511 			}
2512 		}
2513 		NFSUNLOCKNAMEID();
2514 		cnt++;
2515 		ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2516 		    NULL, p);
2517 		if (ret == 0 && cnt < 2)
2518 			goto tryagain;
2519 	} else {
2520 		NFSUNLOCKNAMEID();
2521 	}
2522 
2523 	/*
2524 	 * No match, just return a string of digits.
2525 	 */
2526 	tmp = uid;
2527 	i = 0;
2528 	while (tmp || i == 0) {
2529 		tmp /= 10;
2530 		i++;
2531 	}
2532 	len = (i > len) ? len : i;
2533 	*retlenp = len;
2534 	cp += (len - 1);
2535 	tmp = uid;
2536 	for (i = 0; i < len; i++) {
2537 		*cp-- = '0' + (tmp % 10);
2538 		tmp /= 10;
2539 	}
2540 	return;
2541 }
2542 
2543 /*
2544  * Convert a string to a uid.
2545  * If no conversion is possible return NFSERR_BADOWNER, otherwise
2546  * return 0.
2547  */
2548 APPLESTATIC int
2549 nfsv4_strtouid(u_char *str, int len, uid_t *uidp, NFSPROC_T *p)
2550 {
2551 	int i;
2552 	u_char *cp;
2553 	struct nfsusrgrp *usrp;
2554 	int cnt, ret;
2555 
2556 	if (len == 0)
2557 		return (NFSERR_BADOWNER);
2558 	/*
2559 	 * Look for an '@'.
2560 	 */
2561 	cp = str;
2562 	for (i = 0; i < len; i++)
2563 		if (*cp++ == '@')
2564 			break;
2565 
2566 	cnt = 0;
2567 tryagain:
2568 	NFSLOCKNAMEID();
2569 	/*
2570 	 * If an '@' is found and the domain name matches, search for the name
2571 	 * with dns stripped off.
2572 	 * Mixed case alpahbetics will match for the domain name, but all
2573 	 * upper case will not.
2574 	 */
2575 	if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2576 	    (len - 1 - i) == nfsrv_dnsnamelen &&
2577 	    !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2578 		len -= (nfsrv_dnsnamelen + 1);
2579 		*(cp - 1) = '\0';
2580 	}
2581 
2582 	/*
2583 	 * Check for the special case of "nobody".
2584 	 */
2585 	if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2586 		*uidp = nfsrv_defaultuid;
2587 		NFSUNLOCKNAMEID();
2588 		return (0);
2589 	}
2590 
2591 	LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
2592 		if (usrp->lug_namelen == len &&
2593 		    !NFSBCMP(usrp->lug_name, str, len)) {
2594 			if (usrp->lug_expiry < NFSD_MONOSEC)
2595 				break;
2596 			*uidp = usrp->lug_uid;
2597 			TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2598 			TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2599 			NFSUNLOCKNAMEID();
2600 			return (0);
2601 		}
2602 	}
2603 	NFSUNLOCKNAMEID();
2604 	cnt++;
2605 	ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2606 	    str, p);
2607 	if (ret == 0 && cnt < 2)
2608 		goto tryagain;
2609 	return (NFSERR_BADOWNER);
2610 }
2611 
2612 /*
2613  * Convert a gid to a string.
2614  * gid - the group id
2615  * cpp - points to a buffer of size NFSV4_SMALLSTR
2616  *       (malloc a larger one, as required)
2617  * retlenp - pointer to length to be returned
2618  */
2619 APPLESTATIC void
2620 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2621 {
2622 	int i;
2623 	struct nfsusrgrp *usrp;
2624 	u_char *cp = *cpp;
2625 	gid_t tmp;
2626 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2627 
2628 	cnt = 0;
2629 tryagain:
2630 	NFSLOCKNAMEID();
2631 	if (nfsrv_dnsname) {
2632 		/*
2633 		 * Always map nfsrv_defaultgid to "nogroup".
2634 		 */
2635 		if (gid == nfsrv_defaultgid) {
2636 			i = nfsrv_dnsnamelen + 8;
2637 			if (i > len) {
2638 				NFSUNLOCKNAMEID();
2639 				if (len > NFSV4_SMALLSTR)
2640 					free(cp, M_NFSSTRING);
2641 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
2642 				*cpp = cp;
2643 				len = i;
2644 				goto tryagain;
2645 			}
2646 			*retlenp = i;
2647 			NFSBCOPY("nogroup@", cp, 8);
2648 			cp += 8;
2649 			NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2650 			NFSUNLOCKNAMEID();
2651 			return;
2652 		}
2653 		hasampersand = 0;
2654 		LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
2655 			if (usrp->lug_gid == gid) {
2656 				if (usrp->lug_expiry < NFSD_MONOSEC)
2657 					break;
2658 				/*
2659 				 * If the name doesn't already have an '@'
2660 				 * in it, append @domainname to it.
2661 				 */
2662 				for (i = 0; i < usrp->lug_namelen; i++) {
2663 					if (usrp->lug_name[i] == '@') {
2664 						hasampersand = 1;
2665 						break;
2666 					}
2667 				}
2668 				if (hasampersand)
2669 					i = usrp->lug_namelen;
2670 				else
2671 					i = usrp->lug_namelen +
2672 					    nfsrv_dnsnamelen + 1;
2673 				if (i > len) {
2674 					NFSUNLOCKNAMEID();
2675 					if (len > NFSV4_SMALLSTR)
2676 						free(cp, M_NFSSTRING);
2677 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
2678 					*cpp = cp;
2679 					len = i;
2680 					goto tryagain;
2681 				}
2682 				*retlenp = i;
2683 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2684 				if (!hasampersand) {
2685 					cp += usrp->lug_namelen;
2686 					*cp++ = '@';
2687 					NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2688 				}
2689 				TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2690 				TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2691 				NFSUNLOCKNAMEID();
2692 				return;
2693 			}
2694 		}
2695 		NFSUNLOCKNAMEID();
2696 		cnt++;
2697 		ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2698 		    NULL, p);
2699 		if (ret == 0 && cnt < 2)
2700 			goto tryagain;
2701 	} else {
2702 		NFSUNLOCKNAMEID();
2703 	}
2704 
2705 	/*
2706 	 * No match, just return a string of digits.
2707 	 */
2708 	tmp = gid;
2709 	i = 0;
2710 	while (tmp || i == 0) {
2711 		tmp /= 10;
2712 		i++;
2713 	}
2714 	len = (i > len) ? len : i;
2715 	*retlenp = len;
2716 	cp += (len - 1);
2717 	tmp = gid;
2718 	for (i = 0; i < len; i++) {
2719 		*cp-- = '0' + (tmp % 10);
2720 		tmp /= 10;
2721 	}
2722 	return;
2723 }
2724 
2725 /*
2726  * Convert a string to a gid.
2727  */
2728 APPLESTATIC int
2729 nfsv4_strtogid(u_char *str, int len, gid_t *gidp, NFSPROC_T *p)
2730 {
2731 	int i;
2732 	u_char *cp;
2733 	struct nfsusrgrp *usrp;
2734 	int cnt, ret;
2735 
2736 	if (len == 0)
2737 		return (NFSERR_BADOWNER);
2738 	/*
2739 	 * Look for an '@'.
2740 	 */
2741 	cp = str;
2742 	for (i = 0; i < len; i++)
2743 		if (*cp++ == '@')
2744 			break;
2745 
2746 	cnt = 0;
2747 tryagain:
2748 	NFSLOCKNAMEID();
2749 	/*
2750 	 * If an '@' is found and the dns name matches, search for the name
2751 	 * with the dns stripped off.
2752 	 */
2753 	if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2754 	    (len - 1 - i) == nfsrv_dnsnamelen &&
2755 	    !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2756 		len -= (nfsrv_dnsnamelen + 1);
2757 		*(cp - 1) = '\0';
2758 	}
2759 
2760 	/*
2761 	 * Check for the special case of "nogroup".
2762 	 */
2763 	if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2764 		*gidp = nfsrv_defaultgid;
2765 		NFSUNLOCKNAMEID();
2766 		return (0);
2767 	}
2768 
2769 	LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
2770 		if (usrp->lug_namelen == len &&
2771 		    !NFSBCMP(usrp->lug_name, str, len)) {
2772 			if (usrp->lug_expiry < NFSD_MONOSEC)
2773 				break;
2774 			*gidp = usrp->lug_gid;
2775 			TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2776 			TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2777 			NFSUNLOCKNAMEID();
2778 			return (0);
2779 		}
2780 	}
2781 	NFSUNLOCKNAMEID();
2782 	cnt++;
2783 	ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
2784 	    str, p);
2785 	if (ret == 0 && cnt < 2)
2786 		goto tryagain;
2787 	return (NFSERR_BADOWNER);
2788 }
2789 
2790 /*
2791  * Cmp len chars, allowing mixed case in the first argument to match lower
2792  * case in the second, but not if the first argument is all upper case.
2793  * Return 0 for a match, 1 otherwise.
2794  */
2795 static int
2796 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
2797 {
2798 	int i;
2799 	u_char tmp;
2800 	int fndlower = 0;
2801 
2802 	for (i = 0; i < len; i++) {
2803 		if (*cp >= 'A' && *cp <= 'Z') {
2804 			tmp = *cp++ + ('a' - 'A');
2805 		} else {
2806 			tmp = *cp++;
2807 			if (tmp >= 'a' && tmp <= 'z')
2808 				fndlower = 1;
2809 		}
2810 		if (tmp != *cp2++)
2811 			return (1);
2812 	}
2813 	if (fndlower)
2814 		return (0);
2815 	else
2816 		return (1);
2817 }
2818 
2819 /*
2820  * Set the port for the nfsuserd.
2821  */
2822 APPLESTATIC int
2823 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
2824 {
2825 	struct nfssockreq *rp;
2826 	struct sockaddr_in *ad;
2827 	int error;
2828 
2829 	NFSLOCKNAMEID();
2830 	if (nfsrv_nfsuserd) {
2831 		NFSUNLOCKNAMEID();
2832 		return (EPERM);
2833 	}
2834 	nfsrv_nfsuserd = 1;
2835 	NFSUNLOCKNAMEID();
2836 	/*
2837 	 * Set up the socket record and connect.
2838 	 */
2839 	rp = &nfsrv_nfsuserdsock;
2840 	rp->nr_client = NULL;
2841 	rp->nr_sotype = SOCK_DGRAM;
2842 	rp->nr_soproto = IPPROTO_UDP;
2843 	rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
2844 	rp->nr_cred = NULL;
2845 	NFSSOCKADDRALLOC(rp->nr_nam);
2846 	NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
2847 	ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
2848 	ad->sin_family = AF_INET;
2849 	ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001);	/* 127.0.0.1 */
2850 	ad->sin_port = port;
2851 	rp->nr_prog = RPCPROG_NFSUSERD;
2852 	rp->nr_vers = RPCNFSUSERD_VERS;
2853 	error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
2854 	if (error) {
2855 		NFSSOCKADDRFREE(rp->nr_nam);
2856 		nfsrv_nfsuserd = 0;
2857 	}
2858 	return (error);
2859 }
2860 
2861 /*
2862  * Delete the nfsuserd port.
2863  */
2864 APPLESTATIC void
2865 nfsrv_nfsuserddelport(void)
2866 {
2867 
2868 	NFSLOCKNAMEID();
2869 	if (nfsrv_nfsuserd == 0) {
2870 		NFSUNLOCKNAMEID();
2871 		return;
2872 	}
2873 	nfsrv_nfsuserd = 0;
2874 	NFSUNLOCKNAMEID();
2875 	newnfs_disconnect(&nfsrv_nfsuserdsock);
2876 	NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
2877 }
2878 
2879 /*
2880  * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
2881  * name<-->id cache.
2882  * Returns 0 upon success, non-zero otherwise.
2883  */
2884 static int
2885 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
2886 {
2887 	u_int32_t *tl;
2888 	struct nfsrv_descript *nd;
2889 	int len;
2890 	struct nfsrv_descript nfsd;
2891 	struct ucred *cred;
2892 	int error;
2893 
2894 	NFSLOCKNAMEID();
2895 	if (nfsrv_nfsuserd == 0) {
2896 		NFSUNLOCKNAMEID();
2897 		return (EPERM);
2898 	}
2899 	NFSUNLOCKNAMEID();
2900 	nd = &nfsd;
2901 	cred = newnfs_getcred();
2902 	nd->nd_flag = ND_GSSINITREPLY;
2903 	nfsrvd_rephead(nd);
2904 
2905 	nd->nd_procnum = procnum;
2906 	if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
2907 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2908 		if (procnum == RPCNFSUSERD_GETUID)
2909 			*tl = txdr_unsigned(uid);
2910 		else
2911 			*tl = txdr_unsigned(gid);
2912 	} else {
2913 		len = strlen(name);
2914 		(void) nfsm_strtom(nd, name, len);
2915 	}
2916 	error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
2917 		cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL);
2918 	NFSFREECRED(cred);
2919 	if (!error) {
2920 		mbuf_freem(nd->nd_mrep);
2921 		error = nd->nd_repstat;
2922 	}
2923 	return (error);
2924 }
2925 
2926 /*
2927  * This function is called from the nfssvc(2) system call, to update the
2928  * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
2929  */
2930 APPLESTATIC int
2931 nfssvc_idname(struct nfsd_idargs *nidp)
2932 {
2933 	struct nfsusrgrp *nusrp, *usrp, *newusrp;
2934 	struct nfsuserhashhead *hp;
2935 	int i;
2936 	int error = 0;
2937 	u_char *cp;
2938 
2939 	if (nidp->nid_flag & NFSID_INITIALIZE) {
2940 	    cp = (u_char *)malloc(nidp->nid_namelen + 1,
2941 		M_NFSSTRING, M_WAITOK);
2942 	    error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
2943 		nidp->nid_namelen);
2944 	    NFSLOCKNAMEID();
2945 	    if (nfsrv_dnsname) {
2946 		/*
2947 		 * Free up all the old stuff and reinitialize hash lists.
2948 		 */
2949 		TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
2950 			nfsrv_removeuser(usrp);
2951 		}
2952 		free(nfsrv_dnsname, M_NFSSTRING);
2953 		nfsrv_dnsname = NULL;
2954 	    }
2955 	    TAILQ_INIT(&nfsuserlruhead);
2956 	    for (i = 0; i < NFSUSERHASHSIZE; i++)
2957 		LIST_INIT(&nfsuserhash[i]);
2958 	    for (i = 0; i < NFSGROUPHASHSIZE; i++)
2959 		LIST_INIT(&nfsgrouphash[i]);
2960 	    for (i = 0; i < NFSUSERHASHSIZE; i++)
2961 		LIST_INIT(&nfsusernamehash[i]);
2962 	    for (i = 0; i < NFSGROUPHASHSIZE; i++)
2963 		LIST_INIT(&nfsgroupnamehash[i]);
2964 
2965 	    /*
2966 	     * Put name in "DNS" string.
2967 	     */
2968 	    if (!error) {
2969 		nfsrv_dnsname = cp;
2970 		nfsrv_dnsnamelen = nidp->nid_namelen;
2971 		nfsrv_defaultuid = nidp->nid_uid;
2972 		nfsrv_defaultgid = nidp->nid_gid;
2973 		nfsrv_usercnt = 0;
2974 		nfsrv_usermax = nidp->nid_usermax;
2975 	    }
2976 	    NFSUNLOCKNAMEID();
2977 	    if (error)
2978 		free(cp, M_NFSSTRING);
2979 	    return (error);
2980 	}
2981 
2982 	/*
2983 	 * malloc the new one now, so any potential sleep occurs before
2984 	 * manipulation of the lists.
2985 	 */
2986 	MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
2987 	    nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
2988 	error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
2989 	    nidp->nid_namelen);
2990 	if (error) {
2991 		free((caddr_t)newusrp, M_NFSUSERGROUP);
2992 		return (error);
2993 	}
2994 	newusrp->lug_namelen = nidp->nid_namelen;
2995 
2996 	NFSLOCKNAMEID();
2997 	/*
2998 	 * Delete old entries, as required.
2999 	 */
3000 	if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3001 		hp = NFSUSERHASH(nidp->nid_uid);
3002 		LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3003 			if (usrp->lug_uid == nidp->nid_uid)
3004 				nfsrv_removeuser(usrp);
3005 		}
3006 	}
3007 	if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3008 		hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3009 		LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3010 			if (usrp->lug_namelen == newusrp->lug_namelen &&
3011 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3012 			    usrp->lug_namelen))
3013 				nfsrv_removeuser(usrp);
3014 		}
3015 	}
3016 	if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3017 		hp = NFSGROUPHASH(nidp->nid_gid);
3018 		LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3019 			if (usrp->lug_gid == nidp->nid_gid)
3020 				nfsrv_removeuser(usrp);
3021 		}
3022 	}
3023 	if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3024 		hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3025 		LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3026 			if (usrp->lug_namelen == newusrp->lug_namelen &&
3027 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3028 			    usrp->lug_namelen))
3029 				nfsrv_removeuser(usrp);
3030 		}
3031 	}
3032 	TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3033 		if (usrp->lug_expiry < NFSD_MONOSEC)
3034 			nfsrv_removeuser(usrp);
3035 	}
3036 	while (nfsrv_usercnt >= nfsrv_usermax) {
3037 		usrp = TAILQ_FIRST(&nfsuserlruhead);
3038 		nfsrv_removeuser(usrp);
3039 	}
3040 
3041 	/*
3042 	 * Now, we can add the new one.
3043 	 */
3044 	if (nidp->nid_usertimeout)
3045 		newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3046 	else
3047 		newusrp->lug_expiry = NFSD_MONOSEC + 5;
3048 	if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3049 		newusrp->lug_uid = nidp->nid_uid;
3050 		LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
3051 		    lug_numhash);
3052 		LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
3053 		    newusrp->lug_namelen), newusrp, lug_namehash);
3054 		TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3055 		nfsrv_usercnt++;
3056 	} else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3057 		newusrp->lug_gid = nidp->nid_gid;
3058 		LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
3059 		    lug_numhash);
3060 		LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
3061 		    newusrp->lug_namelen), newusrp, lug_namehash);
3062 		TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3063 		nfsrv_usercnt++;
3064 	} else
3065 		FREE((caddr_t)newusrp, M_NFSUSERGROUP);
3066 	NFSUNLOCKNAMEID();
3067 	return (error);
3068 }
3069 
3070 /*
3071  * Remove a user/group name element.
3072  */
3073 static void
3074 nfsrv_removeuser(struct nfsusrgrp *usrp)
3075 {
3076 
3077 	NFSNAMEIDREQUIRED();
3078 	LIST_REMOVE(usrp, lug_numhash);
3079 	LIST_REMOVE(usrp, lug_namehash);
3080 	TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
3081 	nfsrv_usercnt--;
3082 	FREE((caddr_t)usrp, M_NFSUSERGROUP);
3083 }
3084 
3085 /*
3086  * This function scans a byte string and checks for UTF-8 compliance.
3087  * It returns 0 if it conforms and NFSERR_INVAL if not.
3088  */
3089 APPLESTATIC int
3090 nfsrv_checkutf8(u_int8_t *cp, int len)
3091 {
3092 	u_int32_t val = 0x0;
3093 	int cnt = 0, gotd = 0, shift = 0;
3094 	u_int8_t byte;
3095 	static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3096 
3097 	/*
3098 	 * Here are what the variables are used for:
3099 	 * val - the calculated value of a multibyte char, used to check
3100 	 *       that it was coded with the correct range
3101 	 * cnt - the number of 10xxxxxx bytes to follow
3102 	 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3103 	 * shift - lower order bits of range (ie. "val >> shift" should
3104 	 *       not be 0, in other words, dividing by the lower bound
3105 	 *       of the range should get a non-zero value)
3106 	 * byte - used to calculate cnt
3107 	 */
3108 	while (len > 0) {
3109 		if (cnt > 0) {
3110 			/* This handles the 10xxxxxx bytes */
3111 			if ((*cp & 0xc0) != 0x80 ||
3112 			    (gotd && (*cp & 0x20)))
3113 				return (NFSERR_INVAL);
3114 			gotd = 0;
3115 			val <<= 6;
3116 			val |= (*cp & 0x3f);
3117 			cnt--;
3118 			if (cnt == 0 && (val >> shift) == 0x0)
3119 				return (NFSERR_INVAL);
3120 		} else if (*cp & 0x80) {
3121 			/* first byte of multi byte char */
3122 			byte = *cp;
3123 			while ((byte & 0x40) && cnt < 6) {
3124 				cnt++;
3125 				byte <<= 1;
3126 			}
3127 			if (cnt == 0 || cnt == 6)
3128 				return (NFSERR_INVAL);
3129 			val = (*cp & (0x3f >> cnt));
3130 			shift = utf8_shift[cnt - 1];
3131 			if (cnt == 2 && val == 0xd)
3132 				/* Check for the 0xd800-0xdfff case */
3133 				gotd = 1;
3134 		}
3135 		cp++;
3136 		len--;
3137 	}
3138 	if (cnt > 0)
3139 		return (NFSERR_INVAL);
3140 	return (0);
3141 }
3142 
3143 /*
3144  * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3145  * strings, one with the root path in it and the other with the list of
3146  * locations. The list is in the same format as is found in nfr_refs.
3147  * It is a "," separated list of entries, where each of them is of the
3148  * form <server>:<rootpath>. For example
3149  * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3150  * The nilp argument is set to 1 for the special case of a null fs_root
3151  * and an empty server list.
3152  * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3153  * number of xdr bytes parsed in sump.
3154  */
3155 static int
3156 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3157     int *sump, int *nilp)
3158 {
3159 	u_int32_t *tl;
3160 	u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3161 	int i, j, len, stringlen, cnt, slen, siz, xdrsum, error, nsrv;
3162 	struct list {
3163 		SLIST_ENTRY(list) next;
3164 		int len;
3165 		u_char host[1];
3166 	} *lsp, *nlsp;
3167 	SLIST_HEAD(, list) head;
3168 
3169 	*fsrootp = NULL;
3170 	*srvp = NULL;
3171 	*nilp = 0;
3172 
3173 	/*
3174 	 * Get the fs_root path and check for the special case of null path
3175 	 * and 0 length server list.
3176 	 */
3177 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3178 	len = fxdr_unsigned(int, *tl);
3179 	if (len < 0 || len > 10240)
3180 		return (NFSERR_BADXDR);
3181 	if (len == 0) {
3182 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3183 		if (*tl != 0)
3184 			return (NFSERR_BADXDR);
3185 		*nilp = 1;
3186 		*sump = 2 * NFSX_UNSIGNED;
3187 		return (0);
3188 	}
3189 	cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3190 	error = nfsrv_mtostr(nd, cp, len);
3191 	if (!error) {
3192 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3193 		cnt = fxdr_unsigned(int, *tl);
3194 		if (cnt <= 0)
3195 			error = NFSERR_BADXDR;
3196 	}
3197 	if (error) {
3198 		free(cp, M_NFSSTRING);
3199 		return (error);
3200 	}
3201 
3202 	/*
3203 	 * Now, loop through the location list and make up the srvlist.
3204 	 */
3205 	xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3206 	cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3207 	slen = 1024;
3208 	siz = 0;
3209 	for (i = 0; i < cnt; i++) {
3210 		SLIST_INIT(&head);
3211 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3212 		nsrv = fxdr_unsigned(int, *tl);
3213 		if (nsrv <= 0) {
3214 			free(cp, M_NFSSTRING);
3215 			free(cp2, M_NFSSTRING);
3216 			return (NFSERR_BADXDR);
3217 		}
3218 
3219 		/*
3220 		 * Handle the first server by putting it in the srvstr.
3221 		 */
3222 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3223 		len = fxdr_unsigned(int, *tl);
3224 		if (len <= 0 || len > 1024) {
3225 			free(cp, M_NFSSTRING);
3226 			free(cp2, M_NFSSTRING);
3227 			return (NFSERR_BADXDR);
3228 		}
3229 		nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3230 		if (cp3 != cp2) {
3231 			*cp3++ = ',';
3232 			siz++;
3233 		}
3234 		error = nfsrv_mtostr(nd, cp3, len);
3235 		if (error) {
3236 			free(cp, M_NFSSTRING);
3237 			free(cp2, M_NFSSTRING);
3238 			return (error);
3239 		}
3240 		cp3 += len;
3241 		*cp3++ = ':';
3242 		siz += (len + 1);
3243 		xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3244 		for (j = 1; j < nsrv; j++) {
3245 			/*
3246 			 * Yuck, put them in an slist and process them later.
3247 			 */
3248 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3249 			len = fxdr_unsigned(int, *tl);
3250 			if (len <= 0 || len > 1024) {
3251 				free(cp, M_NFSSTRING);
3252 				free(cp2, M_NFSSTRING);
3253 				return (NFSERR_BADXDR);
3254 			}
3255 			lsp = (struct list *)malloc(sizeof (struct list)
3256 			    + len, M_TEMP, M_WAITOK);
3257 			error = nfsrv_mtostr(nd, lsp->host, len);
3258 			if (error) {
3259 				free(cp, M_NFSSTRING);
3260 				free(cp2, M_NFSSTRING);
3261 				return (error);
3262 			}
3263 			xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3264 			lsp->len = len;
3265 			SLIST_INSERT_HEAD(&head, lsp, next);
3266 		}
3267 
3268 		/*
3269 		 * Finally, we can get the path.
3270 		 */
3271 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3272 		len = fxdr_unsigned(int, *tl);
3273 		if (len <= 0 || len > 1024) {
3274 			free(cp, M_NFSSTRING);
3275 			free(cp2, M_NFSSTRING);
3276 			return (NFSERR_BADXDR);
3277 		}
3278 		nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3279 		error = nfsrv_mtostr(nd, cp3, len);
3280 		if (error) {
3281 			free(cp, M_NFSSTRING);
3282 			free(cp2, M_NFSSTRING);
3283 			return (error);
3284 		}
3285 		xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3286 		str = cp3;
3287 		stringlen = len;
3288 		cp3 += len;
3289 		siz += len;
3290 		SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3291 			nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3292 			    &cp2, &cp3, &slen);
3293 			*cp3++ = ',';
3294 			NFSBCOPY(lsp->host, cp3, lsp->len);
3295 			cp3 += lsp->len;
3296 			*cp3++ = ':';
3297 			NFSBCOPY(str, cp3, stringlen);
3298 			cp3 += stringlen;
3299 			*cp3 = '\0';
3300 			siz += (lsp->len + stringlen + 2);
3301 			free((caddr_t)lsp, M_TEMP);
3302 		}
3303 	}
3304 	*fsrootp = cp;
3305 	*srvp = cp2;
3306 	*sump = xdrsum;
3307 	return (0);
3308 nfsmout:
3309 	if (cp != NULL)
3310 		free(cp, M_NFSSTRING);
3311 	if (cp2 != NULL)
3312 		free(cp2, M_NFSSTRING);
3313 	return (error);
3314 }
3315 
3316 /*
3317  * Make the malloc'd space large enough. This is a pain, but the xdr
3318  * doesn't set an upper bound on the side, so...
3319  */
3320 static void
3321 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3322 {
3323 	u_char *cp;
3324 	int i;
3325 
3326 	if (siz <= *slenp)
3327 		return;
3328 	cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3329 	NFSBCOPY(*cpp, cp, *slenp);
3330 	free(*cpp, M_NFSSTRING);
3331 	i = *cpp2 - *cpp;
3332 	*cpp = cp;
3333 	*cpp2 = cp + i;
3334 	*slenp = siz + 1024;
3335 }
3336 
3337 /*
3338  * Initialize the reply header data structures.
3339  */
3340 APPLESTATIC void
3341 nfsrvd_rephead(struct nfsrv_descript *nd)
3342 {
3343 	mbuf_t mreq;
3344 
3345 	/*
3346 	 * If this is a big reply, use a cluster.
3347 	 */
3348 	if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3349 	    nfs_bigreply[nd->nd_procnum]) {
3350 		NFSMCLGET(mreq, M_WAIT);
3351 		nd->nd_mreq = mreq;
3352 		nd->nd_mb = mreq;
3353 	} else {
3354 		NFSMGET(mreq);
3355 		nd->nd_mreq = mreq;
3356 		nd->nd_mb = mreq;
3357 	}
3358 	nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3359 	mbuf_setlen(mreq, 0);
3360 
3361 	if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3362 		NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3363 }
3364 
3365 /*
3366  * Lock a socket against others.
3367  * Currently used to serialize connect/disconnect attempts.
3368  */
3369 int
3370 newnfs_sndlock(int *flagp)
3371 {
3372 	struct timespec ts;
3373 
3374 	NFSLOCKSOCK();
3375 	while (*flagp & NFSR_SNDLOCK) {
3376 		*flagp |= NFSR_WANTSND;
3377 		ts.tv_sec = 0;
3378 		ts.tv_nsec = 0;
3379 		(void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3380 		    PZERO - 1, "nfsndlck", &ts);
3381 	}
3382 	*flagp |= NFSR_SNDLOCK;
3383 	NFSUNLOCKSOCK();
3384 	return (0);
3385 }
3386 
3387 /*
3388  * Unlock the stream socket for others.
3389  */
3390 void
3391 newnfs_sndunlock(int *flagp)
3392 {
3393 
3394 	NFSLOCKSOCK();
3395 	if ((*flagp & NFSR_SNDLOCK) == 0)
3396 		panic("nfs sndunlock");
3397 	*flagp &= ~NFSR_SNDLOCK;
3398 	if (*flagp & NFSR_WANTSND) {
3399 		*flagp &= ~NFSR_WANTSND;
3400 		wakeup((caddr_t)flagp);
3401 	}
3402 	NFSUNLOCKSOCK();
3403 }
3404 
3405