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