xref: /freebsd/sys/fs/nfs/nfs_commonsubs.c (revision 8d20be1e22095c27faf8fe8b2f0d089739cc742e)
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 	/* If p and cred are NULL, it is a client side call */
2015 	if (p == NULL && cred == NULL) {
2016 		NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2017 		aclp = saclp;
2018 	} else {
2019 		NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2020 		naclp = acl_alloc(M_WAITOK);
2021 		aclp = naclp;
2022 	}
2023 	nfsvno_getfs(&fsinf, isdgram);
2024 #ifndef APPLE
2025 	/*
2026 	 * Get the VFS_STATFS(), since some attributes need them.
2027 	 */
2028 	if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2029 		error = VFS_STATFS(mp, &fs);
2030 		if (error != 0) {
2031 			if (reterr) {
2032 				nd->nd_repstat = NFSERR_ACCES;
2033 				return (0);
2034 			}
2035 			NFSCLRSTATFS_ATTRBIT(retbitp);
2036 		}
2037 	}
2038 #endif
2039 
2040 	/*
2041 	 * And the NFSv4 ACL...
2042 	 */
2043 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2044 	    (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2045 		supports_nfsv4acls == 0))) {
2046 		NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2047 	}
2048 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2049 		if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2050 		    supports_nfsv4acls == 0)) {
2051 			NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2052 		} else if (naclp != NULL) {
2053 			if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2054 				error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2055 				if (error == 0)
2056 					error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2057 					    naclp, cred, p);
2058 				NFSVOPUNLOCK(vp, 0);
2059 			} else
2060 				error = NFSERR_PERM;
2061 			if (error != 0) {
2062 				if (reterr) {
2063 					nd->nd_repstat = NFSERR_ACCES;
2064 					return (0);
2065 				}
2066 				NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2067 			}
2068 		}
2069 	}
2070 	/*
2071 	 * Put out the attribute bitmap for the ones being filled in
2072 	 * and get the field for the number of attributes returned.
2073 	 */
2074 	prefixnum = nfsrv_putattrbit(nd, retbitp);
2075 	NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2076 	prefixnum += NFSX_UNSIGNED;
2077 
2078 	/*
2079 	 * Now, loop around filling in the attributes for each bit set.
2080 	 */
2081 	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2082 	    if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2083 		switch (bitpos) {
2084 		case NFSATTRBIT_SUPPORTEDATTRS:
2085 			NFSSETSUPP_ATTRBIT(&attrbits);
2086 			if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2087 			    && supports_nfsv4acls == 0)) {
2088 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2089 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2090 			}
2091 			retnum += nfsrv_putattrbit(nd, &attrbits);
2092 			break;
2093 		case NFSATTRBIT_TYPE:
2094 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2095 			*tl = vtonfsv34_type(vap->va_type);
2096 			retnum += NFSX_UNSIGNED;
2097 			break;
2098 		case NFSATTRBIT_FHEXPIRETYPE:
2099 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2100 			*tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2101 			retnum += NFSX_UNSIGNED;
2102 			break;
2103 		case NFSATTRBIT_CHANGE:
2104 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2105 			txdr_hyper(vap->va_filerev, tl);
2106 			retnum += NFSX_HYPER;
2107 			break;
2108 		case NFSATTRBIT_SIZE:
2109 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2110 			txdr_hyper(vap->va_size, tl);
2111 			retnum += NFSX_HYPER;
2112 			break;
2113 		case NFSATTRBIT_LINKSUPPORT:
2114 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2115 			if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2116 				*tl = newnfs_true;
2117 			else
2118 				*tl = newnfs_false;
2119 			retnum += NFSX_UNSIGNED;
2120 			break;
2121 		case NFSATTRBIT_SYMLINKSUPPORT:
2122 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2123 			if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2124 				*tl = newnfs_true;
2125 			else
2126 				*tl = newnfs_false;
2127 			retnum += NFSX_UNSIGNED;
2128 			break;
2129 		case NFSATTRBIT_NAMEDATTR:
2130 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2131 			*tl = newnfs_false;
2132 			retnum += NFSX_UNSIGNED;
2133 			break;
2134 		case NFSATTRBIT_FSID:
2135 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2136 			*tl++ = 0;
2137 			*tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2138 			*tl++ = 0;
2139 			*tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2140 			retnum += NFSX_V4FSID;
2141 			break;
2142 		case NFSATTRBIT_UNIQUEHANDLES:
2143 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2144 			*tl = newnfs_true;
2145 			retnum += NFSX_UNSIGNED;
2146 			break;
2147 		case NFSATTRBIT_LEASETIME:
2148 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2149 			*tl = txdr_unsigned(nfsrv_lease);
2150 			retnum += NFSX_UNSIGNED;
2151 			break;
2152 		case NFSATTRBIT_RDATTRERROR:
2153 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2154 			*tl = txdr_unsigned(rderror);
2155 			retnum += NFSX_UNSIGNED;
2156 			break;
2157 		/*
2158 		 * Recommended Attributes. (Only the supported ones.)
2159 		 */
2160 		case NFSATTRBIT_ACL:
2161 			retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2162 			break;
2163 		case NFSATTRBIT_ACLSUPPORT:
2164 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2165 			*tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2166 			retnum += NFSX_UNSIGNED;
2167 			break;
2168 		case NFSATTRBIT_CANSETTIME:
2169 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2170 			if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2171 				*tl = newnfs_true;
2172 			else
2173 				*tl = newnfs_false;
2174 			retnum += NFSX_UNSIGNED;
2175 			break;
2176 		case NFSATTRBIT_CASEINSENSITIVE:
2177 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2178 			*tl = newnfs_false;
2179 			retnum += NFSX_UNSIGNED;
2180 			break;
2181 		case NFSATTRBIT_CASEPRESERVING:
2182 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2183 			*tl = newnfs_true;
2184 			retnum += NFSX_UNSIGNED;
2185 			break;
2186 		case NFSATTRBIT_CHOWNRESTRICTED:
2187 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2188 			*tl = newnfs_true;
2189 			retnum += NFSX_UNSIGNED;
2190 			break;
2191 		case NFSATTRBIT_FILEHANDLE:
2192 			retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2193 			break;
2194 		case NFSATTRBIT_FILEID:
2195 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2196 			*tl++ = 0;
2197 			*tl = txdr_unsigned(vap->va_fileid);
2198 			retnum += NFSX_HYPER;
2199 			break;
2200 		case NFSATTRBIT_FILESAVAIL:
2201 			/*
2202 			 * Check quota and use min(quota, f_ffree).
2203 			 */
2204 			freenum = fs.f_ffree;
2205 #ifdef QUOTA
2206 			/*
2207 			 * ufs_quotactl() insists that the uid argument
2208 			 * equal p_ruid for non-root quota access, so
2209 			 * we'll just make sure that's the case.
2210 			 */
2211 			savuid = p->p_cred->p_ruid;
2212 			p->p_cred->p_ruid = cred->cr_uid;
2213 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2214 			    cred->cr_uid, (caddr_t)&dqb))
2215 			    freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2216 				freenum);
2217 			p->p_cred->p_ruid = savuid;
2218 #endif	/* QUOTA */
2219 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2220 			*tl++ = 0;
2221 			*tl = txdr_unsigned(freenum);
2222 			retnum += NFSX_HYPER;
2223 			break;
2224 		case NFSATTRBIT_FILESFREE:
2225 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2226 			*tl++ = 0;
2227 			*tl = txdr_unsigned(fs.f_ffree);
2228 			retnum += NFSX_HYPER;
2229 			break;
2230 		case NFSATTRBIT_FILESTOTAL:
2231 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2232 			*tl++ = 0;
2233 			*tl = txdr_unsigned(fs.f_files);
2234 			retnum += NFSX_HYPER;
2235 			break;
2236 		case NFSATTRBIT_FSLOCATIONS:
2237 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2238 			*tl++ = 0;
2239 			*tl = 0;
2240 			retnum += 2 * NFSX_UNSIGNED;
2241 			break;
2242 		case NFSATTRBIT_HOMOGENEOUS:
2243 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2244 			if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2245 				*tl = newnfs_true;
2246 			else
2247 				*tl = newnfs_false;
2248 			retnum += NFSX_UNSIGNED;
2249 			break;
2250 		case NFSATTRBIT_MAXFILESIZE:
2251 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2252 			uquad = NFSRV_MAXFILESIZE;
2253 			txdr_hyper(uquad, tl);
2254 			retnum += NFSX_HYPER;
2255 			break;
2256 		case NFSATTRBIT_MAXLINK:
2257 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2258 			*tl = txdr_unsigned(LINK_MAX);
2259 			retnum += NFSX_UNSIGNED;
2260 			break;
2261 		case NFSATTRBIT_MAXNAME:
2262 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2263 			*tl = txdr_unsigned(NFS_MAXNAMLEN);
2264 			retnum += NFSX_UNSIGNED;
2265 			break;
2266 		case NFSATTRBIT_MAXREAD:
2267 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2268 			*tl++ = 0;
2269 			*tl = txdr_unsigned(fsinf.fs_rtmax);
2270 			retnum += NFSX_HYPER;
2271 			break;
2272 		case NFSATTRBIT_MAXWRITE:
2273 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2274 			*tl++ = 0;
2275 			*tl = txdr_unsigned(fsinf.fs_wtmax);
2276 			retnum += NFSX_HYPER;
2277 			break;
2278 		case NFSATTRBIT_MODE:
2279 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2280 			*tl = vtonfsv34_mode(vap->va_mode);
2281 			retnum += NFSX_UNSIGNED;
2282 			break;
2283 		case NFSATTRBIT_NOTRUNC:
2284 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2285 			*tl = newnfs_true;
2286 			retnum += NFSX_UNSIGNED;
2287 			break;
2288 		case NFSATTRBIT_NUMLINKS:
2289 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2290 			*tl = txdr_unsigned(vap->va_nlink);
2291 			retnum += NFSX_UNSIGNED;
2292 			break;
2293 		case NFSATTRBIT_OWNER:
2294 			cp = namestr;
2295 			nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2296 			retnum += nfsm_strtom(nd, cp, siz);
2297 			if (cp != namestr)
2298 				free(cp, M_NFSSTRING);
2299 			break;
2300 		case NFSATTRBIT_OWNERGROUP:
2301 			cp = namestr;
2302 			nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2303 			retnum += nfsm_strtom(nd, cp, siz);
2304 			if (cp != namestr)
2305 				free(cp, M_NFSSTRING);
2306 			break;
2307 		case NFSATTRBIT_QUOTAHARD:
2308 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2309 				freenum = fs.f_bfree;
2310 			else
2311 				freenum = fs.f_bavail;
2312 #ifdef QUOTA
2313 			/*
2314 			 * ufs_quotactl() insists that the uid argument
2315 			 * equal p_ruid for non-root quota access, so
2316 			 * we'll just make sure that's the case.
2317 			 */
2318 			savuid = p->p_cred->p_ruid;
2319 			p->p_cred->p_ruid = cred->cr_uid;
2320 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2321 			    cred->cr_uid, (caddr_t)&dqb))
2322 			    freenum = min(dqb.dqb_bhardlimit, freenum);
2323 			p->p_cred->p_ruid = savuid;
2324 #endif	/* QUOTA */
2325 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2326 			uquad = (u_int64_t)freenum;
2327 			NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2328 			txdr_hyper(uquad, tl);
2329 			retnum += NFSX_HYPER;
2330 			break;
2331 		case NFSATTRBIT_QUOTASOFT:
2332 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2333 				freenum = fs.f_bfree;
2334 			else
2335 				freenum = fs.f_bavail;
2336 #ifdef QUOTA
2337 			/*
2338 			 * ufs_quotactl() insists that the uid argument
2339 			 * equal p_ruid for non-root quota access, so
2340 			 * we'll just make sure that's the case.
2341 			 */
2342 			savuid = p->p_cred->p_ruid;
2343 			p->p_cred->p_ruid = cred->cr_uid;
2344 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2345 			    cred->cr_uid, (caddr_t)&dqb))
2346 			    freenum = min(dqb.dqb_bsoftlimit, freenum);
2347 			p->p_cred->p_ruid = savuid;
2348 #endif	/* QUOTA */
2349 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2350 			uquad = (u_int64_t)freenum;
2351 			NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2352 			txdr_hyper(uquad, tl);
2353 			retnum += NFSX_HYPER;
2354 			break;
2355 		case NFSATTRBIT_QUOTAUSED:
2356 			freenum = 0;
2357 #ifdef QUOTA
2358 			/*
2359 			 * ufs_quotactl() insists that the uid argument
2360 			 * equal p_ruid for non-root quota access, so
2361 			 * we'll just make sure that's the case.
2362 			 */
2363 			savuid = p->p_cred->p_ruid;
2364 			p->p_cred->p_ruid = cred->cr_uid;
2365 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2366 			    cred->cr_uid, (caddr_t)&dqb))
2367 			    freenum = dqb.dqb_curblocks;
2368 			p->p_cred->p_ruid = savuid;
2369 #endif	/* QUOTA */
2370 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2371 			uquad = (u_int64_t)freenum;
2372 			NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2373 			txdr_hyper(uquad, tl);
2374 			retnum += NFSX_HYPER;
2375 			break;
2376 		case NFSATTRBIT_RAWDEV:
2377 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2378 			*tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2379 			*tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2380 			retnum += NFSX_V4SPECDATA;
2381 			break;
2382 		case NFSATTRBIT_SPACEAVAIL:
2383 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2384 			if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2385 				uquad = (u_int64_t)fs.f_bfree;
2386 			else
2387 				uquad = (u_int64_t)fs.f_bavail;
2388 			uquad *= fs.f_bsize;
2389 			txdr_hyper(uquad, tl);
2390 			retnum += NFSX_HYPER;
2391 			break;
2392 		case NFSATTRBIT_SPACEFREE:
2393 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2394 			uquad = (u_int64_t)fs.f_bfree;
2395 			uquad *= fs.f_bsize;
2396 			txdr_hyper(uquad, tl);
2397 			retnum += NFSX_HYPER;
2398 			break;
2399 		case NFSATTRBIT_SPACETOTAL:
2400 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2401 			uquad = (u_int64_t)fs.f_blocks;
2402 			uquad *= fs.f_bsize;
2403 			txdr_hyper(uquad, tl);
2404 			retnum += NFSX_HYPER;
2405 			break;
2406 		case NFSATTRBIT_SPACEUSED:
2407 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2408 			txdr_hyper(vap->va_bytes, tl);
2409 			retnum += NFSX_HYPER;
2410 			break;
2411 		case NFSATTRBIT_TIMEACCESS:
2412 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2413 			txdr_nfsv4time(&vap->va_atime, tl);
2414 			retnum += NFSX_V4TIME;
2415 			break;
2416 		case NFSATTRBIT_TIMEACCESSSET:
2417 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2418 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2419 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2420 				txdr_nfsv4time(&vap->va_atime, tl);
2421 				retnum += NFSX_V4SETTIME;
2422 			} else {
2423 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2424 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2425 				retnum += NFSX_UNSIGNED;
2426 			}
2427 			break;
2428 		case NFSATTRBIT_TIMEDELTA:
2429 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2430 			temptime.tv_sec = 0;
2431 			temptime.tv_nsec = 1000000000 / hz;
2432 			txdr_nfsv4time(&temptime, tl);
2433 			retnum += NFSX_V4TIME;
2434 			break;
2435 		case NFSATTRBIT_TIMEMETADATA:
2436 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2437 			txdr_nfsv4time(&vap->va_ctime, tl);
2438 			retnum += NFSX_V4TIME;
2439 			break;
2440 		case NFSATTRBIT_TIMEMODIFY:
2441 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2442 			txdr_nfsv4time(&vap->va_mtime, tl);
2443 			retnum += NFSX_V4TIME;
2444 			break;
2445 		case NFSATTRBIT_TIMEMODIFYSET:
2446 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2447 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2448 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2449 				txdr_nfsv4time(&vap->va_mtime, tl);
2450 				retnum += NFSX_V4SETTIME;
2451 			} else {
2452 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2453 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2454 				retnum += NFSX_UNSIGNED;
2455 			}
2456 			break;
2457 		case NFSATTRBIT_MOUNTEDONFILEID:
2458 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2459 			if (at_root != 0)
2460 				uquad = mounted_on_fileno;
2461 			else
2462 				uquad = (u_int64_t)vap->va_fileid;
2463 			txdr_hyper(uquad, tl);
2464 			retnum += NFSX_HYPER;
2465 			break;
2466 		default:
2467 			printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2468 		};
2469 	    }
2470 	}
2471 	if (naclp != NULL)
2472 		acl_free(naclp);
2473 	*retnump = txdr_unsigned(retnum);
2474 	return (retnum + prefixnum);
2475 }
2476 
2477 /*
2478  * Put the attribute bits onto an mbuf list.
2479  * Return the number of bytes of output generated.
2480  */
2481 APPLESTATIC int
2482 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2483 {
2484 	u_int32_t *tl;
2485 	int cnt, i, bytesize;
2486 
2487 	for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2488 		if (attrbitp->bits[cnt - 1])
2489 			break;
2490 	bytesize = (cnt + 1) * NFSX_UNSIGNED;
2491 	NFSM_BUILD(tl, u_int32_t *, bytesize);
2492 	*tl++ = txdr_unsigned(cnt);
2493 	for (i = 0; i < cnt; i++)
2494 		*tl++ = txdr_unsigned(attrbitp->bits[i]);
2495 	return (bytesize);
2496 }
2497 
2498 /*
2499  * Convert a uid to a string.
2500  * If the lookup fails, just output the digits.
2501  * uid - the user id
2502  * cpp - points to a buffer of size NFSV4_SMALLSTR
2503  *       (malloc a larger one, as required)
2504  * retlenp - pointer to length to be returned
2505  */
2506 APPLESTATIC void
2507 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2508 {
2509 	int i;
2510 	struct nfsusrgrp *usrp;
2511 	u_char *cp = *cpp;
2512 	uid_t tmp;
2513 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2514 
2515 	cnt = 0;
2516 tryagain:
2517 	NFSLOCKNAMEID();
2518 	if (nfsrv_dnsname) {
2519 		/*
2520 		 * Always map nfsrv_defaultuid to "nobody".
2521 		 */
2522 		if (uid == nfsrv_defaultuid) {
2523 			i = nfsrv_dnsnamelen + 7;
2524 			if (i > len) {
2525 				NFSUNLOCKNAMEID();
2526 				if (len > NFSV4_SMALLSTR)
2527 					free(cp, M_NFSSTRING);
2528 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
2529 				*cpp = cp;
2530 				len = i;
2531 				goto tryagain;
2532 			}
2533 			*retlenp = i;
2534 			NFSBCOPY("nobody@", cp, 7);
2535 			cp += 7;
2536 			NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2537 			NFSUNLOCKNAMEID();
2538 			return;
2539 		}
2540 		hasampersand = 0;
2541 		LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
2542 			if (usrp->lug_uid == uid) {
2543 				if (usrp->lug_expiry < NFSD_MONOSEC)
2544 					break;
2545 				/*
2546 				 * If the name doesn't already have an '@'
2547 				 * in it, append @domainname to it.
2548 				 */
2549 				for (i = 0; i < usrp->lug_namelen; i++) {
2550 					if (usrp->lug_name[i] == '@') {
2551 						hasampersand = 1;
2552 						break;
2553 					}
2554 				}
2555 				if (hasampersand)
2556 					i = usrp->lug_namelen;
2557 				else
2558 					i = usrp->lug_namelen +
2559 					    nfsrv_dnsnamelen + 1;
2560 				if (i > len) {
2561 					NFSUNLOCKNAMEID();
2562 					if (len > NFSV4_SMALLSTR)
2563 						free(cp, M_NFSSTRING);
2564 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
2565 					*cpp = cp;
2566 					len = i;
2567 					goto tryagain;
2568 				}
2569 				*retlenp = i;
2570 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2571 				if (!hasampersand) {
2572 					cp += usrp->lug_namelen;
2573 					*cp++ = '@';
2574 					NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2575 				}
2576 				TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2577 				TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2578 				NFSUNLOCKNAMEID();
2579 				return;
2580 			}
2581 		}
2582 		NFSUNLOCKNAMEID();
2583 		cnt++;
2584 		ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2585 		    NULL, p);
2586 		if (ret == 0 && cnt < 2)
2587 			goto tryagain;
2588 	} else {
2589 		NFSUNLOCKNAMEID();
2590 	}
2591 
2592 	/*
2593 	 * No match, just return a string of digits.
2594 	 */
2595 	tmp = uid;
2596 	i = 0;
2597 	while (tmp || i == 0) {
2598 		tmp /= 10;
2599 		i++;
2600 	}
2601 	len = (i > len) ? len : i;
2602 	*retlenp = len;
2603 	cp += (len - 1);
2604 	tmp = uid;
2605 	for (i = 0; i < len; i++) {
2606 		*cp-- = '0' + (tmp % 10);
2607 		tmp /= 10;
2608 	}
2609 	return;
2610 }
2611 
2612 /*
2613  * Convert a string to a uid.
2614  * If no conversion is possible return NFSERR_BADOWNER, otherwise
2615  * return 0.
2616  * If this is called from a client side mount using AUTH_SYS and the
2617  * string is made up entirely of digits, just convert the string to
2618  * a number.
2619  */
2620 APPLESTATIC int
2621 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2622     NFSPROC_T *p)
2623 {
2624 	int i;
2625 	char *cp, *endstr, *str0;
2626 	struct nfsusrgrp *usrp;
2627 	int cnt, ret;
2628 	int error = 0;
2629 	uid_t tuid;
2630 
2631 	if (len == 0) {
2632 		error = NFSERR_BADOWNER;
2633 		goto out;
2634 	}
2635 	/* If a string of digits and an AUTH_SYS mount, just convert it. */
2636 	str0 = str;
2637 	tuid = (uid_t)strtoul(str0, &endstr, 10);
2638 	if ((endstr - str0) == len &&
2639 	    (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) {
2640 		*uidp = tuid;
2641 		goto out;
2642 	}
2643 	/*
2644 	 * Look for an '@'.
2645 	 */
2646 	cp = strchr(str0, '@');
2647 	if (cp != NULL)
2648 		i = (int)(cp++ - str0);
2649 	else
2650 		i = len;
2651 
2652 	cnt = 0;
2653 tryagain:
2654 	NFSLOCKNAMEID();
2655 	/*
2656 	 * If an '@' is found and the domain name matches, search for the name
2657 	 * with dns stripped off.
2658 	 * Mixed case alpahbetics will match for the domain name, but all
2659 	 * upper case will not.
2660 	 */
2661 	if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2662 	    (len - 1 - i) == nfsrv_dnsnamelen &&
2663 	    !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2664 		len -= (nfsrv_dnsnamelen + 1);
2665 		*(cp - 1) = '\0';
2666 	}
2667 
2668 	/*
2669 	 * Check for the special case of "nobody".
2670 	 */
2671 	if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2672 		*uidp = nfsrv_defaultuid;
2673 		NFSUNLOCKNAMEID();
2674 		error = 0;
2675 		goto out;
2676 	}
2677 
2678 	LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
2679 		if (usrp->lug_namelen == len &&
2680 		    !NFSBCMP(usrp->lug_name, str, len)) {
2681 			if (usrp->lug_expiry < NFSD_MONOSEC)
2682 				break;
2683 			*uidp = usrp->lug_uid;
2684 			TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2685 			TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2686 			NFSUNLOCKNAMEID();
2687 			error = 0;
2688 			goto out;
2689 		}
2690 	}
2691 	NFSUNLOCKNAMEID();
2692 	cnt++;
2693 	ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2694 	    str, p);
2695 	if (ret == 0 && cnt < 2)
2696 		goto tryagain;
2697 	error = NFSERR_BADOWNER;
2698 
2699 out:
2700 	NFSEXITCODE(error);
2701 	return (error);
2702 }
2703 
2704 /*
2705  * Convert a gid to a string.
2706  * gid - the group id
2707  * cpp - points to a buffer of size NFSV4_SMALLSTR
2708  *       (malloc a larger one, as required)
2709  * retlenp - pointer to length to be returned
2710  */
2711 APPLESTATIC void
2712 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2713 {
2714 	int i;
2715 	struct nfsusrgrp *usrp;
2716 	u_char *cp = *cpp;
2717 	gid_t tmp;
2718 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2719 
2720 	cnt = 0;
2721 tryagain:
2722 	NFSLOCKNAMEID();
2723 	if (nfsrv_dnsname) {
2724 		/*
2725 		 * Always map nfsrv_defaultgid to "nogroup".
2726 		 */
2727 		if (gid == nfsrv_defaultgid) {
2728 			i = nfsrv_dnsnamelen + 8;
2729 			if (i > len) {
2730 				NFSUNLOCKNAMEID();
2731 				if (len > NFSV4_SMALLSTR)
2732 					free(cp, M_NFSSTRING);
2733 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
2734 				*cpp = cp;
2735 				len = i;
2736 				goto tryagain;
2737 			}
2738 			*retlenp = i;
2739 			NFSBCOPY("nogroup@", cp, 8);
2740 			cp += 8;
2741 			NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2742 			NFSUNLOCKNAMEID();
2743 			return;
2744 		}
2745 		hasampersand = 0;
2746 		LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
2747 			if (usrp->lug_gid == gid) {
2748 				if (usrp->lug_expiry < NFSD_MONOSEC)
2749 					break;
2750 				/*
2751 				 * If the name doesn't already have an '@'
2752 				 * in it, append @domainname to it.
2753 				 */
2754 				for (i = 0; i < usrp->lug_namelen; i++) {
2755 					if (usrp->lug_name[i] == '@') {
2756 						hasampersand = 1;
2757 						break;
2758 					}
2759 				}
2760 				if (hasampersand)
2761 					i = usrp->lug_namelen;
2762 				else
2763 					i = usrp->lug_namelen +
2764 					    nfsrv_dnsnamelen + 1;
2765 				if (i > len) {
2766 					NFSUNLOCKNAMEID();
2767 					if (len > NFSV4_SMALLSTR)
2768 						free(cp, M_NFSSTRING);
2769 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
2770 					*cpp = cp;
2771 					len = i;
2772 					goto tryagain;
2773 				}
2774 				*retlenp = i;
2775 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2776 				if (!hasampersand) {
2777 					cp += usrp->lug_namelen;
2778 					*cp++ = '@';
2779 					NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2780 				}
2781 				TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2782 				TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2783 				NFSUNLOCKNAMEID();
2784 				return;
2785 			}
2786 		}
2787 		NFSUNLOCKNAMEID();
2788 		cnt++;
2789 		ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2790 		    NULL, p);
2791 		if (ret == 0 && cnt < 2)
2792 			goto tryagain;
2793 	} else {
2794 		NFSUNLOCKNAMEID();
2795 	}
2796 
2797 	/*
2798 	 * No match, just return a string of digits.
2799 	 */
2800 	tmp = gid;
2801 	i = 0;
2802 	while (tmp || i == 0) {
2803 		tmp /= 10;
2804 		i++;
2805 	}
2806 	len = (i > len) ? len : i;
2807 	*retlenp = len;
2808 	cp += (len - 1);
2809 	tmp = gid;
2810 	for (i = 0; i < len; i++) {
2811 		*cp-- = '0' + (tmp % 10);
2812 		tmp /= 10;
2813 	}
2814 	return;
2815 }
2816 
2817 /*
2818  * Convert a string to a gid.
2819  * If no conversion is possible return NFSERR_BADOWNER, otherwise
2820  * return 0.
2821  * If this is called from a client side mount using AUTH_SYS and the
2822  * string is made up entirely of digits, just convert the string to
2823  * a number.
2824  */
2825 APPLESTATIC int
2826 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2827     NFSPROC_T *p)
2828 {
2829 	int i;
2830 	char *cp, *endstr, *str0;
2831 	struct nfsusrgrp *usrp;
2832 	int cnt, ret;
2833 	int error = 0;
2834 	gid_t tgid;
2835 
2836 	if (len == 0) {
2837 		error =  NFSERR_BADOWNER;
2838 		goto out;
2839 	}
2840 	/* If a string of digits and an AUTH_SYS mount, just convert it. */
2841 	str0 = str;
2842 	tgid = (gid_t)strtoul(str0, &endstr, 10);
2843 	if ((endstr - str0) == len &&
2844 	    (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) {
2845 		*gidp = tgid;
2846 		goto out;
2847 	}
2848 	/*
2849 	 * Look for an '@'.
2850 	 */
2851 	cp = strchr(str0, '@');
2852 	if (cp != NULL)
2853 		i = (int)(cp++ - str0);
2854 	else
2855 		i = len;
2856 
2857 	cnt = 0;
2858 tryagain:
2859 	NFSLOCKNAMEID();
2860 	/*
2861 	 * If an '@' is found and the dns name matches, search for the name
2862 	 * with the dns stripped off.
2863 	 */
2864 	if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2865 	    (len - 1 - i) == nfsrv_dnsnamelen &&
2866 	    !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2867 		len -= (nfsrv_dnsnamelen + 1);
2868 		*(cp - 1) = '\0';
2869 	}
2870 
2871 	/*
2872 	 * Check for the special case of "nogroup".
2873 	 */
2874 	if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2875 		*gidp = nfsrv_defaultgid;
2876 		NFSUNLOCKNAMEID();
2877 		error = 0;
2878 		goto out;
2879 	}
2880 
2881 	LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
2882 		if (usrp->lug_namelen == len &&
2883 		    !NFSBCMP(usrp->lug_name, str, len)) {
2884 			if (usrp->lug_expiry < NFSD_MONOSEC)
2885 				break;
2886 			*gidp = usrp->lug_gid;
2887 			TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2888 			TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2889 			NFSUNLOCKNAMEID();
2890 			error = 0;
2891 			goto out;
2892 		}
2893 	}
2894 	NFSUNLOCKNAMEID();
2895 	cnt++;
2896 	ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
2897 	    str, p);
2898 	if (ret == 0 && cnt < 2)
2899 		goto tryagain;
2900 	error = NFSERR_BADOWNER;
2901 
2902 out:
2903 	NFSEXITCODE(error);
2904 	return (error);
2905 }
2906 
2907 /*
2908  * Cmp len chars, allowing mixed case in the first argument to match lower
2909  * case in the second, but not if the first argument is all upper case.
2910  * Return 0 for a match, 1 otherwise.
2911  */
2912 static int
2913 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
2914 {
2915 	int i;
2916 	u_char tmp;
2917 	int fndlower = 0;
2918 
2919 	for (i = 0; i < len; i++) {
2920 		if (*cp >= 'A' && *cp <= 'Z') {
2921 			tmp = *cp++ + ('a' - 'A');
2922 		} else {
2923 			tmp = *cp++;
2924 			if (tmp >= 'a' && tmp <= 'z')
2925 				fndlower = 1;
2926 		}
2927 		if (tmp != *cp2++)
2928 			return (1);
2929 	}
2930 	if (fndlower)
2931 		return (0);
2932 	else
2933 		return (1);
2934 }
2935 
2936 /*
2937  * Set the port for the nfsuserd.
2938  */
2939 APPLESTATIC int
2940 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
2941 {
2942 	struct nfssockreq *rp;
2943 	struct sockaddr_in *ad;
2944 	int error;
2945 
2946 	NFSLOCKNAMEID();
2947 	if (nfsrv_nfsuserd) {
2948 		NFSUNLOCKNAMEID();
2949 		error = EPERM;
2950 		goto out;
2951 	}
2952 	nfsrv_nfsuserd = 1;
2953 	NFSUNLOCKNAMEID();
2954 	/*
2955 	 * Set up the socket record and connect.
2956 	 */
2957 	rp = &nfsrv_nfsuserdsock;
2958 	rp->nr_client = NULL;
2959 	rp->nr_sotype = SOCK_DGRAM;
2960 	rp->nr_soproto = IPPROTO_UDP;
2961 	rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
2962 	rp->nr_cred = NULL;
2963 	NFSSOCKADDRALLOC(rp->nr_nam);
2964 	NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
2965 	ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
2966 	ad->sin_family = AF_INET;
2967 	ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001);	/* 127.0.0.1 */
2968 	ad->sin_port = port;
2969 	rp->nr_prog = RPCPROG_NFSUSERD;
2970 	rp->nr_vers = RPCNFSUSERD_VERS;
2971 	error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
2972 	if (error) {
2973 		NFSSOCKADDRFREE(rp->nr_nam);
2974 		nfsrv_nfsuserd = 0;
2975 	}
2976 out:
2977 	NFSEXITCODE(error);
2978 	return (error);
2979 }
2980 
2981 /*
2982  * Delete the nfsuserd port.
2983  */
2984 APPLESTATIC void
2985 nfsrv_nfsuserddelport(void)
2986 {
2987 
2988 	NFSLOCKNAMEID();
2989 	if (nfsrv_nfsuserd == 0) {
2990 		NFSUNLOCKNAMEID();
2991 		return;
2992 	}
2993 	nfsrv_nfsuserd = 0;
2994 	NFSUNLOCKNAMEID();
2995 	newnfs_disconnect(&nfsrv_nfsuserdsock);
2996 	NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
2997 }
2998 
2999 /*
3000  * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3001  * name<-->id cache.
3002  * Returns 0 upon success, non-zero otherwise.
3003  */
3004 static int
3005 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3006 {
3007 	u_int32_t *tl;
3008 	struct nfsrv_descript *nd;
3009 	int len;
3010 	struct nfsrv_descript nfsd;
3011 	struct ucred *cred;
3012 	int error;
3013 
3014 	NFSLOCKNAMEID();
3015 	if (nfsrv_nfsuserd == 0) {
3016 		NFSUNLOCKNAMEID();
3017 		error = EPERM;
3018 		goto out;
3019 	}
3020 	NFSUNLOCKNAMEID();
3021 	nd = &nfsd;
3022 	cred = newnfs_getcred();
3023 	nd->nd_flag = ND_GSSINITREPLY;
3024 	nfsrvd_rephead(nd);
3025 
3026 	nd->nd_procnum = procnum;
3027 	if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3028 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3029 		if (procnum == RPCNFSUSERD_GETUID)
3030 			*tl = txdr_unsigned(uid);
3031 		else
3032 			*tl = txdr_unsigned(gid);
3033 	} else {
3034 		len = strlen(name);
3035 		(void) nfsm_strtom(nd, name, len);
3036 	}
3037 	error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3038 		cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3039 	NFSFREECRED(cred);
3040 	if (!error) {
3041 		mbuf_freem(nd->nd_mrep);
3042 		error = nd->nd_repstat;
3043 	}
3044 out:
3045 	NFSEXITCODE(error);
3046 	return (error);
3047 }
3048 
3049 /*
3050  * This function is called from the nfssvc(2) system call, to update the
3051  * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3052  */
3053 APPLESTATIC int
3054 nfssvc_idname(struct nfsd_idargs *nidp)
3055 {
3056 	struct nfsusrgrp *nusrp, *usrp, *newusrp;
3057 	struct nfsuserhashhead *hp;
3058 	int i;
3059 	int error = 0;
3060 	u_char *cp;
3061 
3062 	if (nidp->nid_flag & NFSID_INITIALIZE) {
3063 	    cp = (u_char *)malloc(nidp->nid_namelen + 1,
3064 		M_NFSSTRING, M_WAITOK);
3065 	    error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3066 		nidp->nid_namelen);
3067 	    NFSLOCKNAMEID();
3068 	    if (nfsrv_dnsname) {
3069 		/*
3070 		 * Free up all the old stuff and reinitialize hash lists.
3071 		 */
3072 		TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3073 			nfsrv_removeuser(usrp);
3074 		}
3075 		free(nfsrv_dnsname, M_NFSSTRING);
3076 		nfsrv_dnsname = NULL;
3077 	    }
3078 	    TAILQ_INIT(&nfsuserlruhead);
3079 	    for (i = 0; i < NFSUSERHASHSIZE; i++)
3080 		LIST_INIT(&nfsuserhash[i]);
3081 	    for (i = 0; i < NFSGROUPHASHSIZE; i++)
3082 		LIST_INIT(&nfsgrouphash[i]);
3083 	    for (i = 0; i < NFSUSERHASHSIZE; i++)
3084 		LIST_INIT(&nfsusernamehash[i]);
3085 	    for (i = 0; i < NFSGROUPHASHSIZE; i++)
3086 		LIST_INIT(&nfsgroupnamehash[i]);
3087 
3088 	    /*
3089 	     * Put name in "DNS" string.
3090 	     */
3091 	    if (!error) {
3092 		nfsrv_dnsname = cp;
3093 		nfsrv_dnsnamelen = nidp->nid_namelen;
3094 		nfsrv_defaultuid = nidp->nid_uid;
3095 		nfsrv_defaultgid = nidp->nid_gid;
3096 		nfsrv_usercnt = 0;
3097 		nfsrv_usermax = nidp->nid_usermax;
3098 	    }
3099 	    NFSUNLOCKNAMEID();
3100 	    if (error)
3101 		free(cp, M_NFSSTRING);
3102 	    goto out;
3103 	}
3104 
3105 	/*
3106 	 * malloc the new one now, so any potential sleep occurs before
3107 	 * manipulation of the lists.
3108 	 */
3109 	MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
3110 	    nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
3111 	error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3112 	    nidp->nid_namelen);
3113 	if (error) {
3114 		free((caddr_t)newusrp, M_NFSUSERGROUP);
3115 		goto out;
3116 	}
3117 	newusrp->lug_namelen = nidp->nid_namelen;
3118 
3119 	NFSLOCKNAMEID();
3120 	/*
3121 	 * Delete old entries, as required.
3122 	 */
3123 	if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3124 		hp = NFSUSERHASH(nidp->nid_uid);
3125 		LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3126 			if (usrp->lug_uid == nidp->nid_uid)
3127 				nfsrv_removeuser(usrp);
3128 		}
3129 	}
3130 	if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3131 		hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3132 		LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3133 			if (usrp->lug_namelen == newusrp->lug_namelen &&
3134 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3135 			    usrp->lug_namelen))
3136 				nfsrv_removeuser(usrp);
3137 		}
3138 	}
3139 	if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3140 		hp = NFSGROUPHASH(nidp->nid_gid);
3141 		LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3142 			if (usrp->lug_gid == nidp->nid_gid)
3143 				nfsrv_removeuser(usrp);
3144 		}
3145 	}
3146 	if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3147 		hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3148 		LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3149 			if (usrp->lug_namelen == newusrp->lug_namelen &&
3150 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3151 			    usrp->lug_namelen))
3152 				nfsrv_removeuser(usrp);
3153 		}
3154 	}
3155 	TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3156 		if (usrp->lug_expiry < NFSD_MONOSEC)
3157 			nfsrv_removeuser(usrp);
3158 	}
3159 	while (nfsrv_usercnt >= nfsrv_usermax) {
3160 		usrp = TAILQ_FIRST(&nfsuserlruhead);
3161 		nfsrv_removeuser(usrp);
3162 	}
3163 
3164 	/*
3165 	 * Now, we can add the new one.
3166 	 */
3167 	if (nidp->nid_usertimeout)
3168 		newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3169 	else
3170 		newusrp->lug_expiry = NFSD_MONOSEC + 5;
3171 	if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3172 		newusrp->lug_uid = nidp->nid_uid;
3173 		LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
3174 		    lug_numhash);
3175 		LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
3176 		    newusrp->lug_namelen), newusrp, lug_namehash);
3177 		TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3178 		nfsrv_usercnt++;
3179 	} else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3180 		newusrp->lug_gid = nidp->nid_gid;
3181 		LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
3182 		    lug_numhash);
3183 		LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
3184 		    newusrp->lug_namelen), newusrp, lug_namehash);
3185 		TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3186 		nfsrv_usercnt++;
3187 	} else
3188 		FREE((caddr_t)newusrp, M_NFSUSERGROUP);
3189 	NFSUNLOCKNAMEID();
3190 out:
3191 	NFSEXITCODE(error);
3192 	return (error);
3193 }
3194 
3195 /*
3196  * Remove a user/group name element.
3197  */
3198 static void
3199 nfsrv_removeuser(struct nfsusrgrp *usrp)
3200 {
3201 
3202 	NFSNAMEIDREQUIRED();
3203 	LIST_REMOVE(usrp, lug_numhash);
3204 	LIST_REMOVE(usrp, lug_namehash);
3205 	TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
3206 	nfsrv_usercnt--;
3207 	FREE((caddr_t)usrp, M_NFSUSERGROUP);
3208 }
3209 
3210 /*
3211  * This function scans a byte string and checks for UTF-8 compliance.
3212  * It returns 0 if it conforms and NFSERR_INVAL if not.
3213  */
3214 APPLESTATIC int
3215 nfsrv_checkutf8(u_int8_t *cp, int len)
3216 {
3217 	u_int32_t val = 0x0;
3218 	int cnt = 0, gotd = 0, shift = 0;
3219 	u_int8_t byte;
3220 	static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3221 	int error = 0;
3222 
3223 	/*
3224 	 * Here are what the variables are used for:
3225 	 * val - the calculated value of a multibyte char, used to check
3226 	 *       that it was coded with the correct range
3227 	 * cnt - the number of 10xxxxxx bytes to follow
3228 	 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3229 	 * shift - lower order bits of range (ie. "val >> shift" should
3230 	 *       not be 0, in other words, dividing by the lower bound
3231 	 *       of the range should get a non-zero value)
3232 	 * byte - used to calculate cnt
3233 	 */
3234 	while (len > 0) {
3235 		if (cnt > 0) {
3236 			/* This handles the 10xxxxxx bytes */
3237 			if ((*cp & 0xc0) != 0x80 ||
3238 			    (gotd && (*cp & 0x20))) {
3239 				error = NFSERR_INVAL;
3240 				goto out;
3241 			}
3242 			gotd = 0;
3243 			val <<= 6;
3244 			val |= (*cp & 0x3f);
3245 			cnt--;
3246 			if (cnt == 0 && (val >> shift) == 0x0) {
3247 				error = NFSERR_INVAL;
3248 				goto out;
3249 			}
3250 		} else if (*cp & 0x80) {
3251 			/* first byte of multi byte char */
3252 			byte = *cp;
3253 			while ((byte & 0x40) && cnt < 6) {
3254 				cnt++;
3255 				byte <<= 1;
3256 			}
3257 			if (cnt == 0 || cnt == 6) {
3258 				error = NFSERR_INVAL;
3259 				goto out;
3260 			}
3261 			val = (*cp & (0x3f >> cnt));
3262 			shift = utf8_shift[cnt - 1];
3263 			if (cnt == 2 && val == 0xd)
3264 				/* Check for the 0xd800-0xdfff case */
3265 				gotd = 1;
3266 		}
3267 		cp++;
3268 		len--;
3269 	}
3270 	if (cnt > 0)
3271 		error = NFSERR_INVAL;
3272 
3273 out:
3274 	NFSEXITCODE(error);
3275 	return (error);
3276 }
3277 
3278 /*
3279  * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3280  * strings, one with the root path in it and the other with the list of
3281  * locations. The list is in the same format as is found in nfr_refs.
3282  * It is a "," separated list of entries, where each of them is of the
3283  * form <server>:<rootpath>. For example
3284  * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3285  * The nilp argument is set to 1 for the special case of a null fs_root
3286  * and an empty server list.
3287  * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3288  * number of xdr bytes parsed in sump.
3289  */
3290 static int
3291 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3292     int *sump, int *nilp)
3293 {
3294 	u_int32_t *tl;
3295 	u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3296 	int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3297 	struct list {
3298 		SLIST_ENTRY(list) next;
3299 		int len;
3300 		u_char host[1];
3301 	} *lsp, *nlsp;
3302 	SLIST_HEAD(, list) head;
3303 
3304 	*fsrootp = NULL;
3305 	*srvp = NULL;
3306 	*nilp = 0;
3307 
3308 	/*
3309 	 * Get the fs_root path and check for the special case of null path
3310 	 * and 0 length server list.
3311 	 */
3312 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3313 	len = fxdr_unsigned(int, *tl);
3314 	if (len < 0 || len > 10240) {
3315 		error = NFSERR_BADXDR;
3316 		goto nfsmout;
3317 	}
3318 	if (len == 0) {
3319 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3320 		if (*tl != 0) {
3321 			error = NFSERR_BADXDR;
3322 			goto nfsmout;
3323 		}
3324 		*nilp = 1;
3325 		*sump = 2 * NFSX_UNSIGNED;
3326 		error = 0;
3327 		goto nfsmout;
3328 	}
3329 	cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3330 	error = nfsrv_mtostr(nd, cp, len);
3331 	if (!error) {
3332 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3333 		cnt = fxdr_unsigned(int, *tl);
3334 		if (cnt <= 0)
3335 			error = NFSERR_BADXDR;
3336 	}
3337 	if (error)
3338 		goto nfsmout;
3339 
3340 	/*
3341 	 * Now, loop through the location list and make up the srvlist.
3342 	 */
3343 	xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3344 	cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3345 	slen = 1024;
3346 	siz = 0;
3347 	for (i = 0; i < cnt; i++) {
3348 		SLIST_INIT(&head);
3349 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3350 		nsrv = fxdr_unsigned(int, *tl);
3351 		if (nsrv <= 0) {
3352 			error = NFSERR_BADXDR;
3353 			goto nfsmout;
3354 		}
3355 
3356 		/*
3357 		 * Handle the first server by putting it in the srvstr.
3358 		 */
3359 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3360 		len = fxdr_unsigned(int, *tl);
3361 		if (len <= 0 || len > 1024) {
3362 			error = NFSERR_BADXDR;
3363 			goto nfsmout;
3364 		}
3365 		nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3366 		if (cp3 != cp2) {
3367 			*cp3++ = ',';
3368 			siz++;
3369 		}
3370 		error = nfsrv_mtostr(nd, cp3, len);
3371 		if (error)
3372 			goto nfsmout;
3373 		cp3 += len;
3374 		*cp3++ = ':';
3375 		siz += (len + 1);
3376 		xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3377 		for (j = 1; j < nsrv; j++) {
3378 			/*
3379 			 * Yuck, put them in an slist and process them later.
3380 			 */
3381 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3382 			len = fxdr_unsigned(int, *tl);
3383 			if (len <= 0 || len > 1024) {
3384 				error = NFSERR_BADXDR;
3385 				goto nfsmout;
3386 			}
3387 			lsp = (struct list *)malloc(sizeof (struct list)
3388 			    + len, M_TEMP, M_WAITOK);
3389 			error = nfsrv_mtostr(nd, lsp->host, len);
3390 			if (error)
3391 				goto nfsmout;
3392 			xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3393 			lsp->len = len;
3394 			SLIST_INSERT_HEAD(&head, lsp, next);
3395 		}
3396 
3397 		/*
3398 		 * Finally, we can get the path.
3399 		 */
3400 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3401 		len = fxdr_unsigned(int, *tl);
3402 		if (len <= 0 || len > 1024) {
3403 			error = NFSERR_BADXDR;
3404 			goto nfsmout;
3405 		}
3406 		nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3407 		error = nfsrv_mtostr(nd, cp3, len);
3408 		if (error)
3409 			goto nfsmout;
3410 		xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3411 		str = cp3;
3412 		stringlen = len;
3413 		cp3 += len;
3414 		siz += len;
3415 		SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3416 			nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3417 			    &cp2, &cp3, &slen);
3418 			*cp3++ = ',';
3419 			NFSBCOPY(lsp->host, cp3, lsp->len);
3420 			cp3 += lsp->len;
3421 			*cp3++ = ':';
3422 			NFSBCOPY(str, cp3, stringlen);
3423 			cp3 += stringlen;
3424 			*cp3 = '\0';
3425 			siz += (lsp->len + stringlen + 2);
3426 			free((caddr_t)lsp, M_TEMP);
3427 		}
3428 	}
3429 	*fsrootp = cp;
3430 	*srvp = cp2;
3431 	*sump = xdrsum;
3432 	NFSEXITCODE2(0, nd);
3433 	return (0);
3434 nfsmout:
3435 	if (cp != NULL)
3436 		free(cp, M_NFSSTRING);
3437 	if (cp2 != NULL)
3438 		free(cp2, M_NFSSTRING);
3439 	NFSEXITCODE2(error, nd);
3440 	return (error);
3441 }
3442 
3443 /*
3444  * Make the malloc'd space large enough. This is a pain, but the xdr
3445  * doesn't set an upper bound on the side, so...
3446  */
3447 static void
3448 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3449 {
3450 	u_char *cp;
3451 	int i;
3452 
3453 	if (siz <= *slenp)
3454 		return;
3455 	cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3456 	NFSBCOPY(*cpp, cp, *slenp);
3457 	free(*cpp, M_NFSSTRING);
3458 	i = *cpp2 - *cpp;
3459 	*cpp = cp;
3460 	*cpp2 = cp + i;
3461 	*slenp = siz + 1024;
3462 }
3463 
3464 /*
3465  * Initialize the reply header data structures.
3466  */
3467 APPLESTATIC void
3468 nfsrvd_rephead(struct nfsrv_descript *nd)
3469 {
3470 	mbuf_t mreq;
3471 
3472 	/*
3473 	 * If this is a big reply, use a cluster.
3474 	 */
3475 	if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3476 	    nfs_bigreply[nd->nd_procnum]) {
3477 		NFSMCLGET(mreq, M_WAITOK);
3478 		nd->nd_mreq = mreq;
3479 		nd->nd_mb = mreq;
3480 	} else {
3481 		NFSMGET(mreq);
3482 		nd->nd_mreq = mreq;
3483 		nd->nd_mb = mreq;
3484 	}
3485 	nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3486 	mbuf_setlen(mreq, 0);
3487 
3488 	if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3489 		NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3490 }
3491 
3492 /*
3493  * Lock a socket against others.
3494  * Currently used to serialize connect/disconnect attempts.
3495  */
3496 int
3497 newnfs_sndlock(int *flagp)
3498 {
3499 	struct timespec ts;
3500 
3501 	NFSLOCKSOCK();
3502 	while (*flagp & NFSR_SNDLOCK) {
3503 		*flagp |= NFSR_WANTSND;
3504 		ts.tv_sec = 0;
3505 		ts.tv_nsec = 0;
3506 		(void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3507 		    PZERO - 1, "nfsndlck", &ts);
3508 	}
3509 	*flagp |= NFSR_SNDLOCK;
3510 	NFSUNLOCKSOCK();
3511 	return (0);
3512 }
3513 
3514 /*
3515  * Unlock the stream socket for others.
3516  */
3517 void
3518 newnfs_sndunlock(int *flagp)
3519 {
3520 
3521 	NFSLOCKSOCK();
3522 	if ((*flagp & NFSR_SNDLOCK) == 0)
3523 		panic("nfs sndunlock");
3524 	*flagp &= ~NFSR_SNDLOCK;
3525 	if (*flagp & NFSR_WANTSND) {
3526 		*flagp &= ~NFSR_WANTSND;
3527 		wakeup((caddr_t)flagp);
3528 	}
3529 	NFSUNLOCKSOCK();
3530 }
3531 
3532 APPLESTATIC int
3533 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
3534     int *isudp)
3535 {
3536 	struct sockaddr_in *sad;
3537 	struct sockaddr_in6 *sad6;
3538 	struct in_addr saddr;
3539 	uint32_t portnum, *tl;
3540 	int af = 0, i, j, k;
3541 	char addr[64], protocol[5], *cp;
3542 	int cantparse = 0, error = 0;
3543 	uint16_t portv;
3544 
3545 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3546 	i = fxdr_unsigned(int, *tl);
3547 	if (i >= 3 && i <= 4) {
3548 		error = nfsrv_mtostr(nd, protocol, i);
3549 		if (error)
3550 			goto nfsmout;
3551 		if (strcmp(protocol, "tcp") == 0) {
3552 			af = AF_INET;
3553 			*isudp = 0;
3554 		} else if (strcmp(protocol, "udp") == 0) {
3555 			af = AF_INET;
3556 			*isudp = 1;
3557 		} else if (strcmp(protocol, "tcp6") == 0) {
3558 			af = AF_INET6;
3559 			*isudp = 0;
3560 		} else if (strcmp(protocol, "udp6") == 0) {
3561 			af = AF_INET6;
3562 			*isudp = 1;
3563 		} else
3564 			cantparse = 1;
3565 	} else {
3566 		cantparse = 1;
3567 		if (i > 0) {
3568 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3569 			if (error)
3570 				goto nfsmout;
3571 		}
3572 	}
3573 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3574 	i = fxdr_unsigned(int, *tl);
3575 	if (i < 0) {
3576 		error = NFSERR_BADXDR;
3577 		goto nfsmout;
3578 	} else if (cantparse == 0 && i >= 11 && i < 64) {
3579 		/*
3580 		 * The shortest address is 11chars and the longest is < 64.
3581 		 */
3582 		error = nfsrv_mtostr(nd, addr, i);
3583 		if (error)
3584 			goto nfsmout;
3585 
3586 		/* Find the port# at the end and extract that. */
3587 		i = strlen(addr);
3588 		k = 0;
3589 		cp = &addr[i - 1];
3590 		/* Count back two '.'s from end to get port# field. */
3591 		for (j = 0; j < i; j++) {
3592 			if (*cp == '.') {
3593 				k++;
3594 				if (k == 2)
3595 					break;
3596 			}
3597 			cp--;
3598 		}
3599 		if (k == 2) {
3600 			/*
3601 			 * The NFSv4 port# is appended as .N.N, where N is
3602 			 * a decimal # in the range 0-255, just like an inet4
3603 			 * address. Cheat and use inet_aton(), which will
3604 			 * return a Class A address and then shift the high
3605 			 * order 8bits over to convert it to the port#.
3606 			 */
3607 			*cp++ = '\0';
3608 			if (inet_aton(cp, &saddr) == 1) {
3609 				portnum = ntohl(saddr.s_addr);
3610 				portv = (uint16_t)((portnum >> 16) |
3611 				    (portnum & 0xff));
3612 			} else
3613 				cantparse = 1;
3614 		} else
3615 			cantparse = 1;
3616 		if (cantparse == 0) {
3617 			if (af == AF_INET) {
3618 				sad = (struct sockaddr_in *)sa;
3619 				if (inet_pton(af, addr, &sad->sin_addr) == 1) {
3620 					sad->sin_len = sizeof(*sad);
3621 					sad->sin_family = AF_INET;
3622 					sad->sin_port = htons(portv);
3623 					return (0);
3624 				}
3625 			} else {
3626 				sad6 = (struct sockaddr_in6 *)sa;
3627 				if (inet_pton(af, addr, &sad6->sin6_addr)
3628 				    == 1) {
3629 					sad6->sin6_len = sizeof(*sad6);
3630 					sad6->sin6_family = AF_INET6;
3631 					sad6->sin6_port = htons(portv);
3632 					return (0);
3633 				}
3634 			}
3635 		}
3636 	} else {
3637 		if (i > 0) {
3638 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3639 			if (error)
3640 				goto nfsmout;
3641 		}
3642 	}
3643 	error = EPERM;
3644 nfsmout:
3645 	return (error);
3646 }
3647 
3648 /*
3649  * Handle an NFSv4.1 Sequence request for the session.
3650  */
3651 int
3652 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
3653     struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
3654 {
3655 	int error;
3656 
3657 	error = 0;
3658 	*reply = NULL;
3659 	if (slotid > maxslot)
3660 		return (NFSERR_BADSLOT);
3661 	if (seqid == slots[slotid].nfssl_seq) {
3662 		/* A retry. */
3663 		if (slots[slotid].nfssl_inprog != 0)
3664 			error = NFSERR_DELAY;
3665 		else if (slots[slotid].nfssl_reply != NULL) {
3666 			*reply = slots[slotid].nfssl_reply;
3667 			slots[slotid].nfssl_reply = NULL;
3668 			slots[slotid].nfssl_inprog = 1;
3669 		} else
3670 			error = NFSERR_SEQMISORDERED;
3671 	} else if ((slots[slotid].nfssl_seq + 1) == seqid) {
3672 		m_freem(slots[slotid].nfssl_reply);
3673 		slots[slotid].nfssl_reply = NULL;
3674 		slots[slotid].nfssl_inprog = 1;
3675 		slots[slotid].nfssl_seq++;
3676 	} else
3677 		error = NFSERR_SEQMISORDERED;
3678 	return (error);
3679 }
3680 
3681 /*
3682  * Cache this reply for the slot.
3683  */
3684 void
3685 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, struct mbuf *rep)
3686 {
3687 
3688 	slots[slotid].nfssl_reply = rep;
3689 	slots[slotid].nfssl_inprog = 0;
3690 }
3691 
3692 /*
3693  * Generate the xdr for an NFSv4.1 Sequence Operation.
3694  */
3695 APPLESTATIC void
3696 nfsv4_setsequence(struct nfsrv_descript *nd, struct nfsclsession *sep,
3697     int dont_replycache)
3698 {
3699 	uint32_t *tl, slotseq = 0;
3700 	int i, maxslot, slotpos;
3701 	uint64_t bitval;
3702 	uint8_t sessionid[NFSX_V4SESSIONID];
3703 
3704 	/* Find an unused slot. */
3705 	slotpos = -1;
3706 	maxslot = -1;
3707 	mtx_lock(&sep->nfsess_mtx);
3708 	do {
3709 		bitval = 1;
3710 		for (i = 0; i < sep->nfsess_foreslots; i++) {
3711 			if ((bitval & sep->nfsess_slots) == 0) {
3712 				slotpos = i;
3713 				sep->nfsess_slots |= bitval;
3714 				sep->nfsess_slotseq[i]++;
3715 				slotseq = sep->nfsess_slotseq[i];
3716 				break;
3717 			}
3718 			bitval <<= 1;
3719 		}
3720 		if (slotpos == -1)
3721 			(void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
3722 			    PZERO, "nfsclseq", 0);
3723 	} while (slotpos == -1);
3724 	/* Now, find the highest slot in use. (nfsc_slots is 64bits) */
3725 	bitval = 1;
3726 	for (i = 0; i < 64; i++) {
3727 		if ((bitval & sep->nfsess_slots) != 0)
3728 			maxslot = i;
3729 		bitval <<= 1;
3730 	}
3731 	bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
3732 	mtx_unlock(&sep->nfsess_mtx);
3733 	KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot"));
3734 
3735 	/* Build the Sequence arguments. */
3736 	NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
3737 	bcopy(sessionid, tl, NFSX_V4SESSIONID);
3738 	tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
3739 	nd->nd_slotseq = tl;
3740 	*tl++ = txdr_unsigned(slotseq);
3741 	*tl++ = txdr_unsigned(slotpos);
3742 	*tl++ = txdr_unsigned(maxslot);
3743 	if (dont_replycache == 0)
3744 		*tl = newnfs_true;
3745 	else
3746 		*tl = newnfs_false;
3747 	nd->nd_flag |= ND_HASSEQUENCE;
3748 }
3749 
3750 /*
3751  * Free a session slot.
3752  */
3753 APPLESTATIC void
3754 nfsv4_freeslot(struct nfsclsession *sep, int slot)
3755 {
3756 	uint64_t bitval;
3757 
3758 	bitval = 1;
3759 	if (slot > 0)
3760 		bitval <<= slot;
3761 	mtx_lock(&sep->nfsess_mtx);
3762 	if ((bitval & sep->nfsess_slots) == 0)
3763 		printf("freeing free slot!!\n");
3764 	sep->nfsess_slots &= ~bitval;
3765 	wakeup(&sep->nfsess_slots);
3766 	mtx_unlock(&sep->nfsess_mtx);
3767 }
3768 
3769