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