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