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