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