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