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