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