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