xref: /freebsd/sys/fs/nfs/nfs_commonsubs.c (revision 5405b282e1f319b6f3597bb77f68be903e7f248c)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1989, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Rick Macklem at The University of Guelph.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  */
35 
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38 
39 /*
40  * These functions support the macros and help fiddle mbuf chains for
41  * the nfs op functions. They do things like create the rpc header and
42  * copy data between mbuf chains and uio lists.
43  */
44 #ifndef APPLEKEXT
45 #include "opt_inet.h"
46 #include "opt_inet6.h"
47 
48 #include <fs/nfs/nfsport.h>
49 
50 #include <security/mac/mac_framework.h>
51 
52 /*
53  * Data items converted to xdr at startup, since they are constant
54  * This is kinda hokey, but may save a little time doing byte swaps
55  */
56 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
57 
58 /* And other global data */
59 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
60 		      NFFIFO, NFNON };
61 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
62 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
63 struct timeval nfsboottime;	/* Copy boottime once, so it never changes */
64 int nfscl_ticks;
65 int nfsrv_useacl = 1;
66 struct nfssockreq nfsrv_nfsuserdsock;
67 int nfsrv_nfsuserd = 0;
68 struct nfsreqhead nfsd_reqq;
69 uid_t nfsrv_defaultuid = UID_NOBODY;
70 gid_t nfsrv_defaultgid = GID_NOGROUP;
71 int nfsrv_lease = NFSRV_LEASE;
72 int ncl_mbuf_mlen = MLEN;
73 int nfsd_enable_stringtouid = 0;
74 int nfsrv_doflexfile = 0;
75 static int nfs_enable_uidtostring = 0;
76 NFSNAMEIDMUTEX;
77 NFSSOCKMUTEX;
78 extern int nfsrv_lughashsize;
79 extern struct mtx nfsrv_dslock_mtx;
80 extern volatile int nfsrv_devidcnt;
81 extern int nfscl_debuglevel;
82 extern struct nfsdevicehead nfsrv_devidhead;
83 extern struct nfsstatsv1 nfsstatsv1;
84 
85 SYSCTL_DECL(_vfs_nfs);
86 SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
87     &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names");
88 
89 int nfsrv_maxpnfsmirror = 1;
90 SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD,
91     &nfsrv_maxpnfsmirror, 0, "Mirror level for pNFS service");
92 
93 /*
94  * This array of structures indicates, for V4:
95  * retfh - which of 3 types of calling args are used
96  *	0 - doesn't change cfh or use a sfh
97  *	1 - replaces cfh with a new one (unless it returns an error status)
98  *	2 - uses cfh and sfh
99  * needscfh - if the op wants a cfh and premtime
100  *	0 - doesn't use a cfh
101  *	1 - uses a cfh, but doesn't want pre-op attributes
102  *	2 - uses a cfh and wants pre-op attributes
103  * savereply - indicates a non-idempotent Op
104  *	0 - not non-idempotent
105  *	1 - non-idempotent
106  * Ops that are ordered via seqid# are handled separately from these
107  * non-idempotent Ops.
108  * Define it here, since it is used by both the client and server.
109  */
110 struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
111 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* undef */
112 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* undef */
113 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* undef */
114 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Access */
115 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Close */
116 	{ 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 },		/* Commit */
117 	{ 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Create */
118 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Delegpurge */
119 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Delegreturn */
120 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Getattr */
121 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* GetFH */
122 	{ 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Link */
123 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Lock */
124 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* LockT */
125 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* LockU */
126 	{ 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Lookup */
127 	{ 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Lookupp */
128 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* NVerify */
129 	{ 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 },		/* Open */
130 	{ 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* OpenAttr */
131 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* OpenConfirm */
132 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* OpenDowngrade */
133 	{ 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* PutFH */
134 	{ 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* PutPubFH */
135 	{ 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* PutRootFH */
136 	{ 0, 1, 0, 0, LK_SHARED, 1, 0 },		/* Read */
137 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* Readdir */
138 	{ 0, 1, 0, 0, LK_SHARED, 1, 1 },		/* ReadLink */
139 	{ 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Remove */
140 	{ 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },		/* Rename */
141 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Renew */
142 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* RestoreFH */
143 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* SaveFH */
144 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* SecInfo */
145 	{ 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 },		/* Setattr */
146 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* SetClientID */
147 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* SetClientIDConfirm */
148 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Verify */
149 	{ 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 },		/* Write */
150 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* ReleaseLockOwner */
151 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Backchannel Ctrl */
152 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Bind Conn to Sess */
153 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Exchange ID */
154 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Create Session */
155 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Destroy Session */
156 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Free StateID */
157 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Get Dir Deleg */
158 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Get Device Info */
159 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Get Device List */
160 	{ 0, 1, 0, 1, LK_EXCLUSIVE, 1, 1 },		/* Layout Commit */
161 	{ 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Layout Get */
162 	{ 0, 1, 0, 1, LK_EXCLUSIVE, 1, 0 },		/* Layout Return */
163 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Secinfo No name */
164 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Sequence */
165 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Set SSV */
166 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Test StateID */
167 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },		/* Want Delegation */
168 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },		/* Destroy ClientID */
169 	{ 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },		/* Reclaim Complete */
170 };
171 #endif	/* !APPLEKEXT */
172 
173 static int ncl_mbuf_mhlen = MHLEN;
174 static int nfsrv_usercnt = 0;
175 static int nfsrv_dnsnamelen;
176 static u_char *nfsrv_dnsname = NULL;
177 static int nfsrv_usermax = 999999999;
178 struct nfsrv_lughash {
179 	struct mtx		mtx;
180 	struct nfsuserhashhead	lughead;
181 };
182 static struct nfsrv_lughash	*nfsuserhash;
183 static struct nfsrv_lughash	*nfsusernamehash;
184 static struct nfsrv_lughash	*nfsgrouphash;
185 static struct nfsrv_lughash	*nfsgroupnamehash;
186 
187 /*
188  * This static array indicates whether or not the RPC generates a large
189  * reply. This is used by nfs_reply() to decide whether or not an mbuf
190  * cluster should be allocated. (If a cluster is required by an RPC
191  * marked 0 in this array, the code will still work, just not quite as
192  * efficiently.)
193  */
194 static int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
195     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,
196     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 };
197 
198 /* local functions */
199 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
200 static void nfsv4_wanted(struct nfsv4lock *lp);
201 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
202 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name);
203 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
204 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
205     int *, int *);
206 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
207 
208 static struct {
209 	int	op;
210 	int	opcnt;
211 	const u_char *tag;
212 	int	taglen;
213 } nfsv4_opmap[NFSV41_NPROCS] = {
214 	{ 0, 1, "Null", 4 },
215 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
216 	{ NFSV4OP_SETATTR, 2, "Setattr", 7, },
217 	{ NFSV4OP_LOOKUP, 3, "Lookup", 6, },
218 	{ NFSV4OP_ACCESS, 2, "Access", 6, },
219 	{ NFSV4OP_READLINK, 2, "Readlink", 8, },
220 	{ NFSV4OP_READ, 1, "Read", 4, },
221 	{ NFSV4OP_WRITE, 2, "Write", 5, },
222 	{ NFSV4OP_OPEN, 5, "Open", 4, },
223 	{ NFSV4OP_CREATE, 5, "Create", 6, },
224 	{ NFSV4OP_CREATE, 1, "Create", 6, },
225 	{ NFSV4OP_CREATE, 3, "Create", 6, },
226 	{ NFSV4OP_REMOVE, 1, "Remove", 6, },
227 	{ NFSV4OP_REMOVE, 1, "Remove", 6, },
228 	{ NFSV4OP_SAVEFH, 5, "Rename", 6, },
229 	{ NFSV4OP_SAVEFH, 4, "Link", 4, },
230 	{ NFSV4OP_READDIR, 2, "Readdir", 7, },
231 	{ NFSV4OP_READDIR, 2, "Readdir", 7, },
232 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
233 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
234 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
235 	{ NFSV4OP_COMMIT, 2, "Commit", 6, },
236 	{ NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
237 	{ NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
238 	{ NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
239 	{ NFSV4OP_LOCK, 1, "Lock", 4, },
240 	{ NFSV4OP_LOCKU, 1, "LockU", 5, },
241 	{ NFSV4OP_OPEN, 2, "Open", 4, },
242 	{ NFSV4OP_CLOSE, 1, "Close", 5, },
243 	{ NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
244 	{ NFSV4OP_LOCKT, 1, "LockT", 5, },
245 	{ NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
246 	{ NFSV4OP_RENEW, 1, "Renew", 5, },
247 	{ NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
248 	{ NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
249 	{ NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
250 	{ NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
251 	{ NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
252 	{ NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
253 	{ NFSV4OP_GETATTR, 1, "Getacl", 6, },
254 	{ NFSV4OP_SETATTR, 1, "Setacl", 6, },
255 	{ NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
256 	{ NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
257 	{ NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
258 	{ NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
259 	{ NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
260 	{ NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, },
261 	{ NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, },
262 	{ NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, },
263 	{ NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, },
264 	{ NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, },
265 	{ NFSV4OP_WRITE, 1, "WriteDS", 7, },
266 	{ NFSV4OP_READ, 1, "ReadDS", 6, },
267 	{ NFSV4OP_COMMIT, 1, "CommitDS", 8, },
268 	{ NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, },
269 	{ NFSV4OP_OPEN, 8, "CreateLayGet", 12, },
270 };
271 
272 /*
273  * NFS RPCS that have large request message size.
274  */
275 static int nfs_bigrequest[NFSV41_NPROCS] = {
276 	0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
277 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
278 	0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0
279 };
280 
281 /*
282  * Start building a request. Mostly just put the first file handle in
283  * place.
284  */
285 APPLESTATIC void
286 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
287     u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep,
288     int vers, int minorvers)
289 {
290 	struct mbuf *mb;
291 	u_int32_t *tl;
292 	int opcnt;
293 	nfsattrbit_t attrbits;
294 
295 	/*
296 	 * First, fill in some of the fields of nd.
297 	 */
298 	nd->nd_slotseq = NULL;
299 	if (vers == NFS_VER4) {
300 		nd->nd_flag = ND_NFSV4 | ND_NFSCL;
301 		if (minorvers == NFSV41_MINORVERSION)
302 			nd->nd_flag |= ND_NFSV41;
303 	} else if (vers == NFS_VER3)
304 		nd->nd_flag = ND_NFSV3 | ND_NFSCL;
305 	else {
306 		if (NFSHASNFSV4(nmp)) {
307 			nd->nd_flag = ND_NFSV4 | ND_NFSCL;
308 			if (NFSHASNFSV4N(nmp))
309 				nd->nd_flag |= ND_NFSV41;
310 		} else if (NFSHASNFSV3(nmp))
311 			nd->nd_flag = ND_NFSV3 | ND_NFSCL;
312 		else
313 			nd->nd_flag = ND_NFSV2 | ND_NFSCL;
314 	}
315 	nd->nd_procnum = procnum;
316 	nd->nd_repstat = 0;
317 
318 	/*
319 	 * Get the first mbuf for the request.
320 	 */
321 	if (nfs_bigrequest[procnum])
322 		NFSMCLGET(mb, M_WAITOK);
323 	else
324 		NFSMGET(mb);
325 	mbuf_setlen(mb, 0);
326 	nd->nd_mreq = nd->nd_mb = mb;
327 	nd->nd_bpos = NFSMTOD(mb, caddr_t);
328 
329 	/*
330 	 * And fill the first file handle into the request.
331 	 */
332 	if (nd->nd_flag & ND_NFSV4) {
333 		opcnt = nfsv4_opmap[procnum].opcnt +
334 		    nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
335 		if ((nd->nd_flag & ND_NFSV41) != 0) {
336 			opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
337 			if (procnum == NFSPROC_RENEW)
338 				/*
339 				 * For the special case of Renew, just do a
340 				 * Sequence Op.
341 				 */
342 				opcnt = 1;
343 			else if (procnum == NFSPROC_WRITEDS ||
344 			    procnum == NFSPROC_COMMITDS)
345 				/*
346 				 * For the special case of a Writeor Commit to
347 				 * a DS, the opcnt == 3, for Sequence, PutFH,
348 				 * Write/Commit.
349 				 */
350 				opcnt = 3;
351 		}
352 		/*
353 		 * What should the tag really be?
354 		 */
355 		(void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
356 			nfsv4_opmap[procnum].taglen);
357 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
358 		if ((nd->nd_flag & ND_NFSV41) != 0)
359 			*tl++ = txdr_unsigned(NFSV41_MINORVERSION);
360 		else
361 			*tl++ = txdr_unsigned(NFSV4_MINORVERSION);
362 		if (opcntpp != NULL)
363 			*opcntpp = tl;
364 		*tl = txdr_unsigned(opcnt);
365 		if ((nd->nd_flag & ND_NFSV41) != 0 &&
366 		    nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
367 			if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess >
368 			    0)
369 				nd->nd_flag |= ND_LOOPBADSESS;
370 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
371 			*tl = txdr_unsigned(NFSV4OP_SEQUENCE);
372 			if (sep == NULL) {
373 				sep = nfsmnt_mdssession(nmp);
374 				nfsv4_setsequence(nmp, nd, sep,
375 				    nfs_bigreply[procnum]);
376 			} else
377 				nfsv4_setsequence(nmp, nd, sep,
378 				    nfs_bigreply[procnum]);
379 		}
380 		if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
381 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
382 			*tl = txdr_unsigned(NFSV4OP_PUTFH);
383 			(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
384 			if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
385 			    == 2 && procnum != NFSPROC_WRITEDS &&
386 			    procnum != NFSPROC_COMMITDS) {
387 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
388 				*tl = txdr_unsigned(NFSV4OP_GETATTR);
389 				/*
390 				 * For Lookup Ops, we want all the directory
391 				 * attributes, so we can load the name cache.
392 				 */
393 				if (procnum == NFSPROC_LOOKUP ||
394 				    procnum == NFSPROC_LOOKUPP)
395 					NFSGETATTR_ATTRBIT(&attrbits);
396 				else {
397 					NFSWCCATTR_ATTRBIT(&attrbits);
398 					nd->nd_flag |= ND_V4WCCATTR;
399 				}
400 				(void) nfsrv_putattrbit(nd, &attrbits);
401 			}
402 		}
403 		if (procnum != NFSPROC_RENEW ||
404 		    (nd->nd_flag & ND_NFSV41) == 0) {
405 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
406 			*tl = txdr_unsigned(nfsv4_opmap[procnum].op);
407 		}
408 	} else {
409 		(void) nfsm_fhtom(nd, nfhp, fhlen, 0);
410 	}
411 	if (procnum < NFSV41_NPROCS)
412 		NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
413 }
414 
415 /*
416  * Put a state Id in the mbuf list.
417  */
418 APPLESTATIC void
419 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
420 {
421 	nfsv4stateid_t *st;
422 
423 	NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
424 	if (flag == NFSSTATEID_PUTALLZERO) {
425 		st->seqid = 0;
426 		st->other[0] = 0;
427 		st->other[1] = 0;
428 		st->other[2] = 0;
429 	} else if (flag == NFSSTATEID_PUTALLONE) {
430 		st->seqid = 0xffffffff;
431 		st->other[0] = 0xffffffff;
432 		st->other[1] = 0xffffffff;
433 		st->other[2] = 0xffffffff;
434 	} else if (flag == NFSSTATEID_PUTSEQIDZERO) {
435 		st->seqid = 0;
436 		st->other[0] = stateidp->other[0];
437 		st->other[1] = stateidp->other[1];
438 		st->other[2] = stateidp->other[2];
439 	} else {
440 		st->seqid = stateidp->seqid;
441 		st->other[0] = stateidp->other[0];
442 		st->other[1] = stateidp->other[1];
443 		st->other[2] = stateidp->other[2];
444 	}
445 }
446 
447 /*
448  * Fill in the setable attributes. The full argument indicates whether
449  * to fill in them all or just mode and time.
450  */
451 void
452 nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
453     struct vnode *vp, int flags, u_int32_t rdev)
454 {
455 	u_int32_t *tl;
456 	struct nfsv2_sattr *sp;
457 	nfsattrbit_t attrbits;
458 
459 	switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
460 	case ND_NFSV2:
461 		NFSM_BUILD(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
462 		if (vap->va_mode == (mode_t)VNOVAL)
463 			sp->sa_mode = newnfs_xdrneg1;
464 		else
465 			sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
466 		if (vap->va_uid == (uid_t)VNOVAL)
467 			sp->sa_uid = newnfs_xdrneg1;
468 		else
469 			sp->sa_uid = txdr_unsigned(vap->va_uid);
470 		if (vap->va_gid == (gid_t)VNOVAL)
471 			sp->sa_gid = newnfs_xdrneg1;
472 		else
473 			sp->sa_gid = txdr_unsigned(vap->va_gid);
474 		if (flags & NFSSATTR_SIZE0)
475 			sp->sa_size = 0;
476 		else if (flags & NFSSATTR_SIZENEG1)
477 			sp->sa_size = newnfs_xdrneg1;
478 		else if (flags & NFSSATTR_SIZERDEV)
479 			sp->sa_size = txdr_unsigned(rdev);
480 		else
481 			sp->sa_size = txdr_unsigned(vap->va_size);
482 		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
483 		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
484 		break;
485 	case ND_NFSV3:
486 		if (vap->va_mode != (mode_t)VNOVAL) {
487 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
488 			*tl++ = newnfs_true;
489 			*tl = txdr_unsigned(vap->va_mode);
490 		} else {
491 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
492 			*tl = newnfs_false;
493 		}
494 		if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL) {
495 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
496 			*tl++ = newnfs_true;
497 			*tl = txdr_unsigned(vap->va_uid);
498 		} else {
499 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
500 			*tl = newnfs_false;
501 		}
502 		if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL) {
503 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
504 			*tl++ = newnfs_true;
505 			*tl = txdr_unsigned(vap->va_gid);
506 		} else {
507 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
508 			*tl = newnfs_false;
509 		}
510 		if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) {
511 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
512 			*tl++ = newnfs_true;
513 			txdr_hyper(vap->va_size, tl);
514 		} else {
515 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
516 			*tl = newnfs_false;
517 		}
518 		if (vap->va_atime.tv_sec != VNOVAL) {
519 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
520 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
521 				*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
522 				txdr_nfsv3time(&vap->va_atime, tl);
523 			} else {
524 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
525 				*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
526 			}
527 		} else {
528 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
529 			*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
530 		}
531 		if (vap->va_mtime.tv_sec != VNOVAL) {
532 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
533 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
534 				*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
535 				txdr_nfsv3time(&vap->va_mtime, tl);
536 			} else {
537 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
538 				*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
539 			}
540 		} else {
541 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
542 			*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
543 		}
544 		break;
545 	case ND_NFSV4:
546 		NFSZERO_ATTRBIT(&attrbits);
547 		if (vap->va_mode != (mode_t)VNOVAL)
548 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MODE);
549 		if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL)
550 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
551 		if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL)
552 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP);
553 		if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL)
554 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
555 		if (vap->va_atime.tv_sec != VNOVAL)
556 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
557 		if (vap->va_mtime.tv_sec != VNOVAL)
558 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET);
559 		(void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0,
560 		    &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
561 		break;
562 	}
563 }
564 
565 #ifndef APPLE
566 /*
567  * copies mbuf chain to the uio scatter/gather list
568  */
569 int
570 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
571 {
572 	char *mbufcp, *uiocp;
573 	int xfer, left, len;
574 	mbuf_t mp;
575 	long uiosiz, rem;
576 	int error = 0;
577 
578 	mp = nd->nd_md;
579 	mbufcp = nd->nd_dpos;
580 	len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
581 	rem = NFSM_RNDUP(siz) - siz;
582 	while (siz > 0) {
583 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
584 			error = EBADRPC;
585 			goto out;
586 		}
587 		left = uiop->uio_iov->iov_len;
588 		uiocp = uiop->uio_iov->iov_base;
589 		if (left > siz)
590 			left = siz;
591 		uiosiz = left;
592 		while (left > 0) {
593 			while (len == 0) {
594 				mp = mbuf_next(mp);
595 				if (mp == NULL) {
596 					error = EBADRPC;
597 					goto out;
598 				}
599 				mbufcp = NFSMTOD(mp, caddr_t);
600 				len = mbuf_len(mp);
601 				KASSERT(len >= 0,
602 				    ("len %d, corrupted mbuf?", len));
603 			}
604 			xfer = (left > len) ? len : left;
605 #ifdef notdef
606 			/* Not Yet.. */
607 			if (uiop->uio_iov->iov_op != NULL)
608 				(*(uiop->uio_iov->iov_op))
609 				(mbufcp, uiocp, xfer);
610 			else
611 #endif
612 			if (uiop->uio_segflg == UIO_SYSSPACE)
613 				NFSBCOPY(mbufcp, uiocp, xfer);
614 			else
615 				copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
616 			left -= xfer;
617 			len -= xfer;
618 			mbufcp += xfer;
619 			uiocp += xfer;
620 			uiop->uio_offset += xfer;
621 			uiop->uio_resid -= xfer;
622 		}
623 		if (uiop->uio_iov->iov_len <= siz) {
624 			uiop->uio_iovcnt--;
625 			uiop->uio_iov++;
626 		} else {
627 			uiop->uio_iov->iov_base = (void *)
628 				((char *)uiop->uio_iov->iov_base + uiosiz);
629 			uiop->uio_iov->iov_len -= uiosiz;
630 		}
631 		siz -= uiosiz;
632 	}
633 	nd->nd_dpos = mbufcp;
634 	nd->nd_md = mp;
635 	if (rem > 0) {
636 		if (len < rem)
637 			error = nfsm_advance(nd, rem, len);
638 		else
639 			nd->nd_dpos += rem;
640 	}
641 
642 out:
643 	NFSEXITCODE2(error, nd);
644 	return (error);
645 }
646 #endif	/* !APPLE */
647 
648 /*
649  * Help break down an mbuf chain by setting the first siz bytes contiguous
650  * pointed to by returned val.
651  * This is used by the macro NFSM_DISSECT for tough
652  * cases.
653  */
654 APPLESTATIC void *
655 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
656 {
657 	mbuf_t mp2;
658 	int siz2, xfer;
659 	caddr_t p;
660 	int left;
661 	caddr_t retp;
662 
663 	retp = NULL;
664 	left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
665 	while (left == 0) {
666 		nd->nd_md = mbuf_next(nd->nd_md);
667 		if (nd->nd_md == NULL)
668 			return (retp);
669 		left = mbuf_len(nd->nd_md);
670 		nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
671 	}
672 	if (left >= siz) {
673 		retp = nd->nd_dpos;
674 		nd->nd_dpos += siz;
675 	} else if (mbuf_next(nd->nd_md) == NULL) {
676 		return (retp);
677 	} else if (siz > ncl_mbuf_mhlen) {
678 		panic("nfs S too big");
679 	} else {
680 		MGET(mp2, MT_DATA, how);
681 		if (mp2 == NULL)
682 			return (NULL);
683 		mbuf_setnext(mp2, mbuf_next(nd->nd_md));
684 		mbuf_setnext(nd->nd_md, mp2);
685 		mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
686 		nd->nd_md = mp2;
687 		retp = p = NFSMTOD(mp2, caddr_t);
688 		NFSBCOPY(nd->nd_dpos, p, left);	/* Copy what was left */
689 		siz2 = siz - left;
690 		p += left;
691 		mp2 = mbuf_next(mp2);
692 		/* Loop around copying up the siz2 bytes */
693 		while (siz2 > 0) {
694 			if (mp2 == NULL)
695 				return (NULL);
696 			xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
697 			if (xfer > 0) {
698 				NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
699 				NFSM_DATAP(mp2, xfer);
700 				mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
701 				p += xfer;
702 				siz2 -= xfer;
703 			}
704 			if (siz2 > 0)
705 				mp2 = mbuf_next(mp2);
706 		}
707 		mbuf_setlen(nd->nd_md, siz);
708 		nd->nd_md = mp2;
709 		nd->nd_dpos = NFSMTOD(mp2, caddr_t);
710 	}
711 	return (retp);
712 }
713 
714 /*
715  * Advance the position in the mbuf chain.
716  * If offs == 0, this is a no-op, but it is simpler to just return from
717  * here than check for offs > 0 for all calls to nfsm_advance.
718  * If left == -1, it should be calculated here.
719  */
720 APPLESTATIC int
721 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
722 {
723 	int error = 0;
724 
725 	if (offs == 0)
726 		goto out;
727 	/*
728 	 * A negative offs might indicate a corrupted mbuf chain and,
729 	 * as such, a printf is logged.
730 	 */
731 	if (offs < 0) {
732 		printf("nfsrv_advance: negative offs\n");
733 		error = EBADRPC;
734 		goto out;
735 	}
736 
737 	/*
738 	 * If left == -1, calculate it here.
739 	 */
740 	if (left == -1)
741 		left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
742 		    nd->nd_dpos;
743 
744 	/*
745 	 * Loop around, advancing over the mbuf data.
746 	 */
747 	while (offs > left) {
748 		offs -= left;
749 		nd->nd_md = mbuf_next(nd->nd_md);
750 		if (nd->nd_md == NULL) {
751 			error = EBADRPC;
752 			goto out;
753 		}
754 		left = mbuf_len(nd->nd_md);
755 		nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
756 	}
757 	nd->nd_dpos += offs;
758 
759 out:
760 	NFSEXITCODE(error);
761 	return (error);
762 }
763 
764 /*
765  * Copy a string into mbuf(s).
766  * Return the number of bytes output, including XDR overheads.
767  */
768 APPLESTATIC int
769 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
770 {
771 	mbuf_t m2;
772 	int xfer, left;
773 	mbuf_t m1;
774 	int rem, bytesize;
775 	u_int32_t *tl;
776 	char *cp2;
777 
778 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
779 	*tl = txdr_unsigned(siz);
780 	rem = NFSM_RNDUP(siz) - siz;
781 	bytesize = NFSX_UNSIGNED + siz + rem;
782 	m2 = nd->nd_mb;
783 	cp2 = nd->nd_bpos;
784 	left = M_TRAILINGSPACE(m2);
785 
786 	/*
787 	 * Loop around copying the string to mbuf(s).
788 	 */
789 	while (siz > 0) {
790 		if (left == 0) {
791 			if (siz > ncl_mbuf_mlen)
792 				NFSMCLGET(m1, M_WAITOK);
793 			else
794 				NFSMGET(m1);
795 			mbuf_setlen(m1, 0);
796 			mbuf_setnext(m2, m1);
797 			m2 = m1;
798 			cp2 = NFSMTOD(m2, caddr_t);
799 			left = M_TRAILINGSPACE(m2);
800 		}
801 		if (left >= siz)
802 			xfer = siz;
803 		else
804 			xfer = left;
805 		NFSBCOPY(cp, cp2, xfer);
806 		cp += xfer;
807 		mbuf_setlen(m2, mbuf_len(m2) + xfer);
808 		siz -= xfer;
809 		left -= xfer;
810 		if (siz == 0 && rem) {
811 			if (left < rem)
812 				panic("nfsm_strtom");
813 			NFSBZERO(cp2 + xfer, rem);
814 			mbuf_setlen(m2, mbuf_len(m2) + rem);
815 		}
816 	}
817 	nd->nd_mb = m2;
818 	nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
819 	return (bytesize);
820 }
821 
822 /*
823  * Called once to initialize data structures...
824  */
825 APPLESTATIC void
826 newnfs_init(void)
827 {
828 	static int nfs_inited = 0;
829 
830 	if (nfs_inited)
831 		return;
832 	nfs_inited = 1;
833 
834 	newnfs_true = txdr_unsigned(TRUE);
835 	newnfs_false = txdr_unsigned(FALSE);
836 	newnfs_xdrneg1 = txdr_unsigned(-1);
837 	nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
838 	if (nfscl_ticks < 1)
839 		nfscl_ticks = 1;
840 	NFSSETBOOTTIME(nfsboottime);
841 
842 	/*
843 	 * Initialize reply list and start timer
844 	 */
845 	TAILQ_INIT(&nfsd_reqq);
846 	NFS_TIMERINIT;
847 }
848 
849 /*
850  * Put a file handle in an mbuf list.
851  * If the size argument == 0, just use the default size.
852  * set_true == 1 if there should be an newnfs_true prepended on the file handle.
853  * Return the number of bytes output, including XDR overhead.
854  */
855 APPLESTATIC int
856 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
857 {
858 	u_int32_t *tl;
859 	u_int8_t *cp;
860 	int fullsiz, rem, bytesize = 0;
861 
862 	if (size == 0)
863 		size = NFSX_MYFH;
864 	switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
865 	case ND_NFSV2:
866 		if (size > NFSX_V2FH)
867 			panic("fh size > NFSX_V2FH for NFSv2");
868 		NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
869 		NFSBCOPY(fhp, cp, size);
870 		if (size < NFSX_V2FH)
871 			NFSBZERO(cp + size, NFSX_V2FH - size);
872 		bytesize = NFSX_V2FH;
873 		break;
874 	case ND_NFSV3:
875 	case ND_NFSV4:
876 		fullsiz = NFSM_RNDUP(size);
877 		rem = fullsiz - size;
878 		if (set_true) {
879 		    bytesize = 2 * NFSX_UNSIGNED + fullsiz;
880 		    NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
881 		    *tl = newnfs_true;
882 		} else {
883 		    bytesize = NFSX_UNSIGNED + fullsiz;
884 		}
885 		(void) nfsm_strtom(nd, fhp, size);
886 		break;
887 	}
888 	return (bytesize);
889 }
890 
891 /*
892  * This function compares two net addresses by family and returns TRUE
893  * if they are the same host.
894  * If there is any doubt, return FALSE.
895  * The AF_INET family is handled as a special case so that address mbufs
896  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
897  */
898 APPLESTATIC int
899 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
900 {
901 #ifdef INET
902 	struct sockaddr_in *inetaddr;
903 #endif
904 
905 	switch (family) {
906 #ifdef INET
907 	case AF_INET:
908 		inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
909 		if (inetaddr->sin_family == AF_INET &&
910 		    inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
911 			return (1);
912 		break;
913 #endif
914 #ifdef INET6
915 	case AF_INET6:
916 		{
917 		struct sockaddr_in6 *inetaddr6;
918 
919 		inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
920 		/* XXX - should test sin6_scope_id ? */
921 		if (inetaddr6->sin6_family == AF_INET6 &&
922 		    IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
923 			  &haddr->had_inet6))
924 			return (1);
925 		}
926 		break;
927 #endif
928 	}
929 	return (0);
930 }
931 
932 /*
933  * Similar to the above, but takes to NFSSOCKADDR_T args.
934  */
935 APPLESTATIC int
936 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
937 {
938 	struct sockaddr_in *addr1, *addr2;
939 	struct sockaddr *inaddr;
940 
941 	inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
942 	switch (inaddr->sa_family) {
943 	case AF_INET:
944 		addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
945 		addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
946 		if (addr2->sin_family == AF_INET &&
947 		    addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
948 			return (1);
949 		break;
950 #ifdef INET6
951 	case AF_INET6:
952 		{
953 		struct sockaddr_in6 *inet6addr1, *inet6addr2;
954 
955 		inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
956 		inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
957 		/* XXX - should test sin6_scope_id ? */
958 		if (inet6addr2->sin6_family == AF_INET6 &&
959 		    IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
960 			  &inet6addr2->sin6_addr))
961 			return (1);
962 		}
963 		break;
964 #endif
965 	}
966 	return (0);
967 }
968 
969 
970 /*
971  * Trim the stuff already dissected off the mbuf list.
972  */
973 APPLESTATIC void
974 newnfs_trimleading(nd)
975 	struct nfsrv_descript *nd;
976 {
977 	mbuf_t m, n;
978 	int offs;
979 
980 	/*
981 	 * First, free up leading mbufs.
982 	 */
983 	if (nd->nd_mrep != nd->nd_md) {
984 		m = nd->nd_mrep;
985 		while (mbuf_next(m) != nd->nd_md) {
986 			if (mbuf_next(m) == NULL)
987 				panic("nfsm trim leading");
988 			m = mbuf_next(m);
989 		}
990 		mbuf_setnext(m, NULL);
991 		mbuf_freem(nd->nd_mrep);
992 	}
993 	m = nd->nd_md;
994 
995 	/*
996 	 * Now, adjust this mbuf, based on nd_dpos.
997 	 */
998 	offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
999 	if (offs == mbuf_len(m)) {
1000 		n = m;
1001 		m = mbuf_next(m);
1002 		if (m == NULL)
1003 			panic("nfsm trim leading2");
1004 		mbuf_setnext(n, NULL);
1005 		mbuf_freem(n);
1006 	} else if (offs > 0) {
1007 		mbuf_setlen(m, mbuf_len(m) - offs);
1008 		NFSM_DATAP(m, offs);
1009 	} else if (offs < 0)
1010 		panic("nfsm trimleading offs");
1011 	nd->nd_mrep = m;
1012 	nd->nd_md = m;
1013 	nd->nd_dpos = NFSMTOD(m, caddr_t);
1014 }
1015 
1016 /*
1017  * Trim trailing data off the mbuf list being built.
1018  */
1019 APPLESTATIC void
1020 newnfs_trimtrailing(nd, mb, bpos)
1021 	struct nfsrv_descript *nd;
1022 	mbuf_t mb;
1023 	caddr_t bpos;
1024 {
1025 
1026 	if (mbuf_next(mb)) {
1027 		mbuf_freem(mbuf_next(mb));
1028 		mbuf_setnext(mb, NULL);
1029 	}
1030 	mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
1031 	nd->nd_mb = mb;
1032 	nd->nd_bpos = bpos;
1033 }
1034 
1035 /*
1036  * Dissect a file handle on the client.
1037  */
1038 APPLESTATIC int
1039 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
1040 {
1041 	u_int32_t *tl;
1042 	struct nfsfh *nfhp;
1043 	int error, len;
1044 
1045 	*nfhpp = NULL;
1046 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1047 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1048 		if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
1049 			len > NFSX_FHMAX) {
1050 			error = EBADRPC;
1051 			goto nfsmout;
1052 		}
1053 	} else
1054 		len = NFSX_V2FH;
1055 	nfhp = malloc(sizeof (struct nfsfh) + len,
1056 	    M_NFSFH, M_WAITOK);
1057 	error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
1058 	if (error) {
1059 		free(nfhp, M_NFSFH);
1060 		goto nfsmout;
1061 	}
1062 	nfhp->nfh_len = len;
1063 	*nfhpp = nfhp;
1064 nfsmout:
1065 	NFSEXITCODE2(error, nd);
1066 	return (error);
1067 }
1068 
1069 /*
1070  * Break down the nfsv4 acl.
1071  * If the aclp == NULL or won't fit in an acl, just discard the acl info.
1072  */
1073 APPLESTATIC int
1074 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
1075     int *aclsizep, __unused NFSPROC_T *p)
1076 {
1077 	u_int32_t *tl;
1078 	int i, aclsize;
1079 	int acecnt, error = 0, aceerr = 0, acesize;
1080 
1081 	*aclerrp = 0;
1082 	if (aclp)
1083 		aclp->acl_cnt = 0;
1084 	/*
1085 	 * Parse out the ace entries and expect them to conform to
1086 	 * what can be supported by R/W/X bits.
1087 	 */
1088 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1089 	aclsize = NFSX_UNSIGNED;
1090 	acecnt = fxdr_unsigned(int, *tl);
1091 	if (acecnt > ACL_MAX_ENTRIES)
1092 		aceerr = NFSERR_ATTRNOTSUPP;
1093 	if (nfsrv_useacl == 0)
1094 		aceerr = NFSERR_ATTRNOTSUPP;
1095 	for (i = 0; i < acecnt; i++) {
1096 		if (aclp && !aceerr)
1097 			error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
1098 			    &aceerr, &acesize, p);
1099 		else
1100 			error = nfsrv_skipace(nd, &acesize);
1101 		if (error)
1102 			goto nfsmout;
1103 		aclsize += acesize;
1104 	}
1105 	if (aclp && !aceerr)
1106 		aclp->acl_cnt = acecnt;
1107 	if (aceerr)
1108 		*aclerrp = aceerr;
1109 	if (aclsizep)
1110 		*aclsizep = aclsize;
1111 nfsmout:
1112 	NFSEXITCODE2(error, nd);
1113 	return (error);
1114 }
1115 
1116 /*
1117  * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
1118  */
1119 static int
1120 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
1121 {
1122 	u_int32_t *tl;
1123 	int error, len = 0;
1124 
1125 	NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1126 	len = fxdr_unsigned(int, *(tl + 3));
1127 	error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1128 nfsmout:
1129 	*acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
1130 	NFSEXITCODE2(error, nd);
1131 	return (error);
1132 }
1133 
1134 /*
1135  * Get attribute bits from an mbuf list.
1136  * Returns EBADRPC for a parsing error, 0 otherwise.
1137  * If the clearinvalid flag is set, clear the bits not supported.
1138  */
1139 APPLESTATIC int
1140 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
1141     int *retnotsupp)
1142 {
1143 	u_int32_t *tl;
1144 	int cnt, i, outcnt;
1145 	int error = 0;
1146 
1147 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1148 	cnt = fxdr_unsigned(int, *tl);
1149 	if (cnt < 0) {
1150 		error = NFSERR_BADXDR;
1151 		goto nfsmout;
1152 	}
1153 	if (cnt > NFSATTRBIT_MAXWORDS)
1154 		outcnt = NFSATTRBIT_MAXWORDS;
1155 	else
1156 		outcnt = cnt;
1157 	NFSZERO_ATTRBIT(attrbitp);
1158 	if (outcnt > 0) {
1159 		NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
1160 		for (i = 0; i < outcnt; i++)
1161 			attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
1162 	}
1163 	for (i = 0; i < (cnt - outcnt); i++) {
1164 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1165 		if (retnotsupp != NULL && *tl != 0)
1166 			*retnotsupp = NFSERR_ATTRNOTSUPP;
1167 	}
1168 	if (cntp)
1169 		*cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
1170 nfsmout:
1171 	NFSEXITCODE2(error, nd);
1172 	return (error);
1173 }
1174 
1175 /*
1176  * Get the attributes for V4.
1177  * If the compare flag is true, test for any attribute changes,
1178  * otherwise return the attribute values.
1179  * These attributes cover fields in "struct vattr", "struct statfs",
1180  * "struct nfsfsinfo", the file handle and the lease duration.
1181  * The value of retcmpp is set to 1 if all attributes are the same,
1182  * and 0 otherwise.
1183  * Returns EBADRPC if it can't be parsed, 0 otherwise.
1184  */
1185 APPLESTATIC int
1186 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
1187     struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
1188     struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
1189     struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
1190     u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
1191 {
1192 	u_int32_t *tl;
1193 	int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
1194 	int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
1195 	u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
1196 	nfsattrbit_t attrbits, retattrbits, checkattrbits;
1197 	struct nfsfh *tnfhp;
1198 	struct nfsreferral *refp;
1199 	u_quad_t tquad;
1200 	nfsquad_t tnfsquad;
1201 	struct timespec temptime;
1202 	uid_t uid;
1203 	gid_t gid;
1204 	u_int32_t freenum = 0, tuint;
1205 	u_int64_t uquad = 0, thyp, thyp2;
1206 #ifdef QUOTA
1207 	struct dqblk dqb;
1208 	uid_t savuid;
1209 #endif
1210 
1211 	CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
1212 	if (compare) {
1213 		retnotsup = 0;
1214 		error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
1215 	} else {
1216 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1217 	}
1218 	if (error)
1219 		goto nfsmout;
1220 
1221 	if (compare) {
1222 		*retcmpp = retnotsup;
1223 	} else {
1224 		/*
1225 		 * Just set default values to some of the important ones.
1226 		 */
1227 		if (nap != NULL) {
1228 			nap->na_type = VREG;
1229 			nap->na_mode = 0;
1230 			nap->na_rdev = (NFSDEV_T)0;
1231 			nap->na_mtime.tv_sec = 0;
1232 			nap->na_mtime.tv_nsec = 0;
1233 			nap->na_gen = 0;
1234 			nap->na_flags = 0;
1235 			nap->na_blocksize = NFS_FABLKSIZE;
1236 		}
1237 		if (sbp != NULL) {
1238 			sbp->f_bsize = NFS_FABLKSIZE;
1239 			sbp->f_blocks = 0;
1240 			sbp->f_bfree = 0;
1241 			sbp->f_bavail = 0;
1242 			sbp->f_files = 0;
1243 			sbp->f_ffree = 0;
1244 		}
1245 		if (fsp != NULL) {
1246 			fsp->fs_rtmax = 8192;
1247 			fsp->fs_rtpref = 8192;
1248 			fsp->fs_maxname = NFS_MAXNAMLEN;
1249 			fsp->fs_wtmax = 8192;
1250 			fsp->fs_wtpref = 8192;
1251 			fsp->fs_wtmult = NFS_FABLKSIZE;
1252 			fsp->fs_dtpref = 8192;
1253 			fsp->fs_maxfilesize = 0xffffffffffffffffull;
1254 			fsp->fs_timedelta.tv_sec = 0;
1255 			fsp->fs_timedelta.tv_nsec = 1;
1256 			fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
1257 				NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
1258 		}
1259 		if (pc != NULL) {
1260 			pc->pc_linkmax = NFS_LINK_MAX;
1261 			pc->pc_namemax = NAME_MAX;
1262 			pc->pc_notrunc = 0;
1263 			pc->pc_chownrestricted = 0;
1264 			pc->pc_caseinsensitive = 0;
1265 			pc->pc_casepreserving = 1;
1266 		}
1267 		if (sfp != NULL) {
1268 			sfp->sf_ffiles = UINT64_MAX;
1269 			sfp->sf_tfiles = UINT64_MAX;
1270 			sfp->sf_afiles = UINT64_MAX;
1271 			sfp->sf_fbytes = UINT64_MAX;
1272 			sfp->sf_tbytes = UINT64_MAX;
1273 			sfp->sf_abytes = UINT64_MAX;
1274 		}
1275 	}
1276 
1277 	/*
1278 	 * Loop around getting the attributes.
1279 	 */
1280 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1281 	attrsize = fxdr_unsigned(int, *tl);
1282 	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
1283 	    if (attrsum > attrsize) {
1284 		error = NFSERR_BADXDR;
1285 		goto nfsmout;
1286 	    }
1287 	    if (NFSISSET_ATTRBIT(&attrbits, bitpos))
1288 		switch (bitpos) {
1289 		case NFSATTRBIT_SUPPORTEDATTRS:
1290 			retnotsup = 0;
1291 			if (compare || nap == NULL)
1292 			    error = nfsrv_getattrbits(nd, &retattrbits,
1293 				&cnt, &retnotsup);
1294 			else
1295 			    error = nfsrv_getattrbits(nd, &nap->na_suppattr,
1296 				&cnt, &retnotsup);
1297 			if (error)
1298 			    goto nfsmout;
1299 			if (compare && !(*retcmpp)) {
1300 			   NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
1301 
1302 			   /* Some filesystem do not support NFSv4ACL   */
1303 			   if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
1304 				NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
1305 				NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
1306 		   	   }
1307 			   if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
1308 			       || retnotsup)
1309 				*retcmpp = NFSERR_NOTSAME;
1310 			}
1311 			attrsum += cnt;
1312 			break;
1313 		case NFSATTRBIT_TYPE:
1314 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1315 			if (compare) {
1316 				if (!(*retcmpp)) {
1317 				    if (nap->na_type != nfsv34tov_type(*tl))
1318 					*retcmpp = NFSERR_NOTSAME;
1319 				}
1320 			} else if (nap != NULL) {
1321 				nap->na_type = nfsv34tov_type(*tl);
1322 			}
1323 			attrsum += NFSX_UNSIGNED;
1324 			break;
1325 		case NFSATTRBIT_FHEXPIRETYPE:
1326 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1327 			if (compare && !(*retcmpp)) {
1328 				if (fxdr_unsigned(int, *tl) !=
1329 					NFSV4FHTYPE_PERSISTENT)
1330 					*retcmpp = NFSERR_NOTSAME;
1331 			}
1332 			attrsum += NFSX_UNSIGNED;
1333 			break;
1334 		case NFSATTRBIT_CHANGE:
1335 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1336 			if (compare) {
1337 				if (!(*retcmpp)) {
1338 				    if (nap->na_filerev != fxdr_hyper(tl))
1339 					*retcmpp = NFSERR_NOTSAME;
1340 				}
1341 			} else if (nap != NULL) {
1342 				nap->na_filerev = fxdr_hyper(tl);
1343 			}
1344 			attrsum += NFSX_HYPER;
1345 			break;
1346 		case NFSATTRBIT_SIZE:
1347 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1348 			if (compare) {
1349 				if (!(*retcmpp)) {
1350 				    if (nap->na_size != fxdr_hyper(tl))
1351 					*retcmpp = NFSERR_NOTSAME;
1352 				}
1353 			} else if (nap != NULL) {
1354 				nap->na_size = fxdr_hyper(tl);
1355 			}
1356 			attrsum += NFSX_HYPER;
1357 			break;
1358 		case NFSATTRBIT_LINKSUPPORT:
1359 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1360 			if (compare) {
1361 				if (!(*retcmpp)) {
1362 				    if (fsp->fs_properties & NFSV3_FSFLINK) {
1363 					if (*tl == newnfs_false)
1364 						*retcmpp = NFSERR_NOTSAME;
1365 				    } else {
1366 					if (*tl == newnfs_true)
1367 						*retcmpp = NFSERR_NOTSAME;
1368 				    }
1369 				}
1370 			} else if (fsp != NULL) {
1371 				if (*tl == newnfs_true)
1372 					fsp->fs_properties |= NFSV3_FSFLINK;
1373 				else
1374 					fsp->fs_properties &= ~NFSV3_FSFLINK;
1375 			}
1376 			attrsum += NFSX_UNSIGNED;
1377 			break;
1378 		case NFSATTRBIT_SYMLINKSUPPORT:
1379 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1380 			if (compare) {
1381 				if (!(*retcmpp)) {
1382 				    if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
1383 					if (*tl == newnfs_false)
1384 						*retcmpp = NFSERR_NOTSAME;
1385 				    } else {
1386 					if (*tl == newnfs_true)
1387 						*retcmpp = NFSERR_NOTSAME;
1388 				    }
1389 				}
1390 			} else if (fsp != NULL) {
1391 				if (*tl == newnfs_true)
1392 					fsp->fs_properties |= NFSV3_FSFSYMLINK;
1393 				else
1394 					fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
1395 			}
1396 			attrsum += NFSX_UNSIGNED;
1397 			break;
1398 		case NFSATTRBIT_NAMEDATTR:
1399 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1400 			if (compare && !(*retcmpp)) {
1401 				if (*tl != newnfs_false)
1402 					*retcmpp = NFSERR_NOTSAME;
1403 			}
1404 			attrsum += NFSX_UNSIGNED;
1405 			break;
1406 		case NFSATTRBIT_FSID:
1407 			NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1408 			thyp = fxdr_hyper(tl);
1409 			tl += 2;
1410 			thyp2 = fxdr_hyper(tl);
1411 			if (compare) {
1412 			    if (*retcmpp == 0) {
1413 				if (thyp != (u_int64_t)
1414 				    vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1415 				    thyp2 != (u_int64_t)
1416 				    vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1417 					*retcmpp = NFSERR_NOTSAME;
1418 			    }
1419 			} else if (nap != NULL) {
1420 				nap->na_filesid[0] = thyp;
1421 				nap->na_filesid[1] = thyp2;
1422 			}
1423 			attrsum += (4 * NFSX_UNSIGNED);
1424 			break;
1425 		case NFSATTRBIT_UNIQUEHANDLES:
1426 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1427 			if (compare && !(*retcmpp)) {
1428 				if (*tl != newnfs_true)
1429 					*retcmpp = NFSERR_NOTSAME;
1430 			}
1431 			attrsum += NFSX_UNSIGNED;
1432 			break;
1433 		case NFSATTRBIT_LEASETIME:
1434 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1435 			if (compare) {
1436 				if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1437 				    !(*retcmpp))
1438 					*retcmpp = NFSERR_NOTSAME;
1439 			} else if (leasep != NULL) {
1440 				*leasep = fxdr_unsigned(u_int32_t, *tl);
1441 			}
1442 			attrsum += NFSX_UNSIGNED;
1443 			break;
1444 		case NFSATTRBIT_RDATTRERROR:
1445 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1446 			if (compare) {
1447 				 if (!(*retcmpp))
1448 					*retcmpp = NFSERR_INVAL;
1449 			} else if (rderrp != NULL) {
1450 				*rderrp = fxdr_unsigned(u_int32_t, *tl);
1451 			}
1452 			attrsum += NFSX_UNSIGNED;
1453 			break;
1454 		case NFSATTRBIT_ACL:
1455 			if (compare) {
1456 			  if (!(*retcmpp)) {
1457 			    if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1458 				NFSACL_T *naclp;
1459 
1460 				naclp = acl_alloc(M_WAITOK);
1461 				error = nfsrv_dissectacl(nd, naclp, &aceerr,
1462 				    &cnt, p);
1463 				if (error) {
1464 				    acl_free(naclp);
1465 				    goto nfsmout;
1466 				}
1467 				if (aceerr || aclp == NULL ||
1468 				    nfsrv_compareacl(aclp, naclp))
1469 				    *retcmpp = NFSERR_NOTSAME;
1470 				acl_free(naclp);
1471 			    } else {
1472 				error = nfsrv_dissectacl(nd, NULL, &aceerr,
1473 				    &cnt, p);
1474 				*retcmpp = NFSERR_ATTRNOTSUPP;
1475 			    }
1476 			  }
1477 			} else {
1478 				if (vp != NULL && aclp != NULL)
1479 				    error = nfsrv_dissectacl(nd, aclp, &aceerr,
1480 					&cnt, p);
1481 				else
1482 				    error = nfsrv_dissectacl(nd, NULL, &aceerr,
1483 					&cnt, p);
1484 				if (error)
1485 				    goto nfsmout;
1486 			}
1487 
1488 			attrsum += cnt;
1489 			break;
1490 		case NFSATTRBIT_ACLSUPPORT:
1491 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1492 			if (compare && !(*retcmpp)) {
1493 				if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1494 					if (fxdr_unsigned(u_int32_t, *tl) !=
1495 					    NFSV4ACE_SUPTYPES)
1496 						*retcmpp = NFSERR_NOTSAME;
1497 				} else {
1498 					*retcmpp = NFSERR_ATTRNOTSUPP;
1499 				}
1500 			}
1501 			attrsum += NFSX_UNSIGNED;
1502 			break;
1503 		case NFSATTRBIT_ARCHIVE:
1504 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1505 			if (compare && !(*retcmpp))
1506 				*retcmpp = NFSERR_ATTRNOTSUPP;
1507 			attrsum += NFSX_UNSIGNED;
1508 			break;
1509 		case NFSATTRBIT_CANSETTIME:
1510 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1511 			if (compare) {
1512 				if (!(*retcmpp)) {
1513 				    if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1514 					if (*tl == newnfs_false)
1515 						*retcmpp = NFSERR_NOTSAME;
1516 				    } else {
1517 					if (*tl == newnfs_true)
1518 						*retcmpp = NFSERR_NOTSAME;
1519 				    }
1520 				}
1521 			} else if (fsp != NULL) {
1522 				if (*tl == newnfs_true)
1523 					fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1524 				else
1525 					fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1526 			}
1527 			attrsum += NFSX_UNSIGNED;
1528 			break;
1529 		case NFSATTRBIT_CASEINSENSITIVE:
1530 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1531 			if (compare) {
1532 				if (!(*retcmpp)) {
1533 				    if (*tl != newnfs_false)
1534 					*retcmpp = NFSERR_NOTSAME;
1535 				}
1536 			} else if (pc != NULL) {
1537 				pc->pc_caseinsensitive =
1538 				    fxdr_unsigned(u_int32_t, *tl);
1539 			}
1540 			attrsum += NFSX_UNSIGNED;
1541 			break;
1542 		case NFSATTRBIT_CASEPRESERVING:
1543 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1544 			if (compare) {
1545 				if (!(*retcmpp)) {
1546 				    if (*tl != newnfs_true)
1547 					*retcmpp = NFSERR_NOTSAME;
1548 				}
1549 			} else if (pc != NULL) {
1550 				pc->pc_casepreserving =
1551 				    fxdr_unsigned(u_int32_t, *tl);
1552 			}
1553 			attrsum += NFSX_UNSIGNED;
1554 			break;
1555 		case NFSATTRBIT_CHOWNRESTRICTED:
1556 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1557 			if (compare) {
1558 				if (!(*retcmpp)) {
1559 				    if (*tl != newnfs_true)
1560 					*retcmpp = NFSERR_NOTSAME;
1561 				}
1562 			} else if (pc != NULL) {
1563 				pc->pc_chownrestricted =
1564 				    fxdr_unsigned(u_int32_t, *tl);
1565 			}
1566 			attrsum += NFSX_UNSIGNED;
1567 			break;
1568 		case NFSATTRBIT_FILEHANDLE:
1569 			error = nfsm_getfh(nd, &tnfhp);
1570 			if (error)
1571 				goto nfsmout;
1572 			tfhsize = tnfhp->nfh_len;
1573 			if (compare) {
1574 				if (!(*retcmpp) &&
1575 				    !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1576 				     fhp, fhsize))
1577 					*retcmpp = NFSERR_NOTSAME;
1578 				free(tnfhp, M_NFSFH);
1579 			} else if (nfhpp != NULL) {
1580 				*nfhpp = tnfhp;
1581 			} else {
1582 				free(tnfhp, M_NFSFH);
1583 			}
1584 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1585 			break;
1586 		case NFSATTRBIT_FILEID:
1587 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1588 			thyp = fxdr_hyper(tl);
1589 			if (compare) {
1590 				if (!(*retcmpp)) {
1591 					if (nap->na_fileid != thyp)
1592 						*retcmpp = NFSERR_NOTSAME;
1593 				}
1594 			} else if (nap != NULL)
1595 				nap->na_fileid = thyp;
1596 			attrsum += NFSX_HYPER;
1597 			break;
1598 		case NFSATTRBIT_FILESAVAIL:
1599 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1600 			if (compare) {
1601 				if (!(*retcmpp) &&
1602 				    sfp->sf_afiles != fxdr_hyper(tl))
1603 					*retcmpp = NFSERR_NOTSAME;
1604 			} else if (sfp != NULL) {
1605 				sfp->sf_afiles = fxdr_hyper(tl);
1606 			}
1607 			attrsum += NFSX_HYPER;
1608 			break;
1609 		case NFSATTRBIT_FILESFREE:
1610 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1611 			if (compare) {
1612 				if (!(*retcmpp) &&
1613 				    sfp->sf_ffiles != fxdr_hyper(tl))
1614 					*retcmpp = NFSERR_NOTSAME;
1615 			} else if (sfp != NULL) {
1616 				sfp->sf_ffiles = fxdr_hyper(tl);
1617 			}
1618 			attrsum += NFSX_HYPER;
1619 			break;
1620 		case NFSATTRBIT_FILESTOTAL:
1621 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1622 			if (compare) {
1623 				if (!(*retcmpp) &&
1624 				    sfp->sf_tfiles != fxdr_hyper(tl))
1625 					*retcmpp = NFSERR_NOTSAME;
1626 			} else if (sfp != NULL) {
1627 				sfp->sf_tfiles = fxdr_hyper(tl);
1628 			}
1629 			attrsum += NFSX_HYPER;
1630 			break;
1631 		case NFSATTRBIT_FSLOCATIONS:
1632 			error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1633 			if (error)
1634 				goto nfsmout;
1635 			attrsum += l;
1636 			if (compare && !(*retcmpp)) {
1637 				refp = nfsv4root_getreferral(vp, NULL, 0);
1638 				if (refp != NULL) {
1639 					if (cp == NULL || cp2 == NULL ||
1640 					    strcmp(cp, "/") ||
1641 					    strcmp(cp2, refp->nfr_srvlist))
1642 						*retcmpp = NFSERR_NOTSAME;
1643 				} else if (m == 0) {
1644 					*retcmpp = NFSERR_NOTSAME;
1645 				}
1646 			}
1647 			if (cp != NULL)
1648 				free(cp, M_NFSSTRING);
1649 			if (cp2 != NULL)
1650 				free(cp2, M_NFSSTRING);
1651 			break;
1652 		case NFSATTRBIT_HIDDEN:
1653 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1654 			if (compare && !(*retcmpp))
1655 				*retcmpp = NFSERR_ATTRNOTSUPP;
1656 			attrsum += NFSX_UNSIGNED;
1657 			break;
1658 		case NFSATTRBIT_HOMOGENEOUS:
1659 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1660 			if (compare) {
1661 				if (!(*retcmpp)) {
1662 				    if (fsp->fs_properties &
1663 					NFSV3_FSFHOMOGENEOUS) {
1664 					if (*tl == newnfs_false)
1665 						*retcmpp = NFSERR_NOTSAME;
1666 				    } else {
1667 					if (*tl == newnfs_true)
1668 						*retcmpp = NFSERR_NOTSAME;
1669 				    }
1670 				}
1671 			} else if (fsp != NULL) {
1672 				if (*tl == newnfs_true)
1673 				    fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1674 				else
1675 				    fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1676 			}
1677 			attrsum += NFSX_UNSIGNED;
1678 			break;
1679 		case NFSATTRBIT_MAXFILESIZE:
1680 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1681 			tnfsquad.qval = fxdr_hyper(tl);
1682 			if (compare) {
1683 				if (!(*retcmpp)) {
1684 					tquad = NFSRV_MAXFILESIZE;
1685 					if (tquad != tnfsquad.qval)
1686 						*retcmpp = NFSERR_NOTSAME;
1687 				}
1688 			} else if (fsp != NULL) {
1689 				fsp->fs_maxfilesize = tnfsquad.qval;
1690 			}
1691 			attrsum += NFSX_HYPER;
1692 			break;
1693 		case NFSATTRBIT_MAXLINK:
1694 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1695 			if (compare) {
1696 				if (!(*retcmpp)) {
1697 				    if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1698 					*retcmpp = NFSERR_NOTSAME;
1699 				}
1700 			} else if (pc != NULL) {
1701 				pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1702 			}
1703 			attrsum += NFSX_UNSIGNED;
1704 			break;
1705 		case NFSATTRBIT_MAXNAME:
1706 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1707 			if (compare) {
1708 				if (!(*retcmpp)) {
1709 				    if (fsp->fs_maxname !=
1710 					fxdr_unsigned(u_int32_t, *tl))
1711 						*retcmpp = NFSERR_NOTSAME;
1712 				}
1713 			} else {
1714 				tuint = fxdr_unsigned(u_int32_t, *tl);
1715 				/*
1716 				 * Some Linux NFSv4 servers report this
1717 				 * as 0 or 4billion, so I'll set it to
1718 				 * NFS_MAXNAMLEN. If a server actually creates
1719 				 * a name longer than NFS_MAXNAMLEN, it will
1720 				 * get an error back.
1721 				 */
1722 				if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1723 					tuint = NFS_MAXNAMLEN;
1724 				if (fsp != NULL)
1725 					fsp->fs_maxname = tuint;
1726 				if (pc != NULL)
1727 					pc->pc_namemax = tuint;
1728 			}
1729 			attrsum += NFSX_UNSIGNED;
1730 			break;
1731 		case NFSATTRBIT_MAXREAD:
1732 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1733 			if (compare) {
1734 				if (!(*retcmpp)) {
1735 				    if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1736 					*(tl + 1)) || *tl != 0)
1737 					*retcmpp = NFSERR_NOTSAME;
1738 				}
1739 			} else if (fsp != NULL) {
1740 				fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1741 				fsp->fs_rtpref = fsp->fs_rtmax;
1742 				fsp->fs_dtpref = fsp->fs_rtpref;
1743 			}
1744 			attrsum += NFSX_HYPER;
1745 			break;
1746 		case NFSATTRBIT_MAXWRITE:
1747 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1748 			if (compare) {
1749 				if (!(*retcmpp)) {
1750 				    if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1751 					*(tl + 1)) || *tl != 0)
1752 					*retcmpp = NFSERR_NOTSAME;
1753 				}
1754 			} else if (fsp != NULL) {
1755 				fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1756 				fsp->fs_wtpref = fsp->fs_wtmax;
1757 			}
1758 			attrsum += NFSX_HYPER;
1759 			break;
1760 		case NFSATTRBIT_MIMETYPE:
1761 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1762 			i = fxdr_unsigned(int, *tl);
1763 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1764 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1765 			if (error)
1766 				goto nfsmout;
1767 			if (compare && !(*retcmpp))
1768 				*retcmpp = NFSERR_ATTRNOTSUPP;
1769 			break;
1770 		case NFSATTRBIT_MODE:
1771 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1772 			if (compare) {
1773 				if (!(*retcmpp)) {
1774 				    if (nap->na_mode != nfstov_mode(*tl))
1775 					*retcmpp = NFSERR_NOTSAME;
1776 				}
1777 			} else if (nap != NULL) {
1778 				nap->na_mode = nfstov_mode(*tl);
1779 			}
1780 			attrsum += NFSX_UNSIGNED;
1781 			break;
1782 		case NFSATTRBIT_NOTRUNC:
1783 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1784 			if (compare) {
1785 				if (!(*retcmpp)) {
1786 				    if (*tl != newnfs_true)
1787 					*retcmpp = NFSERR_NOTSAME;
1788 				}
1789 			} else if (pc != NULL) {
1790 				pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1791 			}
1792 			attrsum += NFSX_UNSIGNED;
1793 			break;
1794 		case NFSATTRBIT_NUMLINKS:
1795 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1796 			tuint = fxdr_unsigned(u_int32_t, *tl);
1797 			if (compare) {
1798 			    if (!(*retcmpp)) {
1799 				if ((u_int32_t)nap->na_nlink != tuint)
1800 					*retcmpp = NFSERR_NOTSAME;
1801 			    }
1802 			} else if (nap != NULL) {
1803 				nap->na_nlink = tuint;
1804 			}
1805 			attrsum += NFSX_UNSIGNED;
1806 			break;
1807 		case NFSATTRBIT_OWNER:
1808 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1809 			j = fxdr_unsigned(int, *tl);
1810 			if (j < 0) {
1811 				error = NFSERR_BADXDR;
1812 				goto nfsmout;
1813 			}
1814 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1815 			if (j > NFSV4_SMALLSTR)
1816 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1817 			else
1818 				cp = namestr;
1819 			error = nfsrv_mtostr(nd, cp, j);
1820 			if (error) {
1821 				if (j > NFSV4_SMALLSTR)
1822 					free(cp, M_NFSSTRING);
1823 				goto nfsmout;
1824 			}
1825 			if (compare) {
1826 			    if (!(*retcmpp)) {
1827 				if (nfsv4_strtouid(nd, cp, j, &uid) ||
1828 				    nap->na_uid != uid)
1829 				    *retcmpp = NFSERR_NOTSAME;
1830 			    }
1831 			} else if (nap != NULL) {
1832 				if (nfsv4_strtouid(nd, cp, j, &uid))
1833 					nap->na_uid = nfsrv_defaultuid;
1834 				else
1835 					nap->na_uid = uid;
1836 			}
1837 			if (j > NFSV4_SMALLSTR)
1838 				free(cp, M_NFSSTRING);
1839 			break;
1840 		case NFSATTRBIT_OWNERGROUP:
1841 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1842 			j = fxdr_unsigned(int, *tl);
1843 			if (j < 0) {
1844 				error =  NFSERR_BADXDR;
1845 				goto nfsmout;
1846 			}
1847 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1848 			if (j > NFSV4_SMALLSTR)
1849 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1850 			else
1851 				cp = namestr;
1852 			error = nfsrv_mtostr(nd, cp, j);
1853 			if (error) {
1854 				if (j > NFSV4_SMALLSTR)
1855 					free(cp, M_NFSSTRING);
1856 				goto nfsmout;
1857 			}
1858 			if (compare) {
1859 			    if (!(*retcmpp)) {
1860 				if (nfsv4_strtogid(nd, cp, j, &gid) ||
1861 				    nap->na_gid != gid)
1862 				    *retcmpp = NFSERR_NOTSAME;
1863 			    }
1864 			} else if (nap != NULL) {
1865 				if (nfsv4_strtogid(nd, cp, j, &gid))
1866 					nap->na_gid = nfsrv_defaultgid;
1867 				else
1868 					nap->na_gid = gid;
1869 			}
1870 			if (j > NFSV4_SMALLSTR)
1871 				free(cp, M_NFSSTRING);
1872 			break;
1873 		case NFSATTRBIT_QUOTAHARD:
1874 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1875 			if (sbp != NULL) {
1876 			    if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1877 				freenum = sbp->f_bfree;
1878 			    else
1879 				freenum = sbp->f_bavail;
1880 #ifdef QUOTA
1881 			    /*
1882 			     * ufs_quotactl() insists that the uid argument
1883 			     * equal p_ruid for non-root quota access, so
1884 			     * we'll just make sure that's the case.
1885 			     */
1886 			    savuid = p->p_cred->p_ruid;
1887 			    p->p_cred->p_ruid = cred->cr_uid;
1888 			    if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1889 				USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1890 				freenum = min(dqb.dqb_bhardlimit, freenum);
1891 			    p->p_cred->p_ruid = savuid;
1892 #endif	/* QUOTA */
1893 			    uquad = (u_int64_t)freenum;
1894 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1895 			}
1896 			if (compare && !(*retcmpp)) {
1897 				if (uquad != fxdr_hyper(tl))
1898 					*retcmpp = NFSERR_NOTSAME;
1899 			}
1900 			attrsum += NFSX_HYPER;
1901 			break;
1902 		case NFSATTRBIT_QUOTASOFT:
1903 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1904 			if (sbp != NULL) {
1905 			    if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
1906 				freenum = sbp->f_bfree;
1907 			    else
1908 				freenum = sbp->f_bavail;
1909 #ifdef QUOTA
1910 			    /*
1911 			     * ufs_quotactl() insists that the uid argument
1912 			     * equal p_ruid for non-root quota access, so
1913 			     * we'll just make sure that's the case.
1914 			     */
1915 			    savuid = p->p_cred->p_ruid;
1916 			    p->p_cred->p_ruid = cred->cr_uid;
1917 			    if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1918 				USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1919 				freenum = min(dqb.dqb_bsoftlimit, freenum);
1920 			    p->p_cred->p_ruid = savuid;
1921 #endif	/* QUOTA */
1922 			    uquad = (u_int64_t)freenum;
1923 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1924 			}
1925 			if (compare && !(*retcmpp)) {
1926 				if (uquad != fxdr_hyper(tl))
1927 					*retcmpp = NFSERR_NOTSAME;
1928 			}
1929 			attrsum += NFSX_HYPER;
1930 			break;
1931 		case NFSATTRBIT_QUOTAUSED:
1932 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1933 			if (sbp != NULL) {
1934 			    freenum = 0;
1935 #ifdef QUOTA
1936 			    /*
1937 			     * ufs_quotactl() insists that the uid argument
1938 			     * equal p_ruid for non-root quota access, so
1939 			     * we'll just make sure that's the case.
1940 			     */
1941 			    savuid = p->p_cred->p_ruid;
1942 			    p->p_cred->p_ruid = cred->cr_uid;
1943 			    if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1944 				USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1945 				freenum = dqb.dqb_curblocks;
1946 			    p->p_cred->p_ruid = savuid;
1947 #endif	/* QUOTA */
1948 			    uquad = (u_int64_t)freenum;
1949 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1950 			}
1951 			if (compare && !(*retcmpp)) {
1952 				if (uquad != fxdr_hyper(tl))
1953 					*retcmpp = NFSERR_NOTSAME;
1954 			}
1955 			attrsum += NFSX_HYPER;
1956 			break;
1957 		case NFSATTRBIT_RAWDEV:
1958 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1959 			j = fxdr_unsigned(int, *tl++);
1960 			k = fxdr_unsigned(int, *tl);
1961 			if (compare) {
1962 			    if (!(*retcmpp)) {
1963 				if (nap->na_rdev != NFSMAKEDEV(j, k))
1964 					*retcmpp = NFSERR_NOTSAME;
1965 			    }
1966 			} else if (nap != NULL) {
1967 				nap->na_rdev = NFSMAKEDEV(j, k);
1968 			}
1969 			attrsum += NFSX_V4SPECDATA;
1970 			break;
1971 		case NFSATTRBIT_SPACEAVAIL:
1972 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1973 			if (compare) {
1974 				if (!(*retcmpp) &&
1975 				    sfp->sf_abytes != fxdr_hyper(tl))
1976 					*retcmpp = NFSERR_NOTSAME;
1977 			} else if (sfp != NULL) {
1978 				sfp->sf_abytes = fxdr_hyper(tl);
1979 			}
1980 			attrsum += NFSX_HYPER;
1981 			break;
1982 		case NFSATTRBIT_SPACEFREE:
1983 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1984 			if (compare) {
1985 				if (!(*retcmpp) &&
1986 				    sfp->sf_fbytes != fxdr_hyper(tl))
1987 					*retcmpp = NFSERR_NOTSAME;
1988 			} else if (sfp != NULL) {
1989 				sfp->sf_fbytes = fxdr_hyper(tl);
1990 			}
1991 			attrsum += NFSX_HYPER;
1992 			break;
1993 		case NFSATTRBIT_SPACETOTAL:
1994 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1995 			if (compare) {
1996 				if (!(*retcmpp) &&
1997 				    sfp->sf_tbytes != fxdr_hyper(tl))
1998 					*retcmpp = NFSERR_NOTSAME;
1999 			} else if (sfp != NULL) {
2000 				sfp->sf_tbytes = fxdr_hyper(tl);
2001 			}
2002 			attrsum += NFSX_HYPER;
2003 			break;
2004 		case NFSATTRBIT_SPACEUSED:
2005 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2006 			thyp = fxdr_hyper(tl);
2007 			if (compare) {
2008 			    if (!(*retcmpp)) {
2009 				if ((u_int64_t)nap->na_bytes != thyp)
2010 					*retcmpp = NFSERR_NOTSAME;
2011 			    }
2012 			} else if (nap != NULL) {
2013 				nap->na_bytes = thyp;
2014 			}
2015 			attrsum += NFSX_HYPER;
2016 			break;
2017 		case NFSATTRBIT_SYSTEM:
2018 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2019 			if (compare && !(*retcmpp))
2020 				*retcmpp = NFSERR_ATTRNOTSUPP;
2021 			attrsum += NFSX_UNSIGNED;
2022 			break;
2023 		case NFSATTRBIT_TIMEACCESS:
2024 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2025 			fxdr_nfsv4time(tl, &temptime);
2026 			if (compare) {
2027 			    if (!(*retcmpp)) {
2028 				if (!NFS_CMPTIME(temptime, nap->na_atime))
2029 					*retcmpp = NFSERR_NOTSAME;
2030 			    }
2031 			} else if (nap != NULL) {
2032 				nap->na_atime = temptime;
2033 			}
2034 			attrsum += NFSX_V4TIME;
2035 			break;
2036 		case NFSATTRBIT_TIMEACCESSSET:
2037 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2038 			attrsum += NFSX_UNSIGNED;
2039 			i = fxdr_unsigned(int, *tl);
2040 			if (i == NFSV4SATTRTIME_TOCLIENT) {
2041 				NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2042 				attrsum += NFSX_V4TIME;
2043 			}
2044 			if (compare && !(*retcmpp))
2045 				*retcmpp = NFSERR_INVAL;
2046 			break;
2047 		case NFSATTRBIT_TIMEBACKUP:
2048 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2049 			if (compare && !(*retcmpp))
2050 				*retcmpp = NFSERR_ATTRNOTSUPP;
2051 			attrsum += NFSX_V4TIME;
2052 			break;
2053 		case NFSATTRBIT_TIMECREATE:
2054 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2055 			if (compare && !(*retcmpp))
2056 				*retcmpp = NFSERR_ATTRNOTSUPP;
2057 			attrsum += NFSX_V4TIME;
2058 			break;
2059 		case NFSATTRBIT_TIMEDELTA:
2060 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2061 			if (fsp != NULL) {
2062 			    if (compare) {
2063 				if (!(*retcmpp)) {
2064 				    if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
2065 					fxdr_unsigned(u_int32_t, *(tl + 1)) ||
2066 				        (u_int32_t)fsp->fs_timedelta.tv_nsec !=
2067 					(fxdr_unsigned(u_int32_t, *(tl + 2)) %
2068 					 1000000000) ||
2069 					*tl != 0)
2070 					    *retcmpp = NFSERR_NOTSAME;
2071 				}
2072 			    } else {
2073 				fxdr_nfsv4time(tl, &fsp->fs_timedelta);
2074 			    }
2075 			}
2076 			attrsum += NFSX_V4TIME;
2077 			break;
2078 		case NFSATTRBIT_TIMEMETADATA:
2079 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2080 			fxdr_nfsv4time(tl, &temptime);
2081 			if (compare) {
2082 			    if (!(*retcmpp)) {
2083 				if (!NFS_CMPTIME(temptime, nap->na_ctime))
2084 					*retcmpp = NFSERR_NOTSAME;
2085 			    }
2086 			} else if (nap != NULL) {
2087 				nap->na_ctime = temptime;
2088 			}
2089 			attrsum += NFSX_V4TIME;
2090 			break;
2091 		case NFSATTRBIT_TIMEMODIFY:
2092 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2093 			fxdr_nfsv4time(tl, &temptime);
2094 			if (compare) {
2095 			    if (!(*retcmpp)) {
2096 				if (!NFS_CMPTIME(temptime, nap->na_mtime))
2097 					*retcmpp = NFSERR_NOTSAME;
2098 			    }
2099 			} else if (nap != NULL) {
2100 				nap->na_mtime = temptime;
2101 			}
2102 			attrsum += NFSX_V4TIME;
2103 			break;
2104 		case NFSATTRBIT_TIMEMODIFYSET:
2105 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2106 			attrsum += NFSX_UNSIGNED;
2107 			i = fxdr_unsigned(int, *tl);
2108 			if (i == NFSV4SATTRTIME_TOCLIENT) {
2109 				NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2110 				attrsum += NFSX_V4TIME;
2111 			}
2112 			if (compare && !(*retcmpp))
2113 				*retcmpp = NFSERR_INVAL;
2114 			break;
2115 		case NFSATTRBIT_MOUNTEDONFILEID:
2116 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2117 			thyp = fxdr_hyper(tl);
2118 			if (compare) {
2119 				if (!(*retcmpp)) {
2120 					if (!vp || !nfsrv_atroot(vp, &thyp2))
2121 						thyp2 = nap->na_fileid;
2122 					if (thyp2 != thyp)
2123 						*retcmpp = NFSERR_NOTSAME;
2124 				}
2125 			} else if (nap != NULL)
2126 				nap->na_mntonfileno = thyp;
2127 			attrsum += NFSX_HYPER;
2128 			break;
2129 		case NFSATTRBIT_SUPPATTREXCLCREAT:
2130 			retnotsup = 0;
2131 			error = nfsrv_getattrbits(nd, &retattrbits,
2132 			    &cnt, &retnotsup);
2133 			if (error)
2134 			    goto nfsmout;
2135 			if (compare && !(*retcmpp)) {
2136 			   NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
2137 			   NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
2138 			   NFSCLRBIT_ATTRBIT(&checkattrbits,
2139 				NFSATTRBIT_TIMEACCESSSET);
2140 			   if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2141 			       || retnotsup)
2142 				*retcmpp = NFSERR_NOTSAME;
2143 			}
2144 			attrsum += cnt;
2145 			break;
2146 		case NFSATTRBIT_FSLAYOUTTYPE:
2147 		case NFSATTRBIT_LAYOUTTYPE:
2148 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2149 			attrsum += NFSX_UNSIGNED;
2150 			i = fxdr_unsigned(int, *tl);
2151 			if (i > 0) {
2152 				NFSM_DISSECT(tl, u_int32_t *, i *
2153 				    NFSX_UNSIGNED);
2154 				attrsum += i * NFSX_UNSIGNED;
2155 				j = fxdr_unsigned(int, *tl);
2156 				if (i == 1 && compare && !(*retcmpp) &&
2157 				    (((nfsrv_doflexfile != 0 ||
2158 				       nfsrv_maxpnfsmirror > 1) &&
2159 				      j != NFSLAYOUT_FLEXFILE) ||
2160 				    (nfsrv_doflexfile == 0 &&
2161 				     j != NFSLAYOUT_NFSV4_1_FILES)))
2162 					*retcmpp = NFSERR_NOTSAME;
2163 			}
2164 			if (nfsrv_devidcnt == 0) {
2165 				if (compare && !(*retcmpp) && i > 0)
2166 					*retcmpp = NFSERR_NOTSAME;
2167 			} else {
2168 				if (compare && !(*retcmpp) && i != 1)
2169 					*retcmpp = NFSERR_NOTSAME;
2170 			}
2171 			break;
2172 		case NFSATTRBIT_LAYOUTALIGNMENT:
2173 		case NFSATTRBIT_LAYOUTBLKSIZE:
2174 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2175 			attrsum += NFSX_UNSIGNED;
2176 			i = fxdr_unsigned(int, *tl);
2177 			if (compare && !(*retcmpp) && i != NFS_SRVMAXIO)
2178 				*retcmpp = NFSERR_NOTSAME;
2179 			break;
2180 		default:
2181 			printf("EEK! nfsv4_loadattr unknown attr=%d\n",
2182 				bitpos);
2183 			if (compare && !(*retcmpp))
2184 				*retcmpp = NFSERR_ATTRNOTSUPP;
2185 			/*
2186 			 * and get out of the loop, since we can't parse
2187 			 * the unknown attrbute data.
2188 			 */
2189 			bitpos = NFSATTRBIT_MAX;
2190 			break;
2191 		}
2192 	}
2193 
2194 	/*
2195 	 * some clients pad the attrlist, so we need to skip over the
2196 	 * padding.
2197 	 */
2198 	if (attrsum > attrsize) {
2199 		error = NFSERR_BADXDR;
2200 	} else {
2201 		attrsize = NFSM_RNDUP(attrsize);
2202 		if (attrsum < attrsize)
2203 			error = nfsm_advance(nd, attrsize - attrsum, -1);
2204 	}
2205 nfsmout:
2206 	NFSEXITCODE2(error, nd);
2207 	return (error);
2208 }
2209 
2210 /*
2211  * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
2212  * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
2213  * The first argument is a pointer to an nfsv4lock structure.
2214  * The second argument is 1 iff a blocking lock is wanted.
2215  * If this argument is 0, the call waits until no thread either wants nor
2216  * holds an exclusive lock.
2217  * It returns 1 if the lock was acquired, 0 otherwise.
2218  * If several processes call this function concurrently wanting the exclusive
2219  * lock, one will get the lock and the rest will return without getting the
2220  * lock. (If the caller must have the lock, it simply calls this function in a
2221  *  loop until the function returns 1 to indicate the lock was acquired.)
2222  * Any usecnt must be decremented by calling nfsv4_relref() before
2223  * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
2224  * be called in a loop.
2225  * The isleptp argument is set to indicate if the call slept, iff not NULL
2226  * and the mp argument indicates to check for a forced dismount, iff not
2227  * NULL.
2228  */
2229 APPLESTATIC int
2230 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
2231     void *mutex, struct mount *mp)
2232 {
2233 
2234 	if (isleptp)
2235 		*isleptp = 0;
2236 	/*
2237 	 * If a lock is wanted, loop around until the lock is acquired by
2238 	 * someone and then released. If I want the lock, try to acquire it.
2239 	 * For a lock to be issued, no lock must be in force and the usecnt
2240 	 * must be zero.
2241 	 */
2242 	if (iwantlock) {
2243 	    if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2244 		lp->nfslock_usecnt == 0) {
2245 		lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2246 		lp->nfslock_lock |= NFSV4LOCK_LOCK;
2247 		return (1);
2248 	    }
2249 	    lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
2250 	}
2251 	while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
2252 		if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2253 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2254 			return (0);
2255 		}
2256 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
2257 		if (isleptp)
2258 			*isleptp = 1;
2259 		(void) nfsmsleep(&lp->nfslock_lock, mutex,
2260 		    PZERO - 1, "nfsv4lck", NULL);
2261 		if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2262 		    lp->nfslock_usecnt == 0) {
2263 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2264 			lp->nfslock_lock |= NFSV4LOCK_LOCK;
2265 			return (1);
2266 		}
2267 	}
2268 	return (0);
2269 }
2270 
2271 /*
2272  * Release the lock acquired by nfsv4_lock().
2273  * The second argument is set to 1 to indicate the nfslock_usecnt should be
2274  * incremented, as well.
2275  */
2276 APPLESTATIC void
2277 nfsv4_unlock(struct nfsv4lock *lp, int incref)
2278 {
2279 
2280 	lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
2281 	if (incref)
2282 		lp->nfslock_usecnt++;
2283 	nfsv4_wanted(lp);
2284 }
2285 
2286 /*
2287  * Release a reference cnt.
2288  */
2289 APPLESTATIC void
2290 nfsv4_relref(struct nfsv4lock *lp)
2291 {
2292 
2293 	if (lp->nfslock_usecnt <= 0)
2294 		panic("nfsv4root ref cnt");
2295 	lp->nfslock_usecnt--;
2296 	if (lp->nfslock_usecnt == 0)
2297 		nfsv4_wanted(lp);
2298 }
2299 
2300 /*
2301  * Get a reference cnt.
2302  * This function will wait for any exclusive lock to be released, but will
2303  * not wait for threads that want the exclusive lock. If priority needs
2304  * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
2305  * with the 2nd argument == 0 should be done before calling nfsv4_getref().
2306  * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2307  * return without getting a refcnt for that case.
2308  */
2309 APPLESTATIC void
2310 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
2311     struct mount *mp)
2312 {
2313 
2314 	if (isleptp)
2315 		*isleptp = 0;
2316 
2317 	/*
2318 	 * Wait for a lock held.
2319 	 */
2320 	while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
2321 		if (mp != NULL && NFSCL_FORCEDISM(mp))
2322 			return;
2323 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
2324 		if (isleptp)
2325 			*isleptp = 1;
2326 		(void) nfsmsleep(&lp->nfslock_lock, mutex,
2327 		    PZERO - 1, "nfsv4gr", NULL);
2328 	}
2329 	if (mp != NULL && NFSCL_FORCEDISM(mp))
2330 		return;
2331 
2332 	lp->nfslock_usecnt++;
2333 }
2334 
2335 /*
2336  * Get a reference as above, but return failure instead of sleeping if
2337  * an exclusive lock is held.
2338  */
2339 APPLESTATIC int
2340 nfsv4_getref_nonblock(struct nfsv4lock *lp)
2341 {
2342 
2343 	if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
2344 		return (0);
2345 
2346 	lp->nfslock_usecnt++;
2347 	return (1);
2348 }
2349 
2350 /*
2351  * Test for a lock. Return 1 if locked, 0 otherwise.
2352  */
2353 APPLESTATIC int
2354 nfsv4_testlock(struct nfsv4lock *lp)
2355 {
2356 
2357 	if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2358 	    lp->nfslock_usecnt == 0)
2359 		return (0);
2360 	return (1);
2361 }
2362 
2363 /*
2364  * Wake up anyone sleeping, waiting for this lock.
2365  */
2366 static void
2367 nfsv4_wanted(struct nfsv4lock *lp)
2368 {
2369 
2370 	if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
2371 		lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
2372 		wakeup((caddr_t)&lp->nfslock_lock);
2373 	}
2374 }
2375 
2376 /*
2377  * Copy a string from an mbuf list into a character array.
2378  * Return EBADRPC if there is an mbuf error,
2379  * 0 otherwise.
2380  */
2381 APPLESTATIC int
2382 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2383 {
2384 	char *cp;
2385 	int xfer, len;
2386 	mbuf_t mp;
2387 	int rem, error = 0;
2388 
2389 	mp = nd->nd_md;
2390 	cp = nd->nd_dpos;
2391 	len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
2392 	rem = NFSM_RNDUP(siz) - siz;
2393 	while (siz > 0) {
2394 		if (len > siz)
2395 			xfer = siz;
2396 		else
2397 			xfer = len;
2398 		NFSBCOPY(cp, str, xfer);
2399 		str += xfer;
2400 		siz -= xfer;
2401 		if (siz > 0) {
2402 			mp = mbuf_next(mp);
2403 			if (mp == NULL) {
2404 				error = EBADRPC;
2405 				goto out;
2406 			}
2407 			cp = NFSMTOD(mp, caddr_t);
2408 			len = mbuf_len(mp);
2409 		} else {
2410 			cp += xfer;
2411 			len -= xfer;
2412 		}
2413 	}
2414 	*str = '\0';
2415 	nd->nd_dpos = cp;
2416 	nd->nd_md = mp;
2417 	if (rem > 0) {
2418 		if (len < rem)
2419 			error = nfsm_advance(nd, rem, len);
2420 		else
2421 			nd->nd_dpos += rem;
2422 	}
2423 
2424 out:
2425 	NFSEXITCODE2(error, nd);
2426 	return (error);
2427 }
2428 
2429 /*
2430  * Fill in the attributes as marked by the bitmap (V4).
2431  */
2432 APPLESTATIC int
2433 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2434     NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2435     nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2436     int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
2437     struct statfs *pnfssf)
2438 {
2439 	int bitpos, retnum = 0;
2440 	u_int32_t *tl;
2441 	int siz, prefixnum, error;
2442 	u_char *cp, namestr[NFSV4_SMALLSTR];
2443 	nfsattrbit_t attrbits, retbits;
2444 	nfsattrbit_t *retbitp = &retbits;
2445 	u_int32_t freenum, *retnump;
2446 	u_int64_t uquad;
2447 	struct statfs *fs;
2448 	struct nfsfsinfo fsinf;
2449 	struct timespec temptime;
2450 	NFSACL_T *aclp, *naclp = NULL;
2451 #ifdef QUOTA
2452 	struct dqblk dqb;
2453 	uid_t savuid;
2454 #endif
2455 
2456 	/*
2457 	 * First, set the bits that can be filled and get fsinfo.
2458 	 */
2459 	NFSSET_ATTRBIT(retbitp, attrbitp);
2460 	/*
2461 	 * If both p and cred are NULL, it is a client side setattr call.
2462 	 * If both p and cred are not NULL, it is a server side reply call.
2463 	 * If p is not NULL and cred is NULL, it is a client side callback
2464 	 * reply call.
2465 	 */
2466 	if (p == NULL && cred == NULL) {
2467 		NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
2468 		aclp = saclp;
2469 	} else {
2470 		NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
2471 		naclp = acl_alloc(M_WAITOK);
2472 		aclp = naclp;
2473 	}
2474 	nfsvno_getfs(&fsinf, isdgram);
2475 #ifndef APPLE
2476 	/*
2477 	 * Get the VFS_STATFS(), since some attributes need them.
2478 	 */
2479 	fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2480 	if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2481 		error = VFS_STATFS(mp, fs);
2482 		if (error != 0) {
2483 			if (reterr) {
2484 				nd->nd_repstat = NFSERR_ACCES;
2485 				free(fs, M_STATFS);
2486 				return (0);
2487 			}
2488 			NFSCLRSTATFS_ATTRBIT(retbitp);
2489 		}
2490 	}
2491 #endif
2492 
2493 	/*
2494 	 * And the NFSv4 ACL...
2495 	 */
2496 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2497 	    (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2498 		supports_nfsv4acls == 0))) {
2499 		NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2500 	}
2501 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2502 		if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2503 		    supports_nfsv4acls == 0)) {
2504 			NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2505 		} else if (naclp != NULL) {
2506 			if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2507 				error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2508 				if (error == 0)
2509 					error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2510 					    naclp, cred, p);
2511 				NFSVOPUNLOCK(vp, 0);
2512 			} else
2513 				error = NFSERR_PERM;
2514 			if (error != 0) {
2515 				if (reterr) {
2516 					nd->nd_repstat = NFSERR_ACCES;
2517 					free(fs, M_STATFS);
2518 					return (0);
2519 				}
2520 				NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2521 			}
2522 		}
2523 	}
2524 
2525 	/*
2526 	 * Put out the attribute bitmap for the ones being filled in
2527 	 * and get the field for the number of attributes returned.
2528 	 */
2529 	prefixnum = nfsrv_putattrbit(nd, retbitp);
2530 	NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2531 	prefixnum += NFSX_UNSIGNED;
2532 
2533 	/*
2534 	 * Now, loop around filling in the attributes for each bit set.
2535 	 */
2536 	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2537 	    if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2538 		switch (bitpos) {
2539 		case NFSATTRBIT_SUPPORTEDATTRS:
2540 			NFSSETSUPP_ATTRBIT(&attrbits, nd);
2541 			if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2542 			    && supports_nfsv4acls == 0)) {
2543 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2544 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2545 			}
2546 			retnum += nfsrv_putattrbit(nd, &attrbits);
2547 			break;
2548 		case NFSATTRBIT_TYPE:
2549 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2550 			*tl = vtonfsv34_type(vap->va_type);
2551 			retnum += NFSX_UNSIGNED;
2552 			break;
2553 		case NFSATTRBIT_FHEXPIRETYPE:
2554 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2555 			*tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2556 			retnum += NFSX_UNSIGNED;
2557 			break;
2558 		case NFSATTRBIT_CHANGE:
2559 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2560 			txdr_hyper(vap->va_filerev, tl);
2561 			retnum += NFSX_HYPER;
2562 			break;
2563 		case NFSATTRBIT_SIZE:
2564 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2565 			txdr_hyper(vap->va_size, tl);
2566 			retnum += NFSX_HYPER;
2567 			break;
2568 		case NFSATTRBIT_LINKSUPPORT:
2569 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2570 			if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2571 				*tl = newnfs_true;
2572 			else
2573 				*tl = newnfs_false;
2574 			retnum += NFSX_UNSIGNED;
2575 			break;
2576 		case NFSATTRBIT_SYMLINKSUPPORT:
2577 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2578 			if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2579 				*tl = newnfs_true;
2580 			else
2581 				*tl = newnfs_false;
2582 			retnum += NFSX_UNSIGNED;
2583 			break;
2584 		case NFSATTRBIT_NAMEDATTR:
2585 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2586 			*tl = newnfs_false;
2587 			retnum += NFSX_UNSIGNED;
2588 			break;
2589 		case NFSATTRBIT_FSID:
2590 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2591 			*tl++ = 0;
2592 			*tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2593 			*tl++ = 0;
2594 			*tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2595 			retnum += NFSX_V4FSID;
2596 			break;
2597 		case NFSATTRBIT_UNIQUEHANDLES:
2598 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2599 			*tl = newnfs_true;
2600 			retnum += NFSX_UNSIGNED;
2601 			break;
2602 		case NFSATTRBIT_LEASETIME:
2603 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2604 			*tl = txdr_unsigned(nfsrv_lease);
2605 			retnum += NFSX_UNSIGNED;
2606 			break;
2607 		case NFSATTRBIT_RDATTRERROR:
2608 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2609 			*tl = txdr_unsigned(rderror);
2610 			retnum += NFSX_UNSIGNED;
2611 			break;
2612 		/*
2613 		 * Recommended Attributes. (Only the supported ones.)
2614 		 */
2615 		case NFSATTRBIT_ACL:
2616 			retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2617 			break;
2618 		case NFSATTRBIT_ACLSUPPORT:
2619 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2620 			*tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2621 			retnum += NFSX_UNSIGNED;
2622 			break;
2623 		case NFSATTRBIT_CANSETTIME:
2624 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2625 			if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2626 				*tl = newnfs_true;
2627 			else
2628 				*tl = newnfs_false;
2629 			retnum += NFSX_UNSIGNED;
2630 			break;
2631 		case NFSATTRBIT_CASEINSENSITIVE:
2632 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2633 			*tl = newnfs_false;
2634 			retnum += NFSX_UNSIGNED;
2635 			break;
2636 		case NFSATTRBIT_CASEPRESERVING:
2637 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2638 			*tl = newnfs_true;
2639 			retnum += NFSX_UNSIGNED;
2640 			break;
2641 		case NFSATTRBIT_CHOWNRESTRICTED:
2642 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2643 			*tl = newnfs_true;
2644 			retnum += NFSX_UNSIGNED;
2645 			break;
2646 		case NFSATTRBIT_FILEHANDLE:
2647 			retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2648 			break;
2649 		case NFSATTRBIT_FILEID:
2650 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2651 			uquad = vap->va_fileid;
2652 			txdr_hyper(uquad, tl);
2653 			retnum += NFSX_HYPER;
2654 			break;
2655 		case NFSATTRBIT_FILESAVAIL:
2656 			/*
2657 			 * Check quota and use min(quota, f_ffree).
2658 			 */
2659 			freenum = fs->f_ffree;
2660 #ifdef QUOTA
2661 			/*
2662 			 * ufs_quotactl() insists that the uid argument
2663 			 * equal p_ruid for non-root quota access, so
2664 			 * we'll just make sure that's the case.
2665 			 */
2666 			savuid = p->p_cred->p_ruid;
2667 			p->p_cred->p_ruid = cred->cr_uid;
2668 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2669 			    cred->cr_uid, (caddr_t)&dqb))
2670 			    freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2671 				freenum);
2672 			p->p_cred->p_ruid = savuid;
2673 #endif	/* QUOTA */
2674 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2675 			*tl++ = 0;
2676 			*tl = txdr_unsigned(freenum);
2677 			retnum += NFSX_HYPER;
2678 			break;
2679 		case NFSATTRBIT_FILESFREE:
2680 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2681 			*tl++ = 0;
2682 			*tl = txdr_unsigned(fs->f_ffree);
2683 			retnum += NFSX_HYPER;
2684 			break;
2685 		case NFSATTRBIT_FILESTOTAL:
2686 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2687 			*tl++ = 0;
2688 			*tl = txdr_unsigned(fs->f_files);
2689 			retnum += NFSX_HYPER;
2690 			break;
2691 		case NFSATTRBIT_FSLOCATIONS:
2692 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2693 			*tl++ = 0;
2694 			*tl = 0;
2695 			retnum += 2 * NFSX_UNSIGNED;
2696 			break;
2697 		case NFSATTRBIT_HOMOGENEOUS:
2698 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2699 			if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2700 				*tl = newnfs_true;
2701 			else
2702 				*tl = newnfs_false;
2703 			retnum += NFSX_UNSIGNED;
2704 			break;
2705 		case NFSATTRBIT_MAXFILESIZE:
2706 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2707 			uquad = NFSRV_MAXFILESIZE;
2708 			txdr_hyper(uquad, tl);
2709 			retnum += NFSX_HYPER;
2710 			break;
2711 		case NFSATTRBIT_MAXLINK:
2712 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2713 			*tl = txdr_unsigned(NFS_LINK_MAX);
2714 			retnum += NFSX_UNSIGNED;
2715 			break;
2716 		case NFSATTRBIT_MAXNAME:
2717 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2718 			*tl = txdr_unsigned(NFS_MAXNAMLEN);
2719 			retnum += NFSX_UNSIGNED;
2720 			break;
2721 		case NFSATTRBIT_MAXREAD:
2722 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2723 			*tl++ = 0;
2724 			*tl = txdr_unsigned(fsinf.fs_rtmax);
2725 			retnum += NFSX_HYPER;
2726 			break;
2727 		case NFSATTRBIT_MAXWRITE:
2728 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2729 			*tl++ = 0;
2730 			*tl = txdr_unsigned(fsinf.fs_wtmax);
2731 			retnum += NFSX_HYPER;
2732 			break;
2733 		case NFSATTRBIT_MODE:
2734 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2735 			*tl = vtonfsv34_mode(vap->va_mode);
2736 			retnum += NFSX_UNSIGNED;
2737 			break;
2738 		case NFSATTRBIT_NOTRUNC:
2739 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2740 			*tl = newnfs_true;
2741 			retnum += NFSX_UNSIGNED;
2742 			break;
2743 		case NFSATTRBIT_NUMLINKS:
2744 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2745 			*tl = txdr_unsigned(vap->va_nlink);
2746 			retnum += NFSX_UNSIGNED;
2747 			break;
2748 		case NFSATTRBIT_OWNER:
2749 			cp = namestr;
2750 			nfsv4_uidtostr(vap->va_uid, &cp, &siz);
2751 			retnum += nfsm_strtom(nd, cp, siz);
2752 			if (cp != namestr)
2753 				free(cp, M_NFSSTRING);
2754 			break;
2755 		case NFSATTRBIT_OWNERGROUP:
2756 			cp = namestr;
2757 			nfsv4_gidtostr(vap->va_gid, &cp, &siz);
2758 			retnum += nfsm_strtom(nd, cp, siz);
2759 			if (cp != namestr)
2760 				free(cp, M_NFSSTRING);
2761 			break;
2762 		case NFSATTRBIT_QUOTAHARD:
2763 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2764 				freenum = fs->f_bfree;
2765 			else
2766 				freenum = fs->f_bavail;
2767 #ifdef QUOTA
2768 			/*
2769 			 * ufs_quotactl() insists that the uid argument
2770 			 * equal p_ruid for non-root quota access, so
2771 			 * we'll just make sure that's the case.
2772 			 */
2773 			savuid = p->p_cred->p_ruid;
2774 			p->p_cred->p_ruid = cred->cr_uid;
2775 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2776 			    cred->cr_uid, (caddr_t)&dqb))
2777 			    freenum = min(dqb.dqb_bhardlimit, freenum);
2778 			p->p_cred->p_ruid = savuid;
2779 #endif	/* QUOTA */
2780 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2781 			uquad = (u_int64_t)freenum;
2782 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2783 			txdr_hyper(uquad, tl);
2784 			retnum += NFSX_HYPER;
2785 			break;
2786 		case NFSATTRBIT_QUOTASOFT:
2787 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2788 				freenum = fs->f_bfree;
2789 			else
2790 				freenum = fs->f_bavail;
2791 #ifdef QUOTA
2792 			/*
2793 			 * ufs_quotactl() insists that the uid argument
2794 			 * equal p_ruid for non-root quota access, so
2795 			 * we'll just make sure that's the case.
2796 			 */
2797 			savuid = p->p_cred->p_ruid;
2798 			p->p_cred->p_ruid = cred->cr_uid;
2799 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2800 			    cred->cr_uid, (caddr_t)&dqb))
2801 			    freenum = min(dqb.dqb_bsoftlimit, freenum);
2802 			p->p_cred->p_ruid = savuid;
2803 #endif	/* QUOTA */
2804 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2805 			uquad = (u_int64_t)freenum;
2806 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2807 			txdr_hyper(uquad, tl);
2808 			retnum += NFSX_HYPER;
2809 			break;
2810 		case NFSATTRBIT_QUOTAUSED:
2811 			freenum = 0;
2812 #ifdef QUOTA
2813 			/*
2814 			 * ufs_quotactl() insists that the uid argument
2815 			 * equal p_ruid for non-root quota access, so
2816 			 * we'll just make sure that's the case.
2817 			 */
2818 			savuid = p->p_cred->p_ruid;
2819 			p->p_cred->p_ruid = cred->cr_uid;
2820 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2821 			    cred->cr_uid, (caddr_t)&dqb))
2822 			    freenum = dqb.dqb_curblocks;
2823 			p->p_cred->p_ruid = savuid;
2824 #endif	/* QUOTA */
2825 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2826 			uquad = (u_int64_t)freenum;
2827 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
2828 			txdr_hyper(uquad, tl);
2829 			retnum += NFSX_HYPER;
2830 			break;
2831 		case NFSATTRBIT_RAWDEV:
2832 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2833 			*tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2834 			*tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2835 			retnum += NFSX_V4SPECDATA;
2836 			break;
2837 		case NFSATTRBIT_SPACEAVAIL:
2838 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2839 			if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE)) {
2840 				if (pnfssf != NULL)
2841 					uquad = (u_int64_t)pnfssf->f_bfree;
2842 				else
2843 					uquad = (u_int64_t)fs->f_bfree;
2844 			} else {
2845 				if (pnfssf != NULL)
2846 					uquad = (u_int64_t)pnfssf->f_bavail;
2847 				else
2848 					uquad = (u_int64_t)fs->f_bavail;
2849 			}
2850 			if (pnfssf != NULL)
2851 				uquad *= pnfssf->f_bsize;
2852 			else
2853 				uquad *= fs->f_bsize;
2854 			txdr_hyper(uquad, tl);
2855 			retnum += NFSX_HYPER;
2856 			break;
2857 		case NFSATTRBIT_SPACEFREE:
2858 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2859 			if (pnfssf != NULL) {
2860 				uquad = (u_int64_t)pnfssf->f_bfree;
2861 				uquad *= pnfssf->f_bsize;
2862 			} else {
2863 				uquad = (u_int64_t)fs->f_bfree;
2864 				uquad *= fs->f_bsize;
2865 			}
2866 			txdr_hyper(uquad, tl);
2867 			retnum += NFSX_HYPER;
2868 			break;
2869 		case NFSATTRBIT_SPACETOTAL:
2870 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2871 			if (pnfssf != NULL) {
2872 				uquad = (u_int64_t)pnfssf->f_blocks;
2873 				uquad *= pnfssf->f_bsize;
2874 			} else {
2875 				uquad = (u_int64_t)fs->f_blocks;
2876 				uquad *= fs->f_bsize;
2877 			}
2878 			txdr_hyper(uquad, tl);
2879 			retnum += NFSX_HYPER;
2880 			break;
2881 		case NFSATTRBIT_SPACEUSED:
2882 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2883 			txdr_hyper(vap->va_bytes, tl);
2884 			retnum += NFSX_HYPER;
2885 			break;
2886 		case NFSATTRBIT_TIMEACCESS:
2887 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2888 			txdr_nfsv4time(&vap->va_atime, tl);
2889 			retnum += NFSX_V4TIME;
2890 			break;
2891 		case NFSATTRBIT_TIMEACCESSSET:
2892 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2893 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2894 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2895 				txdr_nfsv4time(&vap->va_atime, tl);
2896 				retnum += NFSX_V4SETTIME;
2897 			} else {
2898 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2899 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2900 				retnum += NFSX_UNSIGNED;
2901 			}
2902 			break;
2903 		case NFSATTRBIT_TIMEDELTA:
2904 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2905 			temptime.tv_sec = 0;
2906 			temptime.tv_nsec = 1000000000 / hz;
2907 			txdr_nfsv4time(&temptime, tl);
2908 			retnum += NFSX_V4TIME;
2909 			break;
2910 		case NFSATTRBIT_TIMEMETADATA:
2911 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2912 			txdr_nfsv4time(&vap->va_ctime, tl);
2913 			retnum += NFSX_V4TIME;
2914 			break;
2915 		case NFSATTRBIT_TIMEMODIFY:
2916 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2917 			txdr_nfsv4time(&vap->va_mtime, tl);
2918 			retnum += NFSX_V4TIME;
2919 			break;
2920 		case NFSATTRBIT_TIMEMODIFYSET:
2921 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2922 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2923 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2924 				txdr_nfsv4time(&vap->va_mtime, tl);
2925 				retnum += NFSX_V4SETTIME;
2926 			} else {
2927 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2928 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2929 				retnum += NFSX_UNSIGNED;
2930 			}
2931 			break;
2932 		case NFSATTRBIT_MOUNTEDONFILEID:
2933 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2934 			if (at_root != 0)
2935 				uquad = mounted_on_fileno;
2936 			else
2937 				uquad = vap->va_fileid;
2938 			txdr_hyper(uquad, tl);
2939 			retnum += NFSX_HYPER;
2940 			break;
2941 		case NFSATTRBIT_SUPPATTREXCLCREAT:
2942 			NFSSETSUPP_ATTRBIT(&attrbits, nd);
2943 			NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd);
2944 			NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
2945 			retnum += nfsrv_putattrbit(nd, &attrbits);
2946 			break;
2947 		case NFSATTRBIT_FSLAYOUTTYPE:
2948 		case NFSATTRBIT_LAYOUTTYPE:
2949 			if (nfsrv_devidcnt == 0)
2950 				siz = 1;
2951 			else
2952 				siz = 2;
2953 			if (siz == 2) {
2954 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2955 				*tl++ = txdr_unsigned(1);	/* One entry. */
2956 				if (nfsrv_doflexfile != 0 ||
2957 				    nfsrv_maxpnfsmirror > 1)
2958 					*tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
2959 				else
2960 					*tl = txdr_unsigned(
2961 					    NFSLAYOUT_NFSV4_1_FILES);
2962 			} else {
2963 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2964 				*tl = 0;
2965 			}
2966 			retnum += siz * NFSX_UNSIGNED;
2967 			break;
2968 		case NFSATTRBIT_LAYOUTALIGNMENT:
2969 		case NFSATTRBIT_LAYOUTBLKSIZE:
2970 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2971 			*tl = txdr_unsigned(NFS_SRVMAXIO);
2972 			retnum += NFSX_UNSIGNED;
2973 			break;
2974 		default:
2975 			printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2976 		}
2977 	    }
2978 	}
2979 	if (naclp != NULL)
2980 		acl_free(naclp);
2981 	free(fs, M_STATFS);
2982 	*retnump = txdr_unsigned(retnum);
2983 	return (retnum + prefixnum);
2984 }
2985 
2986 /*
2987  * Put the attribute bits onto an mbuf list.
2988  * Return the number of bytes of output generated.
2989  */
2990 APPLESTATIC int
2991 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2992 {
2993 	u_int32_t *tl;
2994 	int cnt, i, bytesize;
2995 
2996 	for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2997 		if (attrbitp->bits[cnt - 1])
2998 			break;
2999 	bytesize = (cnt + 1) * NFSX_UNSIGNED;
3000 	NFSM_BUILD(tl, u_int32_t *, bytesize);
3001 	*tl++ = txdr_unsigned(cnt);
3002 	for (i = 0; i < cnt; i++)
3003 		*tl++ = txdr_unsigned(attrbitp->bits[i]);
3004 	return (bytesize);
3005 }
3006 
3007 /*
3008  * Convert a uid to a string.
3009  * If the lookup fails, just output the digits.
3010  * uid - the user id
3011  * cpp - points to a buffer of size NFSV4_SMALLSTR
3012  *       (malloc a larger one, as required)
3013  * retlenp - pointer to length to be returned
3014  */
3015 APPLESTATIC void
3016 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp)
3017 {
3018 	int i;
3019 	struct nfsusrgrp *usrp;
3020 	u_char *cp = *cpp;
3021 	uid_t tmp;
3022 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3023 	struct nfsrv_lughash *hp;
3024 
3025 	cnt = 0;
3026 tryagain:
3027 	if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3028 		/*
3029 		 * Always map nfsrv_defaultuid to "nobody".
3030 		 */
3031 		if (uid == nfsrv_defaultuid) {
3032 			i = nfsrv_dnsnamelen + 7;
3033 			if (i > len) {
3034 				if (len > NFSV4_SMALLSTR)
3035 					free(cp, M_NFSSTRING);
3036 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
3037 				*cpp = cp;
3038 				len = i;
3039 				goto tryagain;
3040 			}
3041 			*retlenp = i;
3042 			NFSBCOPY("nobody@", cp, 7);
3043 			cp += 7;
3044 			NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3045 			return;
3046 		}
3047 		hasampersand = 0;
3048 		hp = NFSUSERHASH(uid);
3049 		mtx_lock(&hp->mtx);
3050 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3051 			if (usrp->lug_uid == uid) {
3052 				if (usrp->lug_expiry < NFSD_MONOSEC)
3053 					break;
3054 				/*
3055 				 * If the name doesn't already have an '@'
3056 				 * in it, append @domainname to it.
3057 				 */
3058 				for (i = 0; i < usrp->lug_namelen; i++) {
3059 					if (usrp->lug_name[i] == '@') {
3060 						hasampersand = 1;
3061 						break;
3062 					}
3063 				}
3064 				if (hasampersand)
3065 					i = usrp->lug_namelen;
3066 				else
3067 					i = usrp->lug_namelen +
3068 					    nfsrv_dnsnamelen + 1;
3069 				if (i > len) {
3070 					mtx_unlock(&hp->mtx);
3071 					if (len > NFSV4_SMALLSTR)
3072 						free(cp, M_NFSSTRING);
3073 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
3074 					*cpp = cp;
3075 					len = i;
3076 					goto tryagain;
3077 				}
3078 				*retlenp = i;
3079 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3080 				if (!hasampersand) {
3081 					cp += usrp->lug_namelen;
3082 					*cp++ = '@';
3083 					NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3084 				}
3085 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3086 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3087 				    lug_numhash);
3088 				mtx_unlock(&hp->mtx);
3089 				return;
3090 			}
3091 		}
3092 		mtx_unlock(&hp->mtx);
3093 		cnt++;
3094 		ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3095 		if (ret == 0 && cnt < 2)
3096 			goto tryagain;
3097 	}
3098 
3099 	/*
3100 	 * No match, just return a string of digits.
3101 	 */
3102 	tmp = uid;
3103 	i = 0;
3104 	while (tmp || i == 0) {
3105 		tmp /= 10;
3106 		i++;
3107 	}
3108 	len = (i > len) ? len : i;
3109 	*retlenp = len;
3110 	cp += (len - 1);
3111 	tmp = uid;
3112 	for (i = 0; i < len; i++) {
3113 		*cp-- = '0' + (tmp % 10);
3114 		tmp /= 10;
3115 	}
3116 	return;
3117 }
3118 
3119 /*
3120  * Get a credential for the uid with the server's group list.
3121  * If none is found, just return the credential passed in after
3122  * logging a warning message.
3123  */
3124 struct ucred *
3125 nfsrv_getgrpscred(struct ucred *oldcred)
3126 {
3127 	struct nfsusrgrp *usrp;
3128 	struct ucred *newcred;
3129 	int cnt, ret;
3130 	uid_t uid;
3131 	struct nfsrv_lughash *hp;
3132 
3133 	cnt = 0;
3134 	uid = oldcred->cr_uid;
3135 tryagain:
3136 	if (nfsrv_dnsnamelen > 0) {
3137 		hp = NFSUSERHASH(uid);
3138 		mtx_lock(&hp->mtx);
3139 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3140 			if (usrp->lug_uid == uid) {
3141 				if (usrp->lug_expiry < NFSD_MONOSEC)
3142 					break;
3143 				if (usrp->lug_cred != NULL) {
3144 					newcred = crhold(usrp->lug_cred);
3145 					crfree(oldcred);
3146 				} else
3147 					newcred = oldcred;
3148 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3149 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3150 				    lug_numhash);
3151 				mtx_unlock(&hp->mtx);
3152 				return (newcred);
3153 			}
3154 		}
3155 		mtx_unlock(&hp->mtx);
3156 		cnt++;
3157 		ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3158 		if (ret == 0 && cnt < 2)
3159 			goto tryagain;
3160 	}
3161 	return (oldcred);
3162 }
3163 
3164 /*
3165  * Convert a string to a uid.
3166  * If no conversion is possible return NFSERR_BADOWNER, otherwise
3167  * return 0.
3168  * If this is called from a client side mount using AUTH_SYS and the
3169  * string is made up entirely of digits, just convert the string to
3170  * a number.
3171  */
3172 APPLESTATIC int
3173 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
3174 {
3175 	int i;
3176 	char *cp, *endstr, *str0;
3177 	struct nfsusrgrp *usrp;
3178 	int cnt, ret;
3179 	int error = 0;
3180 	uid_t tuid;
3181 	struct nfsrv_lughash *hp, *hp2;
3182 
3183 	if (len == 0) {
3184 		error = NFSERR_BADOWNER;
3185 		goto out;
3186 	}
3187 	/* If a string of digits and an AUTH_SYS mount, just convert it. */
3188 	str0 = str;
3189 	tuid = (uid_t)strtoul(str0, &endstr, 10);
3190 	if ((endstr - str0) == len) {
3191 		/* A numeric string. */
3192 		if ((nd->nd_flag & ND_KERBV) == 0 &&
3193 		    ((nd->nd_flag & ND_NFSCL) != 0 ||
3194 		      nfsd_enable_stringtouid != 0))
3195 			*uidp = tuid;
3196 		else
3197 			error = NFSERR_BADOWNER;
3198 		goto out;
3199 	}
3200 	/*
3201 	 * Look for an '@'.
3202 	 */
3203 	cp = strchr(str0, '@');
3204 	if (cp != NULL)
3205 		i = (int)(cp++ - str0);
3206 	else
3207 		i = len;
3208 
3209 	cnt = 0;
3210 tryagain:
3211 	if (nfsrv_dnsnamelen > 0) {
3212 		/*
3213 		 * If an '@' is found and the domain name matches, search for
3214 		 * the name with dns stripped off.
3215 		 * Mixed case alpahbetics will match for the domain name, but
3216 		 * all upper case will not.
3217 		 */
3218 		if (cnt == 0 && i < len && i > 0 &&
3219 		    (len - 1 - i) == nfsrv_dnsnamelen &&
3220 		    !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3221 			len -= (nfsrv_dnsnamelen + 1);
3222 			*(cp - 1) = '\0';
3223 		}
3224 
3225 		/*
3226 		 * Check for the special case of "nobody".
3227 		 */
3228 		if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
3229 			*uidp = nfsrv_defaultuid;
3230 			error = 0;
3231 			goto out;
3232 		}
3233 
3234 		hp = NFSUSERNAMEHASH(str, len);
3235 		mtx_lock(&hp->mtx);
3236 		TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3237 			if (usrp->lug_namelen == len &&
3238 			    !NFSBCMP(usrp->lug_name, str, len)) {
3239 				if (usrp->lug_expiry < NFSD_MONOSEC)
3240 					break;
3241 				hp2 = NFSUSERHASH(usrp->lug_uid);
3242 				mtx_lock(&hp2->mtx);
3243 				TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3244 				TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3245 				    lug_numhash);
3246 				*uidp = usrp->lug_uid;
3247 				mtx_unlock(&hp2->mtx);
3248 				mtx_unlock(&hp->mtx);
3249 				error = 0;
3250 				goto out;
3251 			}
3252 		}
3253 		mtx_unlock(&hp->mtx);
3254 		cnt++;
3255 		ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
3256 		    str);
3257 		if (ret == 0 && cnt < 2)
3258 			goto tryagain;
3259 	}
3260 	error = NFSERR_BADOWNER;
3261 
3262 out:
3263 	NFSEXITCODE(error);
3264 	return (error);
3265 }
3266 
3267 /*
3268  * Convert a gid to a string.
3269  * gid - the group id
3270  * cpp - points to a buffer of size NFSV4_SMALLSTR
3271  *       (malloc a larger one, as required)
3272  * retlenp - pointer to length to be returned
3273  */
3274 APPLESTATIC void
3275 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp)
3276 {
3277 	int i;
3278 	struct nfsusrgrp *usrp;
3279 	u_char *cp = *cpp;
3280 	gid_t tmp;
3281 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3282 	struct nfsrv_lughash *hp;
3283 
3284 	cnt = 0;
3285 tryagain:
3286 	if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
3287 		/*
3288 		 * Always map nfsrv_defaultgid to "nogroup".
3289 		 */
3290 		if (gid == nfsrv_defaultgid) {
3291 			i = nfsrv_dnsnamelen + 8;
3292 			if (i > len) {
3293 				if (len > NFSV4_SMALLSTR)
3294 					free(cp, M_NFSSTRING);
3295 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
3296 				*cpp = cp;
3297 				len = i;
3298 				goto tryagain;
3299 			}
3300 			*retlenp = i;
3301 			NFSBCOPY("nogroup@", cp, 8);
3302 			cp += 8;
3303 			NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3304 			return;
3305 		}
3306 		hasampersand = 0;
3307 		hp = NFSGROUPHASH(gid);
3308 		mtx_lock(&hp->mtx);
3309 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3310 			if (usrp->lug_gid == gid) {
3311 				if (usrp->lug_expiry < NFSD_MONOSEC)
3312 					break;
3313 				/*
3314 				 * If the name doesn't already have an '@'
3315 				 * in it, append @domainname to it.
3316 				 */
3317 				for (i = 0; i < usrp->lug_namelen; i++) {
3318 					if (usrp->lug_name[i] == '@') {
3319 						hasampersand = 1;
3320 						break;
3321 					}
3322 				}
3323 				if (hasampersand)
3324 					i = usrp->lug_namelen;
3325 				else
3326 					i = usrp->lug_namelen +
3327 					    nfsrv_dnsnamelen + 1;
3328 				if (i > len) {
3329 					mtx_unlock(&hp->mtx);
3330 					if (len > NFSV4_SMALLSTR)
3331 						free(cp, M_NFSSTRING);
3332 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
3333 					*cpp = cp;
3334 					len = i;
3335 					goto tryagain;
3336 				}
3337 				*retlenp = i;
3338 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3339 				if (!hasampersand) {
3340 					cp += usrp->lug_namelen;
3341 					*cp++ = '@';
3342 					NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
3343 				}
3344 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3345 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3346 				    lug_numhash);
3347 				mtx_unlock(&hp->mtx);
3348 				return;
3349 			}
3350 		}
3351 		mtx_unlock(&hp->mtx);
3352 		cnt++;
3353 		ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL);
3354 		if (ret == 0 && cnt < 2)
3355 			goto tryagain;
3356 	}
3357 
3358 	/*
3359 	 * No match, just return a string of digits.
3360 	 */
3361 	tmp = gid;
3362 	i = 0;
3363 	while (tmp || i == 0) {
3364 		tmp /= 10;
3365 		i++;
3366 	}
3367 	len = (i > len) ? len : i;
3368 	*retlenp = len;
3369 	cp += (len - 1);
3370 	tmp = gid;
3371 	for (i = 0; i < len; i++) {
3372 		*cp-- = '0' + (tmp % 10);
3373 		tmp /= 10;
3374 	}
3375 	return;
3376 }
3377 
3378 /*
3379  * Convert a string to a gid.
3380  * If no conversion is possible return NFSERR_BADOWNER, otherwise
3381  * return 0.
3382  * If this is called from a client side mount using AUTH_SYS and the
3383  * string is made up entirely of digits, just convert the string to
3384  * a number.
3385  */
3386 APPLESTATIC int
3387 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
3388 {
3389 	int i;
3390 	char *cp, *endstr, *str0;
3391 	struct nfsusrgrp *usrp;
3392 	int cnt, ret;
3393 	int error = 0;
3394 	gid_t tgid;
3395 	struct nfsrv_lughash *hp, *hp2;
3396 
3397 	if (len == 0) {
3398 		error =  NFSERR_BADOWNER;
3399 		goto out;
3400 	}
3401 	/* If a string of digits and an AUTH_SYS mount, just convert it. */
3402 	str0 = str;
3403 	tgid = (gid_t)strtoul(str0, &endstr, 10);
3404 	if ((endstr - str0) == len) {
3405 		/* A numeric string. */
3406 		if ((nd->nd_flag & ND_KERBV) == 0 &&
3407 		    ((nd->nd_flag & ND_NFSCL) != 0 ||
3408 		      nfsd_enable_stringtouid != 0))
3409 			*gidp = tgid;
3410 		else
3411 			error = NFSERR_BADOWNER;
3412 		goto out;
3413 	}
3414 	/*
3415 	 * Look for an '@'.
3416 	 */
3417 	cp = strchr(str0, '@');
3418 	if (cp != NULL)
3419 		i = (int)(cp++ - str0);
3420 	else
3421 		i = len;
3422 
3423 	cnt = 0;
3424 tryagain:
3425 	if (nfsrv_dnsnamelen > 0) {
3426 		/*
3427 		 * If an '@' is found and the dns name matches, search for the
3428 		 * name with the dns stripped off.
3429 		 */
3430 		if (cnt == 0 && i < len && i > 0 &&
3431 		    (len - 1 - i) == nfsrv_dnsnamelen &&
3432 		    !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
3433 			len -= (nfsrv_dnsnamelen + 1);
3434 			*(cp - 1) = '\0';
3435 		}
3436 
3437 		/*
3438 		 * Check for the special case of "nogroup".
3439 		 */
3440 		if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3441 			*gidp = nfsrv_defaultgid;
3442 			error = 0;
3443 			goto out;
3444 		}
3445 
3446 		hp = NFSGROUPNAMEHASH(str, len);
3447 		mtx_lock(&hp->mtx);
3448 		TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3449 			if (usrp->lug_namelen == len &&
3450 			    !NFSBCMP(usrp->lug_name, str, len)) {
3451 				if (usrp->lug_expiry < NFSD_MONOSEC)
3452 					break;
3453 				hp2 = NFSGROUPHASH(usrp->lug_gid);
3454 				mtx_lock(&hp2->mtx);
3455 				TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3456 				TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3457 				    lug_numhash);
3458 				*gidp = usrp->lug_gid;
3459 				mtx_unlock(&hp2->mtx);
3460 				mtx_unlock(&hp->mtx);
3461 				error = 0;
3462 				goto out;
3463 			}
3464 		}
3465 		mtx_unlock(&hp->mtx);
3466 		cnt++;
3467 		ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3468 		    str);
3469 		if (ret == 0 && cnt < 2)
3470 			goto tryagain;
3471 	}
3472 	error = NFSERR_BADOWNER;
3473 
3474 out:
3475 	NFSEXITCODE(error);
3476 	return (error);
3477 }
3478 
3479 /*
3480  * Cmp len chars, allowing mixed case in the first argument to match lower
3481  * case in the second, but not if the first argument is all upper case.
3482  * Return 0 for a match, 1 otherwise.
3483  */
3484 static int
3485 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
3486 {
3487 	int i;
3488 	u_char tmp;
3489 	int fndlower = 0;
3490 
3491 	for (i = 0; i < len; i++) {
3492 		if (*cp >= 'A' && *cp <= 'Z') {
3493 			tmp = *cp++ + ('a' - 'A');
3494 		} else {
3495 			tmp = *cp++;
3496 			if (tmp >= 'a' && tmp <= 'z')
3497 				fndlower = 1;
3498 		}
3499 		if (tmp != *cp2++)
3500 			return (1);
3501 	}
3502 	if (fndlower)
3503 		return (0);
3504 	else
3505 		return (1);
3506 }
3507 
3508 /*
3509  * Set the port for the nfsuserd.
3510  */
3511 APPLESTATIC int
3512 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
3513 {
3514 	struct nfssockreq *rp;
3515 #ifdef INET
3516 	struct sockaddr_in *ad;
3517 #endif
3518 #ifdef INET6
3519 	struct sockaddr_in6 *ad6;
3520 	const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
3521 #endif
3522 	int error;
3523 
3524 	NFSLOCKNAMEID();
3525 	if (nfsrv_nfsuserd) {
3526 		NFSUNLOCKNAMEID();
3527 		error = EPERM;
3528 		goto out;
3529 	}
3530 	nfsrv_nfsuserd = 1;
3531 	NFSUNLOCKNAMEID();
3532 	/*
3533 	 * Set up the socket record and connect.
3534 	 */
3535 	rp = &nfsrv_nfsuserdsock;
3536 	rp->nr_client = NULL;
3537 	rp->nr_sotype = SOCK_DGRAM;
3538 	rp->nr_soproto = IPPROTO_UDP;
3539 	rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3540 	rp->nr_cred = NULL;
3541 	rp->nr_prog = RPCPROG_NFSUSERD;
3542 	error = 0;
3543 	switch (nargs->nuserd_family) {
3544 #ifdef INET
3545 	case AF_INET:
3546 		rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME,
3547 		    M_WAITOK | M_ZERO);
3548  		ad = (struct sockaddr_in *)rp->nr_nam;
3549 		ad->sin_len = sizeof(struct sockaddr_in);
3550  		ad->sin_family = AF_INET;
3551 		ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3552 		ad->sin_port = nargs->nuserd_port;
3553 		break;
3554 #endif
3555 #ifdef INET6
3556 	case AF_INET6:
3557 		rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3558 		    M_WAITOK | M_ZERO);
3559 		ad6 = (struct sockaddr_in6 *)rp->nr_nam;
3560 		ad6->sin6_len = sizeof(struct sockaddr_in6);
3561 		ad6->sin6_family = AF_INET6;
3562 		ad6->sin6_addr = in6loopback;
3563 		ad6->sin6_port = nargs->nuserd_port;
3564 		break;
3565 #endif
3566 	default:
3567 		error = ENXIO;
3568  	}
3569 	rp->nr_vers = RPCNFSUSERD_VERS;
3570 	if (error == 0)
3571 		error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
3572 	if (error) {
3573 		free(rp->nr_nam, M_SONAME);
3574 		nfsrv_nfsuserd = 0;
3575 	}
3576 out:
3577 	NFSEXITCODE(error);
3578 	return (error);
3579 }
3580 
3581 /*
3582  * Delete the nfsuserd port.
3583  */
3584 APPLESTATIC void
3585 nfsrv_nfsuserddelport(void)
3586 {
3587 
3588 	NFSLOCKNAMEID();
3589 	if (nfsrv_nfsuserd == 0) {
3590 		NFSUNLOCKNAMEID();
3591 		return;
3592 	}
3593 	nfsrv_nfsuserd = 0;
3594 	NFSUNLOCKNAMEID();
3595 	newnfs_disconnect(&nfsrv_nfsuserdsock);
3596 	free(nfsrv_nfsuserdsock.nr_nam, M_SONAME);
3597 }
3598 
3599 /*
3600  * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3601  * name<-->id cache.
3602  * Returns 0 upon success, non-zero otherwise.
3603  */
3604 static int
3605 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
3606 {
3607 	u_int32_t *tl;
3608 	struct nfsrv_descript *nd;
3609 	int len;
3610 	struct nfsrv_descript nfsd;
3611 	struct ucred *cred;
3612 	int error;
3613 
3614 	NFSLOCKNAMEID();
3615 	if (nfsrv_nfsuserd == 0) {
3616 		NFSUNLOCKNAMEID();
3617 		error = EPERM;
3618 		goto out;
3619 	}
3620 	NFSUNLOCKNAMEID();
3621 	nd = &nfsd;
3622 	cred = newnfs_getcred();
3623 	nd->nd_flag = ND_GSSINITREPLY;
3624 	nfsrvd_rephead(nd);
3625 
3626 	nd->nd_procnum = procnum;
3627 	if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3628 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3629 		if (procnum == RPCNFSUSERD_GETUID)
3630 			*tl = txdr_unsigned(uid);
3631 		else
3632 			*tl = txdr_unsigned(gid);
3633 	} else {
3634 		len = strlen(name);
3635 		(void) nfsm_strtom(nd, name, len);
3636 	}
3637 	error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3638 		cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3639 	NFSFREECRED(cred);
3640 	if (!error) {
3641 		mbuf_freem(nd->nd_mrep);
3642 		error = nd->nd_repstat;
3643 	}
3644 out:
3645 	NFSEXITCODE(error);
3646 	return (error);
3647 }
3648 
3649 /*
3650  * This function is called from the nfssvc(2) system call, to update the
3651  * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3652  */
3653 APPLESTATIC int
3654 nfssvc_idname(struct nfsd_idargs *nidp)
3655 {
3656 	struct nfsusrgrp *nusrp, *usrp, *newusrp;
3657 	struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
3658 	int i, group_locked, groupname_locked, user_locked, username_locked;
3659 	int error = 0;
3660 	u_char *cp;
3661 	gid_t *grps;
3662 	struct ucred *cr;
3663 	static int onethread = 0;
3664 	static time_t lasttime = 0;
3665 
3666 	if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
3667 		error = EINVAL;
3668 		goto out;
3669 	}
3670 	if (nidp->nid_flag & NFSID_INITIALIZE) {
3671 		cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
3672 		error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3673 		    nidp->nid_namelen);
3674 		if (error != 0) {
3675 			free(cp, M_NFSSTRING);
3676 			goto out;
3677 		}
3678 		if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
3679 			/*
3680 			 * Free up all the old stuff and reinitialize hash
3681 			 * lists.  All mutexes for both lists must be locked,
3682 			 * with the user/group name ones before the uid/gid
3683 			 * ones, to avoid a LOR.
3684 			 */
3685 			for (i = 0; i < nfsrv_lughashsize; i++)
3686 				mtx_lock(&nfsusernamehash[i].mtx);
3687 			for (i = 0; i < nfsrv_lughashsize; i++)
3688 				mtx_lock(&nfsuserhash[i].mtx);
3689 			for (i = 0; i < nfsrv_lughashsize; i++)
3690 				TAILQ_FOREACH_SAFE(usrp,
3691 				    &nfsuserhash[i].lughead, lug_numhash, nusrp)
3692 					nfsrv_removeuser(usrp, 1);
3693 			for (i = 0; i < nfsrv_lughashsize; i++)
3694 				mtx_unlock(&nfsuserhash[i].mtx);
3695 			for (i = 0; i < nfsrv_lughashsize; i++)
3696 				mtx_unlock(&nfsusernamehash[i].mtx);
3697 			for (i = 0; i < nfsrv_lughashsize; i++)
3698 				mtx_lock(&nfsgroupnamehash[i].mtx);
3699 			for (i = 0; i < nfsrv_lughashsize; i++)
3700 				mtx_lock(&nfsgrouphash[i].mtx);
3701 			for (i = 0; i < nfsrv_lughashsize; i++)
3702 				TAILQ_FOREACH_SAFE(usrp,
3703 				    &nfsgrouphash[i].lughead, lug_numhash,
3704 				    nusrp)
3705 					nfsrv_removeuser(usrp, 0);
3706 			for (i = 0; i < nfsrv_lughashsize; i++)
3707 				mtx_unlock(&nfsgrouphash[i].mtx);
3708 			for (i = 0; i < nfsrv_lughashsize; i++)
3709 				mtx_unlock(&nfsgroupnamehash[i].mtx);
3710 			free(nfsrv_dnsname, M_NFSSTRING);
3711 			nfsrv_dnsname = NULL;
3712 		}
3713 		if (nfsuserhash == NULL) {
3714 			/* Allocate the hash tables. */
3715 			nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
3716 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3717 			    M_ZERO);
3718 			for (i = 0; i < nfsrv_lughashsize; i++)
3719 				mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
3720 				    NULL, MTX_DEF | MTX_DUPOK);
3721 			nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
3722 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3723 			    M_ZERO);
3724 			for (i = 0; i < nfsrv_lughashsize; i++)
3725 				mtx_init(&nfsusernamehash[i].mtx,
3726 				    "nfsusrhash", NULL, MTX_DEF |
3727 				    MTX_DUPOK);
3728 			nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
3729 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3730 			    M_ZERO);
3731 			for (i = 0; i < nfsrv_lughashsize; i++)
3732 				mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
3733 				    NULL, MTX_DEF | MTX_DUPOK);
3734 			nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
3735 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
3736 			    M_ZERO);
3737 			for (i = 0; i < nfsrv_lughashsize; i++)
3738 			    mtx_init(&nfsgroupnamehash[i].mtx,
3739 			    "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
3740 		}
3741 		/* (Re)initialize the list heads. */
3742 		for (i = 0; i < nfsrv_lughashsize; i++)
3743 			TAILQ_INIT(&nfsuserhash[i].lughead);
3744 		for (i = 0; i < nfsrv_lughashsize; i++)
3745 			TAILQ_INIT(&nfsusernamehash[i].lughead);
3746 		for (i = 0; i < nfsrv_lughashsize; i++)
3747 			TAILQ_INIT(&nfsgrouphash[i].lughead);
3748 		for (i = 0; i < nfsrv_lughashsize; i++)
3749 			TAILQ_INIT(&nfsgroupnamehash[i].lughead);
3750 
3751 		/*
3752 		 * Put name in "DNS" string.
3753 		 */
3754 		nfsrv_dnsname = cp;
3755 		nfsrv_defaultuid = nidp->nid_uid;
3756 		nfsrv_defaultgid = nidp->nid_gid;
3757 		nfsrv_usercnt = 0;
3758 		nfsrv_usermax = nidp->nid_usermax;
3759 		atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
3760 		goto out;
3761 	}
3762 
3763 	/*
3764 	 * malloc the new one now, so any potential sleep occurs before
3765 	 * manipulation of the lists.
3766 	 */
3767 	newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
3768 	    M_NFSUSERGROUP, M_WAITOK | M_ZERO);
3769 	error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3770 	    nidp->nid_namelen);
3771 	if (error == 0 && nidp->nid_ngroup > 0 &&
3772 	    (nidp->nid_flag & NFSID_ADDUID) != 0) {
3773 		grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
3774 		    M_WAITOK);
3775 		error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps,
3776 		    sizeof(gid_t) * nidp->nid_ngroup);
3777 		if (error == 0) {
3778 			/*
3779 			 * Create a credential just like svc_getcred(),
3780 			 * but using the group list provided.
3781 			 */
3782 			cr = crget();
3783 			cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
3784 			crsetgroups(cr, nidp->nid_ngroup, grps);
3785 			cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
3786 			cr->cr_prison = &prison0;
3787 			prison_hold(cr->cr_prison);
3788 #ifdef MAC
3789 			mac_cred_associate_nfsd(cr);
3790 #endif
3791 			newusrp->lug_cred = cr;
3792 		}
3793 		free(grps, M_TEMP);
3794 	}
3795 	if (error) {
3796 		free(newusrp, M_NFSUSERGROUP);
3797 		goto out;
3798 	}
3799 	newusrp->lug_namelen = nidp->nid_namelen;
3800 
3801 	/*
3802 	 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
3803 	 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
3804 	 * The flags user_locked, username_locked, group_locked and
3805 	 * groupname_locked are set to indicate all of those hash lists are
3806 	 * locked. hp_name != NULL  and hp_idnum != NULL indicates that
3807 	 * the respective one mutex is locked.
3808 	 */
3809 	user_locked = username_locked = group_locked = groupname_locked = 0;
3810 	hp_name = hp_idnum = NULL;
3811 
3812 	/*
3813 	 * Delete old entries, as required.
3814 	 */
3815 	if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3816 		/* Must lock all username hash lists first, to avoid a LOR. */
3817 		for (i = 0; i < nfsrv_lughashsize; i++)
3818 			mtx_lock(&nfsusernamehash[i].mtx);
3819 		username_locked = 1;
3820 		hp_idnum = NFSUSERHASH(nidp->nid_uid);
3821 		mtx_lock(&hp_idnum->mtx);
3822 		TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3823 		    nusrp) {
3824 			if (usrp->lug_uid == nidp->nid_uid)
3825 				nfsrv_removeuser(usrp, 1);
3826 		}
3827 	} else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3828 		hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
3829 		    newusrp->lug_namelen);
3830 		mtx_lock(&hp_name->mtx);
3831 		TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3832 		    nusrp) {
3833 			if (usrp->lug_namelen == newusrp->lug_namelen &&
3834 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3835 			    usrp->lug_namelen)) {
3836 				thp = NFSUSERHASH(usrp->lug_uid);
3837 				mtx_lock(&thp->mtx);
3838 				nfsrv_removeuser(usrp, 1);
3839 				mtx_unlock(&thp->mtx);
3840 			}
3841 		}
3842 		hp_idnum = NFSUSERHASH(nidp->nid_uid);
3843 		mtx_lock(&hp_idnum->mtx);
3844 	} else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3845 		/* Must lock all groupname hash lists first, to avoid a LOR. */
3846 		for (i = 0; i < nfsrv_lughashsize; i++)
3847 			mtx_lock(&nfsgroupnamehash[i].mtx);
3848 		groupname_locked = 1;
3849 		hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3850 		mtx_lock(&hp_idnum->mtx);
3851 		TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
3852 		    nusrp) {
3853 			if (usrp->lug_gid == nidp->nid_gid)
3854 				nfsrv_removeuser(usrp, 0);
3855 		}
3856 	} else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3857 		hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
3858 		    newusrp->lug_namelen);
3859 		mtx_lock(&hp_name->mtx);
3860 		TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
3861 		    nusrp) {
3862 			if (usrp->lug_namelen == newusrp->lug_namelen &&
3863 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3864 			    usrp->lug_namelen)) {
3865 				thp = NFSGROUPHASH(usrp->lug_gid);
3866 				mtx_lock(&thp->mtx);
3867 				nfsrv_removeuser(usrp, 0);
3868 				mtx_unlock(&thp->mtx);
3869 			}
3870 		}
3871 		hp_idnum = NFSGROUPHASH(nidp->nid_gid);
3872 		mtx_lock(&hp_idnum->mtx);
3873 	}
3874 
3875 	/*
3876 	 * Now, we can add the new one.
3877 	 */
3878 	if (nidp->nid_usertimeout)
3879 		newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3880 	else
3881 		newusrp->lug_expiry = NFSD_MONOSEC + 5;
3882 	if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3883 		newusrp->lug_uid = nidp->nid_uid;
3884 		thp = NFSUSERHASH(newusrp->lug_uid);
3885 		mtx_assert(&thp->mtx, MA_OWNED);
3886 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3887 		thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3888 		mtx_assert(&thp->mtx, MA_OWNED);
3889 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3890 		atomic_add_int(&nfsrv_usercnt, 1);
3891 	} else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3892 		newusrp->lug_gid = nidp->nid_gid;
3893 		thp = NFSGROUPHASH(newusrp->lug_gid);
3894 		mtx_assert(&thp->mtx, MA_OWNED);
3895 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
3896 		thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3897 		mtx_assert(&thp->mtx, MA_OWNED);
3898 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
3899 		atomic_add_int(&nfsrv_usercnt, 1);
3900 	} else {
3901 		if (newusrp->lug_cred != NULL)
3902 			crfree(newusrp->lug_cred);
3903 		free(newusrp, M_NFSUSERGROUP);
3904 	}
3905 
3906 	/*
3907 	 * Once per second, allow one thread to trim the cache.
3908 	 */
3909 	if (lasttime < NFSD_MONOSEC &&
3910 	    atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
3911 		/*
3912 		 * First, unlock the single mutexes, so that all entries
3913 		 * can be locked and any LOR is avoided.
3914 		 */
3915 		if (hp_name != NULL) {
3916 			mtx_unlock(&hp_name->mtx);
3917 			hp_name = NULL;
3918 		}
3919 		if (hp_idnum != NULL) {
3920 			mtx_unlock(&hp_idnum->mtx);
3921 			hp_idnum = NULL;
3922 		}
3923 
3924 		if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
3925 		    NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
3926 			if (username_locked == 0) {
3927 				for (i = 0; i < nfsrv_lughashsize; i++)
3928 					mtx_lock(&nfsusernamehash[i].mtx);
3929 				username_locked = 1;
3930 			}
3931 			KASSERT(user_locked == 0,
3932 			    ("nfssvc_idname: user_locked"));
3933 			for (i = 0; i < nfsrv_lughashsize; i++)
3934 				mtx_lock(&nfsuserhash[i].mtx);
3935 			user_locked = 1;
3936 			for (i = 0; i < nfsrv_lughashsize; i++) {
3937 				TAILQ_FOREACH_SAFE(usrp,
3938 				    &nfsuserhash[i].lughead, lug_numhash,
3939 				    nusrp)
3940 					if (usrp->lug_expiry < NFSD_MONOSEC)
3941 						nfsrv_removeuser(usrp, 1);
3942 			}
3943 			for (i = 0; i < nfsrv_lughashsize; i++) {
3944 				/*
3945 				 * Trim the cache using an approximate LRU
3946 				 * algorithm.  This code deletes the least
3947 				 * recently used entry on each hash list.
3948 				 */
3949 				if (nfsrv_usercnt <= nfsrv_usermax)
3950 					break;
3951 				usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
3952 				if (usrp != NULL)
3953 					nfsrv_removeuser(usrp, 1);
3954 			}
3955 		} else {
3956 			if (groupname_locked == 0) {
3957 				for (i = 0; i < nfsrv_lughashsize; i++)
3958 					mtx_lock(&nfsgroupnamehash[i].mtx);
3959 				groupname_locked = 1;
3960 			}
3961 			KASSERT(group_locked == 0,
3962 			    ("nfssvc_idname: group_locked"));
3963 			for (i = 0; i < nfsrv_lughashsize; i++)
3964 				mtx_lock(&nfsgrouphash[i].mtx);
3965 			group_locked = 1;
3966 			for (i = 0; i < nfsrv_lughashsize; i++) {
3967 				TAILQ_FOREACH_SAFE(usrp,
3968 				    &nfsgrouphash[i].lughead, lug_numhash,
3969 				    nusrp)
3970 					if (usrp->lug_expiry < NFSD_MONOSEC)
3971 						nfsrv_removeuser(usrp, 0);
3972 			}
3973 			for (i = 0; i < nfsrv_lughashsize; i++) {
3974 				/*
3975 				 * Trim the cache using an approximate LRU
3976 				 * algorithm.  This code deletes the least
3977 				 * recently user entry on each hash list.
3978 				 */
3979 				if (nfsrv_usercnt <= nfsrv_usermax)
3980 					break;
3981 				usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
3982 				if (usrp != NULL)
3983 					nfsrv_removeuser(usrp, 0);
3984 			}
3985 		}
3986 		lasttime = NFSD_MONOSEC;
3987 		atomic_store_rel_int(&onethread, 0);
3988 	}
3989 
3990 	/* Now, unlock all locked mutexes. */
3991 	if (hp_idnum != NULL)
3992 		mtx_unlock(&hp_idnum->mtx);
3993 	if (hp_name != NULL)
3994 		mtx_unlock(&hp_name->mtx);
3995 	if (user_locked != 0)
3996 		for (i = 0; i < nfsrv_lughashsize; i++)
3997 			mtx_unlock(&nfsuserhash[i].mtx);
3998 	if (username_locked != 0)
3999 		for (i = 0; i < nfsrv_lughashsize; i++)
4000 			mtx_unlock(&nfsusernamehash[i].mtx);
4001 	if (group_locked != 0)
4002 		for (i = 0; i < nfsrv_lughashsize; i++)
4003 			mtx_unlock(&nfsgrouphash[i].mtx);
4004 	if (groupname_locked != 0)
4005 		for (i = 0; i < nfsrv_lughashsize; i++)
4006 			mtx_unlock(&nfsgroupnamehash[i].mtx);
4007 out:
4008 	NFSEXITCODE(error);
4009 	return (error);
4010 }
4011 
4012 /*
4013  * Remove a user/group name element.
4014  */
4015 static void
4016 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
4017 {
4018 	struct nfsrv_lughash *hp;
4019 
4020 	if (isuser != 0) {
4021 		hp = NFSUSERHASH(usrp->lug_uid);
4022 		mtx_assert(&hp->mtx, MA_OWNED);
4023 		TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4024 		hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4025 		mtx_assert(&hp->mtx, MA_OWNED);
4026 		TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4027 	} else {
4028 		hp = NFSGROUPHASH(usrp->lug_gid);
4029 		mtx_assert(&hp->mtx, MA_OWNED);
4030 		TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4031 		hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4032 		mtx_assert(&hp->mtx, MA_OWNED);
4033 		TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4034 	}
4035 	atomic_add_int(&nfsrv_usercnt, -1);
4036 	if (usrp->lug_cred != NULL)
4037 		crfree(usrp->lug_cred);
4038 	free(usrp, M_NFSUSERGROUP);
4039 }
4040 
4041 /*
4042  * Free up all the allocations related to the name<-->id cache.
4043  * This function should only be called when the nfsuserd daemon isn't
4044  * running, since it doesn't do any locking.
4045  * This function is meant to be used when the nfscommon module is unloaded.
4046  */
4047 APPLESTATIC void
4048 nfsrv_cleanusergroup(void)
4049 {
4050 	struct nfsrv_lughash *hp, *hp2;
4051 	struct nfsusrgrp *nusrp, *usrp;
4052 	int i;
4053 
4054 	if (nfsuserhash == NULL)
4055 		return;
4056 
4057 	for (i = 0; i < nfsrv_lughashsize; i++) {
4058 		hp = &nfsuserhash[i];
4059 		TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4060 			TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4061 			hp2 = NFSUSERNAMEHASH(usrp->lug_name,
4062 			    usrp->lug_namelen);
4063 			TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4064 			if (usrp->lug_cred != NULL)
4065 				crfree(usrp->lug_cred);
4066 			free(usrp, M_NFSUSERGROUP);
4067 		}
4068 		hp = &nfsgrouphash[i];
4069 		TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4070 			TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4071 			hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
4072 			    usrp->lug_namelen);
4073 			TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4074 			if (usrp->lug_cred != NULL)
4075 				crfree(usrp->lug_cred);
4076 			free(usrp, M_NFSUSERGROUP);
4077 		}
4078 		mtx_destroy(&nfsuserhash[i].mtx);
4079 		mtx_destroy(&nfsusernamehash[i].mtx);
4080 		mtx_destroy(&nfsgroupnamehash[i].mtx);
4081 		mtx_destroy(&nfsgrouphash[i].mtx);
4082 	}
4083 	free(nfsuserhash, M_NFSUSERGROUP);
4084 	free(nfsusernamehash, M_NFSUSERGROUP);
4085 	free(nfsgrouphash, M_NFSUSERGROUP);
4086 	free(nfsgroupnamehash, M_NFSUSERGROUP);
4087 	free(nfsrv_dnsname, M_NFSSTRING);
4088 }
4089 
4090 /*
4091  * This function scans a byte string and checks for UTF-8 compliance.
4092  * It returns 0 if it conforms and NFSERR_INVAL if not.
4093  */
4094 APPLESTATIC int
4095 nfsrv_checkutf8(u_int8_t *cp, int len)
4096 {
4097 	u_int32_t val = 0x0;
4098 	int cnt = 0, gotd = 0, shift = 0;
4099 	u_int8_t byte;
4100 	static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
4101 	int error = 0;
4102 
4103 	/*
4104 	 * Here are what the variables are used for:
4105 	 * val - the calculated value of a multibyte char, used to check
4106 	 *       that it was coded with the correct range
4107 	 * cnt - the number of 10xxxxxx bytes to follow
4108 	 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
4109 	 * shift - lower order bits of range (ie. "val >> shift" should
4110 	 *       not be 0, in other words, dividing by the lower bound
4111 	 *       of the range should get a non-zero value)
4112 	 * byte - used to calculate cnt
4113 	 */
4114 	while (len > 0) {
4115 		if (cnt > 0) {
4116 			/* This handles the 10xxxxxx bytes */
4117 			if ((*cp & 0xc0) != 0x80 ||
4118 			    (gotd && (*cp & 0x20))) {
4119 				error = NFSERR_INVAL;
4120 				goto out;
4121 			}
4122 			gotd = 0;
4123 			val <<= 6;
4124 			val |= (*cp & 0x3f);
4125 			cnt--;
4126 			if (cnt == 0 && (val >> shift) == 0x0) {
4127 				error = NFSERR_INVAL;
4128 				goto out;
4129 			}
4130 		} else if (*cp & 0x80) {
4131 			/* first byte of multi byte char */
4132 			byte = *cp;
4133 			while ((byte & 0x40) && cnt < 6) {
4134 				cnt++;
4135 				byte <<= 1;
4136 			}
4137 			if (cnt == 0 || cnt == 6) {
4138 				error = NFSERR_INVAL;
4139 				goto out;
4140 			}
4141 			val = (*cp & (0x3f >> cnt));
4142 			shift = utf8_shift[cnt - 1];
4143 			if (cnt == 2 && val == 0xd)
4144 				/* Check for the 0xd800-0xdfff case */
4145 				gotd = 1;
4146 		}
4147 		cp++;
4148 		len--;
4149 	}
4150 	if (cnt > 0)
4151 		error = NFSERR_INVAL;
4152 
4153 out:
4154 	NFSEXITCODE(error);
4155 	return (error);
4156 }
4157 
4158 /*
4159  * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
4160  * strings, one with the root path in it and the other with the list of
4161  * locations. The list is in the same format as is found in nfr_refs.
4162  * It is a "," separated list of entries, where each of them is of the
4163  * form <server>:<rootpath>. For example
4164  * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
4165  * The nilp argument is set to 1 for the special case of a null fs_root
4166  * and an empty server list.
4167  * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
4168  * number of xdr bytes parsed in sump.
4169  */
4170 static int
4171 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
4172     int *sump, int *nilp)
4173 {
4174 	u_int32_t *tl;
4175 	u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
4176 	int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
4177 	struct list {
4178 		SLIST_ENTRY(list) next;
4179 		int len;
4180 		u_char host[1];
4181 	} *lsp, *nlsp;
4182 	SLIST_HEAD(, list) head;
4183 
4184 	*fsrootp = NULL;
4185 	*srvp = NULL;
4186 	*nilp = 0;
4187 
4188 	/*
4189 	 * Get the fs_root path and check for the special case of null path
4190 	 * and 0 length server list.
4191 	 */
4192 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4193 	len = fxdr_unsigned(int, *tl);
4194 	if (len < 0 || len > 10240) {
4195 		error = NFSERR_BADXDR;
4196 		goto nfsmout;
4197 	}
4198 	if (len == 0) {
4199 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4200 		if (*tl != 0) {
4201 			error = NFSERR_BADXDR;
4202 			goto nfsmout;
4203 		}
4204 		*nilp = 1;
4205 		*sump = 2 * NFSX_UNSIGNED;
4206 		error = 0;
4207 		goto nfsmout;
4208 	}
4209 	cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
4210 	error = nfsrv_mtostr(nd, cp, len);
4211 	if (!error) {
4212 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4213 		cnt = fxdr_unsigned(int, *tl);
4214 		if (cnt <= 0)
4215 			error = NFSERR_BADXDR;
4216 	}
4217 	if (error)
4218 		goto nfsmout;
4219 
4220 	/*
4221 	 * Now, loop through the location list and make up the srvlist.
4222 	 */
4223 	xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4224 	cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
4225 	slen = 1024;
4226 	siz = 0;
4227 	for (i = 0; i < cnt; i++) {
4228 		SLIST_INIT(&head);
4229 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4230 		nsrv = fxdr_unsigned(int, *tl);
4231 		if (nsrv <= 0) {
4232 			error = NFSERR_BADXDR;
4233 			goto nfsmout;
4234 		}
4235 
4236 		/*
4237 		 * Handle the first server by putting it in the srvstr.
4238 		 */
4239 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4240 		len = fxdr_unsigned(int, *tl);
4241 		if (len <= 0 || len > 1024) {
4242 			error = NFSERR_BADXDR;
4243 			goto nfsmout;
4244 		}
4245 		nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
4246 		if (cp3 != cp2) {
4247 			*cp3++ = ',';
4248 			siz++;
4249 		}
4250 		error = nfsrv_mtostr(nd, cp3, len);
4251 		if (error)
4252 			goto nfsmout;
4253 		cp3 += len;
4254 		*cp3++ = ':';
4255 		siz += (len + 1);
4256 		xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4257 		for (j = 1; j < nsrv; j++) {
4258 			/*
4259 			 * Yuck, put them in an slist and process them later.
4260 			 */
4261 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4262 			len = fxdr_unsigned(int, *tl);
4263 			if (len <= 0 || len > 1024) {
4264 				error = NFSERR_BADXDR;
4265 				goto nfsmout;
4266 			}
4267 			lsp = (struct list *)malloc(sizeof (struct list)
4268 			    + len, M_TEMP, M_WAITOK);
4269 			error = nfsrv_mtostr(nd, lsp->host, len);
4270 			if (error)
4271 				goto nfsmout;
4272 			xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4273 			lsp->len = len;
4274 			SLIST_INSERT_HEAD(&head, lsp, next);
4275 		}
4276 
4277 		/*
4278 		 * Finally, we can get the path.
4279 		 */
4280 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4281 		len = fxdr_unsigned(int, *tl);
4282 		if (len <= 0 || len > 1024) {
4283 			error = NFSERR_BADXDR;
4284 			goto nfsmout;
4285 		}
4286 		nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
4287 		error = nfsrv_mtostr(nd, cp3, len);
4288 		if (error)
4289 			goto nfsmout;
4290 		xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4291 		str = cp3;
4292 		stringlen = len;
4293 		cp3 += len;
4294 		siz += len;
4295 		SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
4296 			nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
4297 			    &cp2, &cp3, &slen);
4298 			*cp3++ = ',';
4299 			NFSBCOPY(lsp->host, cp3, lsp->len);
4300 			cp3 += lsp->len;
4301 			*cp3++ = ':';
4302 			NFSBCOPY(str, cp3, stringlen);
4303 			cp3 += stringlen;
4304 			*cp3 = '\0';
4305 			siz += (lsp->len + stringlen + 2);
4306 			free(lsp, M_TEMP);
4307 		}
4308 	}
4309 	*fsrootp = cp;
4310 	*srvp = cp2;
4311 	*sump = xdrsum;
4312 	NFSEXITCODE2(0, nd);
4313 	return (0);
4314 nfsmout:
4315 	if (cp != NULL)
4316 		free(cp, M_NFSSTRING);
4317 	if (cp2 != NULL)
4318 		free(cp2, M_NFSSTRING);
4319 	NFSEXITCODE2(error, nd);
4320 	return (error);
4321 }
4322 
4323 /*
4324  * Make the malloc'd space large enough. This is a pain, but the xdr
4325  * doesn't set an upper bound on the side, so...
4326  */
4327 static void
4328 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
4329 {
4330 	u_char *cp;
4331 	int i;
4332 
4333 	if (siz <= *slenp)
4334 		return;
4335 	cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
4336 	NFSBCOPY(*cpp, cp, *slenp);
4337 	free(*cpp, M_NFSSTRING);
4338 	i = *cpp2 - *cpp;
4339 	*cpp = cp;
4340 	*cpp2 = cp + i;
4341 	*slenp = siz + 1024;
4342 }
4343 
4344 /*
4345  * Initialize the reply header data structures.
4346  */
4347 APPLESTATIC void
4348 nfsrvd_rephead(struct nfsrv_descript *nd)
4349 {
4350 	mbuf_t mreq;
4351 
4352 	/*
4353 	 * If this is a big reply, use a cluster.
4354 	 */
4355 	if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
4356 	    nfs_bigreply[nd->nd_procnum]) {
4357 		NFSMCLGET(mreq, M_WAITOK);
4358 		nd->nd_mreq = mreq;
4359 		nd->nd_mb = mreq;
4360 	} else {
4361 		NFSMGET(mreq);
4362 		nd->nd_mreq = mreq;
4363 		nd->nd_mb = mreq;
4364 	}
4365 	nd->nd_bpos = NFSMTOD(mreq, caddr_t);
4366 	mbuf_setlen(mreq, 0);
4367 
4368 	if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
4369 		NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
4370 }
4371 
4372 /*
4373  * Lock a socket against others.
4374  * Currently used to serialize connect/disconnect attempts.
4375  */
4376 int
4377 newnfs_sndlock(int *flagp)
4378 {
4379 	struct timespec ts;
4380 
4381 	NFSLOCKSOCK();
4382 	while (*flagp & NFSR_SNDLOCK) {
4383 		*flagp |= NFSR_WANTSND;
4384 		ts.tv_sec = 0;
4385 		ts.tv_nsec = 0;
4386 		(void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
4387 		    PZERO - 1, "nfsndlck", &ts);
4388 	}
4389 	*flagp |= NFSR_SNDLOCK;
4390 	NFSUNLOCKSOCK();
4391 	return (0);
4392 }
4393 
4394 /*
4395  * Unlock the stream socket for others.
4396  */
4397 void
4398 newnfs_sndunlock(int *flagp)
4399 {
4400 
4401 	NFSLOCKSOCK();
4402 	if ((*flagp & NFSR_SNDLOCK) == 0)
4403 		panic("nfs sndunlock");
4404 	*flagp &= ~NFSR_SNDLOCK;
4405 	if (*flagp & NFSR_WANTSND) {
4406 		*flagp &= ~NFSR_WANTSND;
4407 		wakeup((caddr_t)flagp);
4408 	}
4409 	NFSUNLOCKSOCK();
4410 }
4411 
4412 APPLESTATIC int
4413 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
4414     struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
4415 {
4416 	struct in_addr saddr;
4417 	uint32_t portnum, *tl;
4418 	int i, j, k;
4419 	sa_family_t af = AF_UNSPEC;
4420 	char addr[64], protocol[5], *cp;
4421 	int cantparse = 0, error = 0;
4422 	uint16_t portv;
4423 
4424 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4425 	i = fxdr_unsigned(int, *tl);
4426 	if (i >= 3 && i <= 4) {
4427 		error = nfsrv_mtostr(nd, protocol, i);
4428 		if (error)
4429 			goto nfsmout;
4430 		if (strcmp(protocol, "tcp") == 0) {
4431 			af = AF_INET;
4432 			*isudp = 0;
4433 		} else if (strcmp(protocol, "udp") == 0) {
4434 			af = AF_INET;
4435 			*isudp = 1;
4436 		} else if (strcmp(protocol, "tcp6") == 0) {
4437 			af = AF_INET6;
4438 			*isudp = 0;
4439 		} else if (strcmp(protocol, "udp6") == 0) {
4440 			af = AF_INET6;
4441 			*isudp = 1;
4442 		} else
4443 			cantparse = 1;
4444 	} else {
4445 		cantparse = 1;
4446 		if (i > 0) {
4447 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4448 			if (error)
4449 				goto nfsmout;
4450 		}
4451 	}
4452 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4453 	i = fxdr_unsigned(int, *tl);
4454 	if (i < 0) {
4455 		error = NFSERR_BADXDR;
4456 		goto nfsmout;
4457 	} else if (cantparse == 0 && i >= 11 && i < 64) {
4458 		/*
4459 		 * The shortest address is 11chars and the longest is < 64.
4460 		 */
4461 		error = nfsrv_mtostr(nd, addr, i);
4462 		if (error)
4463 			goto nfsmout;
4464 
4465 		/* Find the port# at the end and extract that. */
4466 		i = strlen(addr);
4467 		k = 0;
4468 		cp = &addr[i - 1];
4469 		/* Count back two '.'s from end to get port# field. */
4470 		for (j = 0; j < i; j++) {
4471 			if (*cp == '.') {
4472 				k++;
4473 				if (k == 2)
4474 					break;
4475 			}
4476 			cp--;
4477 		}
4478 		if (k == 2) {
4479 			/*
4480 			 * The NFSv4 port# is appended as .N.N, where N is
4481 			 * a decimal # in the range 0-255, just like an inet4
4482 			 * address. Cheat and use inet_aton(), which will
4483 			 * return a Class A address and then shift the high
4484 			 * order 8bits over to convert it to the port#.
4485 			 */
4486 			*cp++ = '\0';
4487 			if (inet_aton(cp, &saddr) == 1) {
4488 				portnum = ntohl(saddr.s_addr);
4489 				portv = (uint16_t)((portnum >> 16) |
4490 				    (portnum & 0xff));
4491 			} else
4492 				cantparse = 1;
4493 		} else
4494 			cantparse = 1;
4495 		if (cantparse == 0) {
4496 			if (af == AF_INET) {
4497 				if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4498 					sin->sin_len = sizeof(*sin);
4499 					sin->sin_family = AF_INET;
4500 					sin->sin_port = htons(portv);
4501 					*saf = af;
4502 					return (0);
4503 				}
4504 			} else {
4505 				if (inet_pton(af, addr, &sin6->sin6_addr)
4506 				    == 1) {
4507 					sin6->sin6_len = sizeof(*sin6);
4508 					sin6->sin6_family = AF_INET6;
4509 					sin6->sin6_port = htons(portv);
4510 					*saf = af;
4511 					return (0);
4512 				}
4513 			}
4514 		}
4515 	} else {
4516 		if (i > 0) {
4517 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4518 			if (error)
4519 				goto nfsmout;
4520 		}
4521 	}
4522 	error = EPERM;
4523 nfsmout:
4524 	return (error);
4525 }
4526 
4527 /*
4528  * Handle an NFSv4.1 Sequence request for the session.
4529  * If reply != NULL, use it to return the cached reply, as required.
4530  * The client gets a cached reply via this call for callbacks, however the
4531  * server gets a cached reply via the nfsv4_seqsess_cachereply() call.
4532  */
4533 int
4534 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4535     struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4536 {
4537 	int error;
4538 
4539 	error = 0;
4540 	if (reply != NULL)
4541 		*reply = NULL;
4542 	if (slotid > maxslot)
4543 		return (NFSERR_BADSLOT);
4544 	if (seqid == slots[slotid].nfssl_seq) {
4545 		/* A retry. */
4546 		if (slots[slotid].nfssl_inprog != 0)
4547 			error = NFSERR_DELAY;
4548 		else if (slots[slotid].nfssl_reply != NULL) {
4549 			if (reply != NULL) {
4550 				*reply = slots[slotid].nfssl_reply;
4551 				slots[slotid].nfssl_reply = NULL;
4552 			}
4553 			slots[slotid].nfssl_inprog = 1;
4554 			error = NFSERR_REPLYFROMCACHE;
4555 		} else
4556 			/* No reply cached, so just do it. */
4557 			slots[slotid].nfssl_inprog = 1;
4558 	} else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4559 		if (slots[slotid].nfssl_reply != NULL)
4560 			m_freem(slots[slotid].nfssl_reply);
4561 		slots[slotid].nfssl_reply = NULL;
4562 		slots[slotid].nfssl_inprog = 1;
4563 		slots[slotid].nfssl_seq++;
4564 	} else
4565 		error = NFSERR_SEQMISORDERED;
4566 	return (error);
4567 }
4568 
4569 /*
4570  * Cache this reply for the slot.
4571  * Use the "rep" argument to return the cached reply if repstat is set to
4572  * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4573  */
4574 void
4575 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4576    struct mbuf **rep)
4577 {
4578 
4579 	if (repstat == NFSERR_REPLYFROMCACHE) {
4580 		*rep = slots[slotid].nfssl_reply;
4581 		slots[slotid].nfssl_reply = NULL;
4582 	} else {
4583 		if (slots[slotid].nfssl_reply != NULL)
4584 			m_freem(slots[slotid].nfssl_reply);
4585 		slots[slotid].nfssl_reply = *rep;
4586 	}
4587 	slots[slotid].nfssl_inprog = 0;
4588 }
4589 
4590 /*
4591  * Generate the xdr for an NFSv4.1 Sequence Operation.
4592  */
4593 APPLESTATIC void
4594 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
4595     struct nfsclsession *sep, int dont_replycache)
4596 {
4597 	uint32_t *tl, slotseq = 0;
4598 	int error, maxslot, slotpos;
4599 	uint8_t sessionid[NFSX_V4SESSIONID];
4600 
4601 	error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq,
4602 	    sessionid);
4603 
4604 	/* Build the Sequence arguments. */
4605 	NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
4606 	nd->nd_sequence = tl;
4607 	bcopy(sessionid, tl, NFSX_V4SESSIONID);
4608 	tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
4609 	nd->nd_slotseq = tl;
4610 	if (error == 0) {
4611 		nd->nd_flag |= ND_HASSLOTID;
4612 		nd->nd_slotid = slotpos;
4613 		*tl++ = txdr_unsigned(slotseq);
4614 		*tl++ = txdr_unsigned(slotpos);
4615 		*tl++ = txdr_unsigned(maxslot);
4616 		if (dont_replycache == 0)
4617 			*tl = newnfs_true;
4618 		else
4619 			*tl = newnfs_false;
4620 	} else {
4621 		/*
4622 		 * There are two errors and the rest of the session can
4623 		 * just be zeros.
4624 		 * NFSERR_BADSESSION: This bad session should just generate
4625 		 *    the same error again when the RPC is retried.
4626 		 * ESTALE: A forced dismount is in progress and will cause the
4627 		 *    RPC to fail later.
4628 		 */
4629 		*tl++ = 0;
4630 		*tl++ = 0;
4631 		*tl++ = 0;
4632 		*tl = 0;
4633 	}
4634 	nd->nd_flag |= ND_HASSEQUENCE;
4635 }
4636 
4637 int
4638 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
4639     int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid)
4640 {
4641 	int i, maxslot, slotpos;
4642 	uint64_t bitval;
4643 
4644 	/* Find an unused slot. */
4645 	slotpos = -1;
4646 	maxslot = -1;
4647 	mtx_lock(&sep->nfsess_mtx);
4648 	do {
4649 		if (nmp != NULL && sep->nfsess_defunct != 0) {
4650 			/* Just return the bad session. */
4651 			bcopy(sep->nfsess_sessionid, sessionid,
4652 			    NFSX_V4SESSIONID);
4653 			mtx_unlock(&sep->nfsess_mtx);
4654 			return (NFSERR_BADSESSION);
4655 		}
4656 		bitval = 1;
4657 		for (i = 0; i < sep->nfsess_foreslots; i++) {
4658 			if ((bitval & sep->nfsess_slots) == 0) {
4659 				slotpos = i;
4660 				sep->nfsess_slots |= bitval;
4661 				sep->nfsess_slotseq[i]++;
4662 				*slotseqp = sep->nfsess_slotseq[i];
4663 				break;
4664 			}
4665 			bitval <<= 1;
4666 		}
4667 		if (slotpos == -1) {
4668 			/*
4669 			 * If a forced dismount is in progress, just return.
4670 			 * This RPC attempt will fail when it calls
4671 			 * newnfs_request().
4672 			 */
4673 			if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
4674 				mtx_unlock(&sep->nfsess_mtx);
4675 				return (ESTALE);
4676 			}
4677 			/* Wake up once/sec, to check for a forced dismount. */
4678 			(void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
4679 			    PZERO, "nfsclseq", hz);
4680 		}
4681 	} while (slotpos == -1);
4682 	/* Now, find the highest slot in use. (nfsc_slots is 64bits) */
4683 	bitval = 1;
4684 	for (i = 0; i < 64; i++) {
4685 		if ((bitval & sep->nfsess_slots) != 0)
4686 			maxslot = i;
4687 		bitval <<= 1;
4688 	}
4689 	bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
4690 	mtx_unlock(&sep->nfsess_mtx);
4691 	*slotposp = slotpos;
4692 	*maxslotp = maxslot;
4693 	return (0);
4694 }
4695 
4696 /*
4697  * Free a session slot.
4698  */
4699 APPLESTATIC void
4700 nfsv4_freeslot(struct nfsclsession *sep, int slot)
4701 {
4702 	uint64_t bitval;
4703 
4704 	bitval = 1;
4705 	if (slot > 0)
4706 		bitval <<= slot;
4707 	mtx_lock(&sep->nfsess_mtx);
4708 	if ((bitval & sep->nfsess_slots) == 0)
4709 		printf("freeing free slot!!\n");
4710 	sep->nfsess_slots &= ~bitval;
4711 	wakeup(&sep->nfsess_slots);
4712 	mtx_unlock(&sep->nfsess_mtx);
4713 }
4714 
4715 /*
4716  * Search for a matching pnfsd DS, based on the nmp arg.
4717  * Return one if found, NULL otherwise.
4718  */
4719 struct nfsdevice *
4720 nfsv4_findmirror(struct nfsmount *nmp)
4721 {
4722 	struct nfsdevice *ds;
4723 
4724 	mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
4725 	/*
4726 	 * Search the DS server list for a match with nmp.
4727 	 */
4728 	if (nfsrv_devidcnt == 0)
4729 		return (NULL);
4730 	TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
4731 		if (ds->nfsdev_nmp == nmp) {
4732 			NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");
4733 			break;
4734 		}
4735 	}
4736 	return (ds);
4737 }
4738 
4739