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