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