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