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