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