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