xref: /freebsd/sys/fs/nfs/nfs_commonsubs.c (revision 884a2a699669ec61e2366e3e358342dbc94be24a)
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, LK_EXCLUSIVE },		/* undef */
88 	{ 0, 0, 0, 0, LK_EXCLUSIVE },		/* undef */
89 	{ 0, 0, 0, 0, LK_EXCLUSIVE },		/* undef */
90 	{ 0, 1, 0, 0, LK_SHARED },		/* Access */
91 	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* Close */
92 	{ 0, 2, 0, 1, LK_EXCLUSIVE },		/* Commit */
93 	{ 1, 2, 1, 1, LK_EXCLUSIVE },		/* Create */
94 	{ 0, 0, 0, 0, LK_EXCLUSIVE },		/* Delegpurge */
95 	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* Delegreturn */
96 	{ 0, 1, 0, 0, LK_SHARED },		/* Getattr */
97 	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* GetFH */
98 	{ 2, 1, 1, 1, LK_EXCLUSIVE },		/* Link */
99 	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* Lock */
100 	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* LockT */
101 	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* LockU */
102 	{ 1, 1, 0, 0, LK_EXCLUSIVE },		/* Lookup */
103 	{ 1, 1, 0, 0, LK_EXCLUSIVE },		/* Lookupp */
104 	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* NVerify */
105 	{ 1, 1, 0, 1, LK_EXCLUSIVE },		/* Open */
106 	{ 1, 1, 0, 0, LK_EXCLUSIVE },		/* OpenAttr */
107 	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* OpenConfirm */
108 	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* OpenDowngrade */
109 	{ 1, 0, 0, 0, LK_EXCLUSIVE },		/* PutFH */
110 	{ 1, 0, 0, 0, LK_EXCLUSIVE },		/* PutPubFH */
111 	{ 1, 0, 0, 0, LK_EXCLUSIVE },		/* PutRootFH */
112 	{ 0, 1, 0, 0, LK_SHARED },		/* Read */
113 	{ 0, 1, 0, 0, LK_SHARED },		/* Readdir */
114 	{ 0, 1, 0, 0, LK_SHARED },		/* ReadLink */
115 	{ 0, 2, 1, 1, LK_EXCLUSIVE },		/* Remove */
116 	{ 2, 1, 1, 1, LK_EXCLUSIVE },		/* Rename */
117 	{ 0, 0, 0, 0, LK_EXCLUSIVE },		/* Renew */
118 	{ 0, 0, 0, 0, LK_EXCLUSIVE },		/* RestoreFH */
119 	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* SaveFH */
120 	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* SecInfo */
121 	{ 0, 2, 1, 1, LK_EXCLUSIVE },		/* Setattr */
122 	{ 0, 0, 0, 0, LK_EXCLUSIVE },		/* SetClientID */
123 	{ 0, 0, 0, 0, LK_EXCLUSIVE },		/* SetClientIDConfirm */
124 	{ 0, 1, 0, 0, LK_EXCLUSIVE },		/* Verify */
125 	{ 0, 2, 1, 1, LK_EXCLUSIVE },		/* Write */
126 	{ 0, 0, 0, 0, LK_EXCLUSIVE },		/* 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 isleptp argument is set to indicate if the call slept, iff not NULL
1730  * and the mp argument indicates to check for a forced dismount, iff not
1731  * NULL.
1732  */
1733 APPLESTATIC int
1734 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1735     void *mutex, struct mount *mp)
1736 {
1737 
1738 	if (isleptp)
1739 		*isleptp = 0;
1740 	/*
1741 	 * If a lock is wanted, loop around until the lock is acquired by
1742 	 * someone and then released. If I want the lock, try to acquire it.
1743 	 * For a lock to be issued, no lock must be in force and the usecnt
1744 	 * must be zero.
1745 	 */
1746 	if (iwantlock) {
1747 	    if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1748 		lp->nfslock_usecnt == 0) {
1749 		lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1750 		lp->nfslock_lock |= NFSV4LOCK_LOCK;
1751 		return (1);
1752 	    }
1753 	    lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1754 	}
1755 	while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1756 		if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1757 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1758 			return (0);
1759 		}
1760 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
1761 		if (isleptp)
1762 			*isleptp = 1;
1763 		(void) nfsmsleep(&lp->nfslock_lock, mutex,
1764 		    PZERO - 1, "nfsv4lck", NULL);
1765 		if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1766 		    lp->nfslock_usecnt == 0) {
1767 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1768 			lp->nfslock_lock |= NFSV4LOCK_LOCK;
1769 			return (1);
1770 		}
1771 	}
1772 	return (0);
1773 }
1774 
1775 /*
1776  * Release the lock acquired by nfsv4_lock().
1777  * The second argument is set to 1 to indicate the nfslock_usecnt should be
1778  * incremented, as well.
1779  */
1780 APPLESTATIC void
1781 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1782 {
1783 
1784 	lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1785 	if (incref)
1786 		lp->nfslock_usecnt++;
1787 	nfsv4_wanted(lp);
1788 }
1789 
1790 /*
1791  * Release a reference cnt.
1792  */
1793 APPLESTATIC void
1794 nfsv4_relref(struct nfsv4lock *lp)
1795 {
1796 
1797 	if (lp->nfslock_usecnt <= 0)
1798 		panic("nfsv4root ref cnt");
1799 	lp->nfslock_usecnt--;
1800 	if (lp->nfslock_usecnt == 0)
1801 		nfsv4_wanted(lp);
1802 }
1803 
1804 /*
1805  * Get a reference cnt.
1806  * This function will wait for any exclusive lock to be released, but will
1807  * not wait for threads that want the exclusive lock. If priority needs
1808  * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1809  * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1810  * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
1811  * return without getting a refcnt for that case.
1812  */
1813 APPLESTATIC void
1814 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1815     struct mount *mp)
1816 {
1817 
1818 	if (isleptp)
1819 		*isleptp = 0;
1820 
1821 	/*
1822 	 * Wait for a lock held.
1823 	 */
1824 	while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1825 		if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1826 			return;
1827 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
1828 		if (isleptp)
1829 			*isleptp = 1;
1830 		(void) nfsmsleep(&lp->nfslock_lock, mutex,
1831 		    PZERO - 1, "nfsv4lck", NULL);
1832 	}
1833 	if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1834 		return;
1835 
1836 	lp->nfslock_usecnt++;
1837 }
1838 
1839 /*
1840  * Get a reference as above, but return failure instead of sleeping if
1841  * an exclusive lock is held.
1842  */
1843 APPLESTATIC int
1844 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1845 {
1846 
1847 	if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1848 		return (0);
1849 
1850 	lp->nfslock_usecnt++;
1851 	return (1);
1852 }
1853 
1854 /*
1855  * Test for a lock. Return 1 if locked, 0 otherwise.
1856  */
1857 APPLESTATIC int
1858 nfsv4_testlock(struct nfsv4lock *lp)
1859 {
1860 
1861 	if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1862 	    lp->nfslock_usecnt == 0)
1863 		return (0);
1864 	return (1);
1865 }
1866 
1867 /*
1868  * Wake up anyone sleeping, waiting for this lock.
1869  */
1870 static void
1871 nfsv4_wanted(struct nfsv4lock *lp)
1872 {
1873 
1874 	if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1875 		lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1876 		wakeup((caddr_t)&lp->nfslock_lock);
1877 	}
1878 }
1879 
1880 /*
1881  * Copy a string from an mbuf list into a character array.
1882  * Return EBADRPC if there is an mbuf error,
1883  * 0 otherwise.
1884  */
1885 APPLESTATIC int
1886 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1887 {
1888 	char *cp;
1889 	int xfer, len;
1890 	mbuf_t mp;
1891 	int rem, error = 0;
1892 
1893 	mp = nd->nd_md;
1894 	cp = nd->nd_dpos;
1895 	len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1896 	rem = NFSM_RNDUP(siz) - siz;
1897 	while (siz > 0) {
1898 		if (len > siz)
1899 			xfer = siz;
1900 		else
1901 			xfer = len;
1902 		NFSBCOPY(cp, str, xfer);
1903 		str += xfer;
1904 		siz -= xfer;
1905 		if (siz > 0) {
1906 			mp = mbuf_next(mp);
1907 			if (mp == NULL)
1908 				return (EBADRPC);
1909 			cp = NFSMTOD(mp, caddr_t);
1910 			len = mbuf_len(mp);
1911 		} else {
1912 			cp += xfer;
1913 			len -= xfer;
1914 		}
1915 	}
1916 	*str = '\0';
1917 	nd->nd_dpos = cp;
1918 	nd->nd_md = mp;
1919 	if (rem > 0) {
1920 		if (len < rem)
1921 			error = nfsm_advance(nd, rem, len);
1922 		else
1923 			nd->nd_dpos += rem;
1924 	}
1925 	return (error);
1926 }
1927 
1928 /*
1929  * Fill in the attributes as marked by the bitmap (V4).
1930  */
1931 APPLESTATIC int
1932 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
1933     NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
1934     nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
1935     int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
1936 {
1937 	int bitpos, retnum = 0;
1938 	u_int32_t *tl;
1939 	int siz, prefixnum, error;
1940 	u_char *cp, namestr[NFSV4_SMALLSTR];
1941 	nfsattrbit_t attrbits, retbits;
1942 	nfsattrbit_t *retbitp = &retbits;
1943 	u_int32_t freenum, *retnump;
1944 	u_int64_t uquad;
1945 	struct statfs fs;
1946 	struct nfsfsinfo fsinf;
1947 	struct timespec temptime;
1948 	struct timeval curtime;
1949 	NFSACL_T *aclp, *naclp = NULL;
1950 #ifdef QUOTA
1951 	struct dqblk dqb;
1952 	uid_t savuid;
1953 #endif
1954 
1955 	/*
1956 	 * First, set the bits that can be filled and get fsinfo.
1957 	 */
1958 	NFSSET_ATTRBIT(retbitp, attrbitp);
1959 	/* If p and cred are NULL, it is a client side call */
1960 	if (p == NULL && cred == NULL) {
1961 		NFSCLRNOTSETABLE_ATTRBIT(retbitp);
1962 		aclp = saclp;
1963 	} else {
1964 		NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
1965 		naclp = acl_alloc(M_WAITOK);
1966 		aclp = naclp;
1967 	}
1968 	nfsvno_getfs(&fsinf, isdgram);
1969 #ifndef APPLE
1970 	/*
1971 	 * Get the VFS_STATFS(), since some attributes need them.
1972 	 */
1973 	if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
1974 		error = VFS_STATFS(mp, &fs);
1975 		if (error != 0) {
1976 			if (reterr) {
1977 				nd->nd_repstat = NFSERR_ACCES;
1978 				return (0);
1979 			}
1980 			NFSCLRSTATFS_ATTRBIT(retbitp);
1981 		}
1982 	}
1983 #endif
1984 
1985 	/*
1986 	 * And the NFSv4 ACL...
1987 	 */
1988 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
1989 	    (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
1990 		supports_nfsv4acls == 0))) {
1991 		NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
1992 	}
1993 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
1994 		if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
1995 		    supports_nfsv4acls == 0)) {
1996 			NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
1997 		} else if (naclp != NULL) {
1998 			if (vn_lock(vp, LK_SHARED) == 0) {
1999 				error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2000 				if (error == 0)
2001 					error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2002 					    naclp, cred, p);
2003 				VOP_UNLOCK(vp, 0);
2004 			} else
2005 				error = NFSERR_PERM;
2006 			if (error != 0) {
2007 				if (reterr) {
2008 					nd->nd_repstat = NFSERR_ACCES;
2009 					return (0);
2010 				}
2011 				NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2012 			}
2013 		}
2014 	}
2015 	/*
2016 	 * Put out the attribute bitmap for the ones being filled in
2017 	 * and get the field for the number of attributes returned.
2018 	 */
2019 	prefixnum = nfsrv_putattrbit(nd, retbitp);
2020 	NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2021 	prefixnum += NFSX_UNSIGNED;
2022 
2023 	/*
2024 	 * Now, loop around filling in the attributes for each bit set.
2025 	 */
2026 	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2027 	    if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2028 		switch (bitpos) {
2029 		case NFSATTRBIT_SUPPORTEDATTRS:
2030 			NFSSETSUPP_ATTRBIT(&attrbits);
2031 			if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2032 			    && supports_nfsv4acls == 0)) {
2033 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2034 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2035 			}
2036 			retnum += nfsrv_putattrbit(nd, &attrbits);
2037 			break;
2038 		case NFSATTRBIT_TYPE:
2039 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2040 			*tl = vtonfsv34_type(vap->va_type);
2041 			retnum += NFSX_UNSIGNED;
2042 			break;
2043 		case NFSATTRBIT_FHEXPIRETYPE:
2044 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2045 			*tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2046 			retnum += NFSX_UNSIGNED;
2047 			break;
2048 		case NFSATTRBIT_CHANGE:
2049 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2050 			txdr_hyper(vap->va_filerev, tl);
2051 			retnum += NFSX_HYPER;
2052 			break;
2053 		case NFSATTRBIT_SIZE:
2054 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2055 			txdr_hyper(vap->va_size, tl);
2056 			retnum += NFSX_HYPER;
2057 			break;
2058 		case NFSATTRBIT_LINKSUPPORT:
2059 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2060 			if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2061 				*tl = newnfs_true;
2062 			else
2063 				*tl = newnfs_false;
2064 			retnum += NFSX_UNSIGNED;
2065 			break;
2066 		case NFSATTRBIT_SYMLINKSUPPORT:
2067 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2068 			if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2069 				*tl = newnfs_true;
2070 			else
2071 				*tl = newnfs_false;
2072 			retnum += NFSX_UNSIGNED;
2073 			break;
2074 		case NFSATTRBIT_NAMEDATTR:
2075 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2076 			*tl = newnfs_false;
2077 			retnum += NFSX_UNSIGNED;
2078 			break;
2079 		case NFSATTRBIT_FSID:
2080 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2081 			*tl++ = 0;
2082 			*tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2083 			*tl++ = 0;
2084 			*tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2085 			retnum += NFSX_V4FSID;
2086 			break;
2087 		case NFSATTRBIT_UNIQUEHANDLES:
2088 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2089 			*tl = newnfs_true;
2090 			retnum += NFSX_UNSIGNED;
2091 			break;
2092 		case NFSATTRBIT_LEASETIME:
2093 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2094 			*tl = txdr_unsigned(nfsrv_lease);
2095 			retnum += NFSX_UNSIGNED;
2096 			break;
2097 		case NFSATTRBIT_RDATTRERROR:
2098 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2099 			*tl = txdr_unsigned(rderror);
2100 			retnum += NFSX_UNSIGNED;
2101 			break;
2102 		/*
2103 		 * Recommended Attributes. (Only the supported ones.)
2104 		 */
2105 		case NFSATTRBIT_ACL:
2106 			retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2107 			break;
2108 		case NFSATTRBIT_ACLSUPPORT:
2109 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2110 			*tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2111 			retnum += NFSX_UNSIGNED;
2112 			break;
2113 		case NFSATTRBIT_CANSETTIME:
2114 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2115 			if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2116 				*tl = newnfs_true;
2117 			else
2118 				*tl = newnfs_false;
2119 			retnum += NFSX_UNSIGNED;
2120 			break;
2121 		case NFSATTRBIT_CASEINSENSITIVE:
2122 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2123 			*tl = newnfs_false;
2124 			retnum += NFSX_UNSIGNED;
2125 			break;
2126 		case NFSATTRBIT_CASEPRESERVING:
2127 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2128 			*tl = newnfs_true;
2129 			retnum += NFSX_UNSIGNED;
2130 			break;
2131 		case NFSATTRBIT_CHOWNRESTRICTED:
2132 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2133 			*tl = newnfs_true;
2134 			retnum += NFSX_UNSIGNED;
2135 			break;
2136 		case NFSATTRBIT_FILEHANDLE:
2137 			retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2138 			break;
2139 		case NFSATTRBIT_FILEID:
2140 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2141 			*tl++ = 0;
2142 			*tl = txdr_unsigned(vap->va_fileid);
2143 			retnum += NFSX_HYPER;
2144 			break;
2145 		case NFSATTRBIT_FILESAVAIL:
2146 			/*
2147 			 * Check quota and use min(quota, f_ffree).
2148 			 */
2149 			freenum = fs.f_ffree;
2150 #ifdef QUOTA
2151 			/*
2152 			 * ufs_quotactl() insists that the uid argument
2153 			 * equal p_ruid for non-root quota access, so
2154 			 * we'll just make sure that's the case.
2155 			 */
2156 			savuid = p->p_cred->p_ruid;
2157 			p->p_cred->p_ruid = cred->cr_uid;
2158 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2159 			    cred->cr_uid, (caddr_t)&dqb))
2160 			    freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2161 				freenum);
2162 			p->p_cred->p_ruid = savuid;
2163 #endif	/* QUOTA */
2164 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2165 			*tl++ = 0;
2166 			*tl = txdr_unsigned(freenum);
2167 			retnum += NFSX_HYPER;
2168 			break;
2169 		case NFSATTRBIT_FILESFREE:
2170 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2171 			*tl++ = 0;
2172 			*tl = txdr_unsigned(fs.f_ffree);
2173 			retnum += NFSX_HYPER;
2174 			break;
2175 		case NFSATTRBIT_FILESTOTAL:
2176 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2177 			*tl++ = 0;
2178 			*tl = txdr_unsigned(fs.f_files);
2179 			retnum += NFSX_HYPER;
2180 			break;
2181 		case NFSATTRBIT_FSLOCATIONS:
2182 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2183 			*tl++ = 0;
2184 			*tl = 0;
2185 			retnum += 2 * NFSX_UNSIGNED;
2186 			break;
2187 		case NFSATTRBIT_HOMOGENEOUS:
2188 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2189 			if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2190 				*tl = newnfs_true;
2191 			else
2192 				*tl = newnfs_false;
2193 			retnum += NFSX_UNSIGNED;
2194 			break;
2195 		case NFSATTRBIT_MAXFILESIZE:
2196 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2197 			uquad = NFSRV_MAXFILESIZE;
2198 			txdr_hyper(uquad, tl);
2199 			retnum += NFSX_HYPER;
2200 			break;
2201 		case NFSATTRBIT_MAXLINK:
2202 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2203 			*tl = txdr_unsigned(LINK_MAX);
2204 			retnum += NFSX_UNSIGNED;
2205 			break;
2206 		case NFSATTRBIT_MAXNAME:
2207 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2208 			*tl = txdr_unsigned(NFS_MAXNAMLEN);
2209 			retnum += NFSX_UNSIGNED;
2210 			break;
2211 		case NFSATTRBIT_MAXREAD:
2212 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2213 			*tl++ = 0;
2214 			*tl = txdr_unsigned(fsinf.fs_rtmax);
2215 			retnum += NFSX_HYPER;
2216 			break;
2217 		case NFSATTRBIT_MAXWRITE:
2218 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2219 			*tl++ = 0;
2220 			*tl = txdr_unsigned(fsinf.fs_wtmax);
2221 			retnum += NFSX_HYPER;
2222 			break;
2223 		case NFSATTRBIT_MODE:
2224 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2225 			*tl = vtonfsv34_mode(vap->va_mode);
2226 			retnum += NFSX_UNSIGNED;
2227 			break;
2228 		case NFSATTRBIT_NOTRUNC:
2229 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2230 			*tl = newnfs_true;
2231 			retnum += NFSX_UNSIGNED;
2232 			break;
2233 		case NFSATTRBIT_NUMLINKS:
2234 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2235 			*tl = txdr_unsigned(vap->va_nlink);
2236 			retnum += NFSX_UNSIGNED;
2237 			break;
2238 		case NFSATTRBIT_OWNER:
2239 			cp = namestr;
2240 			nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2241 			retnum += nfsm_strtom(nd, cp, siz);
2242 			if (cp != namestr)
2243 				free(cp, M_NFSSTRING);
2244 			break;
2245 		case NFSATTRBIT_OWNERGROUP:
2246 			cp = namestr;
2247 			nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2248 			retnum += nfsm_strtom(nd, cp, siz);
2249 			if (cp != namestr)
2250 				free(cp, M_NFSSTRING);
2251 			break;
2252 		case NFSATTRBIT_QUOTAHARD:
2253 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2254 				freenum = fs.f_bfree;
2255 			else
2256 				freenum = fs.f_bavail;
2257 #ifdef QUOTA
2258 			/*
2259 			 * ufs_quotactl() insists that the uid argument
2260 			 * equal p_ruid for non-root quota access, so
2261 			 * we'll just make sure that's the case.
2262 			 */
2263 			savuid = p->p_cred->p_ruid;
2264 			p->p_cred->p_ruid = cred->cr_uid;
2265 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2266 			    cred->cr_uid, (caddr_t)&dqb))
2267 			    freenum = min(dqb.dqb_bhardlimit, freenum);
2268 			p->p_cred->p_ruid = savuid;
2269 #endif	/* QUOTA */
2270 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2271 			uquad = (u_int64_t)freenum;
2272 			NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2273 			txdr_hyper(uquad, tl);
2274 			retnum += NFSX_HYPER;
2275 			break;
2276 		case NFSATTRBIT_QUOTASOFT:
2277 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2278 				freenum = fs.f_bfree;
2279 			else
2280 				freenum = fs.f_bavail;
2281 #ifdef QUOTA
2282 			/*
2283 			 * ufs_quotactl() insists that the uid argument
2284 			 * equal p_ruid for non-root quota access, so
2285 			 * we'll just make sure that's the case.
2286 			 */
2287 			savuid = p->p_cred->p_ruid;
2288 			p->p_cred->p_ruid = cred->cr_uid;
2289 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2290 			    cred->cr_uid, (caddr_t)&dqb))
2291 			    freenum = min(dqb.dqb_bsoftlimit, freenum);
2292 			p->p_cred->p_ruid = savuid;
2293 #endif	/* QUOTA */
2294 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2295 			uquad = (u_int64_t)freenum;
2296 			NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2297 			txdr_hyper(uquad, tl);
2298 			retnum += NFSX_HYPER;
2299 			break;
2300 		case NFSATTRBIT_QUOTAUSED:
2301 			freenum = 0;
2302 #ifdef QUOTA
2303 			/*
2304 			 * ufs_quotactl() insists that the uid argument
2305 			 * equal p_ruid for non-root quota access, so
2306 			 * we'll just make sure that's the case.
2307 			 */
2308 			savuid = p->p_cred->p_ruid;
2309 			p->p_cred->p_ruid = cred->cr_uid;
2310 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2311 			    cred->cr_uid, (caddr_t)&dqb))
2312 			    freenum = dqb.dqb_curblocks;
2313 			p->p_cred->p_ruid = savuid;
2314 #endif	/* QUOTA */
2315 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2316 			uquad = (u_int64_t)freenum;
2317 			NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2318 			txdr_hyper(uquad, tl);
2319 			retnum += NFSX_HYPER;
2320 			break;
2321 		case NFSATTRBIT_RAWDEV:
2322 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2323 			*tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2324 			*tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2325 			retnum += NFSX_V4SPECDATA;
2326 			break;
2327 		case NFSATTRBIT_SPACEAVAIL:
2328 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2329 			if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2330 				uquad = (u_int64_t)fs.f_bfree;
2331 			else
2332 				uquad = (u_int64_t)fs.f_bavail;
2333 			uquad *= fs.f_bsize;
2334 			txdr_hyper(uquad, tl);
2335 			retnum += NFSX_HYPER;
2336 			break;
2337 		case NFSATTRBIT_SPACEFREE:
2338 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2339 			uquad = (u_int64_t)fs.f_bfree;
2340 			uquad *= fs.f_bsize;
2341 			txdr_hyper(uquad, tl);
2342 			retnum += NFSX_HYPER;
2343 			break;
2344 		case NFSATTRBIT_SPACETOTAL:
2345 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2346 			uquad = (u_int64_t)fs.f_blocks;
2347 			uquad *= fs.f_bsize;
2348 			txdr_hyper(uquad, tl);
2349 			retnum += NFSX_HYPER;
2350 			break;
2351 		case NFSATTRBIT_SPACEUSED:
2352 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2353 			txdr_hyper(vap->va_bytes, tl);
2354 			retnum += NFSX_HYPER;
2355 			break;
2356 		case NFSATTRBIT_TIMEACCESS:
2357 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2358 			txdr_nfsv4time(&vap->va_atime, tl);
2359 			retnum += NFSX_V4TIME;
2360 			break;
2361 		case NFSATTRBIT_TIMEACCESSSET:
2362 			NFSGETTIME(&curtime);
2363 			if (vap->va_atime.tv_sec != curtime.tv_sec) {
2364 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2365 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2366 				txdr_nfsv4time(&vap->va_atime, tl);
2367 				retnum += NFSX_V4SETTIME;
2368 			} else {
2369 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2370 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2371 				retnum += NFSX_UNSIGNED;
2372 			}
2373 			break;
2374 		case NFSATTRBIT_TIMEDELTA:
2375 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2376 			temptime.tv_sec = 0;
2377 			temptime.tv_nsec = 1000000000 / hz;
2378 			txdr_nfsv4time(&temptime, tl);
2379 			retnum += NFSX_V4TIME;
2380 			break;
2381 		case NFSATTRBIT_TIMEMETADATA:
2382 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2383 			txdr_nfsv4time(&vap->va_ctime, tl);
2384 			retnum += NFSX_V4TIME;
2385 			break;
2386 		case NFSATTRBIT_TIMEMODIFY:
2387 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2388 			txdr_nfsv4time(&vap->va_mtime, tl);
2389 			retnum += NFSX_V4TIME;
2390 			break;
2391 		case NFSATTRBIT_TIMEMODIFYSET:
2392 			NFSGETTIME(&curtime);
2393 			if (vap->va_mtime.tv_sec != curtime.tv_sec) {
2394 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2395 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2396 				txdr_nfsv4time(&vap->va_mtime, tl);
2397 				retnum += NFSX_V4SETTIME;
2398 			} else {
2399 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2400 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2401 				retnum += NFSX_UNSIGNED;
2402 			}
2403 			break;
2404 		case NFSATTRBIT_MOUNTEDONFILEID:
2405 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2406 			if (at_root != 0)
2407 				uquad = mounted_on_fileno;
2408 			else
2409 				uquad = (u_int64_t)vap->va_fileid;
2410 			txdr_hyper(uquad, tl);
2411 			retnum += NFSX_HYPER;
2412 			break;
2413 		default:
2414 			printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2415 		};
2416 	    }
2417 	}
2418 	if (naclp != NULL)
2419 		acl_free(naclp);
2420 	*retnump = txdr_unsigned(retnum);
2421 	return (retnum + prefixnum);
2422 }
2423 
2424 /*
2425  * Put the attribute bits onto an mbuf list.
2426  * Return the number of bytes of output generated.
2427  */
2428 APPLESTATIC int
2429 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2430 {
2431 	u_int32_t *tl;
2432 	int cnt, i, bytesize;
2433 
2434 	for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2435 		if (attrbitp->bits[cnt - 1])
2436 			break;
2437 	bytesize = (cnt + 1) * NFSX_UNSIGNED;
2438 	NFSM_BUILD(tl, u_int32_t *, bytesize);
2439 	*tl++ = txdr_unsigned(cnt);
2440 	for (i = 0; i < cnt; i++)
2441 		*tl++ = txdr_unsigned(attrbitp->bits[i]);
2442 	return (bytesize);
2443 }
2444 
2445 /*
2446  * Convert a uid to a string.
2447  * If the lookup fails, just output the digits.
2448  * uid - the user id
2449  * cpp - points to a buffer of size NFSV4_SMALLSTR
2450  *       (malloc a larger one, as required)
2451  * retlenp - pointer to length to be returned
2452  */
2453 APPLESTATIC void
2454 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2455 {
2456 	int i;
2457 	struct nfsusrgrp *usrp;
2458 	u_char *cp = *cpp;
2459 	uid_t tmp;
2460 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2461 
2462 	cnt = 0;
2463 tryagain:
2464 	NFSLOCKNAMEID();
2465 	if (nfsrv_dnsname) {
2466 		/*
2467 		 * Always map nfsrv_defaultuid to "nobody".
2468 		 */
2469 		if (uid == nfsrv_defaultuid) {
2470 			i = nfsrv_dnsnamelen + 7;
2471 			if (i > len) {
2472 				NFSUNLOCKNAMEID();
2473 				if (len > NFSV4_SMALLSTR)
2474 					free(cp, M_NFSSTRING);
2475 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
2476 				*cpp = cp;
2477 				len = i;
2478 				goto tryagain;
2479 			}
2480 			*retlenp = i;
2481 			NFSBCOPY("nobody@", cp, 7);
2482 			cp += 7;
2483 			NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2484 			NFSUNLOCKNAMEID();
2485 			return;
2486 		}
2487 		hasampersand = 0;
2488 		LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
2489 			if (usrp->lug_uid == uid) {
2490 				if (usrp->lug_expiry < NFSD_MONOSEC)
2491 					break;
2492 				/*
2493 				 * If the name doesn't already have an '@'
2494 				 * in it, append @domainname to it.
2495 				 */
2496 				for (i = 0; i < usrp->lug_namelen; i++) {
2497 					if (usrp->lug_name[i] == '@') {
2498 						hasampersand = 1;
2499 						break;
2500 					}
2501 				}
2502 				if (hasampersand)
2503 					i = usrp->lug_namelen;
2504 				else
2505 					i = usrp->lug_namelen +
2506 					    nfsrv_dnsnamelen + 1;
2507 				if (i > len) {
2508 					NFSUNLOCKNAMEID();
2509 					if (len > NFSV4_SMALLSTR)
2510 						free(cp, M_NFSSTRING);
2511 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
2512 					*cpp = cp;
2513 					len = i;
2514 					goto tryagain;
2515 				}
2516 				*retlenp = i;
2517 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2518 				if (!hasampersand) {
2519 					cp += usrp->lug_namelen;
2520 					*cp++ = '@';
2521 					NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2522 				}
2523 				TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2524 				TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2525 				NFSUNLOCKNAMEID();
2526 				return;
2527 			}
2528 		}
2529 		NFSUNLOCKNAMEID();
2530 		cnt++;
2531 		ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2532 		    NULL, p);
2533 		if (ret == 0 && cnt < 2)
2534 			goto tryagain;
2535 	} else {
2536 		NFSUNLOCKNAMEID();
2537 	}
2538 
2539 	/*
2540 	 * No match, just return a string of digits.
2541 	 */
2542 	tmp = uid;
2543 	i = 0;
2544 	while (tmp || i == 0) {
2545 		tmp /= 10;
2546 		i++;
2547 	}
2548 	len = (i > len) ? len : i;
2549 	*retlenp = len;
2550 	cp += (len - 1);
2551 	tmp = uid;
2552 	for (i = 0; i < len; i++) {
2553 		*cp-- = '0' + (tmp % 10);
2554 		tmp /= 10;
2555 	}
2556 	return;
2557 }
2558 
2559 /*
2560  * Convert a string to a uid.
2561  * If no conversion is possible return NFSERR_BADOWNER, otherwise
2562  * return 0.
2563  */
2564 APPLESTATIC int
2565 nfsv4_strtouid(u_char *str, int len, uid_t *uidp, NFSPROC_T *p)
2566 {
2567 	int i;
2568 	u_char *cp;
2569 	struct nfsusrgrp *usrp;
2570 	int cnt, ret;
2571 
2572 	if (len == 0)
2573 		return (NFSERR_BADOWNER);
2574 	/*
2575 	 * Look for an '@'.
2576 	 */
2577 	cp = str;
2578 	for (i = 0; i < len; i++)
2579 		if (*cp++ == '@')
2580 			break;
2581 
2582 	cnt = 0;
2583 tryagain:
2584 	NFSLOCKNAMEID();
2585 	/*
2586 	 * If an '@' is found and the domain name matches, search for the name
2587 	 * with dns stripped off.
2588 	 * Mixed case alpahbetics will match for the domain name, but all
2589 	 * upper case will not.
2590 	 */
2591 	if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2592 	    (len - 1 - i) == nfsrv_dnsnamelen &&
2593 	    !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2594 		len -= (nfsrv_dnsnamelen + 1);
2595 		*(cp - 1) = '\0';
2596 	}
2597 
2598 	/*
2599 	 * Check for the special case of "nobody".
2600 	 */
2601 	if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2602 		*uidp = nfsrv_defaultuid;
2603 		NFSUNLOCKNAMEID();
2604 		return (0);
2605 	}
2606 
2607 	LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
2608 		if (usrp->lug_namelen == len &&
2609 		    !NFSBCMP(usrp->lug_name, str, len)) {
2610 			if (usrp->lug_expiry < NFSD_MONOSEC)
2611 				break;
2612 			*uidp = usrp->lug_uid;
2613 			TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2614 			TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2615 			NFSUNLOCKNAMEID();
2616 			return (0);
2617 		}
2618 	}
2619 	NFSUNLOCKNAMEID();
2620 	cnt++;
2621 	ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2622 	    str, p);
2623 	if (ret == 0 && cnt < 2)
2624 		goto tryagain;
2625 	return (NFSERR_BADOWNER);
2626 }
2627 
2628 /*
2629  * Convert a gid to a string.
2630  * gid - the group id
2631  * cpp - points to a buffer of size NFSV4_SMALLSTR
2632  *       (malloc a larger one, as required)
2633  * retlenp - pointer to length to be returned
2634  */
2635 APPLESTATIC void
2636 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2637 {
2638 	int i;
2639 	struct nfsusrgrp *usrp;
2640 	u_char *cp = *cpp;
2641 	gid_t tmp;
2642 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2643 
2644 	cnt = 0;
2645 tryagain:
2646 	NFSLOCKNAMEID();
2647 	if (nfsrv_dnsname) {
2648 		/*
2649 		 * Always map nfsrv_defaultgid to "nogroup".
2650 		 */
2651 		if (gid == nfsrv_defaultgid) {
2652 			i = nfsrv_dnsnamelen + 8;
2653 			if (i > len) {
2654 				NFSUNLOCKNAMEID();
2655 				if (len > NFSV4_SMALLSTR)
2656 					free(cp, M_NFSSTRING);
2657 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
2658 				*cpp = cp;
2659 				len = i;
2660 				goto tryagain;
2661 			}
2662 			*retlenp = i;
2663 			NFSBCOPY("nogroup@", cp, 8);
2664 			cp += 8;
2665 			NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2666 			NFSUNLOCKNAMEID();
2667 			return;
2668 		}
2669 		hasampersand = 0;
2670 		LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
2671 			if (usrp->lug_gid == gid) {
2672 				if (usrp->lug_expiry < NFSD_MONOSEC)
2673 					break;
2674 				/*
2675 				 * If the name doesn't already have an '@'
2676 				 * in it, append @domainname to it.
2677 				 */
2678 				for (i = 0; i < usrp->lug_namelen; i++) {
2679 					if (usrp->lug_name[i] == '@') {
2680 						hasampersand = 1;
2681 						break;
2682 					}
2683 				}
2684 				if (hasampersand)
2685 					i = usrp->lug_namelen;
2686 				else
2687 					i = usrp->lug_namelen +
2688 					    nfsrv_dnsnamelen + 1;
2689 				if (i > len) {
2690 					NFSUNLOCKNAMEID();
2691 					if (len > NFSV4_SMALLSTR)
2692 						free(cp, M_NFSSTRING);
2693 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
2694 					*cpp = cp;
2695 					len = i;
2696 					goto tryagain;
2697 				}
2698 				*retlenp = i;
2699 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2700 				if (!hasampersand) {
2701 					cp += usrp->lug_namelen;
2702 					*cp++ = '@';
2703 					NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2704 				}
2705 				TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2706 				TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2707 				NFSUNLOCKNAMEID();
2708 				return;
2709 			}
2710 		}
2711 		NFSUNLOCKNAMEID();
2712 		cnt++;
2713 		ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2714 		    NULL, p);
2715 		if (ret == 0 && cnt < 2)
2716 			goto tryagain;
2717 	} else {
2718 		NFSUNLOCKNAMEID();
2719 	}
2720 
2721 	/*
2722 	 * No match, just return a string of digits.
2723 	 */
2724 	tmp = gid;
2725 	i = 0;
2726 	while (tmp || i == 0) {
2727 		tmp /= 10;
2728 		i++;
2729 	}
2730 	len = (i > len) ? len : i;
2731 	*retlenp = len;
2732 	cp += (len - 1);
2733 	tmp = gid;
2734 	for (i = 0; i < len; i++) {
2735 		*cp-- = '0' + (tmp % 10);
2736 		tmp /= 10;
2737 	}
2738 	return;
2739 }
2740 
2741 /*
2742  * Convert a string to a gid.
2743  */
2744 APPLESTATIC int
2745 nfsv4_strtogid(u_char *str, int len, gid_t *gidp, NFSPROC_T *p)
2746 {
2747 	int i;
2748 	u_char *cp;
2749 	struct nfsusrgrp *usrp;
2750 	int cnt, ret;
2751 
2752 	if (len == 0)
2753 		return (NFSERR_BADOWNER);
2754 	/*
2755 	 * Look for an '@'.
2756 	 */
2757 	cp = str;
2758 	for (i = 0; i < len; i++)
2759 		if (*cp++ == '@')
2760 			break;
2761 
2762 	cnt = 0;
2763 tryagain:
2764 	NFSLOCKNAMEID();
2765 	/*
2766 	 * If an '@' is found and the dns name matches, search for the name
2767 	 * with the dns stripped off.
2768 	 */
2769 	if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2770 	    (len - 1 - i) == nfsrv_dnsnamelen &&
2771 	    !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2772 		len -= (nfsrv_dnsnamelen + 1);
2773 		*(cp - 1) = '\0';
2774 	}
2775 
2776 	/*
2777 	 * Check for the special case of "nogroup".
2778 	 */
2779 	if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2780 		*gidp = nfsrv_defaultgid;
2781 		NFSUNLOCKNAMEID();
2782 		return (0);
2783 	}
2784 
2785 	LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
2786 		if (usrp->lug_namelen == len &&
2787 		    !NFSBCMP(usrp->lug_name, str, len)) {
2788 			if (usrp->lug_expiry < NFSD_MONOSEC)
2789 				break;
2790 			*gidp = usrp->lug_gid;
2791 			TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2792 			TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2793 			NFSUNLOCKNAMEID();
2794 			return (0);
2795 		}
2796 	}
2797 	NFSUNLOCKNAMEID();
2798 	cnt++;
2799 	ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
2800 	    str, p);
2801 	if (ret == 0 && cnt < 2)
2802 		goto tryagain;
2803 	return (NFSERR_BADOWNER);
2804 }
2805 
2806 /*
2807  * Cmp len chars, allowing mixed case in the first argument to match lower
2808  * case in the second, but not if the first argument is all upper case.
2809  * Return 0 for a match, 1 otherwise.
2810  */
2811 static int
2812 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
2813 {
2814 	int i;
2815 	u_char tmp;
2816 	int fndlower = 0;
2817 
2818 	for (i = 0; i < len; i++) {
2819 		if (*cp >= 'A' && *cp <= 'Z') {
2820 			tmp = *cp++ + ('a' - 'A');
2821 		} else {
2822 			tmp = *cp++;
2823 			if (tmp >= 'a' && tmp <= 'z')
2824 				fndlower = 1;
2825 		}
2826 		if (tmp != *cp2++)
2827 			return (1);
2828 	}
2829 	if (fndlower)
2830 		return (0);
2831 	else
2832 		return (1);
2833 }
2834 
2835 /*
2836  * Set the port for the nfsuserd.
2837  */
2838 APPLESTATIC int
2839 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
2840 {
2841 	struct nfssockreq *rp;
2842 	struct sockaddr_in *ad;
2843 	int error;
2844 
2845 	NFSLOCKNAMEID();
2846 	if (nfsrv_nfsuserd) {
2847 		NFSUNLOCKNAMEID();
2848 		return (EPERM);
2849 	}
2850 	nfsrv_nfsuserd = 1;
2851 	NFSUNLOCKNAMEID();
2852 	/*
2853 	 * Set up the socket record and connect.
2854 	 */
2855 	rp = &nfsrv_nfsuserdsock;
2856 	rp->nr_client = NULL;
2857 	rp->nr_sotype = SOCK_DGRAM;
2858 	rp->nr_soproto = IPPROTO_UDP;
2859 	rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
2860 	rp->nr_cred = NULL;
2861 	NFSSOCKADDRALLOC(rp->nr_nam);
2862 	NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
2863 	ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
2864 	ad->sin_family = AF_INET;
2865 	ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001);	/* 127.0.0.1 */
2866 	ad->sin_port = port;
2867 	rp->nr_prog = RPCPROG_NFSUSERD;
2868 	rp->nr_vers = RPCNFSUSERD_VERS;
2869 	error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
2870 	if (error) {
2871 		NFSSOCKADDRFREE(rp->nr_nam);
2872 		nfsrv_nfsuserd = 0;
2873 	}
2874 	return (error);
2875 }
2876 
2877 /*
2878  * Delete the nfsuserd port.
2879  */
2880 APPLESTATIC void
2881 nfsrv_nfsuserddelport(void)
2882 {
2883 
2884 	NFSLOCKNAMEID();
2885 	if (nfsrv_nfsuserd == 0) {
2886 		NFSUNLOCKNAMEID();
2887 		return;
2888 	}
2889 	nfsrv_nfsuserd = 0;
2890 	NFSUNLOCKNAMEID();
2891 	newnfs_disconnect(&nfsrv_nfsuserdsock);
2892 	NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
2893 }
2894 
2895 /*
2896  * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
2897  * name<-->id cache.
2898  * Returns 0 upon success, non-zero otherwise.
2899  */
2900 static int
2901 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
2902 {
2903 	u_int32_t *tl;
2904 	struct nfsrv_descript *nd;
2905 	int len;
2906 	struct nfsrv_descript nfsd;
2907 	struct ucred *cred;
2908 	int error;
2909 
2910 	NFSLOCKNAMEID();
2911 	if (nfsrv_nfsuserd == 0) {
2912 		NFSUNLOCKNAMEID();
2913 		return (EPERM);
2914 	}
2915 	NFSUNLOCKNAMEID();
2916 	nd = &nfsd;
2917 	cred = newnfs_getcred();
2918 	nd->nd_flag = ND_GSSINITREPLY;
2919 	nfsrvd_rephead(nd);
2920 
2921 	nd->nd_procnum = procnum;
2922 	if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
2923 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2924 		if (procnum == RPCNFSUSERD_GETUID)
2925 			*tl = txdr_unsigned(uid);
2926 		else
2927 			*tl = txdr_unsigned(gid);
2928 	} else {
2929 		len = strlen(name);
2930 		(void) nfsm_strtom(nd, name, len);
2931 	}
2932 	error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
2933 		cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL);
2934 	NFSFREECRED(cred);
2935 	if (!error) {
2936 		mbuf_freem(nd->nd_mrep);
2937 		error = nd->nd_repstat;
2938 	}
2939 	return (error);
2940 }
2941 
2942 /*
2943  * This function is called from the nfssvc(2) system call, to update the
2944  * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
2945  */
2946 APPLESTATIC int
2947 nfssvc_idname(struct nfsd_idargs *nidp)
2948 {
2949 	struct nfsusrgrp *nusrp, *usrp, *newusrp;
2950 	struct nfsuserhashhead *hp;
2951 	int i;
2952 	int error = 0;
2953 	u_char *cp;
2954 
2955 	if (nidp->nid_flag & NFSID_INITIALIZE) {
2956 	    cp = (u_char *)malloc(nidp->nid_namelen + 1,
2957 		M_NFSSTRING, M_WAITOK);
2958 	    error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
2959 		nidp->nid_namelen);
2960 	    NFSLOCKNAMEID();
2961 	    if (nfsrv_dnsname) {
2962 		/*
2963 		 * Free up all the old stuff and reinitialize hash lists.
2964 		 */
2965 		TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
2966 			nfsrv_removeuser(usrp);
2967 		}
2968 		free(nfsrv_dnsname, M_NFSSTRING);
2969 		nfsrv_dnsname = NULL;
2970 	    }
2971 	    TAILQ_INIT(&nfsuserlruhead);
2972 	    for (i = 0; i < NFSUSERHASHSIZE; i++)
2973 		LIST_INIT(&nfsuserhash[i]);
2974 	    for (i = 0; i < NFSGROUPHASHSIZE; i++)
2975 		LIST_INIT(&nfsgrouphash[i]);
2976 	    for (i = 0; i < NFSUSERHASHSIZE; i++)
2977 		LIST_INIT(&nfsusernamehash[i]);
2978 	    for (i = 0; i < NFSGROUPHASHSIZE; i++)
2979 		LIST_INIT(&nfsgroupnamehash[i]);
2980 
2981 	    /*
2982 	     * Put name in "DNS" string.
2983 	     */
2984 	    if (!error) {
2985 		nfsrv_dnsname = cp;
2986 		nfsrv_dnsnamelen = nidp->nid_namelen;
2987 		nfsrv_defaultuid = nidp->nid_uid;
2988 		nfsrv_defaultgid = nidp->nid_gid;
2989 		nfsrv_usercnt = 0;
2990 		nfsrv_usermax = nidp->nid_usermax;
2991 	    }
2992 	    NFSUNLOCKNAMEID();
2993 	    if (error)
2994 		free(cp, M_NFSSTRING);
2995 	    return (error);
2996 	}
2997 
2998 	/*
2999 	 * malloc the new one now, so any potential sleep occurs before
3000 	 * manipulation of the lists.
3001 	 */
3002 	MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
3003 	    nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
3004 	error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3005 	    nidp->nid_namelen);
3006 	if (error) {
3007 		free((caddr_t)newusrp, M_NFSUSERGROUP);
3008 		return (error);
3009 	}
3010 	newusrp->lug_namelen = nidp->nid_namelen;
3011 
3012 	NFSLOCKNAMEID();
3013 	/*
3014 	 * Delete old entries, as required.
3015 	 */
3016 	if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3017 		hp = NFSUSERHASH(nidp->nid_uid);
3018 		LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3019 			if (usrp->lug_uid == nidp->nid_uid)
3020 				nfsrv_removeuser(usrp);
3021 		}
3022 	}
3023 	if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3024 		hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3025 		LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3026 			if (usrp->lug_namelen == newusrp->lug_namelen &&
3027 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3028 			    usrp->lug_namelen))
3029 				nfsrv_removeuser(usrp);
3030 		}
3031 	}
3032 	if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3033 		hp = NFSGROUPHASH(nidp->nid_gid);
3034 		LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3035 			if (usrp->lug_gid == nidp->nid_gid)
3036 				nfsrv_removeuser(usrp);
3037 		}
3038 	}
3039 	if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3040 		hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3041 		LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3042 			if (usrp->lug_namelen == newusrp->lug_namelen &&
3043 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3044 			    usrp->lug_namelen))
3045 				nfsrv_removeuser(usrp);
3046 		}
3047 	}
3048 	TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3049 		if (usrp->lug_expiry < NFSD_MONOSEC)
3050 			nfsrv_removeuser(usrp);
3051 	}
3052 	while (nfsrv_usercnt >= nfsrv_usermax) {
3053 		usrp = TAILQ_FIRST(&nfsuserlruhead);
3054 		nfsrv_removeuser(usrp);
3055 	}
3056 
3057 	/*
3058 	 * Now, we can add the new one.
3059 	 */
3060 	if (nidp->nid_usertimeout)
3061 		newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3062 	else
3063 		newusrp->lug_expiry = NFSD_MONOSEC + 5;
3064 	if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3065 		newusrp->lug_uid = nidp->nid_uid;
3066 		LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
3067 		    lug_numhash);
3068 		LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
3069 		    newusrp->lug_namelen), newusrp, lug_namehash);
3070 		TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3071 		nfsrv_usercnt++;
3072 	} else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3073 		newusrp->lug_gid = nidp->nid_gid;
3074 		LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
3075 		    lug_numhash);
3076 		LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
3077 		    newusrp->lug_namelen), newusrp, lug_namehash);
3078 		TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3079 		nfsrv_usercnt++;
3080 	} else
3081 		FREE((caddr_t)newusrp, M_NFSUSERGROUP);
3082 	NFSUNLOCKNAMEID();
3083 	return (error);
3084 }
3085 
3086 /*
3087  * Remove a user/group name element.
3088  */
3089 static void
3090 nfsrv_removeuser(struct nfsusrgrp *usrp)
3091 {
3092 
3093 	NFSNAMEIDREQUIRED();
3094 	LIST_REMOVE(usrp, lug_numhash);
3095 	LIST_REMOVE(usrp, lug_namehash);
3096 	TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
3097 	nfsrv_usercnt--;
3098 	FREE((caddr_t)usrp, M_NFSUSERGROUP);
3099 }
3100 
3101 /*
3102  * This function scans a byte string and checks for UTF-8 compliance.
3103  * It returns 0 if it conforms and NFSERR_INVAL if not.
3104  */
3105 APPLESTATIC int
3106 nfsrv_checkutf8(u_int8_t *cp, int len)
3107 {
3108 	u_int32_t val = 0x0;
3109 	int cnt = 0, gotd = 0, shift = 0;
3110 	u_int8_t byte;
3111 	static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3112 
3113 	/*
3114 	 * Here are what the variables are used for:
3115 	 * val - the calculated value of a multibyte char, used to check
3116 	 *       that it was coded with the correct range
3117 	 * cnt - the number of 10xxxxxx bytes to follow
3118 	 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3119 	 * shift - lower order bits of range (ie. "val >> shift" should
3120 	 *       not be 0, in other words, dividing by the lower bound
3121 	 *       of the range should get a non-zero value)
3122 	 * byte - used to calculate cnt
3123 	 */
3124 	while (len > 0) {
3125 		if (cnt > 0) {
3126 			/* This handles the 10xxxxxx bytes */
3127 			if ((*cp & 0xc0) != 0x80 ||
3128 			    (gotd && (*cp & 0x20)))
3129 				return (NFSERR_INVAL);
3130 			gotd = 0;
3131 			val <<= 6;
3132 			val |= (*cp & 0x3f);
3133 			cnt--;
3134 			if (cnt == 0 && (val >> shift) == 0x0)
3135 				return (NFSERR_INVAL);
3136 		} else if (*cp & 0x80) {
3137 			/* first byte of multi byte char */
3138 			byte = *cp;
3139 			while ((byte & 0x40) && cnt < 6) {
3140 				cnt++;
3141 				byte <<= 1;
3142 			}
3143 			if (cnt == 0 || cnt == 6)
3144 				return (NFSERR_INVAL);
3145 			val = (*cp & (0x3f >> cnt));
3146 			shift = utf8_shift[cnt - 1];
3147 			if (cnt == 2 && val == 0xd)
3148 				/* Check for the 0xd800-0xdfff case */
3149 				gotd = 1;
3150 		}
3151 		cp++;
3152 		len--;
3153 	}
3154 	if (cnt > 0)
3155 		return (NFSERR_INVAL);
3156 	return (0);
3157 }
3158 
3159 /*
3160  * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3161  * strings, one with the root path in it and the other with the list of
3162  * locations. The list is in the same format as is found in nfr_refs.
3163  * It is a "," separated list of entries, where each of them is of the
3164  * form <server>:<rootpath>. For example
3165  * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3166  * The nilp argument is set to 1 for the special case of a null fs_root
3167  * and an empty server list.
3168  * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3169  * number of xdr bytes parsed in sump.
3170  */
3171 static int
3172 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3173     int *sump, int *nilp)
3174 {
3175 	u_int32_t *tl;
3176 	u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3177 	int i, j, len, stringlen, cnt, slen, siz, xdrsum, error, nsrv;
3178 	struct list {
3179 		SLIST_ENTRY(list) next;
3180 		int len;
3181 		u_char host[1];
3182 	} *lsp, *nlsp;
3183 	SLIST_HEAD(, list) head;
3184 
3185 	*fsrootp = NULL;
3186 	*srvp = NULL;
3187 	*nilp = 0;
3188 
3189 	/*
3190 	 * Get the fs_root path and check for the special case of null path
3191 	 * and 0 length server list.
3192 	 */
3193 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3194 	len = fxdr_unsigned(int, *tl);
3195 	if (len < 0 || len > 10240)
3196 		return (NFSERR_BADXDR);
3197 	if (len == 0) {
3198 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3199 		if (*tl != 0)
3200 			return (NFSERR_BADXDR);
3201 		*nilp = 1;
3202 		*sump = 2 * NFSX_UNSIGNED;
3203 		return (0);
3204 	}
3205 	cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3206 	error = nfsrv_mtostr(nd, cp, len);
3207 	if (!error) {
3208 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3209 		cnt = fxdr_unsigned(int, *tl);
3210 		if (cnt <= 0)
3211 			error = NFSERR_BADXDR;
3212 	}
3213 	if (error) {
3214 		free(cp, M_NFSSTRING);
3215 		return (error);
3216 	}
3217 
3218 	/*
3219 	 * Now, loop through the location list and make up the srvlist.
3220 	 */
3221 	xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3222 	cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3223 	slen = 1024;
3224 	siz = 0;
3225 	for (i = 0; i < cnt; i++) {
3226 		SLIST_INIT(&head);
3227 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3228 		nsrv = fxdr_unsigned(int, *tl);
3229 		if (nsrv <= 0) {
3230 			free(cp, M_NFSSTRING);
3231 			free(cp2, M_NFSSTRING);
3232 			return (NFSERR_BADXDR);
3233 		}
3234 
3235 		/*
3236 		 * Handle the first server by putting it in the srvstr.
3237 		 */
3238 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3239 		len = fxdr_unsigned(int, *tl);
3240 		if (len <= 0 || len > 1024) {
3241 			free(cp, M_NFSSTRING);
3242 			free(cp2, M_NFSSTRING);
3243 			return (NFSERR_BADXDR);
3244 		}
3245 		nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3246 		if (cp3 != cp2) {
3247 			*cp3++ = ',';
3248 			siz++;
3249 		}
3250 		error = nfsrv_mtostr(nd, cp3, len);
3251 		if (error) {
3252 			free(cp, M_NFSSTRING);
3253 			free(cp2, M_NFSSTRING);
3254 			return (error);
3255 		}
3256 		cp3 += len;
3257 		*cp3++ = ':';
3258 		siz += (len + 1);
3259 		xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3260 		for (j = 1; j < nsrv; j++) {
3261 			/*
3262 			 * Yuck, put them in an slist and process them later.
3263 			 */
3264 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3265 			len = fxdr_unsigned(int, *tl);
3266 			if (len <= 0 || len > 1024) {
3267 				free(cp, M_NFSSTRING);
3268 				free(cp2, M_NFSSTRING);
3269 				return (NFSERR_BADXDR);
3270 			}
3271 			lsp = (struct list *)malloc(sizeof (struct list)
3272 			    + len, M_TEMP, M_WAITOK);
3273 			error = nfsrv_mtostr(nd, lsp->host, len);
3274 			if (error) {
3275 				free(cp, M_NFSSTRING);
3276 				free(cp2, M_NFSSTRING);
3277 				return (error);
3278 			}
3279 			xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3280 			lsp->len = len;
3281 			SLIST_INSERT_HEAD(&head, lsp, next);
3282 		}
3283 
3284 		/*
3285 		 * Finally, we can get the path.
3286 		 */
3287 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3288 		len = fxdr_unsigned(int, *tl);
3289 		if (len <= 0 || len > 1024) {
3290 			free(cp, M_NFSSTRING);
3291 			free(cp2, M_NFSSTRING);
3292 			return (NFSERR_BADXDR);
3293 		}
3294 		nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3295 		error = nfsrv_mtostr(nd, cp3, len);
3296 		if (error) {
3297 			free(cp, M_NFSSTRING);
3298 			free(cp2, M_NFSSTRING);
3299 			return (error);
3300 		}
3301 		xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3302 		str = cp3;
3303 		stringlen = len;
3304 		cp3 += len;
3305 		siz += len;
3306 		SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3307 			nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3308 			    &cp2, &cp3, &slen);
3309 			*cp3++ = ',';
3310 			NFSBCOPY(lsp->host, cp3, lsp->len);
3311 			cp3 += lsp->len;
3312 			*cp3++ = ':';
3313 			NFSBCOPY(str, cp3, stringlen);
3314 			cp3 += stringlen;
3315 			*cp3 = '\0';
3316 			siz += (lsp->len + stringlen + 2);
3317 			free((caddr_t)lsp, M_TEMP);
3318 		}
3319 	}
3320 	*fsrootp = cp;
3321 	*srvp = cp2;
3322 	*sump = xdrsum;
3323 	return (0);
3324 nfsmout:
3325 	if (cp != NULL)
3326 		free(cp, M_NFSSTRING);
3327 	if (cp2 != NULL)
3328 		free(cp2, M_NFSSTRING);
3329 	return (error);
3330 }
3331 
3332 /*
3333  * Make the malloc'd space large enough. This is a pain, but the xdr
3334  * doesn't set an upper bound on the side, so...
3335  */
3336 static void
3337 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3338 {
3339 	u_char *cp;
3340 	int i;
3341 
3342 	if (siz <= *slenp)
3343 		return;
3344 	cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3345 	NFSBCOPY(*cpp, cp, *slenp);
3346 	free(*cpp, M_NFSSTRING);
3347 	i = *cpp2 - *cpp;
3348 	*cpp = cp;
3349 	*cpp2 = cp + i;
3350 	*slenp = siz + 1024;
3351 }
3352 
3353 /*
3354  * Initialize the reply header data structures.
3355  */
3356 APPLESTATIC void
3357 nfsrvd_rephead(struct nfsrv_descript *nd)
3358 {
3359 	mbuf_t mreq;
3360 
3361 	/*
3362 	 * If this is a big reply, use a cluster.
3363 	 */
3364 	if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3365 	    nfs_bigreply[nd->nd_procnum]) {
3366 		NFSMCLGET(mreq, M_WAIT);
3367 		nd->nd_mreq = mreq;
3368 		nd->nd_mb = mreq;
3369 	} else {
3370 		NFSMGET(mreq);
3371 		nd->nd_mreq = mreq;
3372 		nd->nd_mb = mreq;
3373 	}
3374 	nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3375 	mbuf_setlen(mreq, 0);
3376 
3377 	if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3378 		NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3379 }
3380 
3381 /*
3382  * Lock a socket against others.
3383  * Currently used to serialize connect/disconnect attempts.
3384  */
3385 int
3386 newnfs_sndlock(int *flagp)
3387 {
3388 	struct timespec ts;
3389 
3390 	NFSLOCKSOCK();
3391 	while (*flagp & NFSR_SNDLOCK) {
3392 		*flagp |= NFSR_WANTSND;
3393 		ts.tv_sec = 0;
3394 		ts.tv_nsec = 0;
3395 		(void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3396 		    PZERO - 1, "nfsndlck", &ts);
3397 	}
3398 	*flagp |= NFSR_SNDLOCK;
3399 	NFSUNLOCKSOCK();
3400 	return (0);
3401 }
3402 
3403 /*
3404  * Unlock the stream socket for others.
3405  */
3406 void
3407 newnfs_sndunlock(int *flagp)
3408 {
3409 
3410 	NFSLOCKSOCK();
3411 	if ((*flagp & NFSR_SNDLOCK) == 0)
3412 		panic("nfs sndunlock");
3413 	*flagp &= ~NFSR_SNDLOCK;
3414 	if (*flagp & NFSR_WANTSND) {
3415 		*flagp &= ~NFSR_WANTSND;
3416 		wakeup((caddr_t)flagp);
3417 	}
3418 	NFSUNLOCKSOCK();
3419 }
3420 
3421