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