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