xref: /freebsd/sys/fs/nfs/nfs_commonsubs.c (revision a6369fb9e4b40396ea6ef1987436019612c387cd)
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 static int ncl_mbuf_mhlen = MHLEN;
198 struct nfsrv_lughash {
199 	struct mtx		mtx;
200 	struct nfsuserhashhead	lughead;
201 };
202 
203 NFSD_VNET_DEFINE_STATIC(int, nfsrv_usercnt) = 0;
204 NFSD_VNET_DEFINE_STATIC(int, nfsrv_dnsnamelen) = 0;
205 NFSD_VNET_DEFINE_STATIC(int, nfsrv_usermax) = 999999999;
206 NFSD_VNET_DEFINE_STATIC(struct nfsrv_lughash *, nfsuserhash) = NULL;
207 NFSD_VNET_DEFINE_STATIC(struct nfsrv_lughash *, nfsusernamehash) = NULL;
208 NFSD_VNET_DEFINE_STATIC(struct nfsrv_lughash *, nfsgrouphash) = NULL;
209 NFSD_VNET_DEFINE_STATIC(struct nfsrv_lughash *, nfsgroupnamehash) = NULL;
210 NFSD_VNET_DEFINE_STATIC(u_char *, nfsrv_dnsname) = NULL;
211 
212 /*
213  * This static array indicates whether or not the RPC generates a large
214  * reply. This is used by nfs_reply() to decide whether or not an mbuf
215  * cluster should be allocated. (If a cluster is required by an RPC
216  * marked 0 in this array, the code will still work, just not quite as
217  * efficiently.)
218  */
219 static bool nfs_bigreply[NFSV42_NPROCS] = {
220 	[NFSPROC_GETACL] = true,
221 	[NFSPROC_GETEXTATTR] = true,
222 	[NFSPROC_LISTEXTATTR] = true,
223 	[NFSPROC_LOOKUP] = true,
224 	[NFSPROC_READ] = true,
225 	[NFSPROC_READDIR] = true,
226 	[NFSPROC_READDIRPLUS] = true,
227 	[NFSPROC_READDS] = true,
228 	[NFSPROC_READLINK] = true,
229 };
230 
231 /* local functions */
232 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
233 static void nfsv4_wanted(struct nfsv4lock *lp);
234 static uint32_t nfsv4_filesavail(struct statfs *, struct mount *);
235 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name);
236 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
237 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
238     int *, int *);
239 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
240 static uint32_t vtonfsv4_type(struct vattr *);
241 static __enum_uint8(vtype) nfsv4tov_type(uint32_t, uint16_t *);
242 static void nfsv4_setsequence(struct nfsmount *, struct nfsrv_descript *,
243     struct nfsclsession *, bool, struct ucred *);
244 
245 static struct {
246 	int	op;
247 	int	opcnt;
248 	const u_char *tag;
249 	int	taglen;
250 } nfsv4_opmap[NFSV42_NPROCS] = {
251 	{ 0, 1, "Null", 4 },
252 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
253 	{ NFSV4OP_SETATTR, 2, "Setattr", 7, },
254 	{ NFSV4OP_LOOKUP, 3, "Lookup", 6, },
255 	{ NFSV4OP_ACCESS, 2, "Access", 6, },
256 	{ NFSV4OP_READLINK, 2, "Readlink", 8, },
257 	{ NFSV4OP_READ, 1, "Read", 4, },
258 	{ NFSV4OP_WRITE, 2, "Write", 5, },
259 	{ NFSV4OP_OPEN, 5, "Open", 4, },
260 	{ NFSV4OP_CREATE, 5, "Create", 6, },
261 	{ NFSV4OP_CREATE, 1, "Create", 6, },
262 	{ NFSV4OP_CREATE, 3, "Create", 6, },
263 	{ NFSV4OP_REMOVE, 3, "Remove", 6, },
264 	{ NFSV4OP_REMOVE, 1, "Remove", 6, },
265 	{ NFSV4OP_SAVEFH, 7, "Rename", 6, },
266 	{ NFSV4OP_SAVEFH, 6, "Link", 4, },
267 	{ NFSV4OP_READDIR, 2, "Readdir", 7, },
268 	{ NFSV4OP_READDIR, 2, "Readdir", 7, },
269 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
270 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
271 	{ NFSV4OP_GETATTR, 1, "Getattr", 7, },
272 	{ NFSV4OP_COMMIT, 2, "Commit", 6, },
273 	{ NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
274 	{ NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
275 	{ NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
276 	{ NFSV4OP_LOCK, 1, "Lock", 4, },
277 	{ NFSV4OP_LOCKU, 1, "LockU", 5, },
278 	{ NFSV4OP_OPEN, 2, "Open", 4, },
279 	{ NFSV4OP_CLOSE, 1, "Close", 5, },
280 	{ NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
281 	{ NFSV4OP_LOCKT, 1, "LockT", 5, },
282 	{ NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
283 	{ NFSV4OP_RENEW, 1, "Renew", 5, },
284 	{ NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
285 	{ NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
286 	{ NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
287 	{ NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
288 	{ NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
289 	{ NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
290 	{ NFSV4OP_GETATTR, 1, "Getacl", 6, },
291 	{ NFSV4OP_SETATTR, 1, "Setacl", 6, },
292 	{ NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
293 	{ NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
294 	{ NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
295 	{ NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
296 	{ NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
297 	{ NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, },
298 	{ NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, },
299 	{ NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, },
300 	{ NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, },
301 	{ NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, },
302 	{ NFSV4OP_WRITE, 1, "WriteDS", 7, },
303 	{ NFSV4OP_READ, 1, "ReadDS", 6, },
304 	{ NFSV4OP_COMMIT, 1, "CommitDS", 8, },
305 	{ NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, },
306 	{ NFSV4OP_OPEN, 8, "CreateLayGet", 12, },
307 	{ NFSV4OP_IOADVISE, 1, "Advise", 6, },
308 	{ NFSV4OP_ALLOCATE, 2, "Allocate", 8, },
309 	{ NFSV4OP_SAVEFH, 5, "Copy", 4, },
310 	{ NFSV4OP_SEEK, 2, "Seek", 4, },
311 	{ NFSV4OP_SEEK, 1, "SeekDS", 6, },
312 	{ NFSV4OP_GETXATTR, 2, "Getxattr", 8, },
313 	{ NFSV4OP_SETXATTR, 2, "Setxattr", 8, },
314 	{ NFSV4OP_REMOVEXATTR, 2, "Rmxattr", 7, },
315 	{ NFSV4OP_LISTXATTRS, 2, "Listxattr", 9, },
316 	{ NFSV4OP_BINDCONNTOSESS, 1, "BindConSess", 11, },
317 	{ NFSV4OP_LOOKUP, 5, "LookupOpen", 10, },
318 	{ NFSV4OP_DEALLOCATE, 2, "Deallocate", 10, },
319 	{ NFSV4OP_LAYOUTERROR, 1, "LayoutError", 11, },
320 	{ NFSV4OP_VERIFY, 3, "AppendWrite", 11, },
321 	{ NFSV4OP_OPENATTR, 3, "OpenAttr", 8, },
322 	{ NFSV4OP_SAVEFH, 5, "Clone", 5, },
323 };
324 
325 /*
326  * NFS RPCS that have large request message size.
327  */
328 static int nfs_bigrequest[NFSV42_NPROCS] = {
329 	0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
330 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
331 	0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
332 	0, 1, 0, 0
333 };
334 
335 /*
336  * Start building a request. Mostly just put the first file handle in
337  * place.
338  */
339 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)340 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
341     u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep,
342     int vers, int minorvers, struct ucred *cred)
343 {
344 	struct mbuf *mb;
345 	u_int32_t *tl;
346 	int opcnt;
347 	nfsattrbit_t attrbits;
348 
349 	/*
350 	 * First, fill in some of the fields of nd.
351 	 */
352 	nd->nd_slotseq = NULL;
353 	if (vers == NFS_VER4) {
354 		nd->nd_flag = ND_NFSV4 | ND_NFSCL;
355 		if (minorvers == NFSV41_MINORVERSION)
356 			nd->nd_flag |= ND_NFSV41;
357 		else if (minorvers == NFSV42_MINORVERSION)
358 			nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
359 	} else if (vers == NFS_VER3)
360 		nd->nd_flag = ND_NFSV3 | ND_NFSCL;
361 	else {
362 		if (NFSHASNFSV4(nmp)) {
363 			nd->nd_flag = ND_NFSV4 | ND_NFSCL;
364 			if (nmp->nm_minorvers == 1)
365 				nd->nd_flag |= ND_NFSV41;
366 			else if (nmp->nm_minorvers == 2)
367 				nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
368 		} else if (NFSHASNFSV3(nmp))
369 			nd->nd_flag = ND_NFSV3 | ND_NFSCL;
370 		else
371 			nd->nd_flag = ND_NFSV2 | ND_NFSCL;
372 	}
373 	nd->nd_procnum = procnum;
374 	nd->nd_repstat = 0;
375 	nd->nd_maxextsiz = 0;
376 
377 	/*
378 	 * Get the first mbuf for the request.
379 	 */
380 	if (nfs_bigrequest[procnum])
381 		NFSMCLGET(mb, M_WAITOK);
382 	else
383 		NFSMGET(mb);
384 	mb->m_len = 0;
385 	nd->nd_mreq = nd->nd_mb = mb;
386 	nd->nd_bpos = mtod(mb, char *);
387 
388 	/* For NFSPROC_NULL, there are no arguments. */
389 	if (procnum == NFSPROC_NULL)
390 		goto out;
391 
392 	/*
393 	 * And fill the first file handle into the request.
394 	 */
395 	if (nd->nd_flag & ND_NFSV4) {
396 		opcnt = nfsv4_opmap[procnum].opcnt +
397 		    nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
398 		if ((nd->nd_flag & ND_NFSV41) != 0) {
399 			opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
400 			if (procnum == NFSPROC_RENEW)
401 				/*
402 				 * For the special case of Renew, just do a
403 				 * Sequence Op.
404 				 */
405 				opcnt = 1;
406 			else if (procnum == NFSPROC_WRITEDS ||
407 			    procnum == NFSPROC_COMMITDS)
408 				/*
409 				 * For the special case of a Writeor Commit to
410 				 * a DS, the opcnt == 3, for Sequence, PutFH,
411 				 * Write/Commit.
412 				 */
413 				opcnt = 3;
414 		}
415 		/*
416 		 * What should the tag really be?
417 		 */
418 		(void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
419 			nfsv4_opmap[procnum].taglen);
420 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
421 		if ((nd->nd_flag & ND_NFSV42) != 0)
422 			*tl++ = txdr_unsigned(NFSV42_MINORVERSION);
423 		else if ((nd->nd_flag & ND_NFSV41) != 0)
424 			*tl++ = txdr_unsigned(NFSV41_MINORVERSION);
425 		else
426 			*tl++ = txdr_unsigned(NFSV4_MINORVERSION);
427 		if (opcntpp != NULL)
428 			*opcntpp = tl;
429 		*tl = txdr_unsigned(opcnt);
430 		if ((nd->nd_flag & ND_NFSV41) != 0 &&
431 		    nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
432 			if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess >
433 			    0)
434 				nd->nd_flag |= ND_LOOPBADSESS;
435 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
436 			*tl = txdr_unsigned(NFSV4OP_SEQUENCE);
437 			if (sep == NULL) {
438 				sep = nfsmnt_mdssession(nmp);
439 				/*
440 				 * For MDS mount sessions, check for bad
441 				 * slots.  If the caller does not want this
442 				 * check to be done, the "cred" argument can
443 				 * be passed in as NULL.
444 				 */
445 				nfsv4_setsequence(nmp, nd, sep,
446 				    nfs_bigreply[procnum], cred);
447 			} else
448 				nfsv4_setsequence(nmp, nd, sep,
449 				    nfs_bigreply[procnum], NULL);
450 		}
451 		if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
452 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
453 			*tl = txdr_unsigned(NFSV4OP_PUTFH);
454 			(void)nfsm_fhtom(nmp, nd, nfhp, fhlen, 0);
455 			if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
456 			    == 2 && procnum != NFSPROC_WRITEDS &&
457 			    procnum != NFSPROC_COMMITDS) {
458 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
459 				*tl = txdr_unsigned(NFSV4OP_GETATTR);
460 				/*
461 				 * For Lookup Ops, we want all the directory
462 				 * attributes, so we can load the name cache.
463 				 */
464 				if (procnum == NFSPROC_LOOKUP ||
465 				    procnum == NFSPROC_LOOKUPP ||
466 				    procnum == NFSPROC_LOOKUPOPEN)
467 					NFSGETATTR_ATTRBIT(&attrbits);
468 				else {
469 					NFSWCCATTR_ATTRBIT(&attrbits);
470 					/* For AppendWrite, get the size. */
471 					if (procnum == NFSPROC_APPENDWRITE)
472 						NFSSETBIT_ATTRBIT(&attrbits,
473 						    NFSATTRBIT_SIZE);
474 					nd->nd_flag |= ND_V4WCCATTR;
475 				}
476 				(void) nfsrv_putattrbit(nd, &attrbits);
477 			}
478 		}
479 		if (procnum != NFSPROC_RENEW ||
480 		    (nd->nd_flag & ND_NFSV41) == 0) {
481 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
482 			*tl = txdr_unsigned(nfsv4_opmap[procnum].op);
483 		}
484 	} else {
485 		(void)nfsm_fhtom(NULL, nd, nfhp, fhlen, 0);
486 	}
487 out:
488 	if (procnum < NFSV42_NPROCS)
489 		NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
490 }
491 
492 /*
493  * Put a state Id in the mbuf list.
494  */
495 void
nfsm_stateidtom(struct nfsrv_descript * nd,nfsv4stateid_t * stateidp,int flag)496 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
497 {
498 	nfsv4stateid_t *st;
499 
500 	NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
501 	if (flag == NFSSTATEID_PUTALLZERO) {
502 		st->seqid = 0;
503 		st->other[0] = 0;
504 		st->other[1] = 0;
505 		st->other[2] = 0;
506 	} else if (flag == NFSSTATEID_PUTALLONE) {
507 		st->seqid = 0xffffffff;
508 		st->other[0] = 0xffffffff;
509 		st->other[1] = 0xffffffff;
510 		st->other[2] = 0xffffffff;
511 	} else if (flag == NFSSTATEID_PUTSEQIDZERO) {
512 		st->seqid = 0;
513 		st->other[0] = stateidp->other[0];
514 		st->other[1] = stateidp->other[1];
515 		st->other[2] = stateidp->other[2];
516 	} else {
517 		st->seqid = stateidp->seqid;
518 		st->other[0] = stateidp->other[0];
519 		st->other[1] = stateidp->other[1];
520 		st->other[2] = stateidp->other[2];
521 	}
522 }
523 
524 /*
525  * Fill in the setable attributes. The full argument indicates whether
526  * to fill in them all or just mode and time.
527  */
528 void
nfscl_fillsattr(struct nfsrv_descript * nd,struct vattr * vap,struct vnode * vp,int flags,u_int32_t rdev)529 nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
530     struct vnode *vp, int flags, u_int32_t rdev)
531 {
532 	u_int32_t *tl;
533 	struct nfsv2_sattr *sp;
534 	nfsattrbit_t attrbits;
535 	struct nfsnode *np;
536 
537 	switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
538 	case ND_NFSV2:
539 		NFSM_BUILD(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
540 		if (vap->va_mode == (mode_t)VNOVAL)
541 			sp->sa_mode = newnfs_xdrneg1;
542 		else
543 			sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
544 		if (vap->va_uid == (uid_t)VNOVAL)
545 			sp->sa_uid = newnfs_xdrneg1;
546 		else
547 			sp->sa_uid = txdr_unsigned(vap->va_uid);
548 		if (vap->va_gid == (gid_t)VNOVAL)
549 			sp->sa_gid = newnfs_xdrneg1;
550 		else
551 			sp->sa_gid = txdr_unsigned(vap->va_gid);
552 		if (flags & NFSSATTR_SIZE0)
553 			sp->sa_size = 0;
554 		else if (flags & NFSSATTR_SIZENEG1)
555 			sp->sa_size = newnfs_xdrneg1;
556 		else if (flags & NFSSATTR_SIZERDEV)
557 			sp->sa_size = txdr_unsigned(rdev);
558 		else
559 			sp->sa_size = txdr_unsigned(vap->va_size);
560 		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
561 		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
562 		break;
563 	case ND_NFSV3:
564 		if (vap->va_mode != (mode_t)VNOVAL) {
565 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
566 			*tl++ = newnfs_true;
567 			*tl = txdr_unsigned(vap->va_mode);
568 		} else {
569 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
570 			*tl = newnfs_false;
571 		}
572 		if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL) {
573 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
574 			*tl++ = newnfs_true;
575 			*tl = txdr_unsigned(vap->va_uid);
576 		} else {
577 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
578 			*tl = newnfs_false;
579 		}
580 		if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL) {
581 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
582 			*tl++ = newnfs_true;
583 			*tl = txdr_unsigned(vap->va_gid);
584 		} else {
585 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
586 			*tl = newnfs_false;
587 		}
588 		if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) {
589 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
590 			*tl++ = newnfs_true;
591 			txdr_hyper(vap->va_size, tl);
592 		} else {
593 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
594 			*tl = newnfs_false;
595 		}
596 		if (vap->va_atime.tv_sec != VNOVAL) {
597 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
598 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
599 				*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
600 				txdr_nfsv3time(&vap->va_atime, tl);
601 			} else {
602 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
603 				*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
604 			}
605 		} else {
606 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
607 			*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
608 		}
609 		if (vap->va_mtime.tv_sec != VNOVAL) {
610 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
611 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
612 				*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
613 				txdr_nfsv3time(&vap->va_mtime, tl);
614 			} else {
615 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
616 				*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
617 			}
618 		} else {
619 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
620 			*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
621 		}
622 		break;
623 	case ND_NFSV4:
624 		NFSZERO_ATTRBIT(&attrbits);
625 		np = NULL;
626 		if (strcmp(vp->v_mount->mnt_vfc->vfc_name, "nfs") == 0)
627 			np = VTONFS(vp);
628 		if (vap->va_mode != (mode_t)VNOVAL) {
629 			if ((flags & NFSSATTR_NEWFILE) != 0 && np != NULL &&
630 			    NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr,
631 			    NFSATTRBIT_MODEUMASK))
632 				NFSSETBIT_ATTRBIT(&attrbits,
633 				    NFSATTRBIT_MODEUMASK);
634 			else
635 				NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MODE);
636 		}
637 		if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL)
638 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
639 		if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL)
640 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP);
641 		if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL)
642 			NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
643 		if ((flags & NFSSATTR_FULL) && vap->va_flags != VNOVAL) {
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 > ncl_mbuf_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, u_int32_t *, NFSX_UNSIGNED);
1676 			if (compare && !(*retcmpp))
1677 				*retcmpp = NFSERR_ATTRNOTSUPP;
1678 			attrsum += NFSX_UNSIGNED;
1679 			break;
1680 		case NFSATTRBIT_CANSETTIME:
1681 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1682 			if (compare) {
1683 				if (!(*retcmpp)) {
1684 				    if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1685 					if (*tl == newnfs_false)
1686 						*retcmpp = NFSERR_NOTSAME;
1687 				    } else {
1688 					if (*tl == newnfs_true)
1689 						*retcmpp = NFSERR_NOTSAME;
1690 				    }
1691 				}
1692 			} else if (fsp != NULL) {
1693 				if (*tl == newnfs_true)
1694 					fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1695 				else
1696 					fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1697 			}
1698 			attrsum += NFSX_UNSIGNED;
1699 			break;
1700 		case NFSATTRBIT_CASEINSENSITIVE:
1701 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1702 			if (compare) {
1703 				if (!(*retcmpp)) {
1704 				    if (*tl != newnfs_false)
1705 					*retcmpp = NFSERR_NOTSAME;
1706 				}
1707 			} else if (pc != NULL) {
1708 				pc->pc_caseinsensitive =
1709 				    fxdr_unsigned(u_int32_t, *tl);
1710 			}
1711 			attrsum += NFSX_UNSIGNED;
1712 			break;
1713 		case NFSATTRBIT_CASEPRESERVING:
1714 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1715 			if (compare) {
1716 				if (!(*retcmpp)) {
1717 				    if (*tl != newnfs_true)
1718 					*retcmpp = NFSERR_NOTSAME;
1719 				}
1720 			} else if (pc != NULL) {
1721 				pc->pc_casepreserving =
1722 				    fxdr_unsigned(u_int32_t, *tl);
1723 			}
1724 			attrsum += NFSX_UNSIGNED;
1725 			break;
1726 		case NFSATTRBIT_CHOWNRESTRICTED:
1727 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1728 			if (compare) {
1729 				if (!(*retcmpp)) {
1730 				    if (*tl != newnfs_true)
1731 					*retcmpp = NFSERR_NOTSAME;
1732 				}
1733 			} else if (pc != NULL) {
1734 				pc->pc_chownrestricted =
1735 				    fxdr_unsigned(u_int32_t, *tl);
1736 			}
1737 			attrsum += NFSX_UNSIGNED;
1738 			break;
1739 		case NFSATTRBIT_FILEHANDLE:
1740 			error = nfsm_getfh(nd, &tnfhp);
1741 			if (error)
1742 				goto nfsmout;
1743 			tfhsize = tnfhp->nfh_len;
1744 			if (compare) {
1745 				if (tfhsize > NFSX_MYFH)
1746 					tfhsize = NFSX_MYFH;
1747 				if (!(*retcmpp) &&
1748 				    !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1749 				     fhp, fhsize))
1750 					*retcmpp = NFSERR_NOTSAME;
1751 				free(tnfhp, M_NFSFH);
1752 			} else if (nfhpp != NULL) {
1753 				*nfhpp = tnfhp;
1754 			} else {
1755 				free(tnfhp, M_NFSFH);
1756 			}
1757 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1758 			break;
1759 		case NFSATTRBIT_FILEID:
1760 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1761 			thyp = fxdr_hyper(tl);
1762 			if (compare) {
1763 				if (!(*retcmpp)) {
1764 					if (nap->na_fileid != thyp)
1765 						*retcmpp = NFSERR_NOTSAME;
1766 				}
1767 			} else if (nap != NULL)
1768 				nap->na_fileid = thyp;
1769 			attrsum += NFSX_HYPER;
1770 			break;
1771 		case NFSATTRBIT_FILESAVAIL:
1772 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1773 			if (compare) {
1774 				uquad = nfsv4_filesavail(sbp, vp->v_mount);
1775 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1776 					*retcmpp = NFSERR_NOTSAME;
1777 			} else if (sfp != NULL) {
1778 				sfp->sf_afiles = fxdr_hyper(tl);
1779 			}
1780 			attrsum += NFSX_HYPER;
1781 			break;
1782 		case NFSATTRBIT_FILESFREE:
1783 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1784 			if (compare) {
1785 				uquad = (uint64_t)sbp->f_ffree;
1786 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1787 					*retcmpp = NFSERR_NOTSAME;
1788 			} else if (sfp != NULL) {
1789 				sfp->sf_ffiles = fxdr_hyper(tl);
1790 			}
1791 			attrsum += NFSX_HYPER;
1792 			break;
1793 		case NFSATTRBIT_FILESTOTAL:
1794 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1795 			if (compare) {
1796 				uquad = sbp->f_files;
1797 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1798 					*retcmpp = NFSERR_NOTSAME;
1799 			} else if (sfp != NULL) {
1800 				sfp->sf_tfiles = fxdr_hyper(tl);
1801 			}
1802 			attrsum += NFSX_HYPER;
1803 			break;
1804 		case NFSATTRBIT_FSLOCATIONS:
1805 			error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1806 			if (error)
1807 				goto nfsmout;
1808 			attrsum += l;
1809 			if (compare && !(*retcmpp)) {
1810 				refp = nfsv4root_getreferral(vp, NULL, 0);
1811 				if (refp != NULL) {
1812 					if (cp == NULL || cp2 == NULL ||
1813 					    strcmp(cp, "/") ||
1814 					    strcmp(cp2, refp->nfr_srvlist))
1815 						*retcmpp = NFSERR_NOTSAME;
1816 				} else if (m == 0) {
1817 					*retcmpp = NFSERR_NOTSAME;
1818 				}
1819 			}
1820 			if (cp != NULL)
1821 				free(cp, M_NFSSTRING);
1822 			if (cp2 != NULL)
1823 				free(cp2, M_NFSSTRING);
1824 			break;
1825 		case NFSATTRBIT_HIDDEN:
1826 			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
1827 			if (compare) {
1828 				if (!(*retcmpp) && ((*tl == newnfs_true &&
1829 				    (nap->na_flags & UF_HIDDEN) == 0) ||
1830 				    (*tl == newnfs_false &&
1831 				     (nap->na_flags & UF_HIDDEN) != 0)))
1832 					*retcmpp = NFSERR_NOTSAME;
1833 			} else if (nap != NULL) {
1834 				if (*tl == newnfs_true)
1835 					nap->na_flags |= UF_HIDDEN;
1836 			}
1837 			attrsum += NFSX_UNSIGNED;
1838 			break;
1839 		case NFSATTRBIT_HOMOGENEOUS:
1840 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1841 			if (compare) {
1842 				if (!(*retcmpp)) {
1843 				    if (fsp->fs_properties &
1844 					NFSV3_FSFHOMOGENEOUS) {
1845 					if (*tl == newnfs_false)
1846 						*retcmpp = NFSERR_NOTSAME;
1847 				    } else {
1848 					if (*tl == newnfs_true)
1849 						*retcmpp = NFSERR_NOTSAME;
1850 				    }
1851 				}
1852 			} else if (fsp != NULL) {
1853 				if (*tl == newnfs_true)
1854 				    fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1855 				else
1856 				    fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1857 			}
1858 			attrsum += NFSX_UNSIGNED;
1859 			break;
1860 		case NFSATTRBIT_MAXFILESIZE:
1861 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1862 			tnfsquad.qval = fxdr_hyper(tl);
1863 			if (compare) {
1864 				if (!(*retcmpp)) {
1865 					tquad = NFSRV_MAXFILESIZE;
1866 					if (tquad != tnfsquad.qval)
1867 						*retcmpp = NFSERR_NOTSAME;
1868 				}
1869 			} else if (fsp != NULL) {
1870 				fsp->fs_maxfilesize = tnfsquad.qval;
1871 			}
1872 			attrsum += NFSX_HYPER;
1873 			break;
1874 		case NFSATTRBIT_MAXLINK:
1875 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1876 			if (compare) {
1877 				if (!(*retcmpp)) {
1878 				    if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1879 					*retcmpp = NFSERR_NOTSAME;
1880 				}
1881 			} else if (pc != NULL) {
1882 				pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1883 			}
1884 			attrsum += NFSX_UNSIGNED;
1885 			break;
1886 		case NFSATTRBIT_MAXNAME:
1887 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1888 			if (compare) {
1889 				if (!(*retcmpp)) {
1890 				    if (fsp->fs_maxname !=
1891 					fxdr_unsigned(u_int32_t, *tl))
1892 						*retcmpp = NFSERR_NOTSAME;
1893 				}
1894 			} else {
1895 				tuint = fxdr_unsigned(u_int32_t, *tl);
1896 				/*
1897 				 * Some Linux NFSv4 servers report this
1898 				 * as 0 or 4billion, so I'll set it to
1899 				 * NFS_MAXNAMLEN. If a server actually creates
1900 				 * a name longer than NFS_MAXNAMLEN, it will
1901 				 * get an error back.
1902 				 */
1903 				if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1904 					tuint = NFS_MAXNAMLEN;
1905 				if (fsp != NULL)
1906 					fsp->fs_maxname = tuint;
1907 				if (pc != NULL)
1908 					pc->pc_namemax = tuint;
1909 			}
1910 			attrsum += NFSX_UNSIGNED;
1911 			break;
1912 		case NFSATTRBIT_MAXREAD:
1913 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1914 			if (compare) {
1915 				if (!(*retcmpp)) {
1916 				    if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1917 					*(tl + 1)) || *tl != 0)
1918 					*retcmpp = NFSERR_NOTSAME;
1919 				}
1920 			} else if (fsp != NULL) {
1921 				fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1922 				fsp->fs_rtpref = fsp->fs_rtmax;
1923 				fsp->fs_dtpref = fsp->fs_rtpref;
1924 			}
1925 			attrsum += NFSX_HYPER;
1926 			break;
1927 		case NFSATTRBIT_MAXWRITE:
1928 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1929 			if (compare) {
1930 				if (!(*retcmpp)) {
1931 				    if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1932 					*(tl + 1)) || *tl != 0)
1933 					*retcmpp = NFSERR_NOTSAME;
1934 				}
1935 			} else if (fsp != NULL) {
1936 				fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1937 				fsp->fs_wtpref = fsp->fs_wtmax;
1938 			}
1939 			attrsum += NFSX_HYPER;
1940 			break;
1941 		case NFSATTRBIT_MIMETYPE:
1942 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1943 			i = fxdr_unsigned(int, *tl);
1944 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1945 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1946 			if (error)
1947 				goto nfsmout;
1948 			if (compare && !(*retcmpp))
1949 				*retcmpp = NFSERR_ATTRNOTSUPP;
1950 			break;
1951 		case NFSATTRBIT_MODE:
1952 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1953 			if (compare) {
1954 				if (!(*retcmpp)) {
1955 				    if (nap->na_mode != nfstov_mode(*tl))
1956 					*retcmpp = NFSERR_NOTSAME;
1957 				}
1958 			} else if (nap != NULL) {
1959 				nap->na_mode = nfstov_mode(*tl);
1960 			}
1961 			attrsum += NFSX_UNSIGNED;
1962 			break;
1963 		case NFSATTRBIT_NOTRUNC:
1964 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1965 			if (compare) {
1966 				if (!(*retcmpp)) {
1967 				    if (*tl != newnfs_true)
1968 					*retcmpp = NFSERR_NOTSAME;
1969 				}
1970 			} else if (pc != NULL) {
1971 				pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1972 			}
1973 			attrsum += NFSX_UNSIGNED;
1974 			break;
1975 		case NFSATTRBIT_NUMLINKS:
1976 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1977 			tuint = fxdr_unsigned(u_int32_t, *tl);
1978 			if (compare) {
1979 			    if (!(*retcmpp)) {
1980 				if ((u_int32_t)nap->na_nlink != tuint)
1981 					*retcmpp = NFSERR_NOTSAME;
1982 			    }
1983 			} else if (nap != NULL) {
1984 				nap->na_nlink = tuint;
1985 			}
1986 			attrsum += NFSX_UNSIGNED;
1987 			break;
1988 		case NFSATTRBIT_OWNER:
1989 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1990 			j = fxdr_unsigned(int, *tl);
1991 			if (j < 0 || j > NFSV4_MAXOWNERGROUPLEN) {
1992 				error = NFSERR_BADXDR;
1993 				goto nfsmout;
1994 			}
1995 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1996 			if (j > NFSV4_SMALLSTR)
1997 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1998 			else
1999 				cp = namestr;
2000 			error = nfsrv_mtostr(nd, cp, j);
2001 			if (error) {
2002 				if (j > NFSV4_SMALLSTR)
2003 					free(cp, M_NFSSTRING);
2004 				goto nfsmout;
2005 			}
2006 			if (compare) {
2007 			    if (!(*retcmpp)) {
2008 				if (nfsv4_strtouid(nd, cp, j, &uid) ||
2009 				    nap->na_uid != uid)
2010 				    *retcmpp = NFSERR_NOTSAME;
2011 			    }
2012 			} else if (nap != NULL) {
2013 				if (nfsv4_strtouid(nd, cp, j, &uid))
2014 					nap->na_uid =
2015 					    NFSD_VNET(nfsrv_defaultuid);
2016 				else
2017 					nap->na_uid = uid;
2018 			}
2019 			if (j > NFSV4_SMALLSTR)
2020 				free(cp, M_NFSSTRING);
2021 			break;
2022 		case NFSATTRBIT_OWNERGROUP:
2023 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2024 			j = fxdr_unsigned(int, *tl);
2025 			if (j < 0 || j > NFSV4_MAXOWNERGROUPLEN) {
2026 				error =  NFSERR_BADXDR;
2027 				goto nfsmout;
2028 			}
2029 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
2030 			if (j > NFSV4_SMALLSTR)
2031 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
2032 			else
2033 				cp = namestr;
2034 			error = nfsrv_mtostr(nd, cp, j);
2035 			if (error) {
2036 				if (j > NFSV4_SMALLSTR)
2037 					free(cp, M_NFSSTRING);
2038 				goto nfsmout;
2039 			}
2040 			if (compare) {
2041 			    if (!(*retcmpp)) {
2042 				if (nfsv4_strtogid(nd, cp, j, &gid) ||
2043 				    nap->na_gid != gid)
2044 				    *retcmpp = NFSERR_NOTSAME;
2045 			    }
2046 			} else if (nap != NULL) {
2047 				if (nfsv4_strtogid(nd, cp, j, &gid))
2048 					nap->na_gid =
2049 					    NFSD_VNET(nfsrv_defaultgid);
2050 				else
2051 					nap->na_gid = gid;
2052 			}
2053 			if (j > NFSV4_SMALLSTR)
2054 				free(cp, M_NFSSTRING);
2055 			break;
2056 		case NFSATTRBIT_QUOTAHARD:
2057 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2058 			if (sbp != NULL) {
2059 			    if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2060 				freenum = sbp->f_bfree;
2061 			    else
2062 				freenum = sbp->f_bavail;
2063 #ifdef QUOTA
2064 			    /*
2065 			     * ufs_quotactl() insists that the uid argument
2066 			     * equal p_ruid for non-root quota access, so
2067 			     * we'll just make sure that's the case.
2068 			     */
2069 			    savuid = p->p_cred->p_ruid;
2070 			    p->p_cred->p_ruid = cred->cr_uid;
2071 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
2072 				USRQUOTA), cred->cr_uid, &dqb))
2073 				freenum = min(dqb.dqb_bhardlimit, freenum);
2074 			    p->p_cred->p_ruid = savuid;
2075 #endif	/* QUOTA */
2076 			    uquad = (u_int64_t)freenum;
2077 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
2078 			}
2079 			if (compare && !(*retcmpp)) {
2080 				if (uquad != fxdr_hyper(tl))
2081 					*retcmpp = NFSERR_NOTSAME;
2082 			}
2083 			attrsum += NFSX_HYPER;
2084 			break;
2085 		case NFSATTRBIT_QUOTASOFT:
2086 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2087 			if (sbp != NULL) {
2088 			    if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2089 				freenum = sbp->f_bfree;
2090 			    else
2091 				freenum = sbp->f_bavail;
2092 #ifdef QUOTA
2093 			    /*
2094 			     * ufs_quotactl() insists that the uid argument
2095 			     * equal p_ruid for non-root quota access, so
2096 			     * we'll just make sure that's the case.
2097 			     */
2098 			    savuid = p->p_cred->p_ruid;
2099 			    p->p_cred->p_ruid = cred->cr_uid;
2100 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
2101 				USRQUOTA), cred->cr_uid, &dqb))
2102 				freenum = min(dqb.dqb_bsoftlimit, freenum);
2103 			    p->p_cred->p_ruid = savuid;
2104 #endif	/* QUOTA */
2105 			    uquad = (u_int64_t)freenum;
2106 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
2107 			}
2108 			if (compare && !(*retcmpp)) {
2109 				if (uquad != fxdr_hyper(tl))
2110 					*retcmpp = NFSERR_NOTSAME;
2111 			}
2112 			attrsum += NFSX_HYPER;
2113 			break;
2114 		case NFSATTRBIT_QUOTAUSED:
2115 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2116 			if (sbp != NULL) {
2117 			    freenum = 0;
2118 #ifdef QUOTA
2119 			    /*
2120 			     * ufs_quotactl() insists that the uid argument
2121 			     * equal p_ruid for non-root quota access, so
2122 			     * we'll just make sure that's the case.
2123 			     */
2124 			    savuid = p->p_cred->p_ruid;
2125 			    p->p_cred->p_ruid = cred->cr_uid;
2126 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
2127 				USRQUOTA), cred->cr_uid, &dqb))
2128 				freenum = dqb.dqb_curblocks;
2129 			    p->p_cred->p_ruid = savuid;
2130 #endif	/* QUOTA */
2131 			    uquad = (u_int64_t)freenum;
2132 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
2133 			}
2134 			if (compare && !(*retcmpp)) {
2135 				if (uquad != fxdr_hyper(tl))
2136 					*retcmpp = NFSERR_NOTSAME;
2137 			}
2138 			attrsum += NFSX_HYPER;
2139 			break;
2140 		case NFSATTRBIT_RAWDEV:
2141 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
2142 			j = fxdr_unsigned(int, *tl++);
2143 			k = fxdr_unsigned(int, *tl);
2144 			if (compare) {
2145 			    if (!(*retcmpp)) {
2146 				if (nap->na_rdev != NFSMAKEDEV(j, k))
2147 					*retcmpp = NFSERR_NOTSAME;
2148 			    }
2149 			} else if (nap != NULL) {
2150 				nap->na_rdev = NFSMAKEDEV(j, k);
2151 			}
2152 			attrsum += NFSX_V4SPECDATA;
2153 			break;
2154 		case NFSATTRBIT_SPACEAVAIL:
2155 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2156 			if (compare) {
2157 				if (priv_check_cred(cred,
2158 				    PRIV_VFS_BLOCKRESERVE))
2159 					uquad = sbp->f_bfree;
2160 				else
2161 					uquad = (uint64_t)sbp->f_bavail;
2162 				uquad *= sbp->f_bsize;
2163 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2164 					*retcmpp = NFSERR_NOTSAME;
2165 			} else if (sfp != NULL) {
2166 				sfp->sf_abytes = fxdr_hyper(tl);
2167 			}
2168 			attrsum += NFSX_HYPER;
2169 			break;
2170 		case NFSATTRBIT_SPACEFREE:
2171 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2172 			if (compare) {
2173 				uquad = sbp->f_bfree;
2174 				uquad *= sbp->f_bsize;
2175 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2176 					*retcmpp = NFSERR_NOTSAME;
2177 			} else if (sfp != NULL) {
2178 				sfp->sf_fbytes = fxdr_hyper(tl);
2179 			}
2180 			attrsum += NFSX_HYPER;
2181 			break;
2182 		case NFSATTRBIT_SPACETOTAL:
2183 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2184 			if (compare) {
2185 				uquad = sbp->f_blocks;
2186 				uquad *= sbp->f_bsize;
2187 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2188 					*retcmpp = NFSERR_NOTSAME;
2189 			} else if (sfp != NULL) {
2190 				sfp->sf_tbytes = fxdr_hyper(tl);
2191 			}
2192 			attrsum += NFSX_HYPER;
2193 			break;
2194 		case NFSATTRBIT_SPACEUSED:
2195 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2196 			thyp = fxdr_hyper(tl);
2197 			if (compare) {
2198 			    if (!(*retcmpp)) {
2199 				if ((u_int64_t)nap->na_bytes != thyp)
2200 					*retcmpp = NFSERR_NOTSAME;
2201 			    }
2202 			} else if (nap != NULL) {
2203 				nap->na_bytes = thyp;
2204 			}
2205 			attrsum += NFSX_HYPER;
2206 			break;
2207 		case NFSATTRBIT_SYSTEM:
2208 			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
2209 			if (compare) {
2210 				if (!(*retcmpp) && ((*tl == newnfs_true &&
2211 				    (nap->na_flags & UF_SYSTEM) == 0) ||
2212 				    (*tl == newnfs_false &&
2213 				     (nap->na_flags & UF_SYSTEM) != 0)))
2214 					*retcmpp = NFSERR_NOTSAME;
2215 			} else if (nap != NULL) {
2216 				if (*tl == newnfs_true)
2217 					nap->na_flags |= UF_SYSTEM;
2218 			}
2219 			attrsum += NFSX_UNSIGNED;
2220 			break;
2221 		case NFSATTRBIT_TIMEACCESS:
2222 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2223 			fxdr_nfsv4time(tl, &temptime);
2224 			if (compare) {
2225 			    if (!(*retcmpp)) {
2226 				if (!NFS_CMPTIME(temptime, nap->na_atime))
2227 					*retcmpp = NFSERR_NOTSAME;
2228 			    }
2229 			} else if (nap != NULL) {
2230 				nap->na_atime = temptime;
2231 			}
2232 			attrsum += NFSX_V4TIME;
2233 			break;
2234 		case NFSATTRBIT_TIMEACCESSSET:
2235 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2236 			attrsum += NFSX_UNSIGNED;
2237 			i = fxdr_unsigned(int, *tl);
2238 			if (i == NFSV4SATTRTIME_TOCLIENT) {
2239 				NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2240 				attrsum += NFSX_V4TIME;
2241 			}
2242 			if (compare && !(*retcmpp))
2243 				*retcmpp = NFSERR_INVAL;
2244 			break;
2245 		case NFSATTRBIT_TIMEBACKUP:
2246 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2247 			if (compare && !(*retcmpp))
2248 				*retcmpp = NFSERR_ATTRNOTSUPP;
2249 			attrsum += NFSX_V4TIME;
2250 			break;
2251 		case NFSATTRBIT_TIMECREATE:
2252 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2253 			fxdr_nfsv4time(tl, &temptime);
2254 			if (compare) {
2255 			    if (!(*retcmpp)) {
2256 				if (!NFS_CMPTIME(temptime, nap->na_btime))
2257 					*retcmpp = NFSERR_NOTSAME;
2258 			    }
2259 			} else if (nap != NULL) {
2260 				nap->na_btime = temptime;
2261 			}
2262 			attrsum += NFSX_V4TIME;
2263 			break;
2264 		case NFSATTRBIT_TIMEDELTA:
2265 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2266 			if (fsp != NULL) {
2267 			    if (compare) {
2268 				if (!(*retcmpp)) {
2269 				    if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
2270 					fxdr_unsigned(u_int32_t, *(tl + 1)) ||
2271 				        (u_int32_t)fsp->fs_timedelta.tv_nsec !=
2272 					(fxdr_unsigned(u_int32_t, *(tl + 2)) %
2273 					 1000000000) ||
2274 					*tl != 0)
2275 					    *retcmpp = NFSERR_NOTSAME;
2276 				}
2277 			    } else {
2278 				fxdr_nfsv4time(tl, &fsp->fs_timedelta);
2279 			    }
2280 			}
2281 			attrsum += NFSX_V4TIME;
2282 			break;
2283 		case NFSATTRBIT_TIMEMETADATA:
2284 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2285 			fxdr_nfsv4time(tl, &temptime);
2286 			if (compare) {
2287 			    if (!(*retcmpp)) {
2288 				if (!NFS_CMPTIME(temptime, nap->na_ctime))
2289 					*retcmpp = NFSERR_NOTSAME;
2290 			    }
2291 			} else if (nap != NULL) {
2292 				nap->na_ctime = temptime;
2293 			}
2294 			attrsum += NFSX_V4TIME;
2295 			break;
2296 		case NFSATTRBIT_TIMEMODIFY:
2297 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2298 			fxdr_nfsv4time(tl, &temptime);
2299 			if (compare) {
2300 			    if (!(*retcmpp)) {
2301 				if (!NFS_CMPTIME(temptime, nap->na_mtime))
2302 					*retcmpp = NFSERR_NOTSAME;
2303 			    }
2304 			} else if (nap != NULL) {
2305 				nap->na_mtime = temptime;
2306 			}
2307 			attrsum += NFSX_V4TIME;
2308 			break;
2309 		case NFSATTRBIT_TIMEMODIFYSET:
2310 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2311 			attrsum += NFSX_UNSIGNED;
2312 			i = fxdr_unsigned(int, *tl);
2313 			if (i == NFSV4SATTRTIME_TOCLIENT) {
2314 				NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2315 				attrsum += NFSX_V4TIME;
2316 			}
2317 			if (compare && !(*retcmpp))
2318 				*retcmpp = NFSERR_INVAL;
2319 			break;
2320 		case NFSATTRBIT_MOUNTEDONFILEID:
2321 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2322 			thyp = fxdr_hyper(tl);
2323 			if (compare) {
2324 				if (!(*retcmpp)) {
2325 					if (!vp || !nfsrv_atroot(vp, &thyp2))
2326 						thyp2 = nap->na_fileid;
2327 					if (thyp2 != thyp)
2328 						*retcmpp = NFSERR_NOTSAME;
2329 				}
2330 			} else if (nap != NULL)
2331 				nap->na_mntonfileno = thyp;
2332 			attrsum += NFSX_HYPER;
2333 			break;
2334 		case NFSATTRBIT_SUPPATTREXCLCREAT:
2335 			retnotsup = 0;
2336 			error = nfsrv_getattrbits(nd, &retattrbits,
2337 			    &cnt, &retnotsup);
2338 			if (error)
2339 			    goto nfsmout;
2340 			if (compare && !(*retcmpp)) {
2341 			   NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
2342 			   NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
2343 			   NFSCLRBIT_ATTRBIT(&checkattrbits,
2344 				NFSATTRBIT_TIMEACCESSSET);
2345 			   if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2346 			       || retnotsup)
2347 				*retcmpp = NFSERR_NOTSAME;
2348 			}
2349 			attrsum += cnt;
2350 			break;
2351 		case NFSATTRBIT_FSLAYOUTTYPE:
2352 		case NFSATTRBIT_LAYOUTTYPE:
2353 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2354 			attrsum += NFSX_UNSIGNED;
2355 			i = fxdr_unsigned(int, *tl);
2356 			/*
2357 			 * The RFCs do not define an upper limit for the
2358 			 * number of layout types, but 32 should be more
2359 			 * than enough.
2360 			 */
2361 			if (i < 0 || i > 32) {
2362 				error = NFSERR_BADXDR;
2363 				goto nfsmout;
2364 			}
2365 			if (i > 0) {
2366 				NFSM_DISSECT(tl, u_int32_t *, i *
2367 				    NFSX_UNSIGNED);
2368 				attrsum += i * NFSX_UNSIGNED;
2369 				j = fxdr_unsigned(int, *tl);
2370 				if (i == 1 && compare && !(*retcmpp) &&
2371 				    (((nfsrv_doflexfile != 0 ||
2372 				       nfsrv_maxpnfsmirror > 1) &&
2373 				      j != NFSLAYOUT_FLEXFILE) ||
2374 				    (nfsrv_doflexfile == 0 &&
2375 				     j != NFSLAYOUT_NFSV4_1_FILES)))
2376 					*retcmpp = NFSERR_NOTSAME;
2377 			}
2378 			if (nfsrv_devidcnt == 0) {
2379 				if (compare && !(*retcmpp) && i > 0)
2380 					*retcmpp = NFSERR_NOTSAME;
2381 			} else {
2382 				if (compare && !(*retcmpp) && i != 1)
2383 					*retcmpp = NFSERR_NOTSAME;
2384 			}
2385 			break;
2386 		case NFSATTRBIT_LAYOUTALIGNMENT:
2387 		case NFSATTRBIT_LAYOUTBLKSIZE:
2388 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2389 			attrsum += NFSX_UNSIGNED;
2390 			i = fxdr_unsigned(int, *tl);
2391 			if (compare && !(*retcmpp) && i != nfs_srvmaxio)
2392 				*retcmpp = NFSERR_NOTSAME;
2393 			break;
2394 		case NFSATTRBIT_CLONEBLKSIZE:
2395 			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
2396 			if (compare) {
2397 				if (!(*retcmpp)) {
2398 					if (vp == NULL || VOP_PATHCONF(vp,
2399 					    _PC_CLONE_BLKSIZE, &has_pathconf)
2400 					    != 0)
2401 						has_pathconf = 0;
2402 					if (has_pathconf !=
2403 					    fxdr_unsigned(uint32_t, *tl))
2404 						*retcmpp = NFSERR_NOTSAME;
2405 				}
2406 			} else if (clone_blksizep != NULL) {
2407 				*clone_blksizep = fxdr_unsigned(uint32_t, *tl);
2408 			}
2409 			attrsum += NFSX_UNSIGNED;
2410 			break;
2411 		case NFSATTRBIT_CHANGEATTRTYPE:
2412 			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
2413 			if (compare) {
2414 				if (!(*retcmpp)) {
2415 				    tuint = NFSV4CHANGETYPE_UNDEFINED;
2416 				    if ((vp->v_mount->mnt_vfc->vfc_flags &
2417 					VFCF_FILEREVINC) != 0)
2418 					tuint = NFSV4CHANGETYPE_VERS_COUNTER_NOPNFS;
2419 				    else if ((vp->v_mount->mnt_vfc->vfc_flags &
2420 					VFCF_FILEREVCT) != 0)
2421 					tuint = NFSV4CHANGETYPE_TIME_METADATA;
2422 				    if (fxdr_unsigned(uint32_t, *tl) != tuint)
2423 					*retcmpp = NFSERR_NOTSAME;
2424 				}
2425 			}
2426 			attrsum += NFSX_UNSIGNED;
2427 			break;
2428 		default:
2429 			printf("EEK! nfsv4_loadattr unknown attr=%d\n",
2430 				bitpos);
2431 			if (compare && !(*retcmpp))
2432 				*retcmpp = NFSERR_ATTRNOTSUPP;
2433 			/*
2434 			 * and get out of the loop, since we can't parse
2435 			 * the unknown attribute data.
2436 			 */
2437 			bitpos = NFSATTRBIT_MAX;
2438 			break;
2439 		}
2440 	}
2441 
2442 	/*
2443 	 * some clients pad the attrlist, so we need to skip over the
2444 	 * padding.
2445 	 */
2446 	if (attrsum > attrsize) {
2447 		error = NFSERR_BADXDR;
2448 	} else {
2449 		attrsize = NFSM_RNDUP(attrsize);
2450 		if (attrsum < attrsize)
2451 			error = nfsm_advance(nd, attrsize - attrsum, -1);
2452 	}
2453 nfsmout:
2454 	NFSD_CURVNET_RESTORE();
2455 	NFSEXITCODE2(error, nd);
2456 	return (error);
2457 }
2458 
2459 /*
2460  * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
2461  * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
2462  * The first argument is a pointer to an nfsv4lock structure.
2463  * The second argument is 1 iff a blocking lock is wanted.
2464  * If this argument is 0, the call waits until no thread either wants nor
2465  * holds an exclusive lock.
2466  * It returns 1 if the lock was acquired, 0 otherwise.
2467  * If several processes call this function concurrently wanting the exclusive
2468  * lock, one will get the lock and the rest will return without getting the
2469  * lock. (If the caller must have the lock, it simply calls this function in a
2470  *  loop until the function returns 1 to indicate the lock was acquired.)
2471  * Any usecnt must be decremented by calling nfsv4_relref() before
2472  * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
2473  * be called in a loop.
2474  * The isleptp argument is set to indicate if the call slept, iff not NULL
2475  * and the mp argument indicates to check for a forced dismount, iff not
2476  * NULL.
2477  */
2478 int
nfsv4_lock(struct nfsv4lock * lp,int iwantlock,int * isleptp,struct mtx * mutex,struct mount * mp)2479 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
2480     struct mtx *mutex, struct mount *mp)
2481 {
2482 
2483 	if (isleptp)
2484 		*isleptp = 0;
2485 	/*
2486 	 * If a lock is wanted, loop around until the lock is acquired by
2487 	 * someone and then released. If I want the lock, try to acquire it.
2488 	 * For a lock to be issued, no lock must be in force and the usecnt
2489 	 * must be zero.
2490 	 */
2491 	if (iwantlock) {
2492 	    if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2493 		lp->nfslock_usecnt == 0) {
2494 		lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2495 		lp->nfslock_lock |= NFSV4LOCK_LOCK;
2496 		return (1);
2497 	    }
2498 	    lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
2499 	}
2500 	while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
2501 		if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2502 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2503 			return (0);
2504 		}
2505 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
2506 		if (isleptp)
2507 			*isleptp = 1;
2508 		msleep(&lp->nfslock_lock, mutex, PVFS, "nfsv4lck", hz);
2509 		if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2510 		    lp->nfslock_usecnt == 0) {
2511 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2512 			lp->nfslock_lock |= NFSV4LOCK_LOCK;
2513 			return (1);
2514 		}
2515 	}
2516 	return (0);
2517 }
2518 
2519 /*
2520  * Release the lock acquired by nfsv4_lock().
2521  * The second argument is set to 1 to indicate the nfslock_usecnt should be
2522  * incremented, as well.
2523  */
2524 void
nfsv4_unlock(struct nfsv4lock * lp,int incref)2525 nfsv4_unlock(struct nfsv4lock *lp, int incref)
2526 {
2527 
2528 	lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
2529 	if (incref)
2530 		lp->nfslock_usecnt++;
2531 	nfsv4_wanted(lp);
2532 }
2533 
2534 /*
2535  * Release a reference cnt.
2536  */
2537 void
nfsv4_relref(struct nfsv4lock * lp)2538 nfsv4_relref(struct nfsv4lock *lp)
2539 {
2540 
2541 	if (lp->nfslock_usecnt <= 0)
2542 		panic("nfsv4root ref cnt");
2543 	lp->nfslock_usecnt--;
2544 	if (lp->nfslock_usecnt == 0)
2545 		nfsv4_wanted(lp);
2546 }
2547 
2548 /*
2549  * Get a reference cnt.
2550  * This function will wait for any exclusive lock to be released, but will
2551  * not wait for threads that want the exclusive lock. If priority needs
2552  * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
2553  * with the 2nd argument == 0 should be done before calling nfsv4_getref().
2554  * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2555  * return without getting a refcnt for that case.
2556  */
2557 void
nfsv4_getref(struct nfsv4lock * lp,int * isleptp,struct mtx * mutex,struct mount * mp)2558 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, struct mtx *mutex,
2559     struct mount *mp)
2560 {
2561 
2562 	if (isleptp)
2563 		*isleptp = 0;
2564 
2565 	/*
2566 	 * Wait for a lock held.
2567 	 */
2568 	while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
2569 		if (mp != NULL && NFSCL_FORCEDISM(mp))
2570 			return;
2571 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
2572 		if (isleptp)
2573 			*isleptp = 1;
2574 		msleep(&lp->nfslock_lock, mutex, PVFS, "nfsv4gr", hz);
2575 	}
2576 	if (mp != NULL && NFSCL_FORCEDISM(mp))
2577 		return;
2578 
2579 	lp->nfslock_usecnt++;
2580 }
2581 
2582 /*
2583  * Get a reference as above, but return failure instead of sleeping if
2584  * an exclusive lock is held.
2585  */
2586 int
nfsv4_getref_nonblock(struct nfsv4lock * lp)2587 nfsv4_getref_nonblock(struct nfsv4lock *lp)
2588 {
2589 
2590 	if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
2591 		return (0);
2592 
2593 	lp->nfslock_usecnt++;
2594 	return (1);
2595 }
2596 
2597 /*
2598  * Test for a lock. Return 1 if locked, 0 otherwise.
2599  */
2600 int
nfsv4_testlock(struct nfsv4lock * lp)2601 nfsv4_testlock(struct nfsv4lock *lp)
2602 {
2603 
2604 	if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2605 	    lp->nfslock_usecnt == 0)
2606 		return (0);
2607 	return (1);
2608 }
2609 
2610 /*
2611  * Wake up anyone sleeping, waiting for this lock.
2612  */
2613 static void
nfsv4_wanted(struct nfsv4lock * lp)2614 nfsv4_wanted(struct nfsv4lock *lp)
2615 {
2616 
2617 	if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
2618 		lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
2619 		wakeup((caddr_t)&lp->nfslock_lock);
2620 	}
2621 }
2622 
2623 /*
2624  * Copy a string from an mbuf list into a character array.
2625  * Return EBADRPC if there is an mbuf error,
2626  * 0 otherwise.
2627  */
2628 int
nfsrv_mtostr(struct nfsrv_descript * nd,char * str,int siz)2629 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2630 {
2631 	char *cp;
2632 	int xfer, len;
2633 	struct mbuf *mp;
2634 	int rem, error = 0;
2635 
2636 	mp = nd->nd_md;
2637 	cp = nd->nd_dpos;
2638 	len = mtod(mp, caddr_t) + mp->m_len - cp;
2639 	rem = NFSM_RNDUP(siz) - siz;
2640 	while (siz > 0) {
2641 		if (len > siz)
2642 			xfer = siz;
2643 		else
2644 			xfer = len;
2645 		NFSBCOPY(cp, str, xfer);
2646 		str += xfer;
2647 		siz -= xfer;
2648 		if (siz > 0) {
2649 			mp = mp->m_next;
2650 			if (mp == NULL) {
2651 				error = EBADRPC;
2652 				goto out;
2653 			}
2654 			cp = mtod(mp, caddr_t);
2655 			len = mp->m_len;
2656 		} else {
2657 			cp += xfer;
2658 			len -= xfer;
2659 		}
2660 	}
2661 	*str = '\0';
2662 	nd->nd_dpos = cp;
2663 	nd->nd_md = mp;
2664 	if (rem > 0) {
2665 		if (len < rem)
2666 			error = nfsm_advance(nd, rem, len);
2667 		else
2668 			nd->nd_dpos += rem;
2669 	}
2670 
2671 out:
2672 	NFSEXITCODE2(error, nd);
2673 	return (error);
2674 }
2675 
2676 /*
2677  * Fill in the attributes as marked by the bitmap (V4).
2678  */
2679 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)2680 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2681     NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2682     nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2683     int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
2684     struct statfs *pnfssf, bool xattrsupp, bool has_hiddensystem,
2685     bool has_namedattr, uint32_t clone_blksize)
2686 {
2687 	int bitpos, retnum = 0;
2688 	u_int32_t *tl;
2689 	int siz, prefixnum, error;
2690 	u_char *cp, namestr[NFSV4_SMALLSTR];
2691 	nfsattrbit_t attrbits, retbits;
2692 	nfsattrbit_t *retbitp = &retbits;
2693 	u_int32_t freenum, *retnump;
2694 	u_int64_t uquad;
2695 	struct statfs *fs;
2696 	struct nfsfsinfo fsinf;
2697 	struct timespec temptime;
2698 	NFSACL_T *aclp, *naclp = NULL;
2699 	short irflag;
2700 #ifdef QUOTA
2701 	struct dqblk dqb;
2702 	uid_t savuid;
2703 #endif
2704 
2705 	/*
2706 	 * First, set the bits that can be filled and get fsinfo.
2707 	 */
2708 	NFSSET_ATTRBIT(retbitp, attrbitp);
2709 	/*
2710 	 * If both p and cred are NULL, it is a client side setattr call.
2711 	 * If both p and cred are not NULL, it is a server side reply call.
2712 	 * If p is not NULL and cred is NULL, it is a client side callback
2713 	 * reply call.
2714 	 */
2715 	if (p == NULL && cred == NULL) {
2716 		NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
2717 		aclp = saclp;
2718 	} else {
2719 		NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
2720 		naclp = acl_alloc(M_WAITOK);
2721 		aclp = naclp;
2722 	}
2723 	nfsvno_getfs(&fsinf, isdgram);
2724 	/*
2725 	 * Get the VFS_STATFS(), since some attributes need them.
2726 	 */
2727 	fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2728 	if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2729 		error = VFS_STATFS(mp, fs);
2730 		if (error != 0) {
2731 			if (reterr) {
2732 				nd->nd_repstat = NFSERR_ACCES;
2733 				free(fs, M_STATFS);
2734 				return (0);
2735 			}
2736 			NFSCLRSTATFS_ATTRBIT(retbitp);
2737 		}
2738 		/*
2739 		 * Since NFS handles these values as unsigned on the
2740 		 * wire, there is no way to represent negative values,
2741 		 * so set them to 0. Without this, they will appear
2742 		 * to be very large positive values for clients like
2743 		 * Solaris10.
2744 		 */
2745 		if (fs->f_bavail < 0)
2746 			fs->f_bavail = 0;
2747 		if (fs->f_ffree < 0)
2748 			fs->f_ffree = 0;
2749 	}
2750 
2751 	/*
2752 	 * And the NFSv4 ACL...
2753 	 */
2754 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2755 	    (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2756 		supports_nfsv4acls == 0))) {
2757 		NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2758 	}
2759 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2760 		if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2761 		    supports_nfsv4acls == 0)) {
2762 			NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2763 		} else if (naclp != NULL) {
2764 			if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2765 				error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2766 				if (error == 0)
2767 					error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2768 					    naclp, cred, p);
2769 				NFSVOPUNLOCK(vp);
2770 			} else
2771 				error = NFSERR_PERM;
2772 			if (error != 0) {
2773 				if (reterr) {
2774 					nd->nd_repstat = NFSERR_ACCES;
2775 					free(fs, M_STATFS);
2776 					return (0);
2777 				}
2778 				NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2779 			}
2780 		}
2781 	}
2782 
2783 	/*
2784 	 * Put out the attribute bitmap for the ones being filled in
2785 	 * and get the field for the number of attributes returned.
2786 	 */
2787 	prefixnum = nfsrv_putattrbit(nd, retbitp);
2788 	NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2789 	prefixnum += NFSX_UNSIGNED;
2790 
2791 	/*
2792 	 * Now, loop around filling in the attributes for each bit set.
2793 	 */
2794 	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2795 	    if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2796 		switch (bitpos) {
2797 		case NFSATTRBIT_SUPPORTEDATTRS:
2798 			NFSSETSUPP_ATTRBIT(&attrbits, nd);
2799 			if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2800 			    && supports_nfsv4acls == 0)) {
2801 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2802 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2803 			}
2804 			if (!has_hiddensystem) {
2805 			    NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN);
2806 			    NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM);
2807 			}
2808 			if (clone_blksize == 0)
2809 			    NFSCLRBIT_ATTRBIT(&attrbits,
2810 				NFSATTRBIT_CLONEBLKSIZE);
2811 			retnum += nfsrv_putattrbit(nd, &attrbits);
2812 			break;
2813 		case NFSATTRBIT_TYPE:
2814 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2815 			*tl = vtonfsv4_type(vap);
2816 			retnum += NFSX_UNSIGNED;
2817 			break;
2818 		case NFSATTRBIT_FHEXPIRETYPE:
2819 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2820 			*tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2821 			retnum += NFSX_UNSIGNED;
2822 			break;
2823 		case NFSATTRBIT_CHANGE:
2824 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2825 			txdr_hyper(vap->va_filerev, tl);
2826 			retnum += NFSX_HYPER;
2827 			break;
2828 		case NFSATTRBIT_SIZE:
2829 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2830 			txdr_hyper(vap->va_size, tl);
2831 			retnum += NFSX_HYPER;
2832 			break;
2833 		case NFSATTRBIT_LINKSUPPORT:
2834 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2835 			if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2836 				*tl = newnfs_true;
2837 			else
2838 				*tl = newnfs_false;
2839 			retnum += NFSX_UNSIGNED;
2840 			break;
2841 		case NFSATTRBIT_SYMLINKSUPPORT:
2842 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2843 			if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2844 				*tl = newnfs_true;
2845 			else
2846 				*tl = newnfs_false;
2847 			retnum += NFSX_UNSIGNED;
2848 			break;
2849 		case NFSATTRBIT_NAMEDATTR:
2850 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2851 			if (has_namedattr)
2852 				*tl = newnfs_true;
2853 			else
2854 				*tl = newnfs_false;
2855 			retnum += NFSX_UNSIGNED;
2856 			break;
2857 		case NFSATTRBIT_FSID:
2858 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2859 			*tl++ = 0;
2860 			*tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2861 			*tl++ = 0;
2862 			*tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2863 			retnum += NFSX_V4FSID;
2864 			break;
2865 		case NFSATTRBIT_UNIQUEHANDLES:
2866 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2867 			*tl = newnfs_true;
2868 			retnum += NFSX_UNSIGNED;
2869 			break;
2870 		case NFSATTRBIT_LEASETIME:
2871 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2872 			*tl = txdr_unsigned(nfsrv_lease);
2873 			retnum += NFSX_UNSIGNED;
2874 			break;
2875 		case NFSATTRBIT_RDATTRERROR:
2876 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2877 			*tl = txdr_unsigned(rderror);
2878 			retnum += NFSX_UNSIGNED;
2879 			break;
2880 		/*
2881 		 * Recommended Attributes. (Only the supported ones.)
2882 		 */
2883 		case NFSATTRBIT_ACL:
2884 			retnum += nfsrv_buildacl(nd, aclp, vp->v_type, p);
2885 			break;
2886 		case NFSATTRBIT_ACLSUPPORT:
2887 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2888 			*tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2889 			retnum += NFSX_UNSIGNED;
2890 			break;
2891 		case NFSATTRBIT_CANSETTIME:
2892 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2893 			if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2894 				*tl = newnfs_true;
2895 			else
2896 				*tl = newnfs_false;
2897 			retnum += NFSX_UNSIGNED;
2898 			break;
2899 		case NFSATTRBIT_CASEINSENSITIVE:
2900 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2901 			*tl = newnfs_false;
2902 			retnum += NFSX_UNSIGNED;
2903 			break;
2904 		case NFSATTRBIT_CASEPRESERVING:
2905 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2906 			*tl = newnfs_true;
2907 			retnum += NFSX_UNSIGNED;
2908 			break;
2909 		case NFSATTRBIT_CHOWNRESTRICTED:
2910 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2911 			*tl = newnfs_true;
2912 			retnum += NFSX_UNSIGNED;
2913 			break;
2914 		case NFSATTRBIT_FILEHANDLE:
2915 			siz = 0;
2916 			if (vp != NULL) {
2917 				irflag = vn_irflag_read(vp);
2918 				if ((irflag & VIRF_NAMEDDIR) != 0)
2919 					siz = NFSX_FHMAX + 2;
2920 				else if ((irflag & VIRF_NAMEDATTR) != 0)
2921 					siz = NFSX_FHMAX + 3;
2922 			}
2923 			retnum += nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, siz, 0);
2924 			break;
2925 		case NFSATTRBIT_FILEID:
2926 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2927 			uquad = vap->va_fileid;
2928 			txdr_hyper(uquad, tl);
2929 			retnum += NFSX_HYPER;
2930 			break;
2931 		case NFSATTRBIT_FILESAVAIL:
2932 			freenum = nfsv4_filesavail(fs, mp);
2933 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2934 			*tl++ = 0;
2935 			*tl = txdr_unsigned(freenum);
2936 			retnum += NFSX_HYPER;
2937 			break;
2938 		case NFSATTRBIT_FILESFREE:
2939 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2940 			*tl++ = 0;
2941 			*tl = txdr_unsigned(fs->f_ffree);
2942 			retnum += NFSX_HYPER;
2943 			break;
2944 		case NFSATTRBIT_FILESTOTAL:
2945 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2946 			*tl++ = 0;
2947 			*tl = txdr_unsigned(fs->f_files);
2948 			retnum += NFSX_HYPER;
2949 			break;
2950 		case NFSATTRBIT_FSLOCATIONS:
2951 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2952 			*tl++ = 0;
2953 			*tl = 0;
2954 			retnum += 2 * NFSX_UNSIGNED;
2955 			break;
2956 		case NFSATTRBIT_HIDDEN:
2957 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
2958 			if ((vap->va_flags & UF_HIDDEN) != 0)
2959 				*tl = newnfs_true;
2960 			else
2961 				*tl = newnfs_false;
2962 			retnum += NFSX_UNSIGNED;
2963 			break;
2964 		case NFSATTRBIT_HOMOGENEOUS:
2965 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2966 			if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2967 				*tl = newnfs_true;
2968 			else
2969 				*tl = newnfs_false;
2970 			retnum += NFSX_UNSIGNED;
2971 			break;
2972 		case NFSATTRBIT_MAXFILESIZE:
2973 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2974 			uquad = NFSRV_MAXFILESIZE;
2975 			txdr_hyper(uquad, tl);
2976 			retnum += NFSX_HYPER;
2977 			break;
2978 		case NFSATTRBIT_MAXLINK:
2979 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2980 			*tl = txdr_unsigned(NFS_LINK_MAX);
2981 			retnum += NFSX_UNSIGNED;
2982 			break;
2983 		case NFSATTRBIT_MAXNAME:
2984 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2985 			*tl = txdr_unsigned(NFS_MAXNAMLEN);
2986 			retnum += NFSX_UNSIGNED;
2987 			break;
2988 		case NFSATTRBIT_MAXREAD:
2989 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2990 			*tl++ = 0;
2991 			*tl = txdr_unsigned(fsinf.fs_rtmax);
2992 			retnum += NFSX_HYPER;
2993 			break;
2994 		case NFSATTRBIT_MAXWRITE:
2995 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2996 			*tl++ = 0;
2997 			*tl = txdr_unsigned(fsinf.fs_wtmax);
2998 			retnum += NFSX_HYPER;
2999 			break;
3000 		case NFSATTRBIT_MODE:
3001 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3002 			*tl = vtonfsv34_mode(vap->va_mode);
3003 			retnum += NFSX_UNSIGNED;
3004 			break;
3005 		case NFSATTRBIT_NOTRUNC:
3006 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3007 			*tl = newnfs_true;
3008 			retnum += NFSX_UNSIGNED;
3009 			break;
3010 		case NFSATTRBIT_NUMLINKS:
3011 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3012 			*tl = txdr_unsigned(vap->va_nlink);
3013 			retnum += NFSX_UNSIGNED;
3014 			break;
3015 		case NFSATTRBIT_OWNER:
3016 			cp = namestr;
3017 			nfsv4_uidtostr(vap->va_uid, &cp, &siz);
3018 			retnum += nfsm_strtom(nd, cp, siz);
3019 			if (cp != namestr)
3020 				free(cp, M_NFSSTRING);
3021 			break;
3022 		case NFSATTRBIT_OWNERGROUP:
3023 			cp = namestr;
3024 			nfsv4_gidtostr(vap->va_gid, &cp, &siz);
3025 			retnum += nfsm_strtom(nd, cp, siz);
3026 			if (cp != namestr)
3027 				free(cp, M_NFSSTRING);
3028 			break;
3029 		case NFSATTRBIT_QUOTAHARD:
3030 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
3031 				freenum = fs->f_bfree;
3032 			else
3033 				freenum = fs->f_bavail;
3034 #ifdef QUOTA
3035 			/*
3036 			 * ufs_quotactl() insists that the uid argument
3037 			 * equal p_ruid for non-root quota access, so
3038 			 * we'll just make sure that's the case.
3039 			 */
3040 			savuid = p->p_cred->p_ruid;
3041 			p->p_cred->p_ruid = cred->cr_uid;
3042 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
3043 			    cred->cr_uid, &dqb))
3044 			    freenum = min(dqb.dqb_bhardlimit, freenum);
3045 			p->p_cred->p_ruid = savuid;
3046 #endif	/* QUOTA */
3047 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3048 			uquad = (u_int64_t)freenum;
3049 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
3050 			txdr_hyper(uquad, tl);
3051 			retnum += NFSX_HYPER;
3052 			break;
3053 		case NFSATTRBIT_QUOTASOFT:
3054 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
3055 				freenum = fs->f_bfree;
3056 			else
3057 				freenum = fs->f_bavail;
3058 #ifdef QUOTA
3059 			/*
3060 			 * ufs_quotactl() insists that the uid argument
3061 			 * equal p_ruid for non-root quota access, so
3062 			 * we'll just make sure that's the case.
3063 			 */
3064 			savuid = p->p_cred->p_ruid;
3065 			p->p_cred->p_ruid = cred->cr_uid;
3066 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
3067 			    cred->cr_uid, &dqb))
3068 			    freenum = min(dqb.dqb_bsoftlimit, freenum);
3069 			p->p_cred->p_ruid = savuid;
3070 #endif	/* QUOTA */
3071 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3072 			uquad = (u_int64_t)freenum;
3073 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
3074 			txdr_hyper(uquad, tl);
3075 			retnum += NFSX_HYPER;
3076 			break;
3077 		case NFSATTRBIT_QUOTAUSED:
3078 			freenum = 0;
3079 #ifdef QUOTA
3080 			/*
3081 			 * ufs_quotactl() insists that the uid argument
3082 			 * equal p_ruid for non-root quota access, so
3083 			 * we'll just make sure that's the case.
3084 			 */
3085 			savuid = p->p_cred->p_ruid;
3086 			p->p_cred->p_ruid = cred->cr_uid;
3087 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
3088 			    cred->cr_uid, &dqb))
3089 			    freenum = dqb.dqb_curblocks;
3090 			p->p_cred->p_ruid = savuid;
3091 #endif	/* QUOTA */
3092 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3093 			uquad = (u_int64_t)freenum;
3094 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
3095 			txdr_hyper(uquad, tl);
3096 			retnum += NFSX_HYPER;
3097 			break;
3098 		case NFSATTRBIT_RAWDEV:
3099 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
3100 			*tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
3101 			*tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
3102 			retnum += NFSX_V4SPECDATA;
3103 			break;
3104 		case NFSATTRBIT_SPACEAVAIL:
3105 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3106 			if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE)) {
3107 				if (pnfssf != NULL)
3108 					uquad = (u_int64_t)pnfssf->f_bfree;
3109 				else
3110 					uquad = (u_int64_t)fs->f_bfree;
3111 			} else {
3112 				if (pnfssf != NULL)
3113 					uquad = (u_int64_t)pnfssf->f_bavail;
3114 				else
3115 					uquad = (u_int64_t)fs->f_bavail;
3116 			}
3117 			if (pnfssf != NULL)
3118 				uquad *= pnfssf->f_bsize;
3119 			else
3120 				uquad *= fs->f_bsize;
3121 			txdr_hyper(uquad, tl);
3122 			retnum += NFSX_HYPER;
3123 			break;
3124 		case NFSATTRBIT_SPACEFREE:
3125 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3126 			if (pnfssf != NULL) {
3127 				uquad = (u_int64_t)pnfssf->f_bfree;
3128 				uquad *= pnfssf->f_bsize;
3129 			} else {
3130 				uquad = (u_int64_t)fs->f_bfree;
3131 				uquad *= fs->f_bsize;
3132 			}
3133 			txdr_hyper(uquad, tl);
3134 			retnum += NFSX_HYPER;
3135 			break;
3136 		case NFSATTRBIT_SPACETOTAL:
3137 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3138 			if (pnfssf != NULL) {
3139 				uquad = (u_int64_t)pnfssf->f_blocks;
3140 				uquad *= pnfssf->f_bsize;
3141 			} else {
3142 				uquad = (u_int64_t)fs->f_blocks;
3143 				uquad *= fs->f_bsize;
3144 			}
3145 			txdr_hyper(uquad, tl);
3146 			retnum += NFSX_HYPER;
3147 			break;
3148 		case NFSATTRBIT_SPACEUSED:
3149 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3150 			txdr_hyper(vap->va_bytes, tl);
3151 			retnum += NFSX_HYPER;
3152 			break;
3153 		case NFSATTRBIT_SYSTEM:
3154 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3155 			if ((vap->va_flags & UF_SYSTEM) != 0)
3156 				*tl = newnfs_true;
3157 			else
3158 				*tl = newnfs_false;
3159 			retnum += NFSX_UNSIGNED;
3160 			break;
3161 		case NFSATTRBIT_TIMEACCESS:
3162 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
3163 			txdr_nfsv4time(&vap->va_atime, tl);
3164 			retnum += NFSX_V4TIME;
3165 			break;
3166 		case NFSATTRBIT_TIMEACCESSSET:
3167 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
3168 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
3169 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
3170 				txdr_nfsv4time(&vap->va_atime, tl);
3171 				retnum += NFSX_V4SETTIME;
3172 			} else {
3173 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3174 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
3175 				retnum += NFSX_UNSIGNED;
3176 			}
3177 			break;
3178 		case NFSATTRBIT_TIMEDELTA:
3179 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
3180 			temptime.tv_sec = 0;
3181 			temptime.tv_nsec = 1000000000 / hz;
3182 			txdr_nfsv4time(&temptime, tl);
3183 			retnum += NFSX_V4TIME;
3184 			break;
3185 		case NFSATTRBIT_TIMEMETADATA:
3186 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
3187 			txdr_nfsv4time(&vap->va_ctime, tl);
3188 			retnum += NFSX_V4TIME;
3189 			break;
3190 		case NFSATTRBIT_TIMEMODIFY:
3191 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
3192 			txdr_nfsv4time(&vap->va_mtime, tl);
3193 			retnum += NFSX_V4TIME;
3194 			break;
3195 		case NFSATTRBIT_TIMECREATE:
3196 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
3197 			txdr_nfsv4time(&vap->va_birthtime, tl);
3198 			retnum += NFSX_V4TIME;
3199 			break;
3200 		case NFSATTRBIT_TIMEMODIFYSET:
3201 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
3202 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
3203 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
3204 				txdr_nfsv4time(&vap->va_mtime, tl);
3205 				retnum += NFSX_V4SETTIME;
3206 			} else {
3207 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3208 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
3209 				retnum += NFSX_UNSIGNED;
3210 			}
3211 			break;
3212 		case NFSATTRBIT_MOUNTEDONFILEID:
3213 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3214 			if (at_root != 0)
3215 				uquad = mounted_on_fileno;
3216 			else
3217 				uquad = vap->va_fileid;
3218 			txdr_hyper(uquad, tl);
3219 			retnum += NFSX_HYPER;
3220 			break;
3221 		case NFSATTRBIT_SUPPATTREXCLCREAT:
3222 			NFSSETSUPP_ATTRBIT(&attrbits, nd);
3223 			NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd);
3224 			NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
3225 			retnum += nfsrv_putattrbit(nd, &attrbits);
3226 			break;
3227 		case NFSATTRBIT_FSLAYOUTTYPE:
3228 		case NFSATTRBIT_LAYOUTTYPE:
3229 			if (nfsrv_devidcnt == 0)
3230 				siz = 1;
3231 			else
3232 				siz = 2;
3233 			if (siz == 2) {
3234 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3235 				*tl++ = txdr_unsigned(1);	/* One entry. */
3236 				if (nfsrv_doflexfile != 0 ||
3237 				    nfsrv_maxpnfsmirror > 1)
3238 					*tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
3239 				else
3240 					*tl = txdr_unsigned(
3241 					    NFSLAYOUT_NFSV4_1_FILES);
3242 			} else {
3243 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3244 				*tl = 0;
3245 			}
3246 			retnum += siz * NFSX_UNSIGNED;
3247 			break;
3248 		case NFSATTRBIT_LAYOUTALIGNMENT:
3249 		case NFSATTRBIT_LAYOUTBLKSIZE:
3250 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3251 			*tl = txdr_unsigned(nfs_srvmaxio);
3252 			retnum += NFSX_UNSIGNED;
3253 			break;
3254 		case NFSATTRBIT_XATTRSUPPORT:
3255 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3256 			if (xattrsupp)
3257 				*tl = newnfs_true;
3258 			else
3259 				*tl = newnfs_false;
3260 			retnum += NFSX_UNSIGNED;
3261 			break;
3262 		case NFSATTRBIT_MODEUMASK:
3263 			NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3264 			/*
3265 			 * Since FreeBSD applies the umask above the VFS/VOP,
3266 			 * there is no umask to handle here.  If FreeBSD
3267 			 * moves handling of umask to below the VFS/VOP,
3268 			 * this could change.
3269 			 */
3270 			*tl++ = vtonfsv34_mode(vap->va_mode);
3271 			*tl = 0;
3272 			retnum += 2 * NFSX_UNSIGNED;
3273 			break;
3274 		case NFSATTRBIT_CHANGEATTRTYPE:
3275 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3276 			*tl = txdr_unsigned(NFSV4CHANGETYPE_UNDEFINED);
3277 			if (mp != NULL) {
3278 				if ((mp->mnt_vfc->vfc_flags &
3279 				    VFCF_FILEREVINC) != 0)
3280 					*tl = txdr_unsigned(
3281 					   NFSV4CHANGETYPE_VERS_COUNTER_NOPNFS);
3282 				else if ((mp->mnt_vfc->vfc_flags &
3283 				    VFCF_FILEREVCT) != 0)
3284 					*tl = txdr_unsigned(
3285 					   NFSV4CHANGETYPE_TIME_METADATA);
3286 			}
3287 			retnum += NFSX_UNSIGNED;
3288 			break;
3289 		case NFSATTRBIT_CLONEBLKSIZE:
3290 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3291 			*tl = txdr_unsigned(clone_blksize);
3292 			retnum += NFSX_UNSIGNED;
3293 			break;
3294 		default:
3295 			printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
3296 		}
3297 	    }
3298 	}
3299 	if (naclp != NULL)
3300 		acl_free(naclp);
3301 	free(fs, M_STATFS);
3302 	*retnump = txdr_unsigned(retnum);
3303 	return (retnum + prefixnum);
3304 }
3305 
3306 /*
3307  * Calculate the files available attribute value.
3308  */
3309 static uint32_t
nfsv4_filesavail(struct statfs * fs,struct mount * mp)3310 nfsv4_filesavail(struct statfs *fs, struct mount *mp)
3311 {
3312 	uint32_t freenum;
3313 #ifdef QUOTA
3314 	struct dqblk dqb;
3315 	uid_t savuid;
3316 	NFSPROC_T *p;
3317 #endif
3318 
3319 	/*
3320 	 * Check quota and use min(quota, f_ffree).
3321 	 */
3322 	freenum = fs->f_ffree;
3323 #ifdef QUOTA
3324 	/*
3325 	 * This is old OpenBSD code that does not build
3326 	 * for FreeBSD.  I do not know if doing this is
3327 	 * useful, so I will just leave the code here.
3328 	 */
3329 	p = curthread();
3330 	/*
3331 	 * ufs_quotactl() insists that the uid argument
3332 	 * equal p_ruid for non-root quota access, so
3333 	 * we'll just make sure that's the case.
3334 	 */
3335 	savuid = p->p_cred->p_ruid;
3336 	p->p_cred->p_ruid = cred->cr_uid;
3337 	if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
3338 	    cred->cr_uid, &dqb))
3339 	    freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
3340 		freenum);
3341 	p->p_cred->p_ruid = savuid;
3342 #endif	/* QUOTA */
3343 	return (freenum);
3344 }
3345 
3346 /*
3347  * Put the attribute bits onto an mbuf list.
3348  * Return the number of bytes of output generated.
3349  */
3350 int
nfsrv_putattrbit(struct nfsrv_descript * nd,nfsattrbit_t * attrbitp)3351 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
3352 {
3353 	u_int32_t *tl;
3354 	int cnt, i, bytesize;
3355 
3356 	for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
3357 		if (attrbitp->bits[cnt - 1])
3358 			break;
3359 	bytesize = (cnt + 1) * NFSX_UNSIGNED;
3360 	NFSM_BUILD(tl, u_int32_t *, bytesize);
3361 	*tl++ = txdr_unsigned(cnt);
3362 	for (i = 0; i < cnt; i++)
3363 		*tl++ = txdr_unsigned(attrbitp->bits[i]);
3364 	return (bytesize);
3365 }
3366 
3367 /*
3368  * Put the operation bits onto an mbuf list.
3369  * Return the number of bytes of output generated.
3370  */
3371 int
nfsrv_putopbit(struct nfsrv_descript * nd,nfsopbit_t * opbitp)3372 nfsrv_putopbit(struct nfsrv_descript *nd, nfsopbit_t *opbitp)
3373 {
3374 	uint32_t *tl;
3375 	int cnt, i, bytesize;
3376 
3377 	for (cnt = NFSOPBIT_MAXWORDS; cnt > 0; cnt--)
3378 		if (opbitp->bits[cnt - 1])
3379 			break;
3380 	bytesize = (cnt + 1) * NFSX_UNSIGNED;
3381 	NFSM_BUILD(tl, uint32_t *, bytesize);
3382 	*tl++ = txdr_unsigned(cnt);
3383 	for (i = 0; i < cnt; i++)
3384 		*tl++ = txdr_unsigned(opbitp->bits[i]);
3385 	return (bytesize);
3386 }
3387 
3388 /*
3389  * Convert a uid to a string.
3390  * If the lookup fails, just output the digits.
3391  * uid - the user id
3392  * cpp - points to a buffer of size NFSV4_SMALLSTR
3393  *       (malloc a larger one, as required)
3394  * retlenp - pointer to length to be returned
3395  */
3396 void
nfsv4_uidtostr(uid_t uid,u_char ** cpp,int * retlenp)3397 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp)
3398 {
3399 	int i;
3400 	struct nfsusrgrp *usrp;
3401 	u_char *cp = *cpp;
3402 	uid_t tmp;
3403 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3404 	struct nfsrv_lughash *hp;
3405 
3406 	NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
3407 	cnt = 0;
3408 tryagain:
3409 	if (NFSD_VNET(nfsrv_dnsnamelen) > 0 &&
3410 	    !NFSD_VNET(nfs_enable_uidtostring)) {
3411 		/*
3412 		 * Always map nfsrv_defaultuid to "nobody".
3413 		 */
3414 		if (uid == NFSD_VNET(nfsrv_defaultuid)) {
3415 			i = NFSD_VNET(nfsrv_dnsnamelen) + 7;
3416 			if (i > len) {
3417 				if (len > NFSV4_SMALLSTR)
3418 					free(cp, M_NFSSTRING);
3419 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
3420 				*cpp = cp;
3421 				len = i;
3422 				goto tryagain;
3423 			}
3424 			*retlenp = i;
3425 			NFSBCOPY("nobody@", cp, 7);
3426 			cp += 7;
3427 			NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
3428 			    NFSD_VNET(nfsrv_dnsnamelen));
3429 			NFSD_CURVNET_RESTORE();
3430 			return;
3431 		}
3432 		hasampersand = 0;
3433 		hp = NFSUSERHASH(uid);
3434 		mtx_lock(&hp->mtx);
3435 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3436 			if (usrp->lug_uid == uid) {
3437 				if (usrp->lug_expiry < NFSD_MONOSEC)
3438 					break;
3439 				/*
3440 				 * If the name doesn't already have an '@'
3441 				 * in it, append @domainname to it.
3442 				 */
3443 				for (i = 0; i < usrp->lug_namelen; i++) {
3444 					if (usrp->lug_name[i] == '@') {
3445 						hasampersand = 1;
3446 						break;
3447 					}
3448 				}
3449 				if (hasampersand)
3450 					i = usrp->lug_namelen;
3451 				else
3452 					i = usrp->lug_namelen +
3453 					    NFSD_VNET(nfsrv_dnsnamelen) + 1;
3454 				if (i > len) {
3455 					mtx_unlock(&hp->mtx);
3456 					if (len > NFSV4_SMALLSTR)
3457 						free(cp, M_NFSSTRING);
3458 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
3459 					*cpp = cp;
3460 					len = i;
3461 					goto tryagain;
3462 				}
3463 				*retlenp = i;
3464 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3465 				if (!hasampersand) {
3466 					cp += usrp->lug_namelen;
3467 					*cp++ = '@';
3468 					NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
3469 					    NFSD_VNET(nfsrv_dnsnamelen));
3470 				}
3471 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3472 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3473 				    lug_numhash);
3474 				mtx_unlock(&hp->mtx);
3475 				NFSD_CURVNET_RESTORE();
3476 				return;
3477 			}
3478 		}
3479 		mtx_unlock(&hp->mtx);
3480 		cnt++;
3481 		ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3482 		if (ret == 0 && cnt < 2)
3483 			goto tryagain;
3484 	}
3485 
3486 	/*
3487 	 * No match, just return a string of digits.
3488 	 */
3489 	tmp = uid;
3490 	i = 0;
3491 	while (tmp || i == 0) {
3492 		tmp /= 10;
3493 		i++;
3494 	}
3495 	len = (i > len) ? len : i;
3496 	*retlenp = len;
3497 	cp += (len - 1);
3498 	tmp = uid;
3499 	for (i = 0; i < len; i++) {
3500 		*cp-- = '0' + (tmp % 10);
3501 		tmp /= 10;
3502 	}
3503 	NFSD_CURVNET_RESTORE();
3504 	return;
3505 }
3506 
3507 /*
3508  * Get a credential for the uid with the server's group list.
3509  * If none is found, just return the credential passed in after
3510  * logging a warning message.
3511  */
3512 struct ucred *
nfsrv_getgrpscred(struct ucred * oldcred)3513 nfsrv_getgrpscred(struct ucred *oldcred)
3514 {
3515 	struct nfsusrgrp *usrp;
3516 	struct ucred *newcred;
3517 	int cnt, ret;
3518 	uid_t uid;
3519 	struct nfsrv_lughash *hp;
3520 
3521 	cnt = 0;
3522 	uid = oldcred->cr_uid;
3523 tryagain:
3524 	if (NFSD_VNET(nfsrv_dnsnamelen) > 0) {
3525 		hp = NFSUSERHASH(uid);
3526 		mtx_lock(&hp->mtx);
3527 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3528 			if (usrp->lug_uid == uid) {
3529 				if (usrp->lug_expiry < NFSD_MONOSEC)
3530 					break;
3531 				if (usrp->lug_cred != NULL) {
3532 					newcred = crhold(usrp->lug_cred);
3533 					crfree(oldcred);
3534 				} else
3535 					newcred = oldcred;
3536 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3537 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3538 				    lug_numhash);
3539 				mtx_unlock(&hp->mtx);
3540 				return (newcred);
3541 			}
3542 		}
3543 		mtx_unlock(&hp->mtx);
3544 		cnt++;
3545 		ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3546 		if (ret == 0 && cnt < 2)
3547 			goto tryagain;
3548 	}
3549 	return (oldcred);
3550 }
3551 
3552 /*
3553  * Convert a string to a uid.
3554  * If no conversion is possible return NFSERR_BADOWNER, otherwise
3555  * return 0.
3556  * If this is called from a client side mount using AUTH_SYS and the
3557  * string is made up entirely of digits, just convert the string to
3558  * a number.
3559  */
3560 int
nfsv4_strtouid(struct nfsrv_descript * nd,u_char * str,int len,uid_t * uidp)3561 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
3562 {
3563 	int i;
3564 	char *cp, *endstr, *str0;
3565 	struct nfsusrgrp *usrp;
3566 	int cnt, ret;
3567 	int error = 0;
3568 	uid_t tuid;
3569 	struct nfsrv_lughash *hp, *hp2;
3570 
3571 	NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
3572 	if (len == 0) {
3573 		error = NFSERR_BADOWNER;
3574 		goto out;
3575 	}
3576 	/* If a string of digits and an AUTH_SYS mount, just convert it. */
3577 	str0 = str;
3578 	tuid = (uid_t)strtoul(str0, &endstr, 10);
3579 	if ((endstr - str0) == len) {
3580 		/* A numeric string. */
3581 		if ((nd->nd_flag & ND_KERBV) == 0 &&
3582 		    ((nd->nd_flag & ND_NFSCL) != 0 ||
3583 		      NFSD_VNET(nfsd_enable_stringtouid) != 0))
3584 			*uidp = tuid;
3585 		else
3586 			error = NFSERR_BADOWNER;
3587 		goto out;
3588 	}
3589 	/*
3590 	 * Look for an '@'.
3591 	 */
3592 	cp = strchr(str0, '@');
3593 	if (cp != NULL)
3594 		i = (int)(cp++ - str0);
3595 	else
3596 		i = len;
3597 
3598 	cnt = 0;
3599 tryagain:
3600 	if (NFSD_VNET(nfsrv_dnsnamelen) > 0) {
3601 		/*
3602 		 * If an '@' is found and the domain name matches, search for
3603 		 * the name with dns stripped off.
3604 		 * The match for alphabetics in now case insensitive,
3605 		 * since RFC8881 defines this string as a DNS domain name.
3606 		 */
3607 		if (cnt == 0 && i < len && i > 0 &&
3608 		    (len - 1 - i) == NFSD_VNET(nfsrv_dnsnamelen) &&
3609 		    strncasecmp(cp, NFSD_VNET(nfsrv_dnsname),
3610 		     NFSD_VNET(nfsrv_dnsnamelen)) == 0) {
3611 			len -= (NFSD_VNET(nfsrv_dnsnamelen) + 1);
3612 			*(cp - 1) = '\0';
3613 		}
3614 
3615 		/*
3616 		 * Check for the special case of "nobody".
3617 		 */
3618 		if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
3619 			*uidp = NFSD_VNET(nfsrv_defaultuid);
3620 			error = 0;
3621 			goto out;
3622 		}
3623 
3624 		hp = NFSUSERNAMEHASH(str, len);
3625 		mtx_lock(&hp->mtx);
3626 		TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3627 			if (usrp->lug_namelen == len &&
3628 			    !NFSBCMP(usrp->lug_name, str, len)) {
3629 				if (usrp->lug_expiry < NFSD_MONOSEC)
3630 					break;
3631 				hp2 = NFSUSERHASH(usrp->lug_uid);
3632 				mtx_lock(&hp2->mtx);
3633 				TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3634 				TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3635 				    lug_numhash);
3636 				*uidp = usrp->lug_uid;
3637 				mtx_unlock(&hp2->mtx);
3638 				mtx_unlock(&hp->mtx);
3639 				error = 0;
3640 				goto out;
3641 			}
3642 		}
3643 		mtx_unlock(&hp->mtx);
3644 		cnt++;
3645 		ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
3646 		    str);
3647 		if (ret == 0 && cnt < 2)
3648 			goto tryagain;
3649 	}
3650 	error = NFSERR_BADOWNER;
3651 
3652 out:
3653 	NFSD_CURVNET_RESTORE();
3654 	NFSEXITCODE(error);
3655 	return (error);
3656 }
3657 
3658 /*
3659  * Convert a gid to a string.
3660  * gid - the group id
3661  * cpp - points to a buffer of size NFSV4_SMALLSTR
3662  *       (malloc a larger one, as required)
3663  * retlenp - pointer to length to be returned
3664  */
3665 void
nfsv4_gidtostr(gid_t gid,u_char ** cpp,int * retlenp)3666 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp)
3667 {
3668 	int i;
3669 	struct nfsusrgrp *usrp;
3670 	u_char *cp = *cpp;
3671 	gid_t tmp;
3672 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3673 	struct nfsrv_lughash *hp;
3674 
3675 	NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
3676 	cnt = 0;
3677 tryagain:
3678 	if (NFSD_VNET(nfsrv_dnsnamelen) > 0 &&
3679 	    !NFSD_VNET(nfs_enable_uidtostring)) {
3680 		/*
3681 		 * Always map nfsrv_defaultgid to "nogroup".
3682 		 */
3683 		if (gid == NFSD_VNET(nfsrv_defaultgid)) {
3684 			i = NFSD_VNET(nfsrv_dnsnamelen) + 8;
3685 			if (i > len) {
3686 				if (len > NFSV4_SMALLSTR)
3687 					free(cp, M_NFSSTRING);
3688 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
3689 				*cpp = cp;
3690 				len = i;
3691 				goto tryagain;
3692 			}
3693 			*retlenp = i;
3694 			NFSBCOPY("nogroup@", cp, 8);
3695 			cp += 8;
3696 			NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
3697 			    NFSD_VNET(nfsrv_dnsnamelen));
3698 			NFSD_CURVNET_RESTORE();
3699 			return;
3700 		}
3701 		hasampersand = 0;
3702 		hp = NFSGROUPHASH(gid);
3703 		mtx_lock(&hp->mtx);
3704 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3705 			if (usrp->lug_gid == gid) {
3706 				if (usrp->lug_expiry < NFSD_MONOSEC)
3707 					break;
3708 				/*
3709 				 * If the name doesn't already have an '@'
3710 				 * in it, append @domainname to it.
3711 				 */
3712 				for (i = 0; i < usrp->lug_namelen; i++) {
3713 					if (usrp->lug_name[i] == '@') {
3714 						hasampersand = 1;
3715 						break;
3716 					}
3717 				}
3718 				if (hasampersand)
3719 					i = usrp->lug_namelen;
3720 				else
3721 					i = usrp->lug_namelen +
3722 					    NFSD_VNET(nfsrv_dnsnamelen) + 1;
3723 				if (i > len) {
3724 					mtx_unlock(&hp->mtx);
3725 					if (len > NFSV4_SMALLSTR)
3726 						free(cp, M_NFSSTRING);
3727 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
3728 					*cpp = cp;
3729 					len = i;
3730 					goto tryagain;
3731 				}
3732 				*retlenp = i;
3733 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3734 				if (!hasampersand) {
3735 					cp += usrp->lug_namelen;
3736 					*cp++ = '@';
3737 					NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
3738 					    NFSD_VNET(nfsrv_dnsnamelen));
3739 				}
3740 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3741 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3742 				    lug_numhash);
3743 				mtx_unlock(&hp->mtx);
3744 				NFSD_CURVNET_RESTORE();
3745 				return;
3746 			}
3747 		}
3748 		mtx_unlock(&hp->mtx);
3749 		cnt++;
3750 		ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL);
3751 		if (ret == 0 && cnt < 2)
3752 			goto tryagain;
3753 	}
3754 
3755 	/*
3756 	 * No match, just return a string of digits.
3757 	 */
3758 	tmp = gid;
3759 	i = 0;
3760 	while (tmp || i == 0) {
3761 		tmp /= 10;
3762 		i++;
3763 	}
3764 	len = (i > len) ? len : i;
3765 	*retlenp = len;
3766 	cp += (len - 1);
3767 	tmp = gid;
3768 	for (i = 0; i < len; i++) {
3769 		*cp-- = '0' + (tmp % 10);
3770 		tmp /= 10;
3771 	}
3772 	NFSD_CURVNET_RESTORE();
3773 	return;
3774 }
3775 
3776 /*
3777  * Convert a string to a gid.
3778  * If no conversion is possible return NFSERR_BADOWNER, otherwise
3779  * return 0.
3780  * If this is called from a client side mount using AUTH_SYS and the
3781  * string is made up entirely of digits, just convert the string to
3782  * a number.
3783  */
3784 int
nfsv4_strtogid(struct nfsrv_descript * nd,u_char * str,int len,gid_t * gidp)3785 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
3786 {
3787 	int i;
3788 	char *cp, *endstr, *str0;
3789 	struct nfsusrgrp *usrp;
3790 	int cnt, ret;
3791 	int error = 0;
3792 	gid_t tgid;
3793 	struct nfsrv_lughash *hp, *hp2;
3794 
3795 	NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
3796 	if (len == 0) {
3797 		error =  NFSERR_BADOWNER;
3798 		goto out;
3799 	}
3800 	/* If a string of digits and an AUTH_SYS mount, just convert it. */
3801 	str0 = str;
3802 	tgid = (gid_t)strtoul(str0, &endstr, 10);
3803 	if ((endstr - str0) == len) {
3804 		/* A numeric string. */
3805 		if ((nd->nd_flag & ND_KERBV) == 0 &&
3806 		    ((nd->nd_flag & ND_NFSCL) != 0 ||
3807 		      NFSD_VNET(nfsd_enable_stringtouid) != 0))
3808 			*gidp = tgid;
3809 		else
3810 			error = NFSERR_BADOWNER;
3811 		goto out;
3812 	}
3813 	/*
3814 	 * Look for an '@'.
3815 	 */
3816 	cp = strchr(str0, '@');
3817 	if (cp != NULL)
3818 		i = (int)(cp++ - str0);
3819 	else
3820 		i = len;
3821 
3822 	cnt = 0;
3823 tryagain:
3824 	if (NFSD_VNET(nfsrv_dnsnamelen) > 0) {
3825 		/*
3826 		 * If an '@' is found and the dns name matches, search for the
3827 		 * name with the dns stripped off.
3828 		 */
3829 		if (cnt == 0 && i < len && i > 0 &&
3830 		    (len - 1 - i) == NFSD_VNET(nfsrv_dnsnamelen) &&
3831 		    strncasecmp(cp, NFSD_VNET(nfsrv_dnsname),
3832 		    NFSD_VNET(nfsrv_dnsnamelen)) == 0) {
3833 			len -= (NFSD_VNET(nfsrv_dnsnamelen) + 1);
3834 			*(cp - 1) = '\0';
3835 		}
3836 
3837 		/*
3838 		 * Check for the special case of "nogroup".
3839 		 */
3840 		if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
3841 			*gidp = NFSD_VNET(nfsrv_defaultgid);
3842 			error = 0;
3843 			goto out;
3844 		}
3845 
3846 		hp = NFSGROUPNAMEHASH(str, len);
3847 		mtx_lock(&hp->mtx);
3848 		TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3849 			if (usrp->lug_namelen == len &&
3850 			    !NFSBCMP(usrp->lug_name, str, len)) {
3851 				if (usrp->lug_expiry < NFSD_MONOSEC)
3852 					break;
3853 				hp2 = NFSGROUPHASH(usrp->lug_gid);
3854 				mtx_lock(&hp2->mtx);
3855 				TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3856 				TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3857 				    lug_numhash);
3858 				*gidp = usrp->lug_gid;
3859 				mtx_unlock(&hp2->mtx);
3860 				mtx_unlock(&hp->mtx);
3861 				error = 0;
3862 				goto out;
3863 			}
3864 		}
3865 		mtx_unlock(&hp->mtx);
3866 		cnt++;
3867 		ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
3868 		    str);
3869 		if (ret == 0 && cnt < 2)
3870 			goto tryagain;
3871 	}
3872 	error = NFSERR_BADOWNER;
3873 
3874 out:
3875 	NFSD_CURVNET_RESTORE();
3876 	NFSEXITCODE(error);
3877 	return (error);
3878 }
3879 
3880 /*
3881  * Set the port for the nfsuserd.
3882  */
3883 int
nfsrv_nfsuserdport(struct nfsuserd_args * nargs,NFSPROC_T * p)3884 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
3885 {
3886 	struct nfssockreq *rp;
3887 #ifdef INET
3888 	struct sockaddr_in *ad;
3889 #endif
3890 #ifdef INET6
3891 	struct sockaddr_in6 *ad6;
3892 	const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
3893 #endif
3894 	int error;
3895 
3896 	NFSLOCKNAMEID();
3897 	if (NFSD_VNET(nfsrv_nfsuserd) != NOTRUNNING) {
3898 		NFSUNLOCKNAMEID();
3899 		error = EPERM;
3900 		goto out;
3901 	}
3902 	NFSD_VNET(nfsrv_nfsuserd) = STARTSTOP;
3903 	/*
3904 	 * Set up the socket record and connect.
3905 	 * Set nr_client NULL before unlocking, just to ensure that no other
3906 	 * process/thread/core will use a bogus old value.  This could only
3907 	 * occur if the use of the nameid lock to protect nfsrv_nfsuserd is
3908 	 * broken.
3909 	 */
3910 	rp = &NFSD_VNET(nfsrv_nfsuserdsock);
3911 	rp->nr_client = NULL;
3912 	NFSUNLOCKNAMEID();
3913 	rp->nr_sotype = SOCK_DGRAM;
3914 	rp->nr_soproto = IPPROTO_UDP;
3915 	rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
3916 	rp->nr_cred = NULL;
3917 	rp->nr_prog = RPCPROG_NFSUSERD;
3918 	error = 0;
3919 	switch (nargs->nuserd_family) {
3920 #ifdef INET
3921 	case AF_INET:
3922 		rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME,
3923 		    M_WAITOK | M_ZERO);
3924  		ad = (struct sockaddr_in *)rp->nr_nam;
3925 		ad->sin_len = sizeof(struct sockaddr_in);
3926  		ad->sin_family = AF_INET;
3927 		ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3928 		ad->sin_port = nargs->nuserd_port;
3929 		break;
3930 #endif
3931 #ifdef INET6
3932 	case AF_INET6:
3933 		rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
3934 		    M_WAITOK | M_ZERO);
3935 		ad6 = (struct sockaddr_in6 *)rp->nr_nam;
3936 		ad6->sin6_len = sizeof(struct sockaddr_in6);
3937 		ad6->sin6_family = AF_INET6;
3938 		ad6->sin6_addr = in6loopback;
3939 		ad6->sin6_port = nargs->nuserd_port;
3940 		break;
3941 #endif
3942 	default:
3943 		error = ENXIO;
3944  	}
3945 	rp->nr_vers = RPCNFSUSERD_VERS;
3946 	if (error == 0)
3947 		error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0, false,
3948 		    &rp->nr_client);
3949 	if (error == 0) {
3950 		NFSLOCKNAMEID();
3951 		NFSD_VNET(nfsrv_nfsuserd) = RUNNING;
3952 		NFSUNLOCKNAMEID();
3953 	} else {
3954 		free(rp->nr_nam, M_SONAME);
3955 		NFSLOCKNAMEID();
3956 		NFSD_VNET(nfsrv_nfsuserd) = NOTRUNNING;
3957 		NFSUNLOCKNAMEID();
3958 	}
3959 out:
3960 	NFSEXITCODE(error);
3961 	return (error);
3962 }
3963 
3964 /*
3965  * Delete the nfsuserd port.
3966  */
3967 void
nfsrv_nfsuserddelport(void)3968 nfsrv_nfsuserddelport(void)
3969 {
3970 
3971 	NFSLOCKNAMEID();
3972 	if (NFSD_VNET(nfsrv_nfsuserd) != RUNNING) {
3973 		NFSUNLOCKNAMEID();
3974 		return;
3975 	}
3976 	NFSD_VNET(nfsrv_nfsuserd) = STARTSTOP;
3977 	/* Wait for all upcalls to complete. */
3978 	while (NFSD_VNET(nfsrv_userdupcalls) > 0)
3979 		msleep(&NFSD_VNET(nfsrv_userdupcalls), NFSNAMEIDMUTEXPTR, PVFS,
3980 		    "nfsupcalls", 0);
3981 	NFSUNLOCKNAMEID();
3982 	newnfs_disconnect(NULL, &NFSD_VNET(nfsrv_nfsuserdsock));
3983 	free(NFSD_VNET(nfsrv_nfsuserdsock).nr_nam, M_SONAME);
3984 	NFSLOCKNAMEID();
3985 	NFSD_VNET(nfsrv_nfsuserd) = NOTRUNNING;
3986 	NFSUNLOCKNAMEID();
3987 }
3988 
3989 /*
3990  * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3991  * name<-->id cache.
3992  * Returns 0 upon success, non-zero otherwise.
3993  */
3994 static int
nfsrv_getuser(int procnum,uid_t uid,gid_t gid,char * name)3995 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
3996 {
3997 	u_int32_t *tl;
3998 	struct nfsrv_descript *nd;
3999 	int len;
4000 	struct nfsrv_descript nfsd;
4001 	struct ucred *cred;
4002 	int error;
4003 
4004 	NFSLOCKNAMEID();
4005 	if (NFSD_VNET(nfsrv_nfsuserd) != RUNNING) {
4006 		NFSUNLOCKNAMEID();
4007 		error = EPERM;
4008 		goto out;
4009 	}
4010 	/*
4011 	 * Maintain a count of upcalls in progress, so that nfsrv_X()
4012 	 * can wait until no upcalls are in progress.
4013 	 */
4014 	NFSD_VNET(nfsrv_userdupcalls)++;
4015 	NFSUNLOCKNAMEID();
4016 	KASSERT(NFSD_VNET(nfsrv_userdupcalls) > 0,
4017 	    ("nfsrv_getuser: non-positive upcalls"));
4018 	nd = &nfsd;
4019 	cred = newnfs_getcred();
4020 	nd->nd_flag = ND_GSSINITREPLY;
4021 	nfsrvd_rephead(nd);
4022 
4023 	nd->nd_procnum = procnum;
4024 	if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
4025 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4026 		if (procnum == RPCNFSUSERD_GETUID)
4027 			*tl = txdr_unsigned(uid);
4028 		else
4029 			*tl = txdr_unsigned(gid);
4030 	} else {
4031 		len = strlen(name);
4032 		(void) nfsm_strtom(nd, name, len);
4033 	}
4034 	error = newnfs_request(nd, NULL, NULL, &NFSD_VNET(nfsrv_nfsuserdsock),
4035 	    NULL, NULL, cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0,
4036 	    NULL, NULL);
4037 	NFSLOCKNAMEID();
4038 	if (--NFSD_VNET(nfsrv_userdupcalls) == 0 &&
4039 	    NFSD_VNET(nfsrv_nfsuserd) == STARTSTOP)
4040 		wakeup(&NFSD_VNET(nfsrv_userdupcalls));
4041 	NFSUNLOCKNAMEID();
4042 	NFSFREECRED(cred);
4043 	if (!error) {
4044 		m_freem(nd->nd_mrep);
4045 		error = nd->nd_repstat;
4046 	}
4047 out:
4048 	NFSEXITCODE(error);
4049 	return (error);
4050 }
4051 
4052 /*
4053  * This function is called from the nfssvc(2) system call, to update the
4054  * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
4055  */
4056 int
nfssvc_idname(struct nfsd_idargs * nidp)4057 nfssvc_idname(struct nfsd_idargs *nidp)
4058 {
4059 	struct nfsusrgrp *nusrp, *usrp, *newusrp;
4060 	struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
4061 	int i, group_locked, groupname_locked, user_locked, username_locked;
4062 	int error = 0;
4063 	u_char *cp;
4064 	gid_t *grps;
4065 	struct ucred *cr;
4066 	static int onethread = 0;
4067 	static time_t lasttime = 0;
4068 
4069 	if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
4070 		error = EINVAL;
4071 		goto out;
4072 	}
4073 	if (nidp->nid_flag & NFSID_INITIALIZE) {
4074 		cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
4075 		error = copyin(nidp->nid_name, cp, nidp->nid_namelen);
4076 		if (error != 0) {
4077 			free(cp, M_NFSSTRING);
4078 			goto out;
4079 		}
4080 		if (atomic_cmpset_acq_int(&NFSD_VNET(nfsrv_dnsnamelen), 0, 0) ==
4081 		    0) {
4082 			/*
4083 			 * Free up all the old stuff and reinitialize hash
4084 			 * lists.  All mutexes for both lists must be locked,
4085 			 * with the user/group name ones before the uid/gid
4086 			 * ones, to avoid a LOR.
4087 			 */
4088 			for (i = 0; i < nfsrv_lughashsize; i++)
4089 				mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx);
4090 			for (i = 0; i < nfsrv_lughashsize; i++)
4091 				mtx_lock(&NFSD_VNET(nfsuserhash)[i].mtx);
4092 			for (i = 0; i < nfsrv_lughashsize; i++)
4093 				TAILQ_FOREACH_SAFE(usrp,
4094 				    &NFSD_VNET(nfsuserhash)[i].lughead, lug_numhash, nusrp)
4095 					nfsrv_removeuser(usrp, 1);
4096 			for (i = 0; i < nfsrv_lughashsize; i++)
4097 				mtx_unlock(&NFSD_VNET(nfsuserhash)[i].mtx);
4098 			for (i = 0; i < nfsrv_lughashsize; i++)
4099 				mtx_unlock(&NFSD_VNET(nfsusernamehash)[i].mtx);
4100 			for (i = 0; i < nfsrv_lughashsize; i++)
4101 				mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4102 			for (i = 0; i < nfsrv_lughashsize; i++)
4103 				mtx_lock(&NFSD_VNET(nfsgrouphash)[i].mtx);
4104 			for (i = 0; i < nfsrv_lughashsize; i++)
4105 				TAILQ_FOREACH_SAFE(usrp,
4106 				    &NFSD_VNET(nfsgrouphash)[i].lughead, lug_numhash,
4107 				    nusrp)
4108 					nfsrv_removeuser(usrp, 0);
4109 			for (i = 0; i < nfsrv_lughashsize; i++)
4110 				mtx_unlock(&NFSD_VNET(nfsgrouphash)[i].mtx);
4111 			for (i = 0; i < nfsrv_lughashsize; i++)
4112 				mtx_unlock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4113 			free(NFSD_VNET(nfsrv_dnsname), M_NFSSTRING);
4114 			NFSD_VNET(nfsrv_dnsname) = NULL;
4115 		}
4116 		if (NFSD_VNET(nfsuserhash) == NULL) {
4117 			/* Allocate the hash tables. */
4118 			NFSD_VNET(nfsuserhash) = malloc(sizeof(struct nfsrv_lughash) *
4119 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
4120 			    M_ZERO);
4121 			for (i = 0; i < nfsrv_lughashsize; i++)
4122 				mtx_init(&NFSD_VNET(nfsuserhash)[i].mtx, "nfsuidhash",
4123 				    NULL, MTX_DEF | MTX_DUPOK);
4124 			NFSD_VNET(nfsusernamehash) = malloc(sizeof(struct nfsrv_lughash) *
4125 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
4126 			    M_ZERO);
4127 			for (i = 0; i < nfsrv_lughashsize; i++)
4128 				mtx_init(&NFSD_VNET(nfsusernamehash)[i].mtx,
4129 				    "nfsusrhash", NULL, MTX_DEF |
4130 				    MTX_DUPOK);
4131 			NFSD_VNET(nfsgrouphash) = malloc(sizeof(struct nfsrv_lughash) *
4132 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
4133 			    M_ZERO);
4134 			for (i = 0; i < nfsrv_lughashsize; i++)
4135 				mtx_init(&NFSD_VNET(nfsgrouphash)[i].mtx, "nfsgidhash",
4136 				    NULL, MTX_DEF | MTX_DUPOK);
4137 			NFSD_VNET(nfsgroupnamehash) = malloc(sizeof(struct nfsrv_lughash) *
4138 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
4139 			    M_ZERO);
4140 			for (i = 0; i < nfsrv_lughashsize; i++)
4141 			    mtx_init(&NFSD_VNET(nfsgroupnamehash)[i].mtx,
4142 			    "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
4143 		}
4144 		/* (Re)initialize the list heads. */
4145 		for (i = 0; i < nfsrv_lughashsize; i++)
4146 			TAILQ_INIT(&NFSD_VNET(nfsuserhash)[i].lughead);
4147 		for (i = 0; i < nfsrv_lughashsize; i++)
4148 			TAILQ_INIT(&NFSD_VNET(nfsusernamehash)[i].lughead);
4149 		for (i = 0; i < nfsrv_lughashsize; i++)
4150 			TAILQ_INIT(&NFSD_VNET(nfsgrouphash)[i].lughead);
4151 		for (i = 0; i < nfsrv_lughashsize; i++)
4152 			TAILQ_INIT(&NFSD_VNET(nfsgroupnamehash)[i].lughead);
4153 
4154 		/*
4155 		 * Put name in "DNS" string.
4156 		 */
4157 		NFSD_VNET(nfsrv_dnsname) = cp;
4158 		NFSD_VNET(nfsrv_defaultuid) = nidp->nid_uid;
4159 		NFSD_VNET(nfsrv_defaultgid) = nidp->nid_gid;
4160 		NFSD_VNET(nfsrv_usercnt) = 0;
4161 		NFSD_VNET(nfsrv_usermax) = nidp->nid_usermax;
4162 		atomic_store_rel_int(&NFSD_VNET(nfsrv_dnsnamelen),
4163 		    nidp->nid_namelen);
4164 		goto out;
4165 	}
4166 
4167 	/*
4168 	 * malloc the new one now, so any potential sleep occurs before
4169 	 * manipulation of the lists.
4170 	 */
4171 	newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
4172 	    M_NFSUSERGROUP, M_WAITOK | M_ZERO);
4173 	error = copyin(nidp->nid_name, newusrp->lug_name,
4174 	    nidp->nid_namelen);
4175 	if (error == 0 && nidp->nid_ngroup > 0 &&
4176 	    (nidp->nid_flag & NFSID_ADDUID) != 0) {
4177 		grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
4178 		    M_WAITOK);
4179 		error = copyin(nidp->nid_grps, grps,
4180 		    sizeof(gid_t) * nidp->nid_ngroup);
4181 		if (error == 0) {
4182 			/*
4183 			 * Create a credential just like svc_getcred(),
4184 			 * but using the group list provided.
4185 			 */
4186 			cr = crget();
4187 			cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
4188 			crsetgroups_and_egid(cr, nidp->nid_ngroup, grps,
4189 			    GID_NOGROUP);
4190 			cr->cr_rgid = cr->cr_svgid = cr->cr_gid;
4191 			cr->cr_prison = curthread->td_ucred->cr_prison;
4192 			prison_hold(cr->cr_prison);
4193 #ifdef MAC
4194 			mac_cred_associate_nfsd(cr);
4195 #endif
4196 			newusrp->lug_cred = cr;
4197 		}
4198 		free(grps, M_TEMP);
4199 	}
4200 	if (error) {
4201 		free(newusrp, M_NFSUSERGROUP);
4202 		goto out;
4203 	}
4204 	newusrp->lug_namelen = nidp->nid_namelen;
4205 
4206 	/*
4207 	 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
4208 	 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
4209 	 * The flags user_locked, username_locked, group_locked and
4210 	 * groupname_locked are set to indicate all of those hash lists are
4211 	 * locked. hp_name != NULL  and hp_idnum != NULL indicates that
4212 	 * the respective one mutex is locked.
4213 	 */
4214 	user_locked = username_locked = group_locked = groupname_locked = 0;
4215 	hp_name = hp_idnum = NULL;
4216 
4217 	/*
4218 	 * Delete old entries, as required.
4219 	 */
4220 	if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
4221 		/* Must lock all username hash lists first, to avoid a LOR. */
4222 		for (i = 0; i < nfsrv_lughashsize; i++)
4223 			mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx);
4224 		username_locked = 1;
4225 		hp_idnum = NFSUSERHASH(nidp->nid_uid);
4226 		mtx_lock(&hp_idnum->mtx);
4227 		TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
4228 		    nusrp) {
4229 			if (usrp->lug_uid == nidp->nid_uid)
4230 				nfsrv_removeuser(usrp, 1);
4231 		}
4232 	} else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
4233 		hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
4234 		    newusrp->lug_namelen);
4235 		mtx_lock(&hp_name->mtx);
4236 		TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
4237 		    nusrp) {
4238 			if (usrp->lug_namelen == newusrp->lug_namelen &&
4239 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
4240 			    usrp->lug_namelen)) {
4241 				thp = NFSUSERHASH(usrp->lug_uid);
4242 				mtx_lock(&thp->mtx);
4243 				nfsrv_removeuser(usrp, 1);
4244 				mtx_unlock(&thp->mtx);
4245 			}
4246 		}
4247 		hp_idnum = NFSUSERHASH(nidp->nid_uid);
4248 		mtx_lock(&hp_idnum->mtx);
4249 	} else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
4250 		/* Must lock all groupname hash lists first, to avoid a LOR. */
4251 		for (i = 0; i < nfsrv_lughashsize; i++)
4252 			mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4253 		groupname_locked = 1;
4254 		hp_idnum = NFSGROUPHASH(nidp->nid_gid);
4255 		mtx_lock(&hp_idnum->mtx);
4256 		TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
4257 		    nusrp) {
4258 			if (usrp->lug_gid == nidp->nid_gid)
4259 				nfsrv_removeuser(usrp, 0);
4260 		}
4261 	} else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
4262 		hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
4263 		    newusrp->lug_namelen);
4264 		mtx_lock(&hp_name->mtx);
4265 		TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
4266 		    nusrp) {
4267 			if (usrp->lug_namelen == newusrp->lug_namelen &&
4268 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
4269 			    usrp->lug_namelen)) {
4270 				thp = NFSGROUPHASH(usrp->lug_gid);
4271 				mtx_lock(&thp->mtx);
4272 				nfsrv_removeuser(usrp, 0);
4273 				mtx_unlock(&thp->mtx);
4274 			}
4275 		}
4276 		hp_idnum = NFSGROUPHASH(nidp->nid_gid);
4277 		mtx_lock(&hp_idnum->mtx);
4278 	}
4279 
4280 	/*
4281 	 * Now, we can add the new one.
4282 	 */
4283 	if (nidp->nid_usertimeout)
4284 		newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
4285 	else
4286 		newusrp->lug_expiry = NFSD_MONOSEC + 5;
4287 	if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
4288 		newusrp->lug_uid = nidp->nid_uid;
4289 		thp = NFSUSERHASH(newusrp->lug_uid);
4290 		mtx_assert(&thp->mtx, MA_OWNED);
4291 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
4292 		thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
4293 		mtx_assert(&thp->mtx, MA_OWNED);
4294 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
4295 		atomic_add_int(&NFSD_VNET(nfsrv_usercnt), 1);
4296 	} else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
4297 		newusrp->lug_gid = nidp->nid_gid;
4298 		thp = NFSGROUPHASH(newusrp->lug_gid);
4299 		mtx_assert(&thp->mtx, MA_OWNED);
4300 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
4301 		thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
4302 		mtx_assert(&thp->mtx, MA_OWNED);
4303 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
4304 		atomic_add_int(&NFSD_VNET(nfsrv_usercnt), 1);
4305 	} else {
4306 		if (newusrp->lug_cred != NULL)
4307 			crfree(newusrp->lug_cred);
4308 		free(newusrp, M_NFSUSERGROUP);
4309 	}
4310 
4311 	/*
4312 	 * Once per second, allow one thread to trim the cache.
4313 	 */
4314 	if (lasttime < NFSD_MONOSEC &&
4315 	    atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
4316 		/*
4317 		 * First, unlock the single mutexes, so that all entries
4318 		 * can be locked and any LOR is avoided.
4319 		 */
4320 		if (hp_name != NULL) {
4321 			mtx_unlock(&hp_name->mtx);
4322 			hp_name = NULL;
4323 		}
4324 		if (hp_idnum != NULL) {
4325 			mtx_unlock(&hp_idnum->mtx);
4326 			hp_idnum = NULL;
4327 		}
4328 
4329 		if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
4330 		    NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
4331 			if (username_locked == 0) {
4332 				for (i = 0; i < nfsrv_lughashsize; i++)
4333 					mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx);
4334 				username_locked = 1;
4335 			}
4336 			KASSERT(user_locked == 0,
4337 			    ("nfssvc_idname: user_locked"));
4338 			for (i = 0; i < nfsrv_lughashsize; i++)
4339 				mtx_lock(&NFSD_VNET(nfsuserhash)[i].mtx);
4340 			user_locked = 1;
4341 			for (i = 0; i < nfsrv_lughashsize; i++) {
4342 				TAILQ_FOREACH_SAFE(usrp,
4343 				    &NFSD_VNET(nfsuserhash)[i].lughead, lug_numhash,
4344 				    nusrp)
4345 					if (usrp->lug_expiry < NFSD_MONOSEC)
4346 						nfsrv_removeuser(usrp, 1);
4347 			}
4348 			for (i = 0; i < nfsrv_lughashsize; i++) {
4349 				/*
4350 				 * Trim the cache using an approximate LRU
4351 				 * algorithm.  This code deletes the least
4352 				 * recently used entry on each hash list.
4353 				 */
4354 				if (NFSD_VNET(nfsrv_usercnt) <= NFSD_VNET(nfsrv_usermax))
4355 					break;
4356 				usrp = TAILQ_FIRST(&NFSD_VNET(nfsuserhash)[i].lughead);
4357 				if (usrp != NULL)
4358 					nfsrv_removeuser(usrp, 1);
4359 			}
4360 		} else {
4361 			if (groupname_locked == 0) {
4362 				for (i = 0; i < nfsrv_lughashsize; i++)
4363 					mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4364 				groupname_locked = 1;
4365 			}
4366 			KASSERT(group_locked == 0,
4367 			    ("nfssvc_idname: group_locked"));
4368 			for (i = 0; i < nfsrv_lughashsize; i++)
4369 				mtx_lock(&NFSD_VNET(nfsgrouphash)[i].mtx);
4370 			group_locked = 1;
4371 			for (i = 0; i < nfsrv_lughashsize; i++) {
4372 				TAILQ_FOREACH_SAFE(usrp,
4373 				    &NFSD_VNET(nfsgrouphash)[i].lughead, lug_numhash,
4374 				    nusrp)
4375 					if (usrp->lug_expiry < NFSD_MONOSEC)
4376 						nfsrv_removeuser(usrp, 0);
4377 			}
4378 			for (i = 0; i < nfsrv_lughashsize; i++) {
4379 				/*
4380 				 * Trim the cache using an approximate LRU
4381 				 * algorithm.  This code deletes the least
4382 				 * recently user entry on each hash list.
4383 				 */
4384 				if (NFSD_VNET(nfsrv_usercnt) <= NFSD_VNET(nfsrv_usermax))
4385 					break;
4386 				usrp = TAILQ_FIRST(&NFSD_VNET(nfsgrouphash)[i].lughead);
4387 				if (usrp != NULL)
4388 					nfsrv_removeuser(usrp, 0);
4389 			}
4390 		}
4391 		lasttime = NFSD_MONOSEC;
4392 		atomic_store_rel_int(&onethread, 0);
4393 	}
4394 
4395 	/* Now, unlock all locked mutexes. */
4396 	if (hp_idnum != NULL)
4397 		mtx_unlock(&hp_idnum->mtx);
4398 	if (hp_name != NULL)
4399 		mtx_unlock(&hp_name->mtx);
4400 	if (user_locked != 0)
4401 		for (i = 0; i < nfsrv_lughashsize; i++)
4402 			mtx_unlock(&NFSD_VNET(nfsuserhash)[i].mtx);
4403 	if (username_locked != 0)
4404 		for (i = 0; i < nfsrv_lughashsize; i++)
4405 			mtx_unlock(&NFSD_VNET(nfsusernamehash)[i].mtx);
4406 	if (group_locked != 0)
4407 		for (i = 0; i < nfsrv_lughashsize; i++)
4408 			mtx_unlock(&NFSD_VNET(nfsgrouphash)[i].mtx);
4409 	if (groupname_locked != 0)
4410 		for (i = 0; i < nfsrv_lughashsize; i++)
4411 			mtx_unlock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4412 out:
4413 	NFSEXITCODE(error);
4414 	return (error);
4415 }
4416 
4417 /*
4418  * Remove a user/group name element.
4419  */
4420 static void
nfsrv_removeuser(struct nfsusrgrp * usrp,int isuser)4421 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
4422 {
4423 	struct nfsrv_lughash *hp;
4424 
4425 	if (isuser != 0) {
4426 		hp = NFSUSERHASH(usrp->lug_uid);
4427 		mtx_assert(&hp->mtx, MA_OWNED);
4428 		TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4429 		hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4430 		mtx_assert(&hp->mtx, MA_OWNED);
4431 		TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4432 	} else {
4433 		hp = NFSGROUPHASH(usrp->lug_gid);
4434 		mtx_assert(&hp->mtx, MA_OWNED);
4435 		TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4436 		hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4437 		mtx_assert(&hp->mtx, MA_OWNED);
4438 		TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4439 	}
4440 	atomic_add_int(&NFSD_VNET(nfsrv_usercnt), -1);
4441 	if (usrp->lug_cred != NULL)
4442 		crfree(usrp->lug_cred);
4443 	free(usrp, M_NFSUSERGROUP);
4444 }
4445 
4446 /*
4447  * Free up all the allocations related to the name<-->id cache.
4448  * This function should only be called when the nfsuserd daemon isn't
4449  * running, since it doesn't do any locking.
4450  * This function is meant to be called when a vnet jail is destroyed.
4451  */
4452 void
nfsrv_cleanusergroup(void)4453 nfsrv_cleanusergroup(void)
4454 {
4455 	struct nfsrv_lughash *hp, *hp2;
4456 	struct nfsusrgrp *nusrp, *usrp;
4457 	int i;
4458 
4459 	if (NFSD_VNET(nfsuserhash) == NULL)
4460 		return;
4461 
4462 	for (i = 0; i < nfsrv_lughashsize; i++) {
4463 		hp = &NFSD_VNET(nfsuserhash)[i];
4464 		TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4465 			TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4466 			hp2 = NFSUSERNAMEHASH(usrp->lug_name,
4467 			    usrp->lug_namelen);
4468 			TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4469 			if (usrp->lug_cred != NULL)
4470 				crfree(usrp->lug_cred);
4471 			free(usrp, M_NFSUSERGROUP);
4472 		}
4473 		hp = &NFSD_VNET(nfsgrouphash)[i];
4474 		TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4475 			TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4476 			hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
4477 			    usrp->lug_namelen);
4478 			TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4479 			if (usrp->lug_cred != NULL)
4480 				crfree(usrp->lug_cred);
4481 			free(usrp, M_NFSUSERGROUP);
4482 		}
4483 		mtx_destroy(&NFSD_VNET(nfsuserhash)[i].mtx);
4484 		mtx_destroy(&NFSD_VNET(nfsusernamehash)[i].mtx);
4485 		mtx_destroy(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4486 		mtx_destroy(&NFSD_VNET(nfsgrouphash)[i].mtx);
4487 	}
4488 	free(NFSD_VNET(nfsuserhash), M_NFSUSERGROUP);
4489 	free(NFSD_VNET(nfsusernamehash), M_NFSUSERGROUP);
4490 	free(NFSD_VNET(nfsgrouphash), M_NFSUSERGROUP);
4491 	free(NFSD_VNET(nfsgroupnamehash), M_NFSUSERGROUP);
4492 	free(NFSD_VNET(nfsrv_dnsname), M_NFSSTRING);
4493 }
4494 
4495 /*
4496  * This function scans a byte string and checks for UTF-8 compliance.
4497  * It returns 0 if it conforms and NFSERR_INVAL if not.
4498  */
4499 int
nfsrv_checkutf8(u_int8_t * cp,int len)4500 nfsrv_checkutf8(u_int8_t *cp, int len)
4501 {
4502 	u_int32_t val = 0x0;
4503 	int cnt = 0, gotd = 0, shift = 0;
4504 	u_int8_t byte;
4505 	static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
4506 	int error = 0;
4507 
4508 	/*
4509 	 * Here are what the variables are used for:
4510 	 * val - the calculated value of a multibyte char, used to check
4511 	 *       that it was coded with the correct range
4512 	 * cnt - the number of 10xxxxxx bytes to follow
4513 	 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
4514 	 * shift - lower order bits of range (ie. "val >> shift" should
4515 	 *       not be 0, in other words, dividing by the lower bound
4516 	 *       of the range should get a non-zero value)
4517 	 * byte - used to calculate cnt
4518 	 */
4519 	while (len > 0) {
4520 		if (cnt > 0) {
4521 			/* This handles the 10xxxxxx bytes */
4522 			if ((*cp & 0xc0) != 0x80 ||
4523 			    (gotd && (*cp & 0x20))) {
4524 				error = NFSERR_INVAL;
4525 				goto out;
4526 			}
4527 			gotd = 0;
4528 			val <<= 6;
4529 			val |= (*cp & 0x3f);
4530 			cnt--;
4531 			if (cnt == 0 && (val >> shift) == 0x0) {
4532 				error = NFSERR_INVAL;
4533 				goto out;
4534 			}
4535 		} else if (*cp & 0x80) {
4536 			/* first byte of multi byte char */
4537 			byte = *cp;
4538 			while ((byte & 0x40) && cnt < 6) {
4539 				cnt++;
4540 				byte <<= 1;
4541 			}
4542 			if (cnt == 0 || cnt == 6) {
4543 				error = NFSERR_INVAL;
4544 				goto out;
4545 			}
4546 			val = (*cp & (0x3f >> cnt));
4547 			shift = utf8_shift[cnt - 1];
4548 			if (cnt == 2 && val == 0xd)
4549 				/* Check for the 0xd800-0xdfff case */
4550 				gotd = 1;
4551 		}
4552 		cp++;
4553 		len--;
4554 	}
4555 	if (cnt > 0)
4556 		error = NFSERR_INVAL;
4557 
4558 out:
4559 	NFSEXITCODE(error);
4560 	return (error);
4561 }
4562 
4563 /*
4564  * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
4565  * strings, one with the root path in it and the other with the list of
4566  * locations. The list is in the same format as is found in nfr_refs.
4567  * It is a "," separated list of entries, where each of them is of the
4568  * form <server>:<rootpath>. For example
4569  * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
4570  * The nilp argument is set to 1 for the special case of a null fs_root
4571  * and an empty server list.
4572  * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
4573  * number of xdr bytes parsed in sump.
4574  */
4575 static int
nfsrv_getrefstr(struct nfsrv_descript * nd,u_char ** fsrootp,u_char ** srvp,int * sump,int * nilp)4576 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
4577     int *sump, int *nilp)
4578 {
4579 	u_int32_t *tl;
4580 	u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
4581 	int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
4582 	struct list {
4583 		SLIST_ENTRY(list) next;
4584 		int len;
4585 		u_char host[1];
4586 	} *lsp, *nlsp;
4587 	SLIST_HEAD(, list) head;
4588 
4589 	*fsrootp = NULL;
4590 	*srvp = NULL;
4591 	*nilp = 0;
4592 
4593 	/*
4594 	 * Get the fs_root path and check for the special case of null path
4595 	 * and 0 length server list.
4596 	 */
4597 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4598 	len = fxdr_unsigned(int, *tl);
4599 	if (len < 0 || len > 10240) {
4600 		error = NFSERR_BADXDR;
4601 		goto nfsmout;
4602 	}
4603 	if (len == 0) {
4604 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4605 		if (*tl != 0) {
4606 			error = NFSERR_BADXDR;
4607 			goto nfsmout;
4608 		}
4609 		*nilp = 1;
4610 		*sump = 2 * NFSX_UNSIGNED;
4611 		error = 0;
4612 		goto nfsmout;
4613 	}
4614 	cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
4615 	error = nfsrv_mtostr(nd, cp, len);
4616 	if (!error) {
4617 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4618 		cnt = fxdr_unsigned(int, *tl);
4619 		if (cnt <= 0)
4620 			error = NFSERR_BADXDR;
4621 	}
4622 	if (error)
4623 		goto nfsmout;
4624 
4625 	/*
4626 	 * Now, loop through the location list and make up the srvlist.
4627 	 */
4628 	xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4629 	cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
4630 	slen = 1024;
4631 	siz = 0;
4632 	for (i = 0; i < cnt; i++) {
4633 		SLIST_INIT(&head);
4634 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4635 		nsrv = fxdr_unsigned(int, *tl);
4636 		if (nsrv <= 0) {
4637 			error = NFSERR_BADXDR;
4638 			goto nfsmout;
4639 		}
4640 
4641 		/*
4642 		 * Handle the first server by putting it in the srvstr.
4643 		 */
4644 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4645 		len = fxdr_unsigned(int, *tl);
4646 		if (len <= 0 || len > 1024) {
4647 			error = NFSERR_BADXDR;
4648 			goto nfsmout;
4649 		}
4650 		nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
4651 		if (cp3 != cp2) {
4652 			*cp3++ = ',';
4653 			siz++;
4654 		}
4655 		error = nfsrv_mtostr(nd, cp3, len);
4656 		if (error)
4657 			goto nfsmout;
4658 		cp3 += len;
4659 		*cp3++ = ':';
4660 		siz += (len + 1);
4661 		xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4662 		for (j = 1; j < nsrv; j++) {
4663 			/*
4664 			 * Yuck, put them in an slist and process them later.
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 			lsp = (struct list *)malloc(sizeof (struct list)
4673 			    + len, M_TEMP, M_WAITOK);
4674 			error = nfsrv_mtostr(nd, lsp->host, len);
4675 			if (error)
4676 				goto nfsmout;
4677 			xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4678 			lsp->len = len;
4679 			SLIST_INSERT_HEAD(&head, lsp, next);
4680 		}
4681 
4682 		/*
4683 		 * Finally, we can get the path.
4684 		 */
4685 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4686 		len = fxdr_unsigned(int, *tl);
4687 		if (len <= 0 || len > 1024) {
4688 			error = NFSERR_BADXDR;
4689 			goto nfsmout;
4690 		}
4691 		nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
4692 		error = nfsrv_mtostr(nd, cp3, len);
4693 		if (error)
4694 			goto nfsmout;
4695 		xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4696 		str = cp3;
4697 		stringlen = len;
4698 		cp3 += len;
4699 		siz += len;
4700 		SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
4701 			nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
4702 			    &cp2, &cp3, &slen);
4703 			*cp3++ = ',';
4704 			NFSBCOPY(lsp->host, cp3, lsp->len);
4705 			cp3 += lsp->len;
4706 			*cp3++ = ':';
4707 			NFSBCOPY(str, cp3, stringlen);
4708 			cp3 += stringlen;
4709 			*cp3 = '\0';
4710 			siz += (lsp->len + stringlen + 2);
4711 			free(lsp, M_TEMP);
4712 		}
4713 	}
4714 	*fsrootp = cp;
4715 	*srvp = cp2;
4716 	*sump = xdrsum;
4717 	NFSEXITCODE2(0, nd);
4718 	return (0);
4719 nfsmout:
4720 	if (cp != NULL)
4721 		free(cp, M_NFSSTRING);
4722 	if (cp2 != NULL)
4723 		free(cp2, M_NFSSTRING);
4724 	NFSEXITCODE2(error, nd);
4725 	return (error);
4726 }
4727 
4728 /*
4729  * Make the malloc'd space large enough. This is a pain, but the xdr
4730  * doesn't set an upper bound on the side, so...
4731  */
4732 static void
nfsrv_refstrbigenough(int siz,u_char ** cpp,u_char ** cpp2,int * slenp)4733 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
4734 {
4735 	u_char *cp;
4736 	int i;
4737 
4738 	if (siz <= *slenp)
4739 		return;
4740 	cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
4741 	NFSBCOPY(*cpp, cp, *slenp);
4742 	free(*cpp, M_NFSSTRING);
4743 	i = *cpp2 - *cpp;
4744 	*cpp = cp;
4745 	*cpp2 = cp + i;
4746 	*slenp = siz + 1024;
4747 }
4748 
4749 /*
4750  * Initialize the reply header data structures.
4751  */
4752 void
nfsrvd_rephead(struct nfsrv_descript * nd)4753 nfsrvd_rephead(struct nfsrv_descript *nd)
4754 {
4755 	struct mbuf *mreq;
4756 
4757 	if ((nd->nd_flag & ND_EXTPG) != 0) {
4758 		mreq = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
4759 		nd->nd_mreq = nd->nd_mb = mreq;
4760 		nd->nd_bpos = (char *)(void *)
4761 		    PHYS_TO_DMAP(mreq->m_epg_pa[0]);
4762 		nd->nd_bextpg = 0;
4763 		nd->nd_bextpgsiz = PAGE_SIZE;
4764 	} else {
4765 		/*
4766 		 * If this is a big reply, use a cluster.
4767 		 */
4768 		if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
4769 		    nfs_bigreply[nd->nd_procnum]) {
4770 			NFSMCLGET(mreq, M_WAITOK);
4771 			nd->nd_mreq = mreq;
4772 			nd->nd_mb = mreq;
4773 		} else {
4774 			NFSMGET(mreq);
4775 			nd->nd_mreq = mreq;
4776 			nd->nd_mb = mreq;
4777 		}
4778 		nd->nd_bpos = mtod(mreq, char *);
4779 		mreq->m_len = 0;
4780 	}
4781 
4782 	if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
4783 		NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
4784 }
4785 
4786 /*
4787  * Lock a socket against others.
4788  * Currently used to serialize connect/disconnect attempts.
4789  */
4790 int
newnfs_sndlock(int * flagp)4791 newnfs_sndlock(int *flagp)
4792 {
4793 	struct timespec ts;
4794 
4795 	NFSLOCKSOCK();
4796 	while (*flagp & NFSR_SNDLOCK) {
4797 		*flagp |= NFSR_WANTSND;
4798 		ts.tv_sec = 0;
4799 		ts.tv_nsec = 0;
4800 		(void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
4801 		    PVFS, "nfsndlck", &ts);
4802 	}
4803 	*flagp |= NFSR_SNDLOCK;
4804 	NFSUNLOCKSOCK();
4805 	return (0);
4806 }
4807 
4808 /*
4809  * Unlock the stream socket for others.
4810  */
4811 void
newnfs_sndunlock(int * flagp)4812 newnfs_sndunlock(int *flagp)
4813 {
4814 
4815 	NFSLOCKSOCK();
4816 	if ((*flagp & NFSR_SNDLOCK) == 0)
4817 		panic("nfs sndunlock");
4818 	*flagp &= ~NFSR_SNDLOCK;
4819 	if (*flagp & NFSR_WANTSND) {
4820 		*flagp &= ~NFSR_WANTSND;
4821 		wakeup((caddr_t)flagp);
4822 	}
4823 	NFSUNLOCKSOCK();
4824 }
4825 
4826 int
nfsv4_getipaddr(struct nfsrv_descript * nd,struct sockaddr_in * sin,struct sockaddr_in6 * sin6,sa_family_t * saf,int * isudp)4827 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
4828     struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
4829 {
4830 	struct in_addr saddr;
4831 	uint32_t portnum, *tl;
4832 	int i, j, k;
4833 	sa_family_t af = AF_UNSPEC;
4834 	char addr[64], protocol[5], *cp;
4835 	int cantparse = 0, error = 0;
4836 	uint16_t portv;
4837 
4838 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4839 	i = fxdr_unsigned(int, *tl);
4840 	if (i >= 3 && i <= 4) {
4841 		error = nfsrv_mtostr(nd, protocol, i);
4842 		if (error)
4843 			goto nfsmout;
4844 		if (strcmp(protocol, "tcp") == 0) {
4845 			af = AF_INET;
4846 			*isudp = 0;
4847 		} else if (strcmp(protocol, "udp") == 0) {
4848 			af = AF_INET;
4849 			*isudp = 1;
4850 		} else if (strcmp(protocol, "tcp6") == 0) {
4851 			af = AF_INET6;
4852 			*isudp = 0;
4853 		} else if (strcmp(protocol, "udp6") == 0) {
4854 			af = AF_INET6;
4855 			*isudp = 1;
4856 		} else
4857 			cantparse = 1;
4858 	} else {
4859 		cantparse = 1;
4860 		if (i > 0) {
4861 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4862 			if (error)
4863 				goto nfsmout;
4864 		}
4865 	}
4866 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4867 	i = fxdr_unsigned(int, *tl);
4868 	if (i < 0) {
4869 		error = NFSERR_BADXDR;
4870 		goto nfsmout;
4871 	} else if (cantparse == 0 && i >= 11 && i < 64) {
4872 		/*
4873 		 * The shortest address is 11chars and the longest is < 64.
4874 		 */
4875 		error = nfsrv_mtostr(nd, addr, i);
4876 		if (error)
4877 			goto nfsmout;
4878 
4879 		/* Find the port# at the end and extract that. */
4880 		i = strlen(addr);
4881 		k = 0;
4882 		cp = &addr[i - 1];
4883 		/* Count back two '.'s from end to get port# field. */
4884 		for (j = 0; j < i; j++) {
4885 			if (*cp == '.') {
4886 				k++;
4887 				if (k == 2)
4888 					break;
4889 			}
4890 			cp--;
4891 		}
4892 		if (k == 2) {
4893 			/*
4894 			 * The NFSv4 port# is appended as .N.N, where N is
4895 			 * a decimal # in the range 0-255, just like an inet4
4896 			 * address. Cheat and use inet_aton(), which will
4897 			 * return a Class A address and then shift the high
4898 			 * order 8bits over to convert it to the port#.
4899 			 */
4900 			*cp++ = '\0';
4901 			if (inet_aton(cp, &saddr) == 1) {
4902 				portnum = ntohl(saddr.s_addr);
4903 				portv = (uint16_t)((portnum >> 16) |
4904 				    (portnum & 0xff));
4905 			} else
4906 				cantparse = 1;
4907 		} else
4908 			cantparse = 1;
4909 		if (cantparse == 0) {
4910 			if (af == AF_INET) {
4911 				if (inet_pton(af, addr, &sin->sin_addr) == 1) {
4912 					sin->sin_len = sizeof(*sin);
4913 					sin->sin_family = AF_INET;
4914 					sin->sin_port = htons(portv);
4915 					*saf = af;
4916 					return (0);
4917 				}
4918 			} else {
4919 				if (inet_pton(af, addr, &sin6->sin6_addr)
4920 				    == 1) {
4921 					sin6->sin6_len = sizeof(*sin6);
4922 					sin6->sin6_family = AF_INET6;
4923 					sin6->sin6_port = htons(portv);
4924 					*saf = af;
4925 					return (0);
4926 				}
4927 			}
4928 		}
4929 	} else {
4930 		if (i > 0) {
4931 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
4932 			if (error)
4933 				goto nfsmout;
4934 		}
4935 	}
4936 	error = EPERM;
4937 nfsmout:
4938 	return (error);
4939 }
4940 
4941 /*
4942  * Handle an NFSv4.1 Sequence request for the session.
4943  * If reply != NULL, use it to return the cached reply, as required.
4944  * The client gets a cached reply via this call for callbacks, however the
4945  * server gets a cached reply via the nfsv4_seqsess_cacherep() call.
4946  */
4947 int
nfsv4_seqsession(uint32_t seqid,uint32_t slotid,uint32_t highslot,struct nfsslot * slots,struct mbuf ** reply,uint16_t maxslot)4948 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
4949     struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
4950 {
4951 	struct mbuf *m;
4952 	int error;
4953 
4954 	error = 0;
4955 	if (reply != NULL)
4956 		*reply = NULL;
4957 	if (slotid > maxslot)
4958 		return (NFSERR_BADSLOT);
4959 	if (seqid == slots[slotid].nfssl_seq) {
4960 		/* A retry. */
4961 		if (slots[slotid].nfssl_inprog != 0)
4962 			error = NFSERR_DELAY;
4963 		else if (slots[slotid].nfssl_reply != NULL) {
4964 			if (reply != NULL) {
4965 				m = m_copym(slots[slotid].nfssl_reply, 0,
4966 				    M_COPYALL, M_NOWAIT);
4967 				if (m != NULL)
4968 					*reply = m;
4969 				else {
4970 					*reply = slots[slotid].nfssl_reply;
4971 					slots[slotid].nfssl_reply = NULL;
4972 				}
4973 			}
4974 			slots[slotid].nfssl_inprog = 1;
4975 			error = NFSERR_REPLYFROMCACHE;
4976 		} else
4977 			/* No reply cached, so just do it. */
4978 			slots[slotid].nfssl_inprog = 1;
4979 	} else if ((slots[slotid].nfssl_seq + 1) == seqid) {
4980 		if (slots[slotid].nfssl_reply != NULL)
4981 			m_freem(slots[slotid].nfssl_reply);
4982 		slots[slotid].nfssl_reply = NULL;
4983 		slots[slotid].nfssl_inprog = 1;
4984 		slots[slotid].nfssl_seq++;
4985 	} else
4986 		error = NFSERR_SEQMISORDERED;
4987 	return (error);
4988 }
4989 
4990 /*
4991  * Cache this reply for the slot.
4992  * Use the "rep" argument to return the cached reply if repstat is set to
4993  * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
4994  */
4995 void
nfsv4_seqsess_cacherep(uint32_t slotid,struct nfsslot * slots,int repstat,struct mbuf ** rep)4996 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
4997    struct mbuf **rep)
4998 {
4999 	struct mbuf *m;
5000 
5001 	if (repstat == NFSERR_REPLYFROMCACHE) {
5002 		if (slots[slotid].nfssl_reply != NULL) {
5003 			/*
5004 			 * We cannot sleep here, but copy will usually
5005 			 * succeed.
5006 			 */
5007 			m = m_copym(slots[slotid].nfssl_reply, 0, M_COPYALL,
5008 			    M_NOWAIT);
5009 			if (m != NULL)
5010 				*rep = m;
5011 			else {
5012 				/*
5013 				 * Multiple retries would be extremely rare,
5014 				 * so using the cached reply will likely
5015 				 * be ok.
5016 				 */
5017 				*rep = slots[slotid].nfssl_reply;
5018 				slots[slotid].nfssl_reply = NULL;
5019 			}
5020 		} else
5021 			*rep = NULL;
5022 	} else {
5023 		if (slots[slotid].nfssl_reply != NULL)
5024 			m_freem(slots[slotid].nfssl_reply);
5025 		slots[slotid].nfssl_reply = *rep;
5026 	}
5027 	slots[slotid].nfssl_inprog = 0;
5028 }
5029 
5030 /*
5031  * Generate the xdr for an NFSv4.1 Sequence Operation.
5032  */
5033 static void
nfsv4_setsequence(struct nfsmount * nmp,struct nfsrv_descript * nd,struct nfsclsession * sep,bool dont_replycache,struct ucred * cred)5034 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
5035     struct nfsclsession *sep, bool dont_replycache, struct ucred *cred)
5036 {
5037 	uint32_t *tl, slotseq = 0;
5038 	int error, maxslot, slotpos;
5039 	uint8_t sessionid[NFSX_V4SESSIONID];
5040 
5041 	if (cred != NULL) {
5042 		error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot,
5043 		    &slotseq, sessionid, false);
5044 		if (error == NFSERR_SEQMISORDERED) {
5045 			/* If all slots are bad, Destroy the session. */
5046 			nfsrpc_destroysession(nmp, sep, cred, curthread);
5047 		}
5048 	} else
5049 		error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot,
5050 		    &slotseq, sessionid, true);
5051 	nd->nd_maxreq = sep->nfsess_maxreq;
5052 	nd->nd_maxresp = sep->nfsess_maxresp;
5053 
5054 	/* Build the Sequence arguments. */
5055 	NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
5056 	nd->nd_sequence = tl;
5057 	bcopy(sessionid, tl, NFSX_V4SESSIONID);
5058 	tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
5059 	nd->nd_slotseq = tl;
5060 	if (error == 0) {
5061 		nd->nd_flag |= ND_HASSLOTID;
5062 		nd->nd_slotid = slotpos;
5063 		*tl++ = txdr_unsigned(slotseq);
5064 		*tl++ = txdr_unsigned(slotpos);
5065 		*tl++ = txdr_unsigned(maxslot);
5066 		if (!dont_replycache)
5067 			*tl = newnfs_true;
5068 		else
5069 			*tl = newnfs_false;
5070 	} else {
5071 		/*
5072 		 * There are two errors and the rest of the session can
5073 		 * just be zeros.
5074 		 * NFSERR_BADSESSION: This bad session should just generate
5075 		 *    the same error again when the RPC is retried.
5076 		 * ESTALE: A forced dismount is in progress and will cause the
5077 		 *    RPC to fail later.
5078 		 */
5079 		*tl++ = 0;
5080 		*tl++ = 0;
5081 		*tl++ = 0;
5082 		*tl = 0;
5083 	}
5084 	nd->nd_flag |= ND_HASSEQUENCE;
5085 }
5086 
5087 /*
5088  * If fnd_init is true, ignore the badslots.
5089  * If fnd_init is false, return NFSERR_SEQMISORDERED if all slots are bad.
5090  */
5091 int
nfsv4_sequencelookup(struct nfsmount * nmp,struct nfsclsession * sep,int * slotposp,int * maxslotp,uint32_t * slotseqp,uint8_t * sessionid,bool fnd_init)5092 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
5093     int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid,
5094     bool fnd_init)
5095 {
5096 	int i, maxslot, slotpos;
5097 	uint64_t bitval;
5098 	bool fnd_ok;
5099 
5100 	/* Find an unused slot. */
5101 	slotpos = -1;
5102 	maxslot = -1;
5103 	mtx_lock(&sep->nfsess_mtx);
5104 	do {
5105 		if (nmp != NULL && sep->nfsess_defunct != 0) {
5106 			/* Just return the bad session. */
5107 			bcopy(sep->nfsess_sessionid, sessionid,
5108 			    NFSX_V4SESSIONID);
5109 			mtx_unlock(&sep->nfsess_mtx);
5110 			return (NFSERR_BADSESSION);
5111 		}
5112 		fnd_ok = fnd_init;
5113 		bitval = 1;
5114 		for (i = 0; i < sep->nfsess_foreslots; i++) {
5115 			if ((bitval & sep->nfsess_badslots) == 0 || fnd_init) {
5116 				fnd_ok = true;
5117 				if ((bitval & sep->nfsess_slots) == 0) {
5118 					slotpos = i;
5119 					sep->nfsess_slots |= bitval;
5120 					sep->nfsess_slotseq[i]++;
5121 					*slotseqp = sep->nfsess_slotseq[i];
5122 					break;
5123 				}
5124 			}
5125 			bitval <<= 1;
5126 		}
5127 		if (slotpos == -1) {
5128 			/*
5129 			 * If a forced dismount is in progress, just return.
5130 			 * This RPC attempt will fail when it calls
5131 			 * newnfs_request().
5132 			 */
5133 			if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
5134 				mtx_unlock(&sep->nfsess_mtx);
5135 				return (ESTALE);
5136 			}
5137 			/* Wake up once/sec, to check for a forced dismount. */
5138 			if (fnd_ok)
5139 				mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
5140 				    PZERO, "nfsclseq", hz);
5141 		}
5142 	} while (slotpos == -1 && fnd_ok);
5143 	/*
5144 	 * If all slots are bad, just return slot 0 and NFSERR_SEQMISORDERED.
5145 	 * The caller will do a DestroySession, so that the session's use
5146 	 * will get a NFSERR_BADSESSION reply from the server.
5147 	 */
5148 	if (!fnd_ok)
5149 		slotpos = 0;
5150 
5151 	/* Now, find the highest slot in use. (nfsc_slots is 64bits) */
5152 	bitval = 1;
5153 	for (i = 0; i < 64; i++) {
5154 		if ((bitval & sep->nfsess_slots) != 0)
5155 			maxslot = i;
5156 		bitval <<= 1;
5157 	}
5158 	bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
5159 	mtx_unlock(&sep->nfsess_mtx);
5160 	*slotposp = slotpos;
5161 	*maxslotp = maxslot;
5162 
5163 	if (!fnd_ok)
5164 		return (NFSERR_SEQMISORDERED);
5165 	return (0);
5166 }
5167 
5168 /*
5169  * Free a session slot.
5170  */
5171 void
nfsv4_freeslot(struct nfsclsession * sep,int slot,bool resetseq)5172 nfsv4_freeslot(struct nfsclsession *sep, int slot, bool resetseq)
5173 {
5174 	uint64_t bitval;
5175 
5176 	bitval = 1;
5177 	if (slot > 0)
5178 		bitval <<= slot;
5179 	mtx_lock(&sep->nfsess_mtx);
5180 	if (resetseq)
5181 		sep->nfsess_slotseq[slot]--;
5182 	else if (slot > sep->nfsess_foreslots)
5183 		sep->nfsess_slotseq[slot] = 0;
5184 	if ((bitval & sep->nfsess_slots) == 0)
5185 		printf("freeing free slot!!\n");
5186 	sep->nfsess_slots &= ~bitval;
5187 	wakeup(&sep->nfsess_slots);
5188 	mtx_unlock(&sep->nfsess_mtx);
5189 }
5190 
5191 /*
5192  * Search for a matching pnfsd DS, based on the nmp arg.
5193  * Return one if found, NULL otherwise.
5194  */
5195 struct nfsdevice *
nfsv4_findmirror(struct nfsmount * nmp)5196 nfsv4_findmirror(struct nfsmount *nmp)
5197 {
5198 	struct nfsdevice *ds;
5199 
5200 	mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
5201 	/*
5202 	 * Search the DS server list for a match with nmp.
5203 	 */
5204 	if (nfsrv_devidcnt == 0)
5205 		return (NULL);
5206 	TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
5207 		if (ds->nfsdev_nmp == nmp) {
5208 			NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");
5209 			break;
5210 		}
5211 	}
5212 	return (ds);
5213 }
5214 
5215 /*
5216  * Fill in the fields of "struct nfsrv_descript".
5217  */
5218 void
nfsm_set(struct nfsrv_descript * nd,u_int offs)5219 nfsm_set(struct nfsrv_descript *nd, u_int offs)
5220 {
5221 	struct mbuf *m;
5222 	int rlen;
5223 
5224 	m = nd->nd_mb;
5225 	if ((m->m_flags & M_EXTPG) != 0) {
5226 		nd->nd_bextpg = 0;
5227 		while (offs > 0) {
5228 			if (nd->nd_bextpg == 0)
5229 				rlen = m_epg_pagelen(m, 0, m->m_epg_1st_off);
5230 			else
5231 				rlen = m_epg_pagelen(m, nd->nd_bextpg, 0);
5232 			if (offs <= rlen)
5233 				break;
5234 			offs -= rlen;
5235 			nd->nd_bextpg++;
5236 			if (nd->nd_bextpg == m->m_epg_npgs) {
5237 				printf("nfsm_set: build offs "
5238 				    "out of range\n");
5239 				nd->nd_bextpg--;
5240 				break;
5241 			}
5242 		}
5243 		nd->nd_bpos = (char *)(void *)
5244 		    PHYS_TO_DMAP(m->m_epg_pa[nd->nd_bextpg]);
5245 		if (nd->nd_bextpg == 0)
5246 			nd->nd_bpos += m->m_epg_1st_off;
5247 		if (offs > 0) {
5248 			nd->nd_bpos += offs;
5249 			nd->nd_bextpgsiz = rlen - offs;
5250 		} else if (nd->nd_bextpg == 0)
5251 			nd->nd_bextpgsiz = PAGE_SIZE - m->m_epg_1st_off;
5252 		else
5253 			nd->nd_bextpgsiz = PAGE_SIZE;
5254 	} else
5255 		nd->nd_bpos = mtod(m, char *) + offs;
5256 }
5257 
5258 /*
5259  * Grow a ext_pgs mbuf list.  Either allocate another page or add
5260  * an mbuf to the list.
5261  */
5262 struct mbuf *
nfsm_add_ext_pgs(struct mbuf * m,int maxextsiz,int * bextpg)5263 nfsm_add_ext_pgs(struct mbuf *m, int maxextsiz, int *bextpg)
5264 {
5265 	struct mbuf *mp;
5266 	vm_page_t pg;
5267 
5268 	if ((m->m_epg_npgs + 1) * PAGE_SIZE > maxextsiz) {
5269 		mp = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
5270 		*bextpg = 0;
5271 		m->m_next = mp;
5272 	} else {
5273 		pg = vm_page_alloc_noobj(VM_ALLOC_WAITOK | VM_ALLOC_NODUMP |
5274 		    VM_ALLOC_WIRED);
5275 		m->m_epg_pa[m->m_epg_npgs] = VM_PAGE_TO_PHYS(pg);
5276 		*bextpg = m->m_epg_npgs;
5277 		m->m_epg_npgs++;
5278 		m->m_epg_last_len = 0;
5279 		mp = m;
5280 	}
5281 	return (mp);
5282 }
5283 
5284 /*
5285  * Do the NFSv4.1 Destroy Session.
5286  */
5287 int
nfsrpc_destroysession(struct nfsmount * nmp,struct nfsclsession * tsep,struct ucred * cred,NFSPROC_T * p)5288 nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclsession *tsep,
5289     struct ucred *cred, NFSPROC_T *p)
5290 {
5291 	uint32_t *tl;
5292 	struct nfsrv_descript nfsd;
5293 	struct nfsrv_descript *nd = &nfsd;
5294 	int error;
5295 
5296 	if (tsep == NULL)
5297 		tsep = nfsmnt_mdssession(nmp);
5298 	if (tsep == NULL)
5299 		return (0);
5300 	nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL, 0,
5301 	    0, NULL);
5302 	NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
5303 	bcopy(tsep->nfsess_sessionid, tl, NFSX_V4SESSIONID);
5304 	nd->nd_flag |= ND_USEGSSNAME;
5305 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5306 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5307 	if (error != 0)
5308 		return (error);
5309 	error = nd->nd_repstat;
5310 	m_freem(nd->nd_mrep);
5311 	return (error);
5312 }
5313 
5314 /*
5315  * Translate a vnode type into an NFSv4 type, including the named
5316  * attribute types.
5317  */
5318 static uint32_t
vtonfsv4_type(struct vattr * vap)5319 vtonfsv4_type(struct vattr *vap)
5320 {
5321 	nfstype ntyp;
5322 
5323 	if (vap->va_type >= 9)
5324 		ntyp = NFNON;
5325 	else
5326 		ntyp = nfsv34_type[vap->va_type];
5327 	if ((vap->va_bsdflags & SFBSD_NAMEDATTR) != 0) {
5328 		if (ntyp == NFDIR)
5329 			ntyp = NFATTRDIR;
5330 		else if (ntyp == NFREG)
5331 			ntyp = NFNAMEDATTR;
5332 	}
5333 	return (txdr_unsigned((uint32_t)ntyp));
5334 }
5335 
5336 /*
5337  * Translate an NFS type to a vnode type.
5338  */
5339 static __enum_uint8(vtype)
nfsv4tov_type(uint32_t ntyp,uint16_t * bsdflags)5340 nfsv4tov_type(uint32_t ntyp, uint16_t *bsdflags)
5341 {
5342 	__enum_uint8(vtype) vtyp;
5343 
5344 	ntyp = fxdr_unsigned(uint32_t, ntyp) % (NFNAMEDATTR + 1);
5345 	if (ntyp == NFATTRDIR) {
5346 		vtyp = VDIR;
5347 		*bsdflags |= SFBSD_NAMEDATTR;
5348 	} else if (ntyp == NFNAMEDATTR) {
5349 		vtyp = VREG;
5350 		*bsdflags |= SFBSD_NAMEDATTR;
5351 	} else {
5352 		vtyp = nv34tov_type[ntyp];
5353 	}
5354 	return (vtyp);
5355 }
5356