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