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