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