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