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