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