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