xref: /freebsd/sys/fs/nfs/nfs_commonsubs.c (revision 949cff4dceffdbee70fa7741c1d61cf6c5255aeb)
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,int * aclerrp,int * aclsizep,__unused NFSPROC_T * p)1150 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, bool server,
1151     int *aclerrp, int *aclsizep, __unused NFSPROC_T *p)
1152 {
1153 	uint32_t *tl;
1154 	int i, aclsize;
1155 	int acecnt, error = 0, aceerr = 0, acesize;
1156 	bool posixacl = false;
1157 
1158 	*aclerrp = 0;
1159 	if (aclp != NULL)
1160 		aclp->acl_cnt = 0;
1161 	/*
1162 	 * Parse out the ace entries and expect them to conform to
1163 	 * what can be supported by R/W/X bits.
1164 	 */
1165 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
1166 	aclsize = NFSX_UNSIGNED;
1167 	acecnt = fxdr_unsigned(int, *tl);
1168 	/*
1169 	 * The RFCs do not define a fixed limit to the number of ACEs in
1170 	 * an ACL, but 10240 should be more than sufficient.
1171 	 */
1172 	if (acecnt < 0 || acecnt > 10240) {
1173 		error = NFSERR_BADXDR;
1174 		goto nfsmout;
1175 	}
1176 	if (acecnt > ACL_MAX_ENTRIES)
1177 		aceerr = NFSERR_ATTRNOTSUPP;
1178 	if (nfsrv_useacl == 0)
1179 		aceerr = NFSERR_ATTRNOTSUPP;
1180 	for (i = 0; i < acecnt; i++) {
1181 		if (aclp != NULL && aceerr == 0) {
1182 			if (posixacl)
1183 				error = nfsrv_dissectposixace(nd,
1184 				    &aclp->acl_entry[i], server, &aceerr,
1185 				    &acesize);
1186 			else
1187 				error = nfsrv_dissectace(nd,
1188 				    &aclp->acl_entry[i], server, &aceerr,
1189 				    &acesize, p);
1190 		} else if (posixacl)
1191 			error = nfsrv_skipace(nd, ACL_TYPE_ACCESS, &acesize);
1192 		else
1193 			error = nfsrv_skipace(nd, ACL_TYPE_NFS4, &acesize);
1194 		if (error != 0)
1195 			goto nfsmout;
1196 		aclsize += acesize;
1197 	}
1198 	if (aclp != NULL && aceerr == 0)
1199 		aclp->acl_cnt = acecnt;
1200 	if (aceerr != 0)
1201 		*aclerrp = aceerr;
1202 	if (aclsizep != NULL)
1203 		*aclsizep = aclsize;
1204 nfsmout:
1205 	NFSEXITCODE2(error, nd);
1206 	return (error);
1207 }
1208 
1209 /*
1210  * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
1211  */
1212 static int
nfsrv_skipace(struct nfsrv_descript * nd,acl_type_t acltype,int * acesizep)1213 nfsrv_skipace(struct nfsrv_descript *nd, acl_type_t acltype, int *acesizep)
1214 {
1215 	uint32_t *tl;
1216 	int error, len = 0;
1217 
1218 	if (acltype == ACL_TYPE_NFS4) {
1219 		NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
1220 		len = fxdr_unsigned(int, *(tl + 3));
1221 		*acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
1222 	} else {
1223 		NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED);
1224 		len = fxdr_unsigned(int, *(tl + 2));
1225 		*acesizep = NFSM_RNDUP(len) + (3 * NFSX_UNSIGNED);
1226 	}
1227 	error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
1228 nfsmout:
1229 	NFSEXITCODE2(error, nd);
1230 	return (error);
1231 }
1232 
1233 /*
1234  * Get attribute bits from an mbuf list.
1235  * Returns EBADRPC for a parsing error, 0 otherwise.
1236  * If the clearinvalid flag is set, clear the bits not supported.
1237  */
1238 int
nfsrv_getattrbits(struct nfsrv_descript * nd,nfsattrbit_t * attrbitp,int * cntp,int * retnotsupp)1239 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
1240     int *retnotsupp)
1241 {
1242 	u_int32_t *tl;
1243 	int cnt, i, outcnt;
1244 	int error = 0;
1245 
1246 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1247 	cnt = fxdr_unsigned(int, *tl);
1248 	if (cnt < 0) {
1249 		error = NFSERR_BADXDR;
1250 		goto nfsmout;
1251 	}
1252 	if (cnt > NFSATTRBIT_MAXWORDS)
1253 		outcnt = NFSATTRBIT_MAXWORDS;
1254 	else
1255 		outcnt = cnt;
1256 	NFSZERO_ATTRBIT(attrbitp);
1257 	if (outcnt > 0) {
1258 		NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
1259 		for (i = 0; i < outcnt; i++)
1260 			attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
1261 	}
1262 	for (i = 0; i < (cnt - outcnt); i++) {
1263 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1264 		if (retnotsupp != NULL && *tl != 0)
1265 			*retnotsupp = NFSERR_ATTRNOTSUPP;
1266 	}
1267 	if (cntp)
1268 		*cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
1269 nfsmout:
1270 	NFSEXITCODE2(error, nd);
1271 	return (error);
1272 }
1273 
1274 /*
1275  * Get operation bits from an mbuf list.
1276  * Returns EBADRPC for a parsing error, 0 otherwise.
1277  */
1278 int
nfsrv_getopbits(struct nfsrv_descript * nd,nfsopbit_t * opbitp,int * cntp)1279 nfsrv_getopbits(struct nfsrv_descript *nd, nfsopbit_t *opbitp, int *cntp)
1280 {
1281 	uint32_t *tl;
1282 	int cnt, i, outcnt;
1283 	int error = 0;
1284 
1285 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
1286 	cnt = fxdr_unsigned(int, *tl);
1287 	if (cnt < 0) {
1288 		error = NFSERR_BADXDR;
1289 		goto nfsmout;
1290 	}
1291 	if (cnt > NFSOPBIT_MAXWORDS)
1292 		outcnt = NFSOPBIT_MAXWORDS;
1293 	else
1294 		outcnt = cnt;
1295 	NFSZERO_OPBIT(opbitp);
1296 	if (outcnt > 0) {
1297 		NFSM_DISSECT(tl, uint32_t *, outcnt * NFSX_UNSIGNED);
1298 		for (i = 0; i < outcnt; i++)
1299 			opbitp->bits[i] = fxdr_unsigned(uint32_t, *tl++);
1300 	}
1301 	for (i = 0; i < (cnt - outcnt); i++) {
1302 		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
1303 		if (*tl != 0) {
1304 			error = NFSERR_BADXDR;
1305 			goto nfsmout;
1306 		}
1307 	}
1308 	if (cntp != NULL)
1309 		*cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
1310 nfsmout:
1311 	NFSEXITCODE2(error, nd);
1312 	return (error);
1313 }
1314 
1315 /*
1316  * Get the attributes for V4.
1317  * If the compare flag is true, test for any attribute changes,
1318  * otherwise return the attribute values.
1319  * These attributes cover fields in "struct vattr", "struct statfs",
1320  * "struct nfsfsinfo", the file handle and the lease duration.
1321  * The value of retcmpp is set to 1 if all attributes are the same,
1322  * and 0 otherwise.
1323  * Returns EBADRPC if it can't be parsed, 0 otherwise.
1324  */
1325 int
nfsv4_loadattr(struct nfsrv_descript * nd,vnode_t vp,struct nfsvattr * nap,struct nfsfh ** nfhpp,fhandle_t * fhp,int fhsize,struct nfsv3_pathconf * pc,struct statfs * sbp,struct nfsstatfs * sfp,struct nfsfsinfo * fsp,NFSACL_T * aclp,int compare,int * retcmpp,u_int32_t * leasep,u_int32_t * rderrp,bool * has_namedattrp,uint32_t * clone_blksizep,NFSPROC_T * p,struct ucred * cred)1326 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
1327     struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
1328     struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
1329     struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
1330     u_int32_t *leasep, u_int32_t *rderrp, bool *has_namedattrp,
1331     uint32_t *clone_blksizep, NFSPROC_T *p, 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,
1652 				    &aceerr, &cnt, p);
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,
1663 				    &aceerr, &cnt, p);
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 					&aceerr, &cnt, p);
1673 				else
1674 				    error = nfsrv_dissectacl(nd, NULL, false,
1675 					&aceerr, &cnt, p);
1676 				if (error)
1677 				    goto nfsmout;
1678 			}
1679 
1680 			attrsum += cnt;
1681 			break;
1682 		case NFSATTRBIT_ACLSUPPORT:
1683 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1684 			if (compare && !(*retcmpp)) {
1685 				if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
1686 					if (fxdr_unsigned(u_int32_t, *tl) !=
1687 					    NFSV4ACE_SUPTYPES)
1688 						*retcmpp = NFSERR_NOTSAME;
1689 				} else {
1690 					*retcmpp = NFSERR_ATTRNOTSUPP;
1691 				}
1692 			}
1693 			attrsum += NFSX_UNSIGNED;
1694 			break;
1695 		case NFSATTRBIT_ARCHIVE:
1696 			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
1697 			if (compare) {
1698 				if (!(*retcmpp) && ((*tl == newnfs_true &&
1699 				    (nap->na_flags & UF_ARCHIVE) == 0) ||
1700 				    (*tl == newnfs_false &&
1701 				     (nap->na_flags & UF_ARCHIVE) != 0)))
1702 					*retcmpp = NFSERR_NOTSAME;
1703 			} else if (nap != NULL) {
1704 				if (*tl == newnfs_true)
1705 					nap->na_flags |= UF_ARCHIVE;
1706 			}
1707 			attrsum += NFSX_UNSIGNED;
1708 			break;
1709 		case NFSATTRBIT_CANSETTIME:
1710 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1711 			if (compare) {
1712 				if (!(*retcmpp)) {
1713 				    if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1714 					if (*tl == newnfs_false)
1715 						*retcmpp = NFSERR_NOTSAME;
1716 				    } else {
1717 					if (*tl == newnfs_true)
1718 						*retcmpp = NFSERR_NOTSAME;
1719 				    }
1720 				}
1721 			} else if (fsp != NULL) {
1722 				if (*tl == newnfs_true)
1723 					fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1724 				else
1725 					fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1726 			}
1727 			attrsum += NFSX_UNSIGNED;
1728 			break;
1729 		case NFSATTRBIT_CASEINSENSITIVE:
1730 			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
1731 			if (compare) {
1732 				if (!(*retcmpp)) {
1733 					if (vp == NULL || VOP_PATHCONF(vp,
1734 					    _PC_CASE_INSENSITIVE,
1735 					    &has_pathconf) != 0)
1736 						has_pathconf = 0;
1737 					if ((has_pathconf != 0 &&
1738 					     *tl != newnfs_true) ||
1739 					    (has_pathconf == 0 &&
1740 					    *tl != newnfs_false))
1741 						*retcmpp = NFSERR_NOTSAME;
1742 				}
1743 			} else if (pc != NULL) {
1744 				pc->pc_caseinsensitive =
1745 				    fxdr_unsigned(u_int32_t, *tl);
1746 			}
1747 			attrsum += NFSX_UNSIGNED;
1748 			break;
1749 		case NFSATTRBIT_CASEPRESERVING:
1750 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1751 			if (compare) {
1752 				if (!(*retcmpp)) {
1753 				    if (*tl != newnfs_true)
1754 					*retcmpp = NFSERR_NOTSAME;
1755 				}
1756 			} else if (pc != NULL) {
1757 				pc->pc_casepreserving =
1758 				    fxdr_unsigned(u_int32_t, *tl);
1759 			}
1760 			attrsum += NFSX_UNSIGNED;
1761 			break;
1762 		case NFSATTRBIT_CHOWNRESTRICTED:
1763 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1764 			if (compare) {
1765 				if (!(*retcmpp)) {
1766 				    if (*tl != newnfs_true)
1767 					*retcmpp = NFSERR_NOTSAME;
1768 				}
1769 			} else if (pc != NULL) {
1770 				pc->pc_chownrestricted =
1771 				    fxdr_unsigned(u_int32_t, *tl);
1772 			}
1773 			attrsum += NFSX_UNSIGNED;
1774 			break;
1775 		case NFSATTRBIT_FILEHANDLE:
1776 			error = nfsm_getfh(nd, &tnfhp);
1777 			if (error)
1778 				goto nfsmout;
1779 			tfhsize = tnfhp->nfh_len;
1780 			if (compare) {
1781 				if (tfhsize > NFSX_MYFH)
1782 					tfhsize = NFSX_MYFH;
1783 				if (!(*retcmpp) &&
1784 				    !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1785 				     fhp, fhsize))
1786 					*retcmpp = NFSERR_NOTSAME;
1787 				free(tnfhp, M_NFSFH);
1788 			} else if (nfhpp != NULL) {
1789 				*nfhpp = tnfhp;
1790 			} else {
1791 				free(tnfhp, M_NFSFH);
1792 			}
1793 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1794 			break;
1795 		case NFSATTRBIT_FILEID:
1796 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1797 			thyp = fxdr_hyper(tl);
1798 			if (compare) {
1799 				if (!(*retcmpp)) {
1800 					if (nap->na_fileid != thyp)
1801 						*retcmpp = NFSERR_NOTSAME;
1802 				}
1803 			} else if (nap != NULL)
1804 				nap->na_fileid = thyp;
1805 			attrsum += NFSX_HYPER;
1806 			break;
1807 		case NFSATTRBIT_FILESAVAIL:
1808 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1809 			if (compare) {
1810 				uquad = nfsv4_filesavail(sbp, vp->v_mount);
1811 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1812 					*retcmpp = NFSERR_NOTSAME;
1813 			} else if (sfp != NULL) {
1814 				sfp->sf_afiles = fxdr_hyper(tl);
1815 			}
1816 			attrsum += NFSX_HYPER;
1817 			break;
1818 		case NFSATTRBIT_FILESFREE:
1819 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1820 			if (compare) {
1821 				uquad = (uint64_t)sbp->f_ffree;
1822 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1823 					*retcmpp = NFSERR_NOTSAME;
1824 			} else if (sfp != NULL) {
1825 				sfp->sf_ffiles = fxdr_hyper(tl);
1826 			}
1827 			attrsum += NFSX_HYPER;
1828 			break;
1829 		case NFSATTRBIT_FILESTOTAL:
1830 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1831 			if (compare) {
1832 				uquad = sbp->f_files;
1833 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
1834 					*retcmpp = NFSERR_NOTSAME;
1835 			} else if (sfp != NULL) {
1836 				sfp->sf_tfiles = fxdr_hyper(tl);
1837 			}
1838 			attrsum += NFSX_HYPER;
1839 			break;
1840 		case NFSATTRBIT_FSLOCATIONS:
1841 			error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1842 			if (error)
1843 				goto nfsmout;
1844 			attrsum += l;
1845 			if (compare && !(*retcmpp)) {
1846 				refp = nfsv4root_getreferral(vp, NULL, 0);
1847 				if (refp != NULL) {
1848 					if (cp == NULL || cp2 == NULL ||
1849 					    strcmp(cp, "/") ||
1850 					    strcmp(cp2, refp->nfr_srvlist))
1851 						*retcmpp = NFSERR_NOTSAME;
1852 				} else if (m == 0) {
1853 					*retcmpp = NFSERR_NOTSAME;
1854 				}
1855 			}
1856 			if (cp != NULL)
1857 				free(cp, M_NFSSTRING);
1858 			if (cp2 != NULL)
1859 				free(cp2, M_NFSSTRING);
1860 			break;
1861 		case NFSATTRBIT_HIDDEN:
1862 			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
1863 			if (compare) {
1864 				if (!(*retcmpp) && ((*tl == newnfs_true &&
1865 				    (nap->na_flags & UF_HIDDEN) == 0) ||
1866 				    (*tl == newnfs_false &&
1867 				     (nap->na_flags & UF_HIDDEN) != 0)))
1868 					*retcmpp = NFSERR_NOTSAME;
1869 			} else if (nap != NULL) {
1870 				if (*tl == newnfs_true)
1871 					nap->na_flags |= UF_HIDDEN;
1872 			}
1873 			attrsum += NFSX_UNSIGNED;
1874 			break;
1875 		case NFSATTRBIT_HOMOGENEOUS:
1876 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1877 			if (compare) {
1878 				if (!(*retcmpp)) {
1879 				    if (fsp->fs_properties &
1880 					NFSV3_FSFHOMOGENEOUS) {
1881 					if (*tl == newnfs_false)
1882 						*retcmpp = NFSERR_NOTSAME;
1883 				    } else {
1884 					if (*tl == newnfs_true)
1885 						*retcmpp = NFSERR_NOTSAME;
1886 				    }
1887 				}
1888 			} else if (fsp != NULL) {
1889 				if (*tl == newnfs_true)
1890 				    fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1891 				else
1892 				    fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1893 			}
1894 			attrsum += NFSX_UNSIGNED;
1895 			break;
1896 		case NFSATTRBIT_MAXFILESIZE:
1897 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1898 			tnfsquad.qval = fxdr_hyper(tl);
1899 			if (compare) {
1900 				if (!(*retcmpp)) {
1901 					tquad = NFSRV_MAXFILESIZE;
1902 					if (tquad != tnfsquad.qval)
1903 						*retcmpp = NFSERR_NOTSAME;
1904 				}
1905 			} else if (fsp != NULL) {
1906 				fsp->fs_maxfilesize = tnfsquad.qval;
1907 			}
1908 			attrsum += NFSX_HYPER;
1909 			break;
1910 		case NFSATTRBIT_MAXLINK:
1911 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1912 			if (compare) {
1913 				if (!(*retcmpp)) {
1914 				    if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
1915 					*retcmpp = NFSERR_NOTSAME;
1916 				}
1917 			} else if (pc != NULL) {
1918 				pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1919 			}
1920 			attrsum += NFSX_UNSIGNED;
1921 			break;
1922 		case NFSATTRBIT_MAXNAME:
1923 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1924 			if (compare) {
1925 				if (!(*retcmpp)) {
1926 				    if (fsp->fs_maxname !=
1927 					fxdr_unsigned(u_int32_t, *tl))
1928 						*retcmpp = NFSERR_NOTSAME;
1929 				}
1930 			} else {
1931 				tuint = fxdr_unsigned(u_int32_t, *tl);
1932 				/*
1933 				 * Some Linux NFSv4 servers report this
1934 				 * as 0 or 4billion, so I'll set it to
1935 				 * NFS_MAXNAMLEN. If a server actually creates
1936 				 * a name longer than NFS_MAXNAMLEN, it will
1937 				 * get an error back.
1938 				 */
1939 				if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1940 					tuint = NFS_MAXNAMLEN;
1941 				if (fsp != NULL)
1942 					fsp->fs_maxname = tuint;
1943 				if (pc != NULL)
1944 					pc->pc_namemax = tuint;
1945 			}
1946 			attrsum += NFSX_UNSIGNED;
1947 			break;
1948 		case NFSATTRBIT_MAXREAD:
1949 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1950 			if (compare) {
1951 				if (!(*retcmpp)) {
1952 				    if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1953 					*(tl + 1)) || *tl != 0)
1954 					*retcmpp = NFSERR_NOTSAME;
1955 				}
1956 			} else if (fsp != NULL) {
1957 				fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1958 				fsp->fs_rtpref = fsp->fs_rtmax;
1959 				fsp->fs_dtpref = fsp->fs_rtpref;
1960 			}
1961 			attrsum += NFSX_HYPER;
1962 			break;
1963 		case NFSATTRBIT_MAXWRITE:
1964 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1965 			if (compare) {
1966 				if (!(*retcmpp)) {
1967 				    if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1968 					*(tl + 1)) || *tl != 0)
1969 					*retcmpp = NFSERR_NOTSAME;
1970 				}
1971 			} else if (fsp != NULL) {
1972 				fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1973 				fsp->fs_wtpref = fsp->fs_wtmax;
1974 			}
1975 			attrsum += NFSX_HYPER;
1976 			break;
1977 		case NFSATTRBIT_MIMETYPE:
1978 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1979 			i = fxdr_unsigned(int, *tl);
1980 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1981 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1982 			if (error)
1983 				goto nfsmout;
1984 			if (compare && !(*retcmpp))
1985 				*retcmpp = NFSERR_ATTRNOTSUPP;
1986 			break;
1987 		case NFSATTRBIT_MODE:
1988 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1989 			if (compare) {
1990 				if (!(*retcmpp)) {
1991 				    if (nap->na_mode != nfstov_mode(*tl))
1992 					*retcmpp = NFSERR_NOTSAME;
1993 				}
1994 			} else if (nap != NULL) {
1995 				nap->na_mode = nfstov_mode(*tl);
1996 			}
1997 			attrsum += NFSX_UNSIGNED;
1998 			break;
1999 		case NFSATTRBIT_NOTRUNC:
2000 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2001 			if (compare) {
2002 				if (!(*retcmpp)) {
2003 				    if (*tl != newnfs_true)
2004 					*retcmpp = NFSERR_NOTSAME;
2005 				}
2006 			} else if (pc != NULL) {
2007 				pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
2008 			}
2009 			attrsum += NFSX_UNSIGNED;
2010 			break;
2011 		case NFSATTRBIT_NUMLINKS:
2012 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2013 			tuint = fxdr_unsigned(u_int32_t, *tl);
2014 			if (compare) {
2015 			    if (!(*retcmpp)) {
2016 				if ((u_int32_t)nap->na_nlink != tuint)
2017 					*retcmpp = NFSERR_NOTSAME;
2018 			    }
2019 			} else if (nap != NULL) {
2020 				nap->na_nlink = tuint;
2021 			}
2022 			attrsum += NFSX_UNSIGNED;
2023 			break;
2024 		case NFSATTRBIT_OWNER:
2025 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2026 			j = fxdr_unsigned(int, *tl);
2027 			if (j < 0 || j > NFSV4_MAXOWNERGROUPLEN) {
2028 				error = NFSERR_BADXDR;
2029 				goto nfsmout;
2030 			}
2031 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
2032 			if (j > NFSV4_SMALLSTR)
2033 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
2034 			else
2035 				cp = namestr;
2036 			error = nfsrv_mtostr(nd, cp, j);
2037 			if (error) {
2038 				if (j > NFSV4_SMALLSTR)
2039 					free(cp, M_NFSSTRING);
2040 				goto nfsmout;
2041 			}
2042 			if (compare) {
2043 			    if (!(*retcmpp)) {
2044 				if (nfsv4_strtouid(nd, cp, j, &uid) ||
2045 				    nap->na_uid != uid)
2046 				    *retcmpp = NFSERR_NOTSAME;
2047 			    }
2048 			} else if (nap != NULL) {
2049 				if (nfsv4_strtouid(nd, cp, j, &uid))
2050 					nap->na_uid =
2051 					    NFSD_VNET(nfsrv_defaultuid);
2052 				else
2053 					nap->na_uid = uid;
2054 			}
2055 			if (j > NFSV4_SMALLSTR)
2056 				free(cp, M_NFSSTRING);
2057 			break;
2058 		case NFSATTRBIT_OWNERGROUP:
2059 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2060 			j = fxdr_unsigned(int, *tl);
2061 			if (j < 0 || j > NFSV4_MAXOWNERGROUPLEN) {
2062 				error =  NFSERR_BADXDR;
2063 				goto nfsmout;
2064 			}
2065 			attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
2066 			if (j > NFSV4_SMALLSTR)
2067 				cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
2068 			else
2069 				cp = namestr;
2070 			error = nfsrv_mtostr(nd, cp, j);
2071 			if (error) {
2072 				if (j > NFSV4_SMALLSTR)
2073 					free(cp, M_NFSSTRING);
2074 				goto nfsmout;
2075 			}
2076 			if (compare) {
2077 			    if (!(*retcmpp)) {
2078 				if (nfsv4_strtogid(nd, cp, j, &gid) ||
2079 				    nap->na_gid != gid)
2080 				    *retcmpp = NFSERR_NOTSAME;
2081 			    }
2082 			} else if (nap != NULL) {
2083 				if (nfsv4_strtogid(nd, cp, j, &gid))
2084 					nap->na_gid =
2085 					    NFSD_VNET(nfsrv_defaultgid);
2086 				else
2087 					nap->na_gid = gid;
2088 			}
2089 			if (j > NFSV4_SMALLSTR)
2090 				free(cp, M_NFSSTRING);
2091 			break;
2092 		case NFSATTRBIT_QUOTAHARD:
2093 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2094 			if (sbp != NULL) {
2095 			    if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2096 				freenum = sbp->f_bfree;
2097 			    else
2098 				freenum = sbp->f_bavail;
2099 #ifdef QUOTA
2100 			    /*
2101 			     * ufs_quotactl() insists that the uid argument
2102 			     * equal p_ruid for non-root quota access, so
2103 			     * we'll just make sure that's the case.
2104 			     */
2105 			    savuid = p->p_cred->p_ruid;
2106 			    p->p_cred->p_ruid = cred->cr_uid;
2107 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
2108 				USRQUOTA), cred->cr_uid, &dqb))
2109 				freenum = min(dqb.dqb_bhardlimit, freenum);
2110 			    p->p_cred->p_ruid = savuid;
2111 #endif	/* QUOTA */
2112 			    uquad = (u_int64_t)freenum;
2113 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
2114 			}
2115 			if (compare && !(*retcmpp)) {
2116 				if (uquad != fxdr_hyper(tl))
2117 					*retcmpp = NFSERR_NOTSAME;
2118 			}
2119 			attrsum += NFSX_HYPER;
2120 			break;
2121 		case NFSATTRBIT_QUOTASOFT:
2122 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2123 			if (sbp != NULL) {
2124 			    if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
2125 				freenum = sbp->f_bfree;
2126 			    else
2127 				freenum = sbp->f_bavail;
2128 #ifdef QUOTA
2129 			    /*
2130 			     * ufs_quotactl() insists that the uid argument
2131 			     * equal p_ruid for non-root quota access, so
2132 			     * we'll just make sure that's the case.
2133 			     */
2134 			    savuid = p->p_cred->p_ruid;
2135 			    p->p_cred->p_ruid = cred->cr_uid;
2136 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
2137 				USRQUOTA), cred->cr_uid, &dqb))
2138 				freenum = min(dqb.dqb_bsoftlimit, freenum);
2139 			    p->p_cred->p_ruid = savuid;
2140 #endif	/* QUOTA */
2141 			    uquad = (u_int64_t)freenum;
2142 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
2143 			}
2144 			if (compare && !(*retcmpp)) {
2145 				if (uquad != fxdr_hyper(tl))
2146 					*retcmpp = NFSERR_NOTSAME;
2147 			}
2148 			attrsum += NFSX_HYPER;
2149 			break;
2150 		case NFSATTRBIT_QUOTAUSED:
2151 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2152 			if (sbp != NULL) {
2153 			    freenum = 0;
2154 #ifdef QUOTA
2155 			    /*
2156 			     * ufs_quotactl() insists that the uid argument
2157 			     * equal p_ruid for non-root quota access, so
2158 			     * we'll just make sure that's the case.
2159 			     */
2160 			    savuid = p->p_cred->p_ruid;
2161 			    p->p_cred->p_ruid = cred->cr_uid;
2162 			    if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
2163 				USRQUOTA), cred->cr_uid, &dqb))
2164 				freenum = dqb.dqb_curblocks;
2165 			    p->p_cred->p_ruid = savuid;
2166 #endif	/* QUOTA */
2167 			    uquad = (u_int64_t)freenum;
2168 			    NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
2169 			}
2170 			if (compare && !(*retcmpp)) {
2171 				if (uquad != fxdr_hyper(tl))
2172 					*retcmpp = NFSERR_NOTSAME;
2173 			}
2174 			attrsum += NFSX_HYPER;
2175 			break;
2176 		case NFSATTRBIT_RAWDEV:
2177 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
2178 			j = fxdr_unsigned(int, *tl++);
2179 			k = fxdr_unsigned(int, *tl);
2180 			if (compare) {
2181 			    if (!(*retcmpp)) {
2182 				if (nap->na_rdev != NFSMAKEDEV(j, k))
2183 					*retcmpp = NFSERR_NOTSAME;
2184 			    }
2185 			} else if (nap != NULL) {
2186 				nap->na_rdev = NFSMAKEDEV(j, k);
2187 			}
2188 			attrsum += NFSX_V4SPECDATA;
2189 			break;
2190 		case NFSATTRBIT_SPACEAVAIL:
2191 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2192 			if (compare) {
2193 				if (priv_check_cred(cred,
2194 				    PRIV_VFS_BLOCKRESERVE))
2195 					uquad = sbp->f_bfree;
2196 				else
2197 					uquad = (uint64_t)sbp->f_bavail;
2198 				uquad *= sbp->f_bsize;
2199 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2200 					*retcmpp = NFSERR_NOTSAME;
2201 			} else if (sfp != NULL) {
2202 				sfp->sf_abytes = fxdr_hyper(tl);
2203 			}
2204 			attrsum += NFSX_HYPER;
2205 			break;
2206 		case NFSATTRBIT_SPACEFREE:
2207 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2208 			if (compare) {
2209 				uquad = sbp->f_bfree;
2210 				uquad *= sbp->f_bsize;
2211 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2212 					*retcmpp = NFSERR_NOTSAME;
2213 			} else if (sfp != NULL) {
2214 				sfp->sf_fbytes = fxdr_hyper(tl);
2215 			}
2216 			attrsum += NFSX_HYPER;
2217 			break;
2218 		case NFSATTRBIT_SPACETOTAL:
2219 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2220 			if (compare) {
2221 				uquad = sbp->f_blocks;
2222 				uquad *= sbp->f_bsize;
2223 				if (!(*retcmpp) && uquad != fxdr_hyper(tl))
2224 					*retcmpp = NFSERR_NOTSAME;
2225 			} else if (sfp != NULL) {
2226 				sfp->sf_tbytes = fxdr_hyper(tl);
2227 			}
2228 			attrsum += NFSX_HYPER;
2229 			break;
2230 		case NFSATTRBIT_SPACEUSED:
2231 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2232 			thyp = fxdr_hyper(tl);
2233 			if (compare) {
2234 			    if (!(*retcmpp)) {
2235 				if ((u_int64_t)nap->na_bytes != thyp)
2236 					*retcmpp = NFSERR_NOTSAME;
2237 			    }
2238 			} else if (nap != NULL) {
2239 				nap->na_bytes = thyp;
2240 			}
2241 			attrsum += NFSX_HYPER;
2242 			break;
2243 		case NFSATTRBIT_SYSTEM:
2244 			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
2245 			if (compare) {
2246 				if (!(*retcmpp) && ((*tl == newnfs_true &&
2247 				    (nap->na_flags & UF_SYSTEM) == 0) ||
2248 				    (*tl == newnfs_false &&
2249 				     (nap->na_flags & UF_SYSTEM) != 0)))
2250 					*retcmpp = NFSERR_NOTSAME;
2251 			} else if (nap != NULL) {
2252 				if (*tl == newnfs_true)
2253 					nap->na_flags |= UF_SYSTEM;
2254 			}
2255 			attrsum += NFSX_UNSIGNED;
2256 			break;
2257 		case NFSATTRBIT_TIMEACCESS:
2258 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2259 			fxdr_nfsv4time(tl, &temptime);
2260 			if (compare) {
2261 			    if (!(*retcmpp)) {
2262 				if (!NFS_CMPTIME(temptime, nap->na_atime))
2263 					*retcmpp = NFSERR_NOTSAME;
2264 			    }
2265 			} else if (nap != NULL) {
2266 				nap->na_atime = temptime;
2267 			}
2268 			attrsum += NFSX_V4TIME;
2269 			break;
2270 		case NFSATTRBIT_TIMEACCESSSET:
2271 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2272 			attrsum += NFSX_UNSIGNED;
2273 			i = fxdr_unsigned(int, *tl);
2274 			if (i == NFSV4SATTRTIME_TOCLIENT) {
2275 				NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2276 				attrsum += NFSX_V4TIME;
2277 			}
2278 			if (compare && !(*retcmpp))
2279 				*retcmpp = NFSERR_INVAL;
2280 			break;
2281 		case NFSATTRBIT_TIMEBACKUP:
2282 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2283 			if (compare && !(*retcmpp))
2284 				*retcmpp = NFSERR_ATTRNOTSUPP;
2285 			attrsum += NFSX_V4TIME;
2286 			break;
2287 		case NFSATTRBIT_TIMECREATE:
2288 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2289 			fxdr_nfsv4time(tl, &temptime);
2290 			if (compare) {
2291 			    if (!(*retcmpp)) {
2292 				if (!NFS_CMPTIME(temptime, nap->na_btime))
2293 					*retcmpp = NFSERR_NOTSAME;
2294 			    }
2295 			} else if (nap != NULL) {
2296 				nap->na_btime = temptime;
2297 			}
2298 			attrsum += NFSX_V4TIME;
2299 			break;
2300 		case NFSATTRBIT_TIMEDELTA:
2301 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2302 			if (fsp != NULL) {
2303 			    if (compare) {
2304 				if (!(*retcmpp)) {
2305 				    if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
2306 					fxdr_unsigned(u_int32_t, *(tl + 1)) ||
2307 				        (u_int32_t)fsp->fs_timedelta.tv_nsec !=
2308 					(fxdr_unsigned(u_int32_t, *(tl + 2)) %
2309 					 1000000000) ||
2310 					*tl != 0)
2311 					    *retcmpp = NFSERR_NOTSAME;
2312 				}
2313 			    } else {
2314 				fxdr_nfsv4time(tl, &fsp->fs_timedelta);
2315 			    }
2316 			}
2317 			attrsum += NFSX_V4TIME;
2318 			break;
2319 		case NFSATTRBIT_TIMEMETADATA:
2320 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2321 			fxdr_nfsv4time(tl, &temptime);
2322 			if (compare) {
2323 			    if (!(*retcmpp)) {
2324 				if (!NFS_CMPTIME(temptime, nap->na_ctime))
2325 					*retcmpp = NFSERR_NOTSAME;
2326 			    }
2327 			} else if (nap != NULL) {
2328 				nap->na_ctime = temptime;
2329 			}
2330 			attrsum += NFSX_V4TIME;
2331 			break;
2332 		case NFSATTRBIT_TIMEMODIFY:
2333 			NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2334 			fxdr_nfsv4time(tl, &temptime);
2335 			if (compare) {
2336 			    if (!(*retcmpp)) {
2337 				if (!NFS_CMPTIME(temptime, nap->na_mtime))
2338 					*retcmpp = NFSERR_NOTSAME;
2339 			    }
2340 			} else if (nap != NULL) {
2341 				nap->na_mtime = temptime;
2342 			}
2343 			attrsum += NFSX_V4TIME;
2344 			break;
2345 		case NFSATTRBIT_TIMEMODIFYSET:
2346 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2347 			attrsum += NFSX_UNSIGNED;
2348 			i = fxdr_unsigned(int, *tl);
2349 			if (i == NFSV4SATTRTIME_TOCLIENT) {
2350 				NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
2351 				attrsum += NFSX_V4TIME;
2352 			}
2353 			if (compare && !(*retcmpp))
2354 				*retcmpp = NFSERR_INVAL;
2355 			break;
2356 		case NFSATTRBIT_MOUNTEDONFILEID:
2357 			NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
2358 			thyp = fxdr_hyper(tl);
2359 			if (compare) {
2360 				if (!(*retcmpp)) {
2361 					if (!vp || !nfsrv_atroot(vp, &thyp2))
2362 						thyp2 = nap->na_fileid;
2363 					if (thyp2 != thyp)
2364 						*retcmpp = NFSERR_NOTSAME;
2365 				}
2366 			} else if (nap != NULL)
2367 				nap->na_mntonfileno = thyp;
2368 			attrsum += NFSX_HYPER;
2369 			break;
2370 		case NFSATTRBIT_SUPPATTREXCLCREAT:
2371 			retnotsup = 0;
2372 			error = nfsrv_getattrbits(nd, &retattrbits,
2373 			    &cnt, &retnotsup);
2374 			if (error)
2375 			    goto nfsmout;
2376 			if (compare && !(*retcmpp)) {
2377 			   NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
2378 			   NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
2379 			   NFSCLRBIT_ATTRBIT(&checkattrbits,
2380 				NFSATTRBIT_TIMEACCESSSET);
2381 			   if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
2382 			       || retnotsup)
2383 				*retcmpp = NFSERR_NOTSAME;
2384 			}
2385 			attrsum += cnt;
2386 			break;
2387 		case NFSATTRBIT_FSLAYOUTTYPE:
2388 		case NFSATTRBIT_LAYOUTTYPE:
2389 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2390 			attrsum += NFSX_UNSIGNED;
2391 			i = fxdr_unsigned(int, *tl);
2392 			/*
2393 			 * The RFCs do not define an upper limit for the
2394 			 * number of layout types, but 32 should be more
2395 			 * than enough.
2396 			 */
2397 			if (i < 0 || i > 32) {
2398 				error = NFSERR_BADXDR;
2399 				goto nfsmout;
2400 			}
2401 			if (i > 0) {
2402 				NFSM_DISSECT(tl, u_int32_t *, i *
2403 				    NFSX_UNSIGNED);
2404 				attrsum += i * NFSX_UNSIGNED;
2405 				j = fxdr_unsigned(int, *tl);
2406 				if (i == 1 && compare && !(*retcmpp) &&
2407 				    (((nfsrv_doflexfile != 0 ||
2408 				       nfsrv_maxpnfsmirror > 1) &&
2409 				      j != NFSLAYOUT_FLEXFILE) ||
2410 				    (nfsrv_doflexfile == 0 &&
2411 				     j != NFSLAYOUT_NFSV4_1_FILES)))
2412 					*retcmpp = NFSERR_NOTSAME;
2413 			}
2414 			if (nfsrv_devidcnt == 0) {
2415 				if (compare && !(*retcmpp) && i > 0)
2416 					*retcmpp = NFSERR_NOTSAME;
2417 			} else {
2418 				if (compare && !(*retcmpp) && i != 1)
2419 					*retcmpp = NFSERR_NOTSAME;
2420 			}
2421 			break;
2422 		case NFSATTRBIT_LAYOUTALIGNMENT:
2423 		case NFSATTRBIT_LAYOUTBLKSIZE:
2424 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2425 			attrsum += NFSX_UNSIGNED;
2426 			i = fxdr_unsigned(int, *tl);
2427 			if (compare && !(*retcmpp) && i != nfs_srvmaxio)
2428 				*retcmpp = NFSERR_NOTSAME;
2429 			break;
2430 		case NFSATTRBIT_CLONEBLKSIZE:
2431 			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
2432 			if (compare) {
2433 				if (!(*retcmpp)) {
2434 					if (vp == NULL || VOP_PATHCONF(vp,
2435 					    _PC_CLONE_BLKSIZE, &has_pathconf)
2436 					    != 0)
2437 						has_pathconf = 0;
2438 					if (has_pathconf !=
2439 					    fxdr_unsigned(uint32_t, *tl))
2440 						*retcmpp = NFSERR_NOTSAME;
2441 				}
2442 			} else if (clone_blksizep != NULL) {
2443 				*clone_blksizep = fxdr_unsigned(uint32_t, *tl);
2444 			}
2445 			attrsum += NFSX_UNSIGNED;
2446 			break;
2447 		case NFSATTRBIT_CHANGEATTRTYPE:
2448 			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
2449 			if (compare) {
2450 				if (!(*retcmpp)) {
2451 				    tuint = NFSV4CHANGETYPE_UNDEFINED;
2452 				    if ((vp->v_mount->mnt_vfc->vfc_flags &
2453 					VFCF_FILEREVINC) != 0)
2454 					tuint = NFSV4CHANGETYPE_VERS_COUNTER_NOPNFS;
2455 				    else if ((vp->v_mount->mnt_vfc->vfc_flags &
2456 					VFCF_FILEREVCT) != 0)
2457 					tuint = NFSV4CHANGETYPE_TIME_METADATA;
2458 				    if (fxdr_unsigned(uint32_t, *tl) != tuint)
2459 					*retcmpp = NFSERR_NOTSAME;
2460 				}
2461 			}
2462 			attrsum += NFSX_UNSIGNED;
2463 			break;
2464 		case NFSATTRBIT_ACLTRUEFORM:
2465 			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
2466 			if (compare) {
2467 				if (!(*retcmpp)) {
2468 					tuint = nfs_trueform(vp);
2469 					if (tuint != fxdr_unsigned(uint32_t,
2470 					    *tl))
2471 						*retcmpp = NFSERR_NOTSAME;
2472 				}
2473 #ifdef notyet
2474 			} else if (trueformp != NULL) {
2475 				*trueformp = fxdr_unsigned(uint32_t, *tl);
2476 			}
2477 #else
2478 			}
2479 #endif
2480 			attrsum += NFSX_UNSIGNED;
2481 			break;
2482 		case NFSATTRBIT_ACLTRUEFORMSCOPE:
2483 			NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
2484 			if (compare) {
2485 				if (!(*retcmpp)) {
2486 					if (fxdr_unsigned(uint32_t, *tl) !=
2487 					    NFSV4_ACL_SCOPE_FILE_SYSTEM)
2488 						*retcmpp = NFSERR_NOTSAME;
2489 				}
2490 			}
2491 			attrsum += NFSX_UNSIGNED;
2492 			break;
2493 		case NFSATTRBIT_POSIXACCESSACL:
2494 			if (compare) {
2495 			  if (!(*retcmpp)) {
2496 			    if (nfsrv_useacl && nfs_supportsposixacls(vp)) {
2497 				NFSACL_T *naclp;
2498 
2499 				naclp = acl_alloc(M_WAITOK);
2500 				error = nfsrv_dissectacl(nd, naclp, true,
2501 				    &aceerr, &cnt, p);
2502 				if (error) {
2503 				    acl_free(naclp);
2504 				    goto nfsmout;
2505 				}
2506 				if (aceerr || aclp == NULL ||
2507 				    nfsrv_compareacl(aclp, naclp))
2508 				    *retcmpp = NFSERR_NOTSAME;
2509 				acl_free(naclp);
2510 			    } else {
2511 				error = nfsrv_dissectacl(nd, NULL, true,
2512 				    &aceerr, &cnt, p);
2513 				if (error)
2514 				    goto nfsmout;
2515 				*retcmpp = NFSERR_ATTRNOTSUPP;
2516 			    }
2517 			  }
2518 			} else {
2519 				if (vp != NULL && aclp != NULL)
2520 				    error = nfsrv_dissectacl(nd, aclp, false,
2521 					&aceerr, &cnt, p);
2522 				else
2523 				    error = nfsrv_dissectacl(nd, NULL, false,
2524 					&aceerr, &cnt, p);
2525 				if (error)
2526 				    goto nfsmout;
2527 			}
2528 
2529 			attrsum += cnt;
2530 			break;
2531 		case NFSATTRBIT_POSIXDEFAULTACL:
2532 			if (compare) {
2533 			  if (!(*retcmpp)) {
2534 			    if (nfsrv_useacl && nfs_supportsposixacls(vp)) {
2535 				NFSACL_T *naclp;
2536 
2537 				naclp = acl_alloc(M_WAITOK);
2538 				error = nfsrv_dissectacl(nd, naclp, true,
2539 				    &aceerr, &cnt, p);
2540 				if (error) {
2541 				    acl_free(naclp);
2542 				    goto nfsmout;
2543 				}
2544 				if (aceerr || aclp == NULL ||
2545 				    nfsrv_compareacl(aclp, naclp))
2546 				    *retcmpp = NFSERR_NOTSAME;
2547 				acl_free(naclp);
2548 			    } else {
2549 				error = nfsrv_dissectacl(nd, NULL, true,
2550 				    &aceerr, &cnt, p);
2551 				if (error)
2552 				    goto nfsmout;
2553 				*retcmpp = NFSERR_ATTRNOTSUPP;
2554 			    }
2555 			  }
2556 			} else {
2557 				if (vp != NULL && aclp != NULL)
2558 				    error = nfsrv_dissectacl(nd, aclp, false,
2559 					&aceerr, &cnt, p);
2560 				else
2561 				    error = nfsrv_dissectacl(nd, NULL, false,
2562 					&aceerr, &cnt, p);
2563 				if (error)
2564 				    goto nfsmout;
2565 			}
2566 
2567 			attrsum += cnt;
2568 			break;
2569 		default:
2570 			printf("EEK! nfsv4_loadattr unknown attr=%d\n",
2571 				bitpos);
2572 			if (compare && !(*retcmpp))
2573 				*retcmpp = NFSERR_ATTRNOTSUPP;
2574 			/*
2575 			 * and get out of the loop, since we can't parse
2576 			 * the unknown attribute data.
2577 			 */
2578 			bitpos = NFSATTRBIT_MAX;
2579 			break;
2580 		}
2581 	}
2582 
2583 	/*
2584 	 * some clients pad the attrlist, so we need to skip over the
2585 	 * padding.
2586 	 */
2587 	if (attrsum > attrsize) {
2588 		error = NFSERR_BADXDR;
2589 	} else {
2590 		attrsize = NFSM_RNDUP(attrsize);
2591 		if (attrsum < attrsize)
2592 			error = nfsm_advance(nd, attrsize - attrsum, -1);
2593 	}
2594 nfsmout:
2595 	NFSD_CURVNET_RESTORE();
2596 	NFSEXITCODE2(error, nd);
2597 	return (error);
2598 }
2599 
2600 /*
2601  * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
2602  * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
2603  * The first argument is a pointer to an nfsv4lock structure.
2604  * The second argument is 1 iff a blocking lock is wanted.
2605  * If this argument is 0, the call waits until no thread either wants nor
2606  * holds an exclusive lock.
2607  * It returns 1 if the lock was acquired, 0 otherwise.
2608  * If several processes call this function concurrently wanting the exclusive
2609  * lock, one will get the lock and the rest will return without getting the
2610  * lock. (If the caller must have the lock, it simply calls this function in a
2611  *  loop until the function returns 1 to indicate the lock was acquired.)
2612  * Any usecnt must be decremented by calling nfsv4_relref() before
2613  * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
2614  * be called in a loop.
2615  * The isleptp argument is set to indicate if the call slept, iff not NULL
2616  * and the mp argument indicates to check for a forced dismount, iff not
2617  * NULL.
2618  */
2619 int
nfsv4_lock(struct nfsv4lock * lp,int iwantlock,int * isleptp,struct mtx * mutex,struct mount * mp)2620 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
2621     struct mtx *mutex, struct mount *mp)
2622 {
2623 
2624 	if (isleptp)
2625 		*isleptp = 0;
2626 	/*
2627 	 * If a lock is wanted, loop around until the lock is acquired by
2628 	 * someone and then released. If I want the lock, try to acquire it.
2629 	 * For a lock to be issued, no lock must be in force and the usecnt
2630 	 * must be zero.
2631 	 */
2632 	if (iwantlock) {
2633 	    if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2634 		lp->nfslock_usecnt == 0) {
2635 		lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2636 		lp->nfslock_lock |= NFSV4LOCK_LOCK;
2637 		return (1);
2638 	    }
2639 	    lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
2640 	}
2641 	while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
2642 		if (mp != NULL && NFSCL_FORCEDISM(mp)) {
2643 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2644 			return (0);
2645 		}
2646 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
2647 		if (isleptp)
2648 			*isleptp = 1;
2649 		msleep(&lp->nfslock_lock, mutex, PVFS, "nfsv4lck", hz);
2650 		if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
2651 		    lp->nfslock_usecnt == 0) {
2652 			lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
2653 			lp->nfslock_lock |= NFSV4LOCK_LOCK;
2654 			return (1);
2655 		}
2656 	}
2657 	return (0);
2658 }
2659 
2660 /*
2661  * Release the lock acquired by nfsv4_lock().
2662  * The second argument is set to 1 to indicate the nfslock_usecnt should be
2663  * incremented, as well.
2664  */
2665 void
nfsv4_unlock(struct nfsv4lock * lp,int incref)2666 nfsv4_unlock(struct nfsv4lock *lp, int incref)
2667 {
2668 
2669 	lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
2670 	if (incref)
2671 		lp->nfslock_usecnt++;
2672 	nfsv4_wanted(lp);
2673 }
2674 
2675 /*
2676  * Release a reference cnt.
2677  */
2678 void
nfsv4_relref(struct nfsv4lock * lp)2679 nfsv4_relref(struct nfsv4lock *lp)
2680 {
2681 
2682 	if (lp->nfslock_usecnt <= 0)
2683 		panic("nfsv4root ref cnt");
2684 	lp->nfslock_usecnt--;
2685 	if (lp->nfslock_usecnt == 0)
2686 		nfsv4_wanted(lp);
2687 }
2688 
2689 /*
2690  * Get a reference cnt.
2691  * This function will wait for any exclusive lock to be released, but will
2692  * not wait for threads that want the exclusive lock. If priority needs
2693  * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
2694  * with the 2nd argument == 0 should be done before calling nfsv4_getref().
2695  * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
2696  * return without getting a refcnt for that case.
2697  */
2698 void
nfsv4_getref(struct nfsv4lock * lp,int * isleptp,struct mtx * mutex,struct mount * mp)2699 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, struct mtx *mutex,
2700     struct mount *mp)
2701 {
2702 
2703 	if (isleptp)
2704 		*isleptp = 0;
2705 
2706 	/*
2707 	 * Wait for a lock held.
2708 	 */
2709 	while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
2710 		if (mp != NULL && NFSCL_FORCEDISM(mp))
2711 			return;
2712 		lp->nfslock_lock |= NFSV4LOCK_WANTED;
2713 		if (isleptp)
2714 			*isleptp = 1;
2715 		msleep(&lp->nfslock_lock, mutex, PVFS, "nfsv4gr", hz);
2716 	}
2717 	if (mp != NULL && NFSCL_FORCEDISM(mp))
2718 		return;
2719 
2720 	lp->nfslock_usecnt++;
2721 }
2722 
2723 /*
2724  * Get a reference as above, but return failure instead of sleeping if
2725  * an exclusive lock is held.
2726  */
2727 int
nfsv4_getref_nonblock(struct nfsv4lock * lp)2728 nfsv4_getref_nonblock(struct nfsv4lock *lp)
2729 {
2730 
2731 	if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
2732 		return (0);
2733 
2734 	lp->nfslock_usecnt++;
2735 	return (1);
2736 }
2737 
2738 /*
2739  * Test for a lock. Return 1 if locked, 0 otherwise.
2740  */
2741 int
nfsv4_testlock(struct nfsv4lock * lp)2742 nfsv4_testlock(struct nfsv4lock *lp)
2743 {
2744 
2745 	if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
2746 	    lp->nfslock_usecnt == 0)
2747 		return (0);
2748 	return (1);
2749 }
2750 
2751 /*
2752  * Wake up anyone sleeping, waiting for this lock.
2753  */
2754 static void
nfsv4_wanted(struct nfsv4lock * lp)2755 nfsv4_wanted(struct nfsv4lock *lp)
2756 {
2757 
2758 	if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
2759 		lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
2760 		wakeup((caddr_t)&lp->nfslock_lock);
2761 	}
2762 }
2763 
2764 /*
2765  * Copy a string from an mbuf list into a character array.
2766  * Return EBADRPC if there is an mbuf error,
2767  * 0 otherwise.
2768  */
2769 int
nfsrv_mtostr(struct nfsrv_descript * nd,char * str,int siz)2770 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
2771 {
2772 	char *cp;
2773 	int xfer, len;
2774 	struct mbuf *mp;
2775 	int rem, error = 0;
2776 
2777 	mp = nd->nd_md;
2778 	cp = nd->nd_dpos;
2779 	len = mtod(mp, caddr_t) + mp->m_len - cp;
2780 	rem = NFSM_RNDUP(siz) - siz;
2781 	while (siz > 0) {
2782 		if (len > siz)
2783 			xfer = siz;
2784 		else
2785 			xfer = len;
2786 		NFSBCOPY(cp, str, xfer);
2787 		str += xfer;
2788 		siz -= xfer;
2789 		if (siz > 0) {
2790 			mp = mp->m_next;
2791 			if (mp == NULL) {
2792 				error = EBADRPC;
2793 				goto out;
2794 			}
2795 			cp = mtod(mp, caddr_t);
2796 			len = mp->m_len;
2797 		} else {
2798 			cp += xfer;
2799 			len -= xfer;
2800 		}
2801 	}
2802 	*str = '\0';
2803 	nd->nd_dpos = cp;
2804 	nd->nd_md = mp;
2805 	if (rem > 0) {
2806 		if (len < rem)
2807 			error = nfsm_advance(nd, rem, len);
2808 		else
2809 			nd->nd_dpos += rem;
2810 	}
2811 
2812 out:
2813 	NFSEXITCODE2(error, nd);
2814 	return (error);
2815 }
2816 
2817 /*
2818  * Fill in the attributes as marked by the bitmap (V4).
2819  */
2820 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)2821 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
2822     NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
2823     nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
2824     int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
2825     struct statfs *pnfssf, bool xattrsupp, bool has_hiddensystem,
2826     bool has_namedattr, uint32_t clone_blksize, fsid_t *fsidp,
2827     bool has_caseinsensitive)
2828 {
2829 	int bitpos, retnum = 0;
2830 	u_int32_t *tl;
2831 	int siz, prefixnum, error;
2832 	u_char *cp, namestr[NFSV4_SMALLSTR];
2833 	nfsattrbit_t attrbits, retbits;
2834 	nfsattrbit_t *retbitp = &retbits;
2835 	u_int32_t freenum, *retnump;
2836 	u_int64_t uquad;
2837 	struct statfs *fs;
2838 	struct nfsfsinfo fsinf;
2839 	struct timespec temptime;
2840 	NFSACL_T *aclp, *naclp = NULL, *paclp, *npaclp = NULL, *daclp;
2841 	NFSACL_T *ndaclp = NULL;
2842 	short irflag;
2843 #ifdef QUOTA
2844 	struct dqblk dqb;
2845 	uid_t savuid;
2846 #endif
2847 
2848 	/*
2849 	 * First, set the bits that can be filled and get fsinfo.
2850 	 */
2851 	NFSSET_ATTRBIT(retbitp, attrbitp);
2852 	/*
2853 	 * If both p and cred are NULL, it is a client side setattr call.
2854 	 * If both p and cred are not NULL, it is a server side reply call.
2855 	 * If p is not NULL and cred is NULL, it is a client side callback
2856 	 * reply call.
2857 	 */
2858 	if (p == NULL && cred == NULL) {
2859 		NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
2860 		/* Only one of the ACL types can be set for a call. */
2861 		if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL))
2862 			aclp = saclp;
2863 		else if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_POSIXACCESSACL))
2864 			paclp = saclp;
2865 		else if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_POSIXDEFAULTACL))
2866 			daclp = saclp;
2867 	} else {
2868 		NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
2869 		naclp = acl_alloc(M_WAITOK);
2870 		aclp = naclp;
2871 		npaclp = acl_alloc(M_WAITOK);
2872 		paclp = npaclp;
2873 		ndaclp = acl_alloc(M_WAITOK);
2874 		daclp = ndaclp;
2875 	}
2876 	nfsvno_getfs(&fsinf, isdgram);
2877 	/*
2878 	 * Get the VFS_STATFS(), since some attributes need them.
2879 	 */
2880 	fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2881 	if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2882 		error = VFS_STATFS(mp, fs);
2883 		if (error != 0) {
2884 			if (reterr) {
2885 				nd->nd_repstat = NFSERR_ACCES;
2886 				free(fs, M_STATFS);
2887 				return (0);
2888 			}
2889 			NFSCLRSTATFS_ATTRBIT(retbitp);
2890 		}
2891 		/*
2892 		 * Since NFS handles these values as unsigned on the
2893 		 * wire, there is no way to represent negative values,
2894 		 * so set them to 0. Without this, they will appear
2895 		 * to be very large positive values for clients like
2896 		 * Solaris10.
2897 		 */
2898 		if (fs->f_bavail < 0)
2899 			fs->f_bavail = 0;
2900 		if (fs->f_ffree < 0)
2901 			fs->f_ffree = 0;
2902 	}
2903 
2904 	/*
2905 	 * And the NFSv4 ACL...
2906 	 */
2907 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2908 	    (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2909 		supports_nfsv4acls != SUPPACL_NFSV4))) {
2910 		NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2911 	}
2912 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2913 		if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2914 		    supports_nfsv4acls != SUPPACL_NFSV4)) {
2915 			NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2916 		} else if (naclp != NULL) {
2917 			if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2918 				error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2919 				if (error == 0)
2920 					error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2921 					    naclp, cred, p);
2922 				NFSVOPUNLOCK(vp);
2923 			} else
2924 				error = NFSERR_PERM;
2925 			if (error != 0) {
2926 				if (reterr) {
2927 					nd->nd_repstat = NFSERR_ACCES;
2928 					free(fs, M_STATFS);
2929 					return (0);
2930 				}
2931 				NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2932 			}
2933 		}
2934 	}
2935 
2936 	/* and the POSIX draft ACL. */
2937 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_POSIXACCESSACL)) {
2938 		if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2939 		    supports_nfsv4acls != SUPPACL_POSIX)) {
2940 			NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_POSIXACCESSACL);
2941 		} else if (npaclp != NULL) {
2942 			if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2943 				error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2944 				if (error == 0)
2945 					error = VOP_GETACL(vp, ACL_TYPE_ACCESS,
2946 					    npaclp, cred, p);
2947 				NFSVOPUNLOCK(vp);
2948 			} else
2949 				error = NFSERR_PERM;
2950 			if (error != 0) {
2951 				if (reterr) {
2952 					nd->nd_repstat = NFSERR_INVAL;
2953 					free(fs, M_STATFS);
2954 					return (0);
2955 				}
2956 				NFSCLRBIT_ATTRBIT(retbitp,
2957 				    NFSATTRBIT_POSIXACCESSACL);
2958 			}
2959 		}
2960 	}
2961 	if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_POSIXDEFAULTACL)) {
2962 		if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2963 		    supports_nfsv4acls != SUPPACL_POSIX)) {
2964 			NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_POSIXDEFAULTACL);
2965 		} else if (ndaclp != NULL) {
2966 			if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2967 				error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2968 				if (error == 0)
2969 					error = VOP_GETACL(vp, ACL_TYPE_DEFAULT,
2970 					    ndaclp, cred, p);
2971 				NFSVOPUNLOCK(vp);
2972 			} else
2973 				error = NFSERR_PERM;
2974 			if (error != 0)
2975 				ndaclp->acl_cnt = 0;
2976 		}
2977 	}
2978 
2979 	/*
2980 	 * Put out the attribute bitmap for the ones being filled in
2981 	 * and get the field for the number of attributes returned.
2982 	 */
2983 	prefixnum = nfsrv_putattrbit(nd, retbitp);
2984 	NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2985 	prefixnum += NFSX_UNSIGNED;
2986 
2987 	/*
2988 	 * Now, loop around filling in the attributes for each bit set.
2989 	 */
2990 	for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2991 	    if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2992 		switch (bitpos) {
2993 		case NFSATTRBIT_SUPPORTEDATTRS:
2994 			NFSSETSUPP_ATTRBIT(&attrbits, nd);
2995 			if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2996 			    && supports_nfsv4acls != SUPPACL_NFSV4)) {
2997 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2998 			    NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2999 			}
3000 			if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
3001 			    && supports_nfsv4acls != SUPPACL_POSIX)) {
3002 				NFSCLRBIT_ATTRBIT(&attrbits,
3003 				    NFSATTRBIT_POSIXACCESSACL);
3004 				NFSCLRBIT_ATTRBIT(&attrbits,
3005 				    NFSATTRBIT_POSIXDEFAULTACL);
3006 			}
3007 			if (!has_hiddensystem) {
3008 			    NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN);
3009 			    NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM);
3010 			    NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_ARCHIVE);
3011 			}
3012 			if (clone_blksize == 0)
3013 			    NFSCLRBIT_ATTRBIT(&attrbits,
3014 				NFSATTRBIT_CLONEBLKSIZE);
3015 			retnum += nfsrv_putattrbit(nd, &attrbits);
3016 			break;
3017 		case NFSATTRBIT_TYPE:
3018 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3019 			*tl = vtonfsv4_type(vap);
3020 			retnum += NFSX_UNSIGNED;
3021 			break;
3022 		case NFSATTRBIT_FHEXPIRETYPE:
3023 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3024 			*tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
3025 			retnum += NFSX_UNSIGNED;
3026 			break;
3027 		case NFSATTRBIT_CHANGE:
3028 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3029 			txdr_hyper(vap->va_filerev, tl);
3030 			retnum += NFSX_HYPER;
3031 			break;
3032 		case NFSATTRBIT_SIZE:
3033 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3034 			txdr_hyper(vap->va_size, tl);
3035 			retnum += NFSX_HYPER;
3036 			break;
3037 		case NFSATTRBIT_LINKSUPPORT:
3038 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3039 			if (fsinf.fs_properties & NFSV3FSINFO_LINK)
3040 				*tl = newnfs_true;
3041 			else
3042 				*tl = newnfs_false;
3043 			retnum += NFSX_UNSIGNED;
3044 			break;
3045 		case NFSATTRBIT_SYMLINKSUPPORT:
3046 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3047 			if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
3048 				*tl = newnfs_true;
3049 			else
3050 				*tl = newnfs_false;
3051 			retnum += NFSX_UNSIGNED;
3052 			break;
3053 		case NFSATTRBIT_NAMEDATTR:
3054 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3055 			if (has_namedattr)
3056 				*tl = newnfs_true;
3057 			else
3058 				*tl = newnfs_false;
3059 			retnum += NFSX_UNSIGNED;
3060 			break;
3061 		case NFSATTRBIT_FSID:
3062 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
3063 			if (fsidp == NULL)
3064 				fsidp = &mp->mnt_stat.f_fsid;
3065 			*tl++ = 0;
3066 			*tl++ = txdr_unsigned(fsidp->val[0]);
3067 			*tl++ = 0;
3068 			*tl = txdr_unsigned(fsidp->val[1]);
3069 			retnum += NFSX_V4FSID;
3070 			break;
3071 		case NFSATTRBIT_UNIQUEHANDLES:
3072 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3073 			*tl = newnfs_true;
3074 			retnum += NFSX_UNSIGNED;
3075 			break;
3076 		case NFSATTRBIT_LEASETIME:
3077 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3078 			*tl = txdr_unsigned(nfsrv_lease);
3079 			retnum += NFSX_UNSIGNED;
3080 			break;
3081 		case NFSATTRBIT_RDATTRERROR:
3082 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3083 			*tl = txdr_unsigned(rderror);
3084 			retnum += NFSX_UNSIGNED;
3085 			break;
3086 		/*
3087 		 * Recommended Attributes. (Only the supported ones.)
3088 		 */
3089 		case NFSATTRBIT_ACL:
3090 			retnum += nfsrv_buildacl(nd, aclp, vp->v_type, p);
3091 			break;
3092 		case NFSATTRBIT_ACLSUPPORT:
3093 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3094 			*tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
3095 			retnum += NFSX_UNSIGNED;
3096 			break;
3097 		case NFSATTRBIT_ARCHIVE:
3098 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3099 			if ((vap->va_flags & UF_ARCHIVE) != 0)
3100 				*tl = newnfs_true;
3101 			else
3102 				*tl = newnfs_false;
3103 			retnum += NFSX_UNSIGNED;
3104 			break;
3105 		case NFSATTRBIT_CANSETTIME:
3106 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3107 			if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
3108 				*tl = newnfs_true;
3109 			else
3110 				*tl = newnfs_false;
3111 			retnum += NFSX_UNSIGNED;
3112 			break;
3113 		case NFSATTRBIT_CASEINSENSITIVE:
3114 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3115 			if (has_caseinsensitive)
3116 				*tl = newnfs_true;
3117 			else
3118 				*tl = newnfs_false;
3119 			retnum += NFSX_UNSIGNED;
3120 			break;
3121 		case NFSATTRBIT_CASEPRESERVING:
3122 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3123 			*tl = newnfs_true;
3124 			retnum += NFSX_UNSIGNED;
3125 			break;
3126 		case NFSATTRBIT_CHOWNRESTRICTED:
3127 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3128 			*tl = newnfs_true;
3129 			retnum += NFSX_UNSIGNED;
3130 			break;
3131 		case NFSATTRBIT_FILEHANDLE:
3132 			siz = 0;
3133 			if (vp != NULL) {
3134 				irflag = vn_irflag_read(vp);
3135 				if ((irflag & VIRF_NAMEDDIR) != 0)
3136 					siz = NFSX_FHMAX + 2;
3137 				else if ((irflag & VIRF_NAMEDATTR) != 0)
3138 					siz = NFSX_FHMAX + 3;
3139 			}
3140 			retnum += nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, siz, 0);
3141 			break;
3142 		case NFSATTRBIT_FILEID:
3143 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3144 			uquad = vap->va_fileid;
3145 			txdr_hyper(uquad, tl);
3146 			retnum += NFSX_HYPER;
3147 			break;
3148 		case NFSATTRBIT_FILESAVAIL:
3149 			freenum = nfsv4_filesavail(fs, mp);
3150 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3151 			*tl++ = 0;
3152 			*tl = txdr_unsigned(freenum);
3153 			retnum += NFSX_HYPER;
3154 			break;
3155 		case NFSATTRBIT_FILESFREE:
3156 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3157 			*tl++ = 0;
3158 			*tl = txdr_unsigned(fs->f_ffree);
3159 			retnum += NFSX_HYPER;
3160 			break;
3161 		case NFSATTRBIT_FILESTOTAL:
3162 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3163 			*tl++ = 0;
3164 			*tl = txdr_unsigned(fs->f_files);
3165 			retnum += NFSX_HYPER;
3166 			break;
3167 		case NFSATTRBIT_FSLOCATIONS:
3168 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3169 			*tl++ = 0;
3170 			*tl = 0;
3171 			retnum += 2 * NFSX_UNSIGNED;
3172 			break;
3173 		case NFSATTRBIT_HIDDEN:
3174 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3175 			if ((vap->va_flags & UF_HIDDEN) != 0)
3176 				*tl = newnfs_true;
3177 			else
3178 				*tl = newnfs_false;
3179 			retnum += NFSX_UNSIGNED;
3180 			break;
3181 		case NFSATTRBIT_HOMOGENEOUS:
3182 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3183 			if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
3184 				*tl = newnfs_true;
3185 			else
3186 				*tl = newnfs_false;
3187 			retnum += NFSX_UNSIGNED;
3188 			break;
3189 		case NFSATTRBIT_MAXFILESIZE:
3190 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3191 			uquad = NFSRV_MAXFILESIZE;
3192 			txdr_hyper(uquad, tl);
3193 			retnum += NFSX_HYPER;
3194 			break;
3195 		case NFSATTRBIT_MAXLINK:
3196 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3197 			*tl = txdr_unsigned(NFS_LINK_MAX);
3198 			retnum += NFSX_UNSIGNED;
3199 			break;
3200 		case NFSATTRBIT_MAXNAME:
3201 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3202 			*tl = txdr_unsigned(NFS_MAXNAMLEN);
3203 			retnum += NFSX_UNSIGNED;
3204 			break;
3205 		case NFSATTRBIT_MAXREAD:
3206 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3207 			*tl++ = 0;
3208 			*tl = txdr_unsigned(fsinf.fs_rtmax);
3209 			retnum += NFSX_HYPER;
3210 			break;
3211 		case NFSATTRBIT_MAXWRITE:
3212 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3213 			*tl++ = 0;
3214 			*tl = txdr_unsigned(fsinf.fs_wtmax);
3215 			retnum += NFSX_HYPER;
3216 			break;
3217 		case NFSATTRBIT_MODE:
3218 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3219 			*tl = vtonfsv34_mode(vap->va_mode);
3220 			retnum += NFSX_UNSIGNED;
3221 			break;
3222 		case NFSATTRBIT_NOTRUNC:
3223 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3224 			*tl = newnfs_true;
3225 			retnum += NFSX_UNSIGNED;
3226 			break;
3227 		case NFSATTRBIT_NUMLINKS:
3228 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3229 			*tl = txdr_unsigned(vap->va_nlink);
3230 			retnum += NFSX_UNSIGNED;
3231 			break;
3232 		case NFSATTRBIT_OWNER:
3233 			cp = namestr;
3234 			nfsv4_uidtostr(vap->va_uid, &cp, &siz);
3235 			retnum += nfsm_strtom(nd, cp, siz);
3236 			if (cp != namestr)
3237 				free(cp, M_NFSSTRING);
3238 			break;
3239 		case NFSATTRBIT_OWNERGROUP:
3240 			cp = namestr;
3241 			nfsv4_gidtostr(vap->va_gid, &cp, &siz);
3242 			retnum += nfsm_strtom(nd, cp, siz);
3243 			if (cp != namestr)
3244 				free(cp, M_NFSSTRING);
3245 			break;
3246 		case NFSATTRBIT_QUOTAHARD:
3247 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
3248 				freenum = fs->f_bfree;
3249 			else
3250 				freenum = fs->f_bavail;
3251 #ifdef QUOTA
3252 			/*
3253 			 * ufs_quotactl() insists that the uid argument
3254 			 * equal p_ruid for non-root quota access, so
3255 			 * we'll just make sure that's the case.
3256 			 */
3257 			savuid = p->p_cred->p_ruid;
3258 			p->p_cred->p_ruid = cred->cr_uid;
3259 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
3260 			    cred->cr_uid, &dqb))
3261 			    freenum = min(dqb.dqb_bhardlimit, freenum);
3262 			p->p_cred->p_ruid = savuid;
3263 #endif	/* QUOTA */
3264 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3265 			uquad = (u_int64_t)freenum;
3266 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
3267 			txdr_hyper(uquad, tl);
3268 			retnum += NFSX_HYPER;
3269 			break;
3270 		case NFSATTRBIT_QUOTASOFT:
3271 			if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
3272 				freenum = fs->f_bfree;
3273 			else
3274 				freenum = fs->f_bavail;
3275 #ifdef QUOTA
3276 			/*
3277 			 * ufs_quotactl() insists that the uid argument
3278 			 * equal p_ruid for non-root quota access, so
3279 			 * we'll just make sure that's the case.
3280 			 */
3281 			savuid = p->p_cred->p_ruid;
3282 			p->p_cred->p_ruid = cred->cr_uid;
3283 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
3284 			    cred->cr_uid, &dqb))
3285 			    freenum = min(dqb.dqb_bsoftlimit, freenum);
3286 			p->p_cred->p_ruid = savuid;
3287 #endif	/* QUOTA */
3288 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3289 			uquad = (u_int64_t)freenum;
3290 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
3291 			txdr_hyper(uquad, tl);
3292 			retnum += NFSX_HYPER;
3293 			break;
3294 		case NFSATTRBIT_QUOTAUSED:
3295 			freenum = 0;
3296 #ifdef QUOTA
3297 			/*
3298 			 * ufs_quotactl() insists that the uid argument
3299 			 * equal p_ruid for non-root quota access, so
3300 			 * we'll just make sure that's the case.
3301 			 */
3302 			savuid = p->p_cred->p_ruid;
3303 			p->p_cred->p_ruid = cred->cr_uid;
3304 			if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
3305 			    cred->cr_uid, &dqb))
3306 			    freenum = dqb.dqb_curblocks;
3307 			p->p_cred->p_ruid = savuid;
3308 #endif	/* QUOTA */
3309 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3310 			uquad = (u_int64_t)freenum;
3311 			NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
3312 			txdr_hyper(uquad, tl);
3313 			retnum += NFSX_HYPER;
3314 			break;
3315 		case NFSATTRBIT_RAWDEV:
3316 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
3317 			*tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
3318 			*tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
3319 			retnum += NFSX_V4SPECDATA;
3320 			break;
3321 		case NFSATTRBIT_SPACEAVAIL:
3322 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3323 			if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE)) {
3324 				if (pnfssf != NULL)
3325 					uquad = (u_int64_t)pnfssf->f_bfree;
3326 				else
3327 					uquad = (u_int64_t)fs->f_bfree;
3328 			} else {
3329 				if (pnfssf != NULL)
3330 					uquad = (u_int64_t)pnfssf->f_bavail;
3331 				else
3332 					uquad = (u_int64_t)fs->f_bavail;
3333 			}
3334 			if (pnfssf != NULL)
3335 				uquad *= pnfssf->f_bsize;
3336 			else
3337 				uquad *= fs->f_bsize;
3338 			txdr_hyper(uquad, tl);
3339 			retnum += NFSX_HYPER;
3340 			break;
3341 		case NFSATTRBIT_SPACEFREE:
3342 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3343 			if (pnfssf != NULL) {
3344 				uquad = (u_int64_t)pnfssf->f_bfree;
3345 				uquad *= pnfssf->f_bsize;
3346 			} else {
3347 				uquad = (u_int64_t)fs->f_bfree;
3348 				uquad *= fs->f_bsize;
3349 			}
3350 			txdr_hyper(uquad, tl);
3351 			retnum += NFSX_HYPER;
3352 			break;
3353 		case NFSATTRBIT_SPACETOTAL:
3354 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3355 			if (pnfssf != NULL) {
3356 				uquad = (u_int64_t)pnfssf->f_blocks;
3357 				uquad *= pnfssf->f_bsize;
3358 			} else {
3359 				uquad = (u_int64_t)fs->f_blocks;
3360 				uquad *= fs->f_bsize;
3361 			}
3362 			txdr_hyper(uquad, tl);
3363 			retnum += NFSX_HYPER;
3364 			break;
3365 		case NFSATTRBIT_SPACEUSED:
3366 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3367 			txdr_hyper(vap->va_bytes, tl);
3368 			retnum += NFSX_HYPER;
3369 			break;
3370 		case NFSATTRBIT_SYSTEM:
3371 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3372 			if ((vap->va_flags & UF_SYSTEM) != 0)
3373 				*tl = newnfs_true;
3374 			else
3375 				*tl = newnfs_false;
3376 			retnum += NFSX_UNSIGNED;
3377 			break;
3378 		case NFSATTRBIT_TIMEACCESS:
3379 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
3380 			txdr_nfsv4time(&vap->va_atime, tl);
3381 			retnum += NFSX_V4TIME;
3382 			break;
3383 		case NFSATTRBIT_TIMEACCESSSET:
3384 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
3385 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
3386 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
3387 				txdr_nfsv4time(&vap->va_atime, tl);
3388 				retnum += NFSX_V4SETTIME;
3389 			} else {
3390 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3391 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
3392 				retnum += NFSX_UNSIGNED;
3393 			}
3394 			break;
3395 		case NFSATTRBIT_TIMEDELTA:
3396 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
3397 			temptime.tv_sec = 0;
3398 			temptime.tv_nsec = 1000000000 / hz;
3399 			txdr_nfsv4time(&temptime, tl);
3400 			retnum += NFSX_V4TIME;
3401 			break;
3402 		case NFSATTRBIT_TIMEMETADATA:
3403 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
3404 			txdr_nfsv4time(&vap->va_ctime, tl);
3405 			retnum += NFSX_V4TIME;
3406 			break;
3407 		case NFSATTRBIT_TIMEMODIFY:
3408 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
3409 			txdr_nfsv4time(&vap->va_mtime, tl);
3410 			retnum += NFSX_V4TIME;
3411 			break;
3412 		case NFSATTRBIT_TIMECREATE:
3413 			NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
3414 			txdr_nfsv4time(&vap->va_birthtime, tl);
3415 			retnum += NFSX_V4TIME;
3416 			break;
3417 		case NFSATTRBIT_TIMEMODIFYSET:
3418 			if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
3419 				NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
3420 				*tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
3421 				txdr_nfsv4time(&vap->va_mtime, tl);
3422 				retnum += NFSX_V4SETTIME;
3423 			} else {
3424 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3425 				*tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
3426 				retnum += NFSX_UNSIGNED;
3427 			}
3428 			break;
3429 		case NFSATTRBIT_MOUNTEDONFILEID:
3430 			NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
3431 			if (at_root != 0)
3432 				uquad = mounted_on_fileno;
3433 			else
3434 				uquad = vap->va_fileid;
3435 			txdr_hyper(uquad, tl);
3436 			retnum += NFSX_HYPER;
3437 			break;
3438 		case NFSATTRBIT_SUPPATTREXCLCREAT:
3439 			NFSSETSUPP_ATTRBIT(&attrbits, nd);
3440 			NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd);
3441 			NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
3442 			retnum += nfsrv_putattrbit(nd, &attrbits);
3443 			break;
3444 		case NFSATTRBIT_FSLAYOUTTYPE:
3445 		case NFSATTRBIT_LAYOUTTYPE:
3446 			if (nfsrv_devidcnt == 0)
3447 				siz = 1;
3448 			else
3449 				siz = 2;
3450 			if (siz == 2) {
3451 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3452 				*tl++ = txdr_unsigned(1);	/* One entry. */
3453 				if (nfsrv_doflexfile != 0 ||
3454 				    nfsrv_maxpnfsmirror > 1)
3455 					*tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
3456 				else
3457 					*tl = txdr_unsigned(
3458 					    NFSLAYOUT_NFSV4_1_FILES);
3459 			} else {
3460 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3461 				*tl = 0;
3462 			}
3463 			retnum += siz * NFSX_UNSIGNED;
3464 			break;
3465 		case NFSATTRBIT_LAYOUTALIGNMENT:
3466 		case NFSATTRBIT_LAYOUTBLKSIZE:
3467 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3468 			*tl = txdr_unsigned(nfs_srvmaxio);
3469 			retnum += NFSX_UNSIGNED;
3470 			break;
3471 		case NFSATTRBIT_XATTRSUPPORT:
3472 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3473 			if (xattrsupp)
3474 				*tl = newnfs_true;
3475 			else
3476 				*tl = newnfs_false;
3477 			retnum += NFSX_UNSIGNED;
3478 			break;
3479 		case NFSATTRBIT_MODEUMASK:
3480 			NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3481 			/*
3482 			 * Since FreeBSD applies the umask above the VFS/VOP,
3483 			 * there is no umask to handle here.  If FreeBSD
3484 			 * moves handling of umask to below the VFS/VOP,
3485 			 * this could change.
3486 			 */
3487 			*tl++ = vtonfsv34_mode(vap->va_mode);
3488 			*tl = 0;
3489 			retnum += 2 * NFSX_UNSIGNED;
3490 			break;
3491 		case NFSATTRBIT_CHANGEATTRTYPE:
3492 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3493 			*tl = txdr_unsigned(NFSV4CHANGETYPE_UNDEFINED);
3494 			if (mp != NULL) {
3495 				if ((mp->mnt_vfc->vfc_flags &
3496 				    VFCF_FILEREVINC) != 0)
3497 					*tl = txdr_unsigned(
3498 					   NFSV4CHANGETYPE_VERS_COUNTER_NOPNFS);
3499 				else if ((mp->mnt_vfc->vfc_flags &
3500 				    VFCF_FILEREVCT) != 0)
3501 					*tl = txdr_unsigned(
3502 					   NFSV4CHANGETYPE_TIME_METADATA);
3503 			}
3504 			retnum += NFSX_UNSIGNED;
3505 			break;
3506 		case NFSATTRBIT_CLONEBLKSIZE:
3507 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3508 			*tl = txdr_unsigned(clone_blksize);
3509 			retnum += NFSX_UNSIGNED;
3510 			break;
3511 		case NFSATTRBIT_ACLTRUEFORM:
3512 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3513 			*tl = txdr_unsigned(nfs_trueform(vp));
3514 			retnum += NFSX_UNSIGNED;
3515 			break;
3516 		case NFSATTRBIT_ACLTRUEFORMSCOPE:
3517 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3518 			*tl = txdr_unsigned(NFSV4_ACL_SCOPE_FILE_SYSTEM);
3519 			retnum += NFSX_UNSIGNED;
3520 			break;
3521 		case NFSATTRBIT_POSIXACCESSACL:
3522 			retnum += nfsrv_buildposixacl(nd, paclp,
3523 			    ACL_TYPE_ACCESS);
3524 			break;
3525 		case NFSATTRBIT_POSIXDEFAULTACL:
3526 			retnum += nfsrv_buildposixacl(nd, daclp,
3527 			    ACL_TYPE_DEFAULT);
3528 			break;
3529 		default:
3530 			printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
3531 		}
3532 	    }
3533 	}
3534 	if (naclp != NULL)
3535 		acl_free(naclp);
3536 	if (npaclp != NULL)
3537 		acl_free(npaclp);
3538 	if (ndaclp != NULL)
3539 		acl_free(ndaclp);
3540 	free(fs, M_STATFS);
3541 	*retnump = txdr_unsigned(retnum);
3542 	return (retnum + prefixnum);
3543 }
3544 
3545 /*
3546  * Calculate the files available attribute value.
3547  */
3548 static uint32_t
nfsv4_filesavail(struct statfs * fs,struct mount * mp)3549 nfsv4_filesavail(struct statfs *fs, struct mount *mp)
3550 {
3551 	uint32_t freenum;
3552 #ifdef QUOTA
3553 	struct dqblk dqb;
3554 	uid_t savuid;
3555 	NFSPROC_T *p;
3556 #endif
3557 
3558 	/*
3559 	 * Check quota and use min(quota, f_ffree).
3560 	 */
3561 	freenum = fs->f_ffree;
3562 #ifdef QUOTA
3563 	/*
3564 	 * This is old OpenBSD code that does not build
3565 	 * for FreeBSD.  I do not know if doing this is
3566 	 * useful, so I will just leave the code here.
3567 	 */
3568 	p = curthread();
3569 	/*
3570 	 * ufs_quotactl() insists that the uid argument
3571 	 * equal p_ruid for non-root quota access, so
3572 	 * we'll just make sure that's the case.
3573 	 */
3574 	savuid = p->p_cred->p_ruid;
3575 	p->p_cred->p_ruid = cred->cr_uid;
3576 	if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
3577 	    cred->cr_uid, &dqb))
3578 	    freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
3579 		freenum);
3580 	p->p_cred->p_ruid = savuid;
3581 #endif	/* QUOTA */
3582 	return (freenum);
3583 }
3584 
3585 /*
3586  * Put the attribute bits onto an mbuf list.
3587  * Return the number of bytes of output generated.
3588  */
3589 int
nfsrv_putattrbit(struct nfsrv_descript * nd,nfsattrbit_t * attrbitp)3590 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
3591 {
3592 	u_int32_t *tl;
3593 	int cnt, i, bytesize;
3594 
3595 	for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
3596 		if (attrbitp->bits[cnt - 1])
3597 			break;
3598 	bytesize = (cnt + 1) * NFSX_UNSIGNED;
3599 	NFSM_BUILD(tl, u_int32_t *, bytesize);
3600 	*tl++ = txdr_unsigned(cnt);
3601 	for (i = 0; i < cnt; i++)
3602 		*tl++ = txdr_unsigned(attrbitp->bits[i]);
3603 	return (bytesize);
3604 }
3605 
3606 /*
3607  * Put the operation bits onto an mbuf list.
3608  * Return the number of bytes of output generated.
3609  */
3610 int
nfsrv_putopbit(struct nfsrv_descript * nd,nfsopbit_t * opbitp)3611 nfsrv_putopbit(struct nfsrv_descript *nd, nfsopbit_t *opbitp)
3612 {
3613 	uint32_t *tl;
3614 	int cnt, i, bytesize;
3615 
3616 	for (cnt = NFSOPBIT_MAXWORDS; cnt > 0; cnt--)
3617 		if (opbitp->bits[cnt - 1])
3618 			break;
3619 	bytesize = (cnt + 1) * NFSX_UNSIGNED;
3620 	NFSM_BUILD(tl, uint32_t *, bytesize);
3621 	*tl++ = txdr_unsigned(cnt);
3622 	for (i = 0; i < cnt; i++)
3623 		*tl++ = txdr_unsigned(opbitp->bits[i]);
3624 	return (bytesize);
3625 }
3626 
3627 /*
3628  * Convert a uid to a string.
3629  * If the lookup fails, just output the digits.
3630  * uid - the user id
3631  * cpp - points to a buffer of size NFSV4_SMALLSTR
3632  *       (malloc a larger one, as required)
3633  * retlenp - pointer to length to be returned
3634  */
3635 void
nfsv4_uidtostr(uid_t uid,u_char ** cpp,int * retlenp)3636 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp)
3637 {
3638 	int i;
3639 	struct nfsusrgrp *usrp;
3640 	u_char *cp = *cpp;
3641 	uid_t tmp;
3642 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3643 	struct nfsrv_lughash *hp;
3644 
3645 	NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
3646 	cnt = 0;
3647 tryagain:
3648 	if (NFSD_VNET(nfsrv_dnsnamelen) > 0 &&
3649 	    !NFSD_VNET(nfs_enable_uidtostring)) {
3650 		/*
3651 		 * Always map nfsrv_defaultuid to "nobody".
3652 		 */
3653 		if (uid == NFSD_VNET(nfsrv_defaultuid)) {
3654 			i = NFSD_VNET(nfsrv_dnsnamelen) + 7;
3655 			if (i > len) {
3656 				if (len > NFSV4_SMALLSTR)
3657 					free(cp, M_NFSSTRING);
3658 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
3659 				*cpp = cp;
3660 				len = i;
3661 				goto tryagain;
3662 			}
3663 			*retlenp = i;
3664 			NFSBCOPY("nobody@", cp, 7);
3665 			cp += 7;
3666 			NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
3667 			    NFSD_VNET(nfsrv_dnsnamelen));
3668 			NFSD_CURVNET_RESTORE();
3669 			return;
3670 		}
3671 		hasampersand = 0;
3672 		hp = NFSUSERHASH(uid);
3673 		mtx_lock(&hp->mtx);
3674 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3675 			if (usrp->lug_uid == uid) {
3676 				if (usrp->lug_expiry < NFSD_MONOSEC)
3677 					break;
3678 				/*
3679 				 * If the name doesn't already have an '@'
3680 				 * in it, append @domainname to it.
3681 				 */
3682 				for (i = 0; i < usrp->lug_namelen; i++) {
3683 					if (usrp->lug_name[i] == '@') {
3684 						hasampersand = 1;
3685 						break;
3686 					}
3687 				}
3688 				if (hasampersand)
3689 					i = usrp->lug_namelen;
3690 				else
3691 					i = usrp->lug_namelen +
3692 					    NFSD_VNET(nfsrv_dnsnamelen) + 1;
3693 				if (i > len) {
3694 					mtx_unlock(&hp->mtx);
3695 					if (len > NFSV4_SMALLSTR)
3696 						free(cp, M_NFSSTRING);
3697 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
3698 					*cpp = cp;
3699 					len = i;
3700 					goto tryagain;
3701 				}
3702 				*retlenp = i;
3703 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3704 				if (!hasampersand) {
3705 					cp += usrp->lug_namelen;
3706 					*cp++ = '@';
3707 					NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
3708 					    NFSD_VNET(nfsrv_dnsnamelen));
3709 				}
3710 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3711 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3712 				    lug_numhash);
3713 				mtx_unlock(&hp->mtx);
3714 				NFSD_CURVNET_RESTORE();
3715 				return;
3716 			}
3717 		}
3718 		mtx_unlock(&hp->mtx);
3719 		cnt++;
3720 		ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3721 		if (ret == 0 && cnt < 2)
3722 			goto tryagain;
3723 	}
3724 
3725 	/*
3726 	 * No match, just return a string of digits.
3727 	 */
3728 	tmp = uid;
3729 	i = 0;
3730 	while (tmp || i == 0) {
3731 		tmp /= 10;
3732 		i++;
3733 	}
3734 	len = (i > len) ? len : i;
3735 	*retlenp = len;
3736 	cp += (len - 1);
3737 	tmp = uid;
3738 	for (i = 0; i < len; i++) {
3739 		*cp-- = '0' + (tmp % 10);
3740 		tmp /= 10;
3741 	}
3742 	NFSD_CURVNET_RESTORE();
3743 	return;
3744 }
3745 
3746 /*
3747  * Get a credential for the uid with the server's group list.
3748  * If none is found, just return the credential passed in after
3749  * logging a warning message.
3750  */
3751 struct ucred *
nfsrv_getgrpscred(struct ucred * oldcred)3752 nfsrv_getgrpscred(struct ucred *oldcred)
3753 {
3754 	struct nfsusrgrp *usrp;
3755 	struct ucred *newcred;
3756 	int cnt, ret;
3757 	uid_t uid;
3758 	struct nfsrv_lughash *hp;
3759 
3760 	cnt = 0;
3761 	uid = oldcred->cr_uid;
3762 tryagain:
3763 	if (NFSD_VNET(nfsrv_dnsnamelen) > 0) {
3764 		hp = NFSUSERHASH(uid);
3765 		mtx_lock(&hp->mtx);
3766 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3767 			if (usrp->lug_uid == uid) {
3768 				if (usrp->lug_expiry < NFSD_MONOSEC)
3769 					break;
3770 				if (usrp->lug_cred != NULL) {
3771 					newcred = crhold(usrp->lug_cred);
3772 					crfree(oldcred);
3773 				} else
3774 					newcred = oldcred;
3775 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3776 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3777 				    lug_numhash);
3778 				mtx_unlock(&hp->mtx);
3779 				return (newcred);
3780 			}
3781 		}
3782 		mtx_unlock(&hp->mtx);
3783 		cnt++;
3784 		ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
3785 		if (ret == 0 && cnt < 2)
3786 			goto tryagain;
3787 	}
3788 	return (oldcred);
3789 }
3790 
3791 /*
3792  * Convert a string to a uid.
3793  * If no conversion is possible return NFSERR_BADOWNER, otherwise
3794  * return 0.
3795  * If this is called from a client side mount using AUTH_SYS and the
3796  * string is made up entirely of digits, just convert the string to
3797  * a number.
3798  */
3799 int
nfsv4_strtouid(struct nfsrv_descript * nd,u_char * str,int len,uid_t * uidp)3800 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
3801 {
3802 	int i;
3803 	char *cp, *endstr, *str0;
3804 	struct nfsusrgrp *usrp;
3805 	int cnt, ret;
3806 	int error = 0;
3807 	uid_t tuid;
3808 	struct nfsrv_lughash *hp, *hp2;
3809 
3810 	NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
3811 	if (len == 0) {
3812 		error = NFSERR_BADOWNER;
3813 		goto out;
3814 	}
3815 	/* If a string of digits and an AUTH_SYS mount, just convert it. */
3816 	str0 = str;
3817 	tuid = (uid_t)strtoul(str0, &endstr, 10);
3818 	if ((endstr - str0) == len) {
3819 		/* A numeric string. */
3820 		if ((nd->nd_flag & ND_KERBV) == 0 &&
3821 		    ((nd->nd_flag & ND_NFSCL) != 0 ||
3822 		      NFSD_VNET(nfsd_enable_stringtouid) != 0))
3823 			*uidp = tuid;
3824 		else
3825 			error = NFSERR_BADOWNER;
3826 		goto out;
3827 	}
3828 	/*
3829 	 * Look for an '@'.
3830 	 */
3831 	cp = strchr(str0, '@');
3832 	if (cp != NULL)
3833 		i = (int)(cp++ - str0);
3834 	else
3835 		i = len;
3836 
3837 	cnt = 0;
3838 tryagain:
3839 	if (NFSD_VNET(nfsrv_dnsnamelen) > 0) {
3840 		/*
3841 		 * If an '@' is found and the domain name matches, search for
3842 		 * the name with dns stripped off.
3843 		 * The match for alphabetics in now case insensitive,
3844 		 * since RFC8881 defines this string as a DNS domain name.
3845 		 */
3846 		if (cnt == 0 && i < len && i > 0 &&
3847 		    (len - 1 - i) == NFSD_VNET(nfsrv_dnsnamelen) &&
3848 		    strncasecmp(cp, NFSD_VNET(nfsrv_dnsname),
3849 		     NFSD_VNET(nfsrv_dnsnamelen)) == 0) {
3850 			len -= (NFSD_VNET(nfsrv_dnsnamelen) + 1);
3851 			*(cp - 1) = '\0';
3852 		}
3853 
3854 		/*
3855 		 * Check for the special case of "nobody".
3856 		 */
3857 		if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
3858 			*uidp = NFSD_VNET(nfsrv_defaultuid);
3859 			error = 0;
3860 			goto out;
3861 		}
3862 
3863 		hp = NFSUSERNAMEHASH(str, len);
3864 		mtx_lock(&hp->mtx);
3865 		TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
3866 			if (usrp->lug_namelen == len &&
3867 			    !NFSBCMP(usrp->lug_name, str, len)) {
3868 				if (usrp->lug_expiry < NFSD_MONOSEC)
3869 					break;
3870 				hp2 = NFSUSERHASH(usrp->lug_uid);
3871 				mtx_lock(&hp2->mtx);
3872 				TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
3873 				TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
3874 				    lug_numhash);
3875 				*uidp = usrp->lug_uid;
3876 				mtx_unlock(&hp2->mtx);
3877 				mtx_unlock(&hp->mtx);
3878 				error = 0;
3879 				goto out;
3880 			}
3881 		}
3882 		mtx_unlock(&hp->mtx);
3883 		cnt++;
3884 		ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
3885 		    str);
3886 		if (ret == 0 && cnt < 2)
3887 			goto tryagain;
3888 	}
3889 	error = NFSERR_BADOWNER;
3890 
3891 out:
3892 	NFSD_CURVNET_RESTORE();
3893 	NFSEXITCODE(error);
3894 	return (error);
3895 }
3896 
3897 /*
3898  * Convert a gid to a string.
3899  * gid - the group id
3900  * cpp - points to a buffer of size NFSV4_SMALLSTR
3901  *       (malloc a larger one, as required)
3902  * retlenp - pointer to length to be returned
3903  */
3904 void
nfsv4_gidtostr(gid_t gid,u_char ** cpp,int * retlenp)3905 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp)
3906 {
3907 	int i;
3908 	struct nfsusrgrp *usrp;
3909 	u_char *cp = *cpp;
3910 	gid_t tmp;
3911 	int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
3912 	struct nfsrv_lughash *hp;
3913 
3914 	NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
3915 	cnt = 0;
3916 tryagain:
3917 	if (NFSD_VNET(nfsrv_dnsnamelen) > 0 &&
3918 	    !NFSD_VNET(nfs_enable_uidtostring)) {
3919 		/*
3920 		 * Always map nfsrv_defaultgid to "nogroup".
3921 		 */
3922 		if (gid == NFSD_VNET(nfsrv_defaultgid)) {
3923 			i = NFSD_VNET(nfsrv_dnsnamelen) + 8;
3924 			if (i > len) {
3925 				if (len > NFSV4_SMALLSTR)
3926 					free(cp, M_NFSSTRING);
3927 				cp = malloc(i, M_NFSSTRING, M_WAITOK);
3928 				*cpp = cp;
3929 				len = i;
3930 				goto tryagain;
3931 			}
3932 			*retlenp = i;
3933 			NFSBCOPY("nogroup@", cp, 8);
3934 			cp += 8;
3935 			NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
3936 			    NFSD_VNET(nfsrv_dnsnamelen));
3937 			NFSD_CURVNET_RESTORE();
3938 			return;
3939 		}
3940 		hasampersand = 0;
3941 		hp = NFSGROUPHASH(gid);
3942 		mtx_lock(&hp->mtx);
3943 		TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
3944 			if (usrp->lug_gid == gid) {
3945 				if (usrp->lug_expiry < NFSD_MONOSEC)
3946 					break;
3947 				/*
3948 				 * If the name doesn't already have an '@'
3949 				 * in it, append @domainname to it.
3950 				 */
3951 				for (i = 0; i < usrp->lug_namelen; i++) {
3952 					if (usrp->lug_name[i] == '@') {
3953 						hasampersand = 1;
3954 						break;
3955 					}
3956 				}
3957 				if (hasampersand)
3958 					i = usrp->lug_namelen;
3959 				else
3960 					i = usrp->lug_namelen +
3961 					    NFSD_VNET(nfsrv_dnsnamelen) + 1;
3962 				if (i > len) {
3963 					mtx_unlock(&hp->mtx);
3964 					if (len > NFSV4_SMALLSTR)
3965 						free(cp, M_NFSSTRING);
3966 					cp = malloc(i, M_NFSSTRING, M_WAITOK);
3967 					*cpp = cp;
3968 					len = i;
3969 					goto tryagain;
3970 				}
3971 				*retlenp = i;
3972 				NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
3973 				if (!hasampersand) {
3974 					cp += usrp->lug_namelen;
3975 					*cp++ = '@';
3976 					NFSBCOPY(NFSD_VNET(nfsrv_dnsname), cp,
3977 					    NFSD_VNET(nfsrv_dnsnamelen));
3978 				}
3979 				TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
3980 				TAILQ_INSERT_TAIL(&hp->lughead, usrp,
3981 				    lug_numhash);
3982 				mtx_unlock(&hp->mtx);
3983 				NFSD_CURVNET_RESTORE();
3984 				return;
3985 			}
3986 		}
3987 		mtx_unlock(&hp->mtx);
3988 		cnt++;
3989 		ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL);
3990 		if (ret == 0 && cnt < 2)
3991 			goto tryagain;
3992 	}
3993 
3994 	/*
3995 	 * No match, just return a string of digits.
3996 	 */
3997 	tmp = gid;
3998 	i = 0;
3999 	while (tmp || i == 0) {
4000 		tmp /= 10;
4001 		i++;
4002 	}
4003 	len = (i > len) ? len : i;
4004 	*retlenp = len;
4005 	cp += (len - 1);
4006 	tmp = gid;
4007 	for (i = 0; i < len; i++) {
4008 		*cp-- = '0' + (tmp % 10);
4009 		tmp /= 10;
4010 	}
4011 	NFSD_CURVNET_RESTORE();
4012 	return;
4013 }
4014 
4015 /*
4016  * Convert a string to a gid.
4017  * If no conversion is possible return NFSERR_BADOWNER, otherwise
4018  * return 0.
4019  * If this is called from a client side mount using AUTH_SYS and the
4020  * string is made up entirely of digits, just convert the string to
4021  * a number.
4022  */
4023 int
nfsv4_strtogid(struct nfsrv_descript * nd,u_char * str,int len,gid_t * gidp)4024 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
4025 {
4026 	int i;
4027 	char *cp, *endstr, *str0;
4028 	struct nfsusrgrp *usrp;
4029 	int cnt, ret;
4030 	int error = 0;
4031 	gid_t tgid;
4032 	struct nfsrv_lughash *hp, *hp2;
4033 
4034 	NFSD_CURVNET_SET_QUIET(NFSD_TD_TO_VNET(curthread));
4035 	if (len == 0) {
4036 		error =  NFSERR_BADOWNER;
4037 		goto out;
4038 	}
4039 	/* If a string of digits and an AUTH_SYS mount, just convert it. */
4040 	str0 = str;
4041 	tgid = (gid_t)strtoul(str0, &endstr, 10);
4042 	if ((endstr - str0) == len) {
4043 		/* A numeric string. */
4044 		if ((nd->nd_flag & ND_KERBV) == 0 &&
4045 		    ((nd->nd_flag & ND_NFSCL) != 0 ||
4046 		      NFSD_VNET(nfsd_enable_stringtouid) != 0))
4047 			*gidp = tgid;
4048 		else
4049 			error = NFSERR_BADOWNER;
4050 		goto out;
4051 	}
4052 	/*
4053 	 * Look for an '@'.
4054 	 */
4055 	cp = strchr(str0, '@');
4056 	if (cp != NULL)
4057 		i = (int)(cp++ - str0);
4058 	else
4059 		i = len;
4060 
4061 	cnt = 0;
4062 tryagain:
4063 	if (NFSD_VNET(nfsrv_dnsnamelen) > 0) {
4064 		/*
4065 		 * If an '@' is found and the dns name matches, search for the
4066 		 * name with the dns stripped off.
4067 		 */
4068 		if (cnt == 0 && i < len && i > 0 &&
4069 		    (len - 1 - i) == NFSD_VNET(nfsrv_dnsnamelen) &&
4070 		    strncasecmp(cp, NFSD_VNET(nfsrv_dnsname),
4071 		    NFSD_VNET(nfsrv_dnsnamelen)) == 0) {
4072 			len -= (NFSD_VNET(nfsrv_dnsnamelen) + 1);
4073 			*(cp - 1) = '\0';
4074 		}
4075 
4076 		/*
4077 		 * Check for the special case of "nogroup".
4078 		 */
4079 		if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
4080 			*gidp = NFSD_VNET(nfsrv_defaultgid);
4081 			error = 0;
4082 			goto out;
4083 		}
4084 
4085 		hp = NFSGROUPNAMEHASH(str, len);
4086 		mtx_lock(&hp->mtx);
4087 		TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
4088 			if (usrp->lug_namelen == len &&
4089 			    !NFSBCMP(usrp->lug_name, str, len)) {
4090 				if (usrp->lug_expiry < NFSD_MONOSEC)
4091 					break;
4092 				hp2 = NFSGROUPHASH(usrp->lug_gid);
4093 				mtx_lock(&hp2->mtx);
4094 				TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
4095 				TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
4096 				    lug_numhash);
4097 				*gidp = usrp->lug_gid;
4098 				mtx_unlock(&hp2->mtx);
4099 				mtx_unlock(&hp->mtx);
4100 				error = 0;
4101 				goto out;
4102 			}
4103 		}
4104 		mtx_unlock(&hp->mtx);
4105 		cnt++;
4106 		ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
4107 		    str);
4108 		if (ret == 0 && cnt < 2)
4109 			goto tryagain;
4110 	}
4111 	error = NFSERR_BADOWNER;
4112 
4113 out:
4114 	NFSD_CURVNET_RESTORE();
4115 	NFSEXITCODE(error);
4116 	return (error);
4117 }
4118 
4119 /*
4120  * Set the port for the nfsuserd.
4121  */
4122 int
nfsrv_nfsuserdport(struct nfsuserd_args * nargs,NFSPROC_T * p)4123 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
4124 {
4125 	struct nfssockreq *rp;
4126 #ifdef INET
4127 	struct sockaddr_in *ad;
4128 #endif
4129 #ifdef INET6
4130 	struct sockaddr_in6 *ad6;
4131 	const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
4132 #endif
4133 	int error;
4134 
4135 	NFSLOCKNAMEID();
4136 	if (NFSD_VNET(nfsrv_nfsuserd) != NOTRUNNING) {
4137 		NFSUNLOCKNAMEID();
4138 		error = EPERM;
4139 		goto out;
4140 	}
4141 	NFSD_VNET(nfsrv_nfsuserd) = STARTSTOP;
4142 	/*
4143 	 * Set up the socket record and connect.
4144 	 * Set nr_client NULL before unlocking, just to ensure that no other
4145 	 * process/thread/core will use a bogus old value.  This could only
4146 	 * occur if the use of the nameid lock to protect nfsrv_nfsuserd is
4147 	 * broken.
4148 	 */
4149 	rp = &NFSD_VNET(nfsrv_nfsuserdsock);
4150 	rp->nr_client = NULL;
4151 	NFSUNLOCKNAMEID();
4152 	rp->nr_sotype = SOCK_DGRAM;
4153 	rp->nr_soproto = IPPROTO_UDP;
4154 	rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
4155 	rp->nr_cred = NULL;
4156 	rp->nr_prog = RPCPROG_NFSUSERD;
4157 	error = 0;
4158 	switch (nargs->nuserd_family) {
4159 #ifdef INET
4160 	case AF_INET:
4161 		rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME,
4162 		    M_WAITOK | M_ZERO);
4163  		ad = (struct sockaddr_in *)rp->nr_nam;
4164 		ad->sin_len = sizeof(struct sockaddr_in);
4165  		ad->sin_family = AF_INET;
4166 		ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
4167 		ad->sin_port = nargs->nuserd_port;
4168 		break;
4169 #endif
4170 #ifdef INET6
4171 	case AF_INET6:
4172 		rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
4173 		    M_WAITOK | M_ZERO);
4174 		ad6 = (struct sockaddr_in6 *)rp->nr_nam;
4175 		ad6->sin6_len = sizeof(struct sockaddr_in6);
4176 		ad6->sin6_family = AF_INET6;
4177 		ad6->sin6_addr = in6loopback;
4178 		ad6->sin6_port = nargs->nuserd_port;
4179 		break;
4180 #endif
4181 	default:
4182 		error = ENXIO;
4183  	}
4184 	rp->nr_vers = RPCNFSUSERD_VERS;
4185 	if (error == 0)
4186 		error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0, false,
4187 		    &rp->nr_client);
4188 	if (error == 0) {
4189 		NFSLOCKNAMEID();
4190 		NFSD_VNET(nfsrv_nfsuserd) = RUNNING;
4191 		NFSUNLOCKNAMEID();
4192 	} else {
4193 		free(rp->nr_nam, M_SONAME);
4194 		NFSLOCKNAMEID();
4195 		NFSD_VNET(nfsrv_nfsuserd) = NOTRUNNING;
4196 		NFSUNLOCKNAMEID();
4197 	}
4198 out:
4199 	NFSEXITCODE(error);
4200 	return (error);
4201 }
4202 
4203 /*
4204  * Delete the nfsuserd port.
4205  */
4206 void
nfsrv_nfsuserddelport(void)4207 nfsrv_nfsuserddelport(void)
4208 {
4209 
4210 	NFSLOCKNAMEID();
4211 	if (NFSD_VNET(nfsrv_nfsuserd) != RUNNING) {
4212 		NFSUNLOCKNAMEID();
4213 		return;
4214 	}
4215 	NFSD_VNET(nfsrv_nfsuserd) = STARTSTOP;
4216 	/* Wait for all upcalls to complete. */
4217 	while (NFSD_VNET(nfsrv_userdupcalls) > 0)
4218 		msleep(&NFSD_VNET(nfsrv_userdupcalls), NFSNAMEIDMUTEXPTR, PVFS,
4219 		    "nfsupcalls", 0);
4220 	NFSUNLOCKNAMEID();
4221 	newnfs_disconnect(NULL, &NFSD_VNET(nfsrv_nfsuserdsock));
4222 	free(NFSD_VNET(nfsrv_nfsuserdsock).nr_nam, M_SONAME);
4223 	NFSLOCKNAMEID();
4224 	NFSD_VNET(nfsrv_nfsuserd) = NOTRUNNING;
4225 	NFSUNLOCKNAMEID();
4226 }
4227 
4228 /*
4229  * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
4230  * name<-->id cache.
4231  * Returns 0 upon success, non-zero otherwise.
4232  */
4233 static int
nfsrv_getuser(int procnum,uid_t uid,gid_t gid,char * name)4234 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
4235 {
4236 	u_int32_t *tl;
4237 	struct nfsrv_descript *nd;
4238 	int len;
4239 	struct nfsrv_descript nfsd;
4240 	struct ucred *cred;
4241 	int error;
4242 
4243 	NFSLOCKNAMEID();
4244 	if (NFSD_VNET(nfsrv_nfsuserd) != RUNNING) {
4245 		NFSUNLOCKNAMEID();
4246 		error = EPERM;
4247 		goto out;
4248 	}
4249 	/*
4250 	 * Maintain a count of upcalls in progress, so that nfsrv_X()
4251 	 * can wait until no upcalls are in progress.
4252 	 */
4253 	NFSD_VNET(nfsrv_userdupcalls)++;
4254 	NFSUNLOCKNAMEID();
4255 	KASSERT(NFSD_VNET(nfsrv_userdupcalls) > 0,
4256 	    ("nfsrv_getuser: non-positive upcalls"));
4257 	nd = &nfsd;
4258 	cred = newnfs_getcred();
4259 	nd->nd_flag = ND_GSSINITREPLY;
4260 	nfsrvd_rephead(nd);
4261 
4262 	nd->nd_procnum = procnum;
4263 	if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
4264 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4265 		if (procnum == RPCNFSUSERD_GETUID)
4266 			*tl = txdr_unsigned(uid);
4267 		else
4268 			*tl = txdr_unsigned(gid);
4269 	} else {
4270 		len = strlen(name);
4271 		(void) nfsm_strtom(nd, name, len);
4272 	}
4273 	error = newnfs_request(nd, NULL, NULL, &NFSD_VNET(nfsrv_nfsuserdsock),
4274 	    NULL, NULL, cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0,
4275 	    NULL, NULL);
4276 	NFSLOCKNAMEID();
4277 	if (--NFSD_VNET(nfsrv_userdupcalls) == 0 &&
4278 	    NFSD_VNET(nfsrv_nfsuserd) == STARTSTOP)
4279 		wakeup(&NFSD_VNET(nfsrv_userdupcalls));
4280 	NFSUNLOCKNAMEID();
4281 	NFSFREECRED(cred);
4282 	if (!error) {
4283 		m_freem(nd->nd_mrep);
4284 		error = nd->nd_repstat;
4285 	}
4286 out:
4287 	NFSEXITCODE(error);
4288 	return (error);
4289 }
4290 
4291 /*
4292  * This function is called from the nfssvc(2) system call, to update the
4293  * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
4294  */
4295 int
nfssvc_idname(struct nfsd_idargs * nidp)4296 nfssvc_idname(struct nfsd_idargs *nidp)
4297 {
4298 	struct nfsusrgrp *nusrp, *usrp, *newusrp;
4299 	struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
4300 	int i, group_locked, groupname_locked, user_locked, username_locked;
4301 	int error = 0;
4302 	u_char *cp;
4303 	gid_t *grps;
4304 	struct ucred *cr;
4305 	static int onethread = 0;
4306 	static time_t lasttime = 0;
4307 
4308 	if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
4309 		error = EINVAL;
4310 		goto out;
4311 	}
4312 	if (nidp->nid_flag & NFSID_INITIALIZE) {
4313 		cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
4314 		error = copyin(nidp->nid_name, cp, nidp->nid_namelen);
4315 		if (error != 0) {
4316 			free(cp, M_NFSSTRING);
4317 			goto out;
4318 		}
4319 		if (atomic_cmpset_acq_int(&NFSD_VNET(nfsrv_dnsnamelen), 0, 0) ==
4320 		    0) {
4321 			/*
4322 			 * Free up all the old stuff and reinitialize hash
4323 			 * lists.  All mutexes for both lists must be locked,
4324 			 * with the user/group name ones before the uid/gid
4325 			 * ones, to avoid a LOR.
4326 			 */
4327 			for (i = 0; i < nfsrv_lughashsize; i++)
4328 				mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx);
4329 			for (i = 0; i < nfsrv_lughashsize; i++)
4330 				mtx_lock(&NFSD_VNET(nfsuserhash)[i].mtx);
4331 			for (i = 0; i < nfsrv_lughashsize; i++)
4332 				TAILQ_FOREACH_SAFE(usrp,
4333 				    &NFSD_VNET(nfsuserhash)[i].lughead, lug_numhash, nusrp)
4334 					nfsrv_removeuser(usrp, 1);
4335 			for (i = 0; i < nfsrv_lughashsize; i++)
4336 				mtx_unlock(&NFSD_VNET(nfsuserhash)[i].mtx);
4337 			for (i = 0; i < nfsrv_lughashsize; i++)
4338 				mtx_unlock(&NFSD_VNET(nfsusernamehash)[i].mtx);
4339 			for (i = 0; i < nfsrv_lughashsize; i++)
4340 				mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4341 			for (i = 0; i < nfsrv_lughashsize; i++)
4342 				mtx_lock(&NFSD_VNET(nfsgrouphash)[i].mtx);
4343 			for (i = 0; i < nfsrv_lughashsize; i++)
4344 				TAILQ_FOREACH_SAFE(usrp,
4345 				    &NFSD_VNET(nfsgrouphash)[i].lughead, lug_numhash,
4346 				    nusrp)
4347 					nfsrv_removeuser(usrp, 0);
4348 			for (i = 0; i < nfsrv_lughashsize; i++)
4349 				mtx_unlock(&NFSD_VNET(nfsgrouphash)[i].mtx);
4350 			for (i = 0; i < nfsrv_lughashsize; i++)
4351 				mtx_unlock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4352 			free(NFSD_VNET(nfsrv_dnsname), M_NFSSTRING);
4353 			NFSD_VNET(nfsrv_dnsname) = NULL;
4354 		}
4355 		if (NFSD_VNET(nfsuserhash) == NULL) {
4356 			/* Allocate the hash tables. */
4357 			NFSD_VNET(nfsuserhash) = malloc(sizeof(struct nfsrv_lughash) *
4358 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
4359 			    M_ZERO);
4360 			for (i = 0; i < nfsrv_lughashsize; i++)
4361 				mtx_init(&NFSD_VNET(nfsuserhash)[i].mtx, "nfsuidhash",
4362 				    NULL, MTX_DEF | MTX_DUPOK);
4363 			NFSD_VNET(nfsusernamehash) = 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(nfsusernamehash)[i].mtx,
4368 				    "nfsusrhash", NULL, MTX_DEF |
4369 				    MTX_DUPOK);
4370 			NFSD_VNET(nfsgrouphash) = malloc(sizeof(struct nfsrv_lughash) *
4371 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
4372 			    M_ZERO);
4373 			for (i = 0; i < nfsrv_lughashsize; i++)
4374 				mtx_init(&NFSD_VNET(nfsgrouphash)[i].mtx, "nfsgidhash",
4375 				    NULL, MTX_DEF | MTX_DUPOK);
4376 			NFSD_VNET(nfsgroupnamehash) = malloc(sizeof(struct nfsrv_lughash) *
4377 			    nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
4378 			    M_ZERO);
4379 			for (i = 0; i < nfsrv_lughashsize; i++)
4380 			    mtx_init(&NFSD_VNET(nfsgroupnamehash)[i].mtx,
4381 			    "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
4382 		}
4383 		/* (Re)initialize the list heads. */
4384 		for (i = 0; i < nfsrv_lughashsize; i++)
4385 			TAILQ_INIT(&NFSD_VNET(nfsuserhash)[i].lughead);
4386 		for (i = 0; i < nfsrv_lughashsize; i++)
4387 			TAILQ_INIT(&NFSD_VNET(nfsusernamehash)[i].lughead);
4388 		for (i = 0; i < nfsrv_lughashsize; i++)
4389 			TAILQ_INIT(&NFSD_VNET(nfsgrouphash)[i].lughead);
4390 		for (i = 0; i < nfsrv_lughashsize; i++)
4391 			TAILQ_INIT(&NFSD_VNET(nfsgroupnamehash)[i].lughead);
4392 
4393 		/*
4394 		 * Put name in "DNS" string.
4395 		 */
4396 		NFSD_VNET(nfsrv_dnsname) = cp;
4397 		NFSD_VNET(nfsrv_defaultuid) = nidp->nid_uid;
4398 		NFSD_VNET(nfsrv_defaultgid) = nidp->nid_gid;
4399 		NFSD_VNET(nfsrv_usercnt) = 0;
4400 		NFSD_VNET(nfsrv_usermax) = nidp->nid_usermax;
4401 		atomic_store_rel_int(&NFSD_VNET(nfsrv_dnsnamelen),
4402 		    nidp->nid_namelen);
4403 		goto out;
4404 	}
4405 
4406 	/*
4407 	 * malloc the new one now, so any potential sleep occurs before
4408 	 * manipulation of the lists.
4409 	 */
4410 	newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
4411 	    M_NFSUSERGROUP, M_WAITOK | M_ZERO);
4412 	error = copyin(nidp->nid_name, newusrp->lug_name,
4413 	    nidp->nid_namelen);
4414 	if (error == 0 && nidp->nid_ngroup > 0 &&
4415 	    (nidp->nid_flag & NFSID_ADDUID) != 0) {
4416 		grps = NULL;
4417 		if (nidp->nid_ngroup > NGROUPS_MAX)
4418 			error = EINVAL;
4419 		if (error == 0) {
4420 			grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
4421 			    M_WAITOK);
4422 			error = copyin(nidp->nid_grps, grps,
4423 			    sizeof(gid_t) * nidp->nid_ngroup);
4424 		}
4425 		if (error == 0) {
4426 			/*
4427 			 * Create a credential just like svc_getcred(),
4428 			 * but using the group list provided.
4429 			 */
4430 			cr = crget();
4431 			cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
4432 			crsetgroups_and_egid(cr, nidp->nid_ngroup, grps,
4433 			    GID_NOGROUP);
4434 			cr->cr_rgid = cr->cr_svgid = cr->cr_gid;
4435 			cr->cr_prison = curthread->td_ucred->cr_prison;
4436 			prison_hold(cr->cr_prison);
4437 #ifdef MAC
4438 			mac_cred_associate_nfsd(cr);
4439 #endif
4440 			newusrp->lug_cred = cr;
4441 		}
4442 		free(grps, M_TEMP);
4443 	}
4444 	if (error) {
4445 		free(newusrp, M_NFSUSERGROUP);
4446 		goto out;
4447 	}
4448 	newusrp->lug_namelen = nidp->nid_namelen;
4449 
4450 	/*
4451 	 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
4452 	 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
4453 	 * The flags user_locked, username_locked, group_locked and
4454 	 * groupname_locked are set to indicate all of those hash lists are
4455 	 * locked. hp_name != NULL  and hp_idnum != NULL indicates that
4456 	 * the respective one mutex is locked.
4457 	 */
4458 	user_locked = username_locked = group_locked = groupname_locked = 0;
4459 	hp_name = hp_idnum = NULL;
4460 
4461 	/*
4462 	 * Delete old entries, as required.
4463 	 */
4464 	if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
4465 		/* Must lock all username hash lists first, to avoid a LOR. */
4466 		for (i = 0; i < nfsrv_lughashsize; i++)
4467 			mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx);
4468 		username_locked = 1;
4469 		hp_idnum = NFSUSERHASH(nidp->nid_uid);
4470 		mtx_lock(&hp_idnum->mtx);
4471 		TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
4472 		    nusrp) {
4473 			if (usrp->lug_uid == nidp->nid_uid)
4474 				nfsrv_removeuser(usrp, 1);
4475 		}
4476 	} else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
4477 		hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
4478 		    newusrp->lug_namelen);
4479 		mtx_lock(&hp_name->mtx);
4480 		TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
4481 		    nusrp) {
4482 			if (usrp->lug_namelen == newusrp->lug_namelen &&
4483 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
4484 			    usrp->lug_namelen)) {
4485 				thp = NFSUSERHASH(usrp->lug_uid);
4486 				mtx_lock(&thp->mtx);
4487 				nfsrv_removeuser(usrp, 1);
4488 				mtx_unlock(&thp->mtx);
4489 			}
4490 		}
4491 		hp_idnum = NFSUSERHASH(nidp->nid_uid);
4492 		mtx_lock(&hp_idnum->mtx);
4493 	} else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
4494 		/* Must lock all groupname hash lists first, to avoid a LOR. */
4495 		for (i = 0; i < nfsrv_lughashsize; i++)
4496 			mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4497 		groupname_locked = 1;
4498 		hp_idnum = NFSGROUPHASH(nidp->nid_gid);
4499 		mtx_lock(&hp_idnum->mtx);
4500 		TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
4501 		    nusrp) {
4502 			if (usrp->lug_gid == nidp->nid_gid)
4503 				nfsrv_removeuser(usrp, 0);
4504 		}
4505 	} else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
4506 		hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
4507 		    newusrp->lug_namelen);
4508 		mtx_lock(&hp_name->mtx);
4509 		TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
4510 		    nusrp) {
4511 			if (usrp->lug_namelen == newusrp->lug_namelen &&
4512 			    !NFSBCMP(usrp->lug_name, newusrp->lug_name,
4513 			    usrp->lug_namelen)) {
4514 				thp = NFSGROUPHASH(usrp->lug_gid);
4515 				mtx_lock(&thp->mtx);
4516 				nfsrv_removeuser(usrp, 0);
4517 				mtx_unlock(&thp->mtx);
4518 			}
4519 		}
4520 		hp_idnum = NFSGROUPHASH(nidp->nid_gid);
4521 		mtx_lock(&hp_idnum->mtx);
4522 	}
4523 
4524 	/*
4525 	 * Now, we can add the new one.
4526 	 */
4527 	if (nidp->nid_usertimeout)
4528 		newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
4529 	else
4530 		newusrp->lug_expiry = NFSD_MONOSEC + 5;
4531 	if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
4532 		newusrp->lug_uid = nidp->nid_uid;
4533 		thp = NFSUSERHASH(newusrp->lug_uid);
4534 		mtx_assert(&thp->mtx, MA_OWNED);
4535 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
4536 		thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
4537 		mtx_assert(&thp->mtx, MA_OWNED);
4538 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
4539 		atomic_add_int(&NFSD_VNET(nfsrv_usercnt), 1);
4540 	} else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
4541 		newusrp->lug_gid = nidp->nid_gid;
4542 		thp = NFSGROUPHASH(newusrp->lug_gid);
4543 		mtx_assert(&thp->mtx, MA_OWNED);
4544 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
4545 		thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
4546 		mtx_assert(&thp->mtx, MA_OWNED);
4547 		TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
4548 		atomic_add_int(&NFSD_VNET(nfsrv_usercnt), 1);
4549 	} else {
4550 		if (newusrp->lug_cred != NULL)
4551 			crfree(newusrp->lug_cred);
4552 		free(newusrp, M_NFSUSERGROUP);
4553 	}
4554 
4555 	/*
4556 	 * Once per second, allow one thread to trim the cache.
4557 	 */
4558 	if (lasttime < NFSD_MONOSEC &&
4559 	    atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
4560 		/*
4561 		 * First, unlock the single mutexes, so that all entries
4562 		 * can be locked and any LOR is avoided.
4563 		 */
4564 		if (hp_name != NULL) {
4565 			mtx_unlock(&hp_name->mtx);
4566 			hp_name = NULL;
4567 		}
4568 		if (hp_idnum != NULL) {
4569 			mtx_unlock(&hp_idnum->mtx);
4570 			hp_idnum = NULL;
4571 		}
4572 
4573 		if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
4574 		    NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
4575 			if (username_locked == 0) {
4576 				for (i = 0; i < nfsrv_lughashsize; i++)
4577 					mtx_lock(&NFSD_VNET(nfsusernamehash)[i].mtx);
4578 				username_locked = 1;
4579 			}
4580 			KASSERT(user_locked == 0,
4581 			    ("nfssvc_idname: user_locked"));
4582 			for (i = 0; i < nfsrv_lughashsize; i++)
4583 				mtx_lock(&NFSD_VNET(nfsuserhash)[i].mtx);
4584 			user_locked = 1;
4585 			for (i = 0; i < nfsrv_lughashsize; i++) {
4586 				TAILQ_FOREACH_SAFE(usrp,
4587 				    &NFSD_VNET(nfsuserhash)[i].lughead, lug_numhash,
4588 				    nusrp)
4589 					if (usrp->lug_expiry < NFSD_MONOSEC)
4590 						nfsrv_removeuser(usrp, 1);
4591 			}
4592 			for (i = 0; i < nfsrv_lughashsize; i++) {
4593 				/*
4594 				 * Trim the cache using an approximate LRU
4595 				 * algorithm.  This code deletes the least
4596 				 * recently used entry on each hash list.
4597 				 */
4598 				if (NFSD_VNET(nfsrv_usercnt) <= NFSD_VNET(nfsrv_usermax))
4599 					break;
4600 				usrp = TAILQ_FIRST(&NFSD_VNET(nfsuserhash)[i].lughead);
4601 				if (usrp != NULL)
4602 					nfsrv_removeuser(usrp, 1);
4603 			}
4604 		} else {
4605 			if (groupname_locked == 0) {
4606 				for (i = 0; i < nfsrv_lughashsize; i++)
4607 					mtx_lock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4608 				groupname_locked = 1;
4609 			}
4610 			KASSERT(group_locked == 0,
4611 			    ("nfssvc_idname: group_locked"));
4612 			for (i = 0; i < nfsrv_lughashsize; i++)
4613 				mtx_lock(&NFSD_VNET(nfsgrouphash)[i].mtx);
4614 			group_locked = 1;
4615 			for (i = 0; i < nfsrv_lughashsize; i++) {
4616 				TAILQ_FOREACH_SAFE(usrp,
4617 				    &NFSD_VNET(nfsgrouphash)[i].lughead, lug_numhash,
4618 				    nusrp)
4619 					if (usrp->lug_expiry < NFSD_MONOSEC)
4620 						nfsrv_removeuser(usrp, 0);
4621 			}
4622 			for (i = 0; i < nfsrv_lughashsize; i++) {
4623 				/*
4624 				 * Trim the cache using an approximate LRU
4625 				 * algorithm.  This code deletes the least
4626 				 * recently user entry on each hash list.
4627 				 */
4628 				if (NFSD_VNET(nfsrv_usercnt) <= NFSD_VNET(nfsrv_usermax))
4629 					break;
4630 				usrp = TAILQ_FIRST(&NFSD_VNET(nfsgrouphash)[i].lughead);
4631 				if (usrp != NULL)
4632 					nfsrv_removeuser(usrp, 0);
4633 			}
4634 		}
4635 		lasttime = NFSD_MONOSEC;
4636 		atomic_store_rel_int(&onethread, 0);
4637 	}
4638 
4639 	/* Now, unlock all locked mutexes. */
4640 	if (hp_idnum != NULL)
4641 		mtx_unlock(&hp_idnum->mtx);
4642 	if (hp_name != NULL)
4643 		mtx_unlock(&hp_name->mtx);
4644 	if (user_locked != 0)
4645 		for (i = 0; i < nfsrv_lughashsize; i++)
4646 			mtx_unlock(&NFSD_VNET(nfsuserhash)[i].mtx);
4647 	if (username_locked != 0)
4648 		for (i = 0; i < nfsrv_lughashsize; i++)
4649 			mtx_unlock(&NFSD_VNET(nfsusernamehash)[i].mtx);
4650 	if (group_locked != 0)
4651 		for (i = 0; i < nfsrv_lughashsize; i++)
4652 			mtx_unlock(&NFSD_VNET(nfsgrouphash)[i].mtx);
4653 	if (groupname_locked != 0)
4654 		for (i = 0; i < nfsrv_lughashsize; i++)
4655 			mtx_unlock(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4656 out:
4657 	NFSEXITCODE(error);
4658 	return (error);
4659 }
4660 
4661 /*
4662  * Remove a user/group name element.
4663  */
4664 static void
nfsrv_removeuser(struct nfsusrgrp * usrp,int isuser)4665 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
4666 {
4667 	struct nfsrv_lughash *hp;
4668 
4669 	if (isuser != 0) {
4670 		hp = NFSUSERHASH(usrp->lug_uid);
4671 		mtx_assert(&hp->mtx, MA_OWNED);
4672 		TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4673 		hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4674 		mtx_assert(&hp->mtx, MA_OWNED);
4675 		TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4676 	} else {
4677 		hp = NFSGROUPHASH(usrp->lug_gid);
4678 		mtx_assert(&hp->mtx, MA_OWNED);
4679 		TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4680 		hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
4681 		mtx_assert(&hp->mtx, MA_OWNED);
4682 		TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
4683 	}
4684 	atomic_add_int(&NFSD_VNET(nfsrv_usercnt), -1);
4685 	if (usrp->lug_cred != NULL)
4686 		crfree(usrp->lug_cred);
4687 	free(usrp, M_NFSUSERGROUP);
4688 }
4689 
4690 /*
4691  * Free up all the allocations related to the name<-->id cache.
4692  * This function should only be called when the nfsuserd daemon isn't
4693  * running, since it doesn't do any locking.
4694  * This function is meant to be called when a vnet jail is destroyed.
4695  */
4696 void
nfsrv_cleanusergroup(void)4697 nfsrv_cleanusergroup(void)
4698 {
4699 	struct nfsrv_lughash *hp, *hp2;
4700 	struct nfsusrgrp *nusrp, *usrp;
4701 	int i;
4702 
4703 	if (NFSD_VNET(nfsuserhash) == NULL)
4704 		return;
4705 
4706 	for (i = 0; i < nfsrv_lughashsize; i++) {
4707 		hp = &NFSD_VNET(nfsuserhash)[i];
4708 		TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4709 			TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4710 			hp2 = NFSUSERNAMEHASH(usrp->lug_name,
4711 			    usrp->lug_namelen);
4712 			TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4713 			if (usrp->lug_cred != NULL)
4714 				crfree(usrp->lug_cred);
4715 			free(usrp, M_NFSUSERGROUP);
4716 		}
4717 		hp = &NFSD_VNET(nfsgrouphash)[i];
4718 		TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
4719 			TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
4720 			hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
4721 			    usrp->lug_namelen);
4722 			TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
4723 			if (usrp->lug_cred != NULL)
4724 				crfree(usrp->lug_cred);
4725 			free(usrp, M_NFSUSERGROUP);
4726 		}
4727 		mtx_destroy(&NFSD_VNET(nfsuserhash)[i].mtx);
4728 		mtx_destroy(&NFSD_VNET(nfsusernamehash)[i].mtx);
4729 		mtx_destroy(&NFSD_VNET(nfsgroupnamehash)[i].mtx);
4730 		mtx_destroy(&NFSD_VNET(nfsgrouphash)[i].mtx);
4731 	}
4732 	free(NFSD_VNET(nfsuserhash), M_NFSUSERGROUP);
4733 	free(NFSD_VNET(nfsusernamehash), M_NFSUSERGROUP);
4734 	free(NFSD_VNET(nfsgrouphash), M_NFSUSERGROUP);
4735 	free(NFSD_VNET(nfsgroupnamehash), M_NFSUSERGROUP);
4736 	free(NFSD_VNET(nfsrv_dnsname), M_NFSSTRING);
4737 }
4738 
4739 /*
4740  * This function scans a byte string and checks for UTF-8 compliance.
4741  * It returns 0 if it conforms and NFSERR_INVAL if not.
4742  */
4743 int
nfsrv_checkutf8(u_int8_t * cp,int len)4744 nfsrv_checkutf8(u_int8_t *cp, int len)
4745 {
4746 	u_int32_t val = 0x0;
4747 	int cnt = 0, gotd = 0, shift = 0;
4748 	u_int8_t byte;
4749 	static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
4750 	int error = 0;
4751 
4752 	/*
4753 	 * Here are what the variables are used for:
4754 	 * val - the calculated value of a multibyte char, used to check
4755 	 *       that it was coded with the correct range
4756 	 * cnt - the number of 10xxxxxx bytes to follow
4757 	 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
4758 	 * shift - lower order bits of range (ie. "val >> shift" should
4759 	 *       not be 0, in other words, dividing by the lower bound
4760 	 *       of the range should get a non-zero value)
4761 	 * byte - used to calculate cnt
4762 	 */
4763 	while (len > 0) {
4764 		if (cnt > 0) {
4765 			/* This handles the 10xxxxxx bytes */
4766 			if ((*cp & 0xc0) != 0x80 ||
4767 			    (gotd && (*cp & 0x20))) {
4768 				error = NFSERR_INVAL;
4769 				goto out;
4770 			}
4771 			gotd = 0;
4772 			val <<= 6;
4773 			val |= (*cp & 0x3f);
4774 			cnt--;
4775 			if (cnt == 0 && (val >> shift) == 0x0) {
4776 				error = NFSERR_INVAL;
4777 				goto out;
4778 			}
4779 		} else if (*cp & 0x80) {
4780 			/* first byte of multi byte char */
4781 			byte = *cp;
4782 			while ((byte & 0x40) && cnt < 6) {
4783 				cnt++;
4784 				byte <<= 1;
4785 			}
4786 			if (cnt == 0 || cnt == 6) {
4787 				error = NFSERR_INVAL;
4788 				goto out;
4789 			}
4790 			val = (*cp & (0x3f >> cnt));
4791 			shift = utf8_shift[cnt - 1];
4792 			if (cnt == 2 && val == 0xd)
4793 				/* Check for the 0xd800-0xdfff case */
4794 				gotd = 1;
4795 		}
4796 		cp++;
4797 		len--;
4798 	}
4799 	if (cnt > 0)
4800 		error = NFSERR_INVAL;
4801 
4802 out:
4803 	NFSEXITCODE(error);
4804 	return (error);
4805 }
4806 
4807 /*
4808  * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
4809  * strings, one with the root path in it and the other with the list of
4810  * locations. The list is in the same format as is found in nfr_refs.
4811  * It is a "," separated list of entries, where each of them is of the
4812  * form <server>:<rootpath>. For example
4813  * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
4814  * The nilp argument is set to 1 for the special case of a null fs_root
4815  * and an empty server list.
4816  * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
4817  * number of xdr bytes parsed in sump.
4818  */
4819 static int
nfsrv_getrefstr(struct nfsrv_descript * nd,u_char ** fsrootp,u_char ** srvp,int * sump,int * nilp)4820 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
4821     int *sump, int *nilp)
4822 {
4823 	u_int32_t *tl;
4824 	u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
4825 	int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
4826 	struct list {
4827 		SLIST_ENTRY(list) next;
4828 		int len;
4829 		u_char host[1];
4830 	} *lsp, *nlsp;
4831 	SLIST_HEAD(, list) head;
4832 
4833 	*fsrootp = NULL;
4834 	*srvp = NULL;
4835 	*nilp = 0;
4836 
4837 	/*
4838 	 * Get the fs_root path and check for the special case of null path
4839 	 * and 0 length server list.
4840 	 */
4841 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4842 	len = fxdr_unsigned(int, *tl);
4843 	if (len < 0 || len > 10240) {
4844 		error = NFSERR_BADXDR;
4845 		goto nfsmout;
4846 	}
4847 	if (len == 0) {
4848 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4849 		if (*tl != 0) {
4850 			error = NFSERR_BADXDR;
4851 			goto nfsmout;
4852 		}
4853 		*nilp = 1;
4854 		*sump = 2 * NFSX_UNSIGNED;
4855 		error = 0;
4856 		goto nfsmout;
4857 	}
4858 	cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
4859 	error = nfsrv_mtostr(nd, cp, len);
4860 	if (!error) {
4861 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4862 		cnt = fxdr_unsigned(int, *tl);
4863 		if (cnt <= 0)
4864 			error = NFSERR_BADXDR;
4865 	}
4866 	if (error)
4867 		goto nfsmout;
4868 
4869 	/*
4870 	 * Now, loop through the location list and make up the srvlist.
4871 	 */
4872 	xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4873 	cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
4874 	slen = 1024;
4875 	siz = 0;
4876 	for (i = 0; i < cnt; i++) {
4877 		SLIST_INIT(&head);
4878 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4879 		nsrv = fxdr_unsigned(int, *tl);
4880 		if (nsrv <= 0) {
4881 			error = NFSERR_BADXDR;
4882 			goto nfsmout;
4883 		}
4884 
4885 		/*
4886 		 * Handle the first server by putting it in the srvstr.
4887 		 */
4888 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4889 		len = fxdr_unsigned(int, *tl);
4890 		if (len <= 0 || len > 1024) {
4891 			error = NFSERR_BADXDR;
4892 			goto nfsmout;
4893 		}
4894 		nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
4895 		if (cp3 != cp2) {
4896 			*cp3++ = ',';
4897 			siz++;
4898 		}
4899 		error = nfsrv_mtostr(nd, cp3, len);
4900 		if (error)
4901 			goto nfsmout;
4902 		cp3 += len;
4903 		*cp3++ = ':';
4904 		siz += (len + 1);
4905 		xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
4906 		for (j = 1; j < nsrv; j++) {
4907 			/*
4908 			 * Yuck, put them in an slist and process them later.
4909 			 */
4910 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4911 			len = fxdr_unsigned(int, *tl);
4912 			if (len <= 0 || len > 1024) {
4913 				error = NFSERR_BADXDR;
4914 				goto nfsmout;
4915 			}
4916 			lsp = (struct list *)malloc(sizeof (struct list)
4917 			    + len, M_TEMP, M_WAITOK);
4918 			error = nfsrv_mtostr(nd, lsp->host, len);
4919 			if (error)
4920 				goto nfsmout;
4921 			xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4922 			lsp->len = len;
4923 			SLIST_INSERT_HEAD(&head, lsp, next);
4924 		}
4925 
4926 		/*
4927 		 * Finally, we can get the path.
4928 		 */
4929 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4930 		len = fxdr_unsigned(int, *tl);
4931 		if (len <= 0 || len > 1024) {
4932 			error = NFSERR_BADXDR;
4933 			goto nfsmout;
4934 		}
4935 		nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
4936 		error = nfsrv_mtostr(nd, cp3, len);
4937 		if (error)
4938 			goto nfsmout;
4939 		xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
4940 		str = cp3;
4941 		stringlen = len;
4942 		cp3 += len;
4943 		siz += len;
4944 		SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
4945 			nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
4946 			    &cp2, &cp3, &slen);
4947 			*cp3++ = ',';
4948 			NFSBCOPY(lsp->host, cp3, lsp->len);
4949 			cp3 += lsp->len;
4950 			*cp3++ = ':';
4951 			NFSBCOPY(str, cp3, stringlen);
4952 			cp3 += stringlen;
4953 			*cp3 = '\0';
4954 			siz += (lsp->len + stringlen + 2);
4955 			free(lsp, M_TEMP);
4956 		}
4957 	}
4958 	*fsrootp = cp;
4959 	*srvp = cp2;
4960 	*sump = xdrsum;
4961 	NFSEXITCODE2(0, nd);
4962 	return (0);
4963 nfsmout:
4964 	if (cp != NULL)
4965 		free(cp, M_NFSSTRING);
4966 	if (cp2 != NULL)
4967 		free(cp2, M_NFSSTRING);
4968 	NFSEXITCODE2(error, nd);
4969 	return (error);
4970 }
4971 
4972 /*
4973  * Make the malloc'd space large enough. This is a pain, but the xdr
4974  * doesn't set an upper bound on the side, so...
4975  */
4976 static void
nfsrv_refstrbigenough(int siz,u_char ** cpp,u_char ** cpp2,int * slenp)4977 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
4978 {
4979 	u_char *cp;
4980 	int i;
4981 
4982 	if (siz <= *slenp)
4983 		return;
4984 	cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
4985 	NFSBCOPY(*cpp, cp, *slenp);
4986 	free(*cpp, M_NFSSTRING);
4987 	i = *cpp2 - *cpp;
4988 	*cpp = cp;
4989 	*cpp2 = cp + i;
4990 	*slenp = siz + 1024;
4991 }
4992 
4993 /*
4994  * Initialize the reply header data structures.
4995  */
4996 void
nfsrvd_rephead(struct nfsrv_descript * nd)4997 nfsrvd_rephead(struct nfsrv_descript *nd)
4998 {
4999 	struct mbuf *mreq;
5000 
5001 	if ((nd->nd_flag & ND_EXTPG) != 0) {
5002 		mreq = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
5003 		nd->nd_mreq = nd->nd_mb = mreq;
5004 		nd->nd_bpos = (char *)(void *)
5005 		    PHYS_TO_DMAP(mreq->m_epg_pa[0]);
5006 		nd->nd_bextpg = 0;
5007 		nd->nd_bextpgsiz = PAGE_SIZE;
5008 	} else {
5009 		/*
5010 		 * If this is a big reply, use a cluster.
5011 		 */
5012 		if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
5013 		    nfs_bigreply[nd->nd_procnum]) {
5014 			NFSMCLGET(mreq, M_WAITOK);
5015 			nd->nd_mreq = mreq;
5016 			nd->nd_mb = mreq;
5017 		} else {
5018 			NFSMGET(mreq);
5019 			nd->nd_mreq = mreq;
5020 			nd->nd_mb = mreq;
5021 		}
5022 		nd->nd_bpos = mtod(mreq, char *);
5023 		mreq->m_len = 0;
5024 	}
5025 
5026 	if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
5027 		NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
5028 }
5029 
5030 /*
5031  * Lock a socket against others.
5032  * Currently used to serialize connect/disconnect attempts.
5033  */
5034 int
newnfs_sndlock(int * flagp)5035 newnfs_sndlock(int *flagp)
5036 {
5037 	struct timespec ts;
5038 
5039 	NFSLOCKSOCK();
5040 	while (*flagp & NFSR_SNDLOCK) {
5041 		*flagp |= NFSR_WANTSND;
5042 		ts.tv_sec = 0;
5043 		ts.tv_nsec = 0;
5044 		(void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
5045 		    PVFS, "nfsndlck", &ts);
5046 	}
5047 	*flagp |= NFSR_SNDLOCK;
5048 	NFSUNLOCKSOCK();
5049 	return (0);
5050 }
5051 
5052 /*
5053  * Unlock the stream socket for others.
5054  */
5055 void
newnfs_sndunlock(int * flagp)5056 newnfs_sndunlock(int *flagp)
5057 {
5058 
5059 	NFSLOCKSOCK();
5060 	if ((*flagp & NFSR_SNDLOCK) == 0)
5061 		panic("nfs sndunlock");
5062 	*flagp &= ~NFSR_SNDLOCK;
5063 	if (*flagp & NFSR_WANTSND) {
5064 		*flagp &= ~NFSR_WANTSND;
5065 		wakeup((caddr_t)flagp);
5066 	}
5067 	NFSUNLOCKSOCK();
5068 }
5069 
5070 int
nfsv4_getipaddr(struct nfsrv_descript * nd,struct sockaddr_in * sin,struct sockaddr_in6 * sin6,sa_family_t * saf,int * isudp)5071 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
5072     struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
5073 {
5074 	struct in_addr saddr;
5075 	uint32_t portnum, *tl;
5076 	int i, j, k;
5077 	sa_family_t af = AF_UNSPEC;
5078 	char addr[64], protocol[5], *cp;
5079 	int cantparse = 0, error = 0;
5080 	uint16_t portv;
5081 
5082 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
5083 	i = fxdr_unsigned(int, *tl);
5084 	if (i >= 3 && i <= 4) {
5085 		error = nfsrv_mtostr(nd, protocol, i);
5086 		if (error)
5087 			goto nfsmout;
5088 		if (strcmp(protocol, "tcp") == 0) {
5089 			af = AF_INET;
5090 			*isudp = 0;
5091 		} else if (strcmp(protocol, "udp") == 0) {
5092 			af = AF_INET;
5093 			*isudp = 1;
5094 		} else if (strcmp(protocol, "tcp6") == 0) {
5095 			af = AF_INET6;
5096 			*isudp = 0;
5097 		} else if (strcmp(protocol, "udp6") == 0) {
5098 			af = AF_INET6;
5099 			*isudp = 1;
5100 		} else
5101 			cantparse = 1;
5102 	} else {
5103 		cantparse = 1;
5104 		if (i > 0) {
5105 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
5106 			if (error)
5107 				goto nfsmout;
5108 		}
5109 	}
5110 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
5111 	i = fxdr_unsigned(int, *tl);
5112 	if (i < 0) {
5113 		error = NFSERR_BADXDR;
5114 		goto nfsmout;
5115 	} else if (cantparse == 0 && i >= 11 && i < 64) {
5116 		/*
5117 		 * The shortest address is 11chars and the longest is < 64.
5118 		 */
5119 		error = nfsrv_mtostr(nd, addr, i);
5120 		if (error)
5121 			goto nfsmout;
5122 
5123 		/* Find the port# at the end and extract that. */
5124 		i = strlen(addr);
5125 		k = 0;
5126 		cp = &addr[i - 1];
5127 		/* Count back two '.'s from end to get port# field. */
5128 		for (j = 0; j < i; j++) {
5129 			if (*cp == '.') {
5130 				k++;
5131 				if (k == 2)
5132 					break;
5133 			}
5134 			cp--;
5135 		}
5136 		if (k == 2) {
5137 			/*
5138 			 * The NFSv4 port# is appended as .N.N, where N is
5139 			 * a decimal # in the range 0-255, just like an inet4
5140 			 * address. Cheat and use inet_aton(), which will
5141 			 * return a Class A address and then shift the high
5142 			 * order 8bits over to convert it to the port#.
5143 			 */
5144 			*cp++ = '\0';
5145 			if (inet_aton(cp, &saddr) == 1) {
5146 				portnum = ntohl(saddr.s_addr);
5147 				portv = (uint16_t)((portnum >> 16) |
5148 				    (portnum & 0xff));
5149 			} else
5150 				cantparse = 1;
5151 		} else
5152 			cantparse = 1;
5153 		if (cantparse == 0) {
5154 			if (af == AF_INET) {
5155 				if (inet_pton(af, addr, &sin->sin_addr) == 1) {
5156 					sin->sin_len = sizeof(*sin);
5157 					sin->sin_family = AF_INET;
5158 					sin->sin_port = htons(portv);
5159 					*saf = af;
5160 					return (0);
5161 				}
5162 			} else {
5163 				if (inet_pton(af, addr, &sin6->sin6_addr)
5164 				    == 1) {
5165 					sin6->sin6_len = sizeof(*sin6);
5166 					sin6->sin6_family = AF_INET6;
5167 					sin6->sin6_port = htons(portv);
5168 					*saf = af;
5169 					return (0);
5170 				}
5171 			}
5172 		}
5173 	} else {
5174 		if (i > 0) {
5175 			error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
5176 			if (error)
5177 				goto nfsmout;
5178 		}
5179 	}
5180 	error = EPERM;
5181 nfsmout:
5182 	return (error);
5183 }
5184 
5185 /*
5186  * Handle an NFSv4.1 Sequence request for the session.
5187  * If reply != NULL, use it to return the cached reply, as required.
5188  * The client gets a cached reply via this call for callbacks, however the
5189  * server gets a cached reply via the nfsv4_seqsess_cacherep() call.
5190  */
5191 int
nfsv4_seqsession(uint32_t seqid,uint32_t slotid,uint32_t highslot,struct nfsslot * slots,struct mbuf ** reply,uint16_t maxslot)5192 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
5193     struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
5194 {
5195 	struct mbuf *m;
5196 	int error;
5197 
5198 	error = 0;
5199 	if (reply != NULL)
5200 		*reply = NULL;
5201 	if (slotid > maxslot)
5202 		return (NFSERR_BADSLOT);
5203 	if (seqid == slots[slotid].nfssl_seq) {
5204 		/* A retry. */
5205 		if (slots[slotid].nfssl_inprog != 0)
5206 			error = NFSERR_DELAY;
5207 		else if (slots[slotid].nfssl_reply != NULL) {
5208 			if (reply != NULL) {
5209 				m = m_copym(slots[slotid].nfssl_reply, 0,
5210 				    M_COPYALL, M_NOWAIT);
5211 				if (m != NULL)
5212 					*reply = m;
5213 				else {
5214 					*reply = slots[slotid].nfssl_reply;
5215 					slots[slotid].nfssl_reply = NULL;
5216 				}
5217 			}
5218 			slots[slotid].nfssl_inprog = 1;
5219 			error = NFSERR_REPLYFROMCACHE;
5220 		} else
5221 			/* No reply cached, so just do it. */
5222 			slots[slotid].nfssl_inprog = 1;
5223 	} else if ((slots[slotid].nfssl_seq + 1) == seqid) {
5224 		if (slots[slotid].nfssl_reply != NULL)
5225 			m_freem(slots[slotid].nfssl_reply);
5226 		slots[slotid].nfssl_reply = NULL;
5227 		slots[slotid].nfssl_inprog = 1;
5228 		slots[slotid].nfssl_seq++;
5229 	} else
5230 		error = NFSERR_SEQMISORDERED;
5231 	return (error);
5232 }
5233 
5234 /*
5235  * Cache this reply for the slot.
5236  * Use the "rep" argument to return the cached reply if repstat is set to
5237  * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
5238  */
5239 void
nfsv4_seqsess_cacherep(uint32_t slotid,struct nfsslot * slots,int repstat,struct mbuf ** rep)5240 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
5241    struct mbuf **rep)
5242 {
5243 	struct mbuf *m;
5244 
5245 	if (repstat == NFSERR_REPLYFROMCACHE) {
5246 		if (slots[slotid].nfssl_reply != NULL) {
5247 			/*
5248 			 * We cannot sleep here, but copy will usually
5249 			 * succeed.
5250 			 */
5251 			m = m_copym(slots[slotid].nfssl_reply, 0, M_COPYALL,
5252 			    M_NOWAIT);
5253 			if (m != NULL)
5254 				*rep = m;
5255 			else {
5256 				/*
5257 				 * Multiple retries would be extremely rare,
5258 				 * so using the cached reply will likely
5259 				 * be ok.
5260 				 */
5261 				*rep = slots[slotid].nfssl_reply;
5262 				slots[slotid].nfssl_reply = NULL;
5263 			}
5264 		} else
5265 			*rep = NULL;
5266 	} else {
5267 		if (slots[slotid].nfssl_reply != NULL)
5268 			m_freem(slots[slotid].nfssl_reply);
5269 		slots[slotid].nfssl_reply = *rep;
5270 	}
5271 	slots[slotid].nfssl_inprog = 0;
5272 }
5273 
5274 /*
5275  * Generate the xdr for an NFSv4.1 Sequence Operation.
5276  */
5277 static void
nfsv4_setsequence(struct nfsmount * nmp,struct nfsrv_descript * nd,struct nfsclsession * sep,bool dont_replycache,struct ucred * cred)5278 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
5279     struct nfsclsession *sep, bool dont_replycache, struct ucred *cred)
5280 {
5281 	uint32_t *tl, slotseq = 0;
5282 	int error, maxslot, slotpos;
5283 	uint8_t sessionid[NFSX_V4SESSIONID];
5284 
5285 	if (cred != NULL) {
5286 		error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot,
5287 		    &slotseq, sessionid, false);
5288 		if (error == NFSERR_SEQMISORDERED) {
5289 			/* If all slots are bad, Destroy the session. */
5290 			nfsrpc_destroysession(nmp, sep, cred, curthread);
5291 		}
5292 	} else
5293 		error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot,
5294 		    &slotseq, sessionid, true);
5295 	nd->nd_maxreq = sep->nfsess_maxreq;
5296 	nd->nd_maxresp = sep->nfsess_maxresp;
5297 
5298 	/* Build the Sequence arguments. */
5299 	NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
5300 	nd->nd_sequence = tl;
5301 	bcopy(sessionid, tl, NFSX_V4SESSIONID);
5302 	tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
5303 	nd->nd_slotseq = tl;
5304 	if (error == 0) {
5305 		nd->nd_flag |= ND_HASSLOTID;
5306 		nd->nd_slotid = slotpos;
5307 		*tl++ = txdr_unsigned(slotseq);
5308 		*tl++ = txdr_unsigned(slotpos);
5309 		*tl++ = txdr_unsigned(maxslot);
5310 		if (!dont_replycache)
5311 			*tl = newnfs_true;
5312 		else
5313 			*tl = newnfs_false;
5314 	} else {
5315 		/*
5316 		 * There are two errors and the rest of the session can
5317 		 * just be zeros.
5318 		 * NFSERR_BADSESSION: This bad session should just generate
5319 		 *    the same error again when the RPC is retried.
5320 		 * ESTALE: A forced dismount is in progress and will cause the
5321 		 *    RPC to fail later.
5322 		 */
5323 		*tl++ = 0;
5324 		*tl++ = 0;
5325 		*tl++ = 0;
5326 		*tl = 0;
5327 	}
5328 	nd->nd_flag |= ND_HASSEQUENCE;
5329 }
5330 
5331 /*
5332  * If fnd_init is true, ignore the badslots.
5333  * If fnd_init is false, return NFSERR_SEQMISORDERED if all slots are bad.
5334  */
5335 int
nfsv4_sequencelookup(struct nfsmount * nmp,struct nfsclsession * sep,int * slotposp,int * maxslotp,uint32_t * slotseqp,uint8_t * sessionid,bool fnd_init)5336 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
5337     int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid,
5338     bool fnd_init)
5339 {
5340 	int i, maxslot, slotpos;
5341 	uint64_t bitval;
5342 	bool fnd_ok;
5343 
5344 	/* Find an unused slot. */
5345 	slotpos = -1;
5346 	maxslot = -1;
5347 	mtx_lock(&sep->nfsess_mtx);
5348 	do {
5349 		if (nmp != NULL && sep->nfsess_defunct != 0) {
5350 			/* Just return the bad session. */
5351 			bcopy(sep->nfsess_sessionid, sessionid,
5352 			    NFSX_V4SESSIONID);
5353 			mtx_unlock(&sep->nfsess_mtx);
5354 			return (NFSERR_BADSESSION);
5355 		}
5356 		fnd_ok = fnd_init;
5357 		bitval = 1;
5358 		for (i = 0; i < sep->nfsess_foreslots; i++) {
5359 			if ((bitval & sep->nfsess_badslots) == 0 || fnd_init) {
5360 				fnd_ok = true;
5361 				if ((bitval & sep->nfsess_slots) == 0) {
5362 					slotpos = i;
5363 					sep->nfsess_slots |= bitval;
5364 					sep->nfsess_slotseq[i]++;
5365 					*slotseqp = sep->nfsess_slotseq[i];
5366 					break;
5367 				}
5368 			}
5369 			bitval <<= 1;
5370 		}
5371 		if (slotpos == -1) {
5372 			/*
5373 			 * If a forced dismount is in progress, just return.
5374 			 * This RPC attempt will fail when it calls
5375 			 * newnfs_request().
5376 			 */
5377 			if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
5378 				mtx_unlock(&sep->nfsess_mtx);
5379 				return (ESTALE);
5380 			}
5381 			/* Wake up once/sec, to check for a forced dismount. */
5382 			if (fnd_ok)
5383 				mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
5384 				    PZERO, "nfsclseq", hz);
5385 		}
5386 	} while (slotpos == -1 && fnd_ok);
5387 	/*
5388 	 * If all slots are bad, just return slot 0 and NFSERR_SEQMISORDERED.
5389 	 * The caller will do a DestroySession, so that the session's use
5390 	 * will get a NFSERR_BADSESSION reply from the server.
5391 	 */
5392 	if (!fnd_ok)
5393 		slotpos = 0;
5394 
5395 	/* Now, find the highest slot in use. (nfsc_slots is 64bits) */
5396 	bitval = 1;
5397 	for (i = 0; i < 64; i++) {
5398 		if ((bitval & sep->nfsess_slots) != 0)
5399 			maxslot = i;
5400 		bitval <<= 1;
5401 	}
5402 	bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
5403 	mtx_unlock(&sep->nfsess_mtx);
5404 	*slotposp = slotpos;
5405 	*maxslotp = maxslot;
5406 
5407 	if (!fnd_ok)
5408 		return (NFSERR_SEQMISORDERED);
5409 	return (0);
5410 }
5411 
5412 /*
5413  * Free a session slot.
5414  */
5415 void
nfsv4_freeslot(struct nfsclsession * sep,int slot,bool resetseq)5416 nfsv4_freeslot(struct nfsclsession *sep, int slot, bool resetseq)
5417 {
5418 	uint64_t bitval;
5419 
5420 	bitval = 1;
5421 	if (slot > 0)
5422 		bitval <<= slot;
5423 	mtx_lock(&sep->nfsess_mtx);
5424 	if (resetseq)
5425 		sep->nfsess_slotseq[slot]--;
5426 	else if (slot > sep->nfsess_foreslots)
5427 		sep->nfsess_slotseq[slot] = 0;
5428 	if ((bitval & sep->nfsess_slots) == 0)
5429 		printf("freeing free slot!!\n");
5430 	sep->nfsess_slots &= ~bitval;
5431 	wakeup(&sep->nfsess_slots);
5432 	mtx_unlock(&sep->nfsess_mtx);
5433 }
5434 
5435 /*
5436  * Search for a matching pnfsd DS, based on the nmp arg.
5437  * Return one if found, NULL otherwise.
5438  */
5439 struct nfsdevice *
nfsv4_findmirror(struct nfsmount * nmp)5440 nfsv4_findmirror(struct nfsmount *nmp)
5441 {
5442 	struct nfsdevice *ds;
5443 
5444 	mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
5445 	/*
5446 	 * Search the DS server list for a match with nmp.
5447 	 */
5448 	if (nfsrv_devidcnt == 0)
5449 		return (NULL);
5450 	TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
5451 		if (ds->nfsdev_nmp == nmp) {
5452 			NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");
5453 			break;
5454 		}
5455 	}
5456 	return (ds);
5457 }
5458 
5459 /*
5460  * Fill in the fields of "struct nfsrv_descript".
5461  */
5462 void
nfsm_set(struct nfsrv_descript * nd,u_int offs)5463 nfsm_set(struct nfsrv_descript *nd, u_int offs)
5464 {
5465 	struct mbuf *m;
5466 	int rlen;
5467 
5468 	m = nd->nd_mb;
5469 	if ((m->m_flags & M_EXTPG) != 0) {
5470 		nd->nd_bextpg = 0;
5471 		while (offs > 0) {
5472 			if (nd->nd_bextpg == 0)
5473 				rlen = m_epg_pagelen(m, 0, m->m_epg_1st_off);
5474 			else
5475 				rlen = m_epg_pagelen(m, nd->nd_bextpg, 0);
5476 			if (offs <= rlen)
5477 				break;
5478 			offs -= rlen;
5479 			nd->nd_bextpg++;
5480 			if (nd->nd_bextpg == m->m_epg_npgs) {
5481 				printf("nfsm_set: build offs "
5482 				    "out of range\n");
5483 				nd->nd_bextpg--;
5484 				break;
5485 			}
5486 		}
5487 		nd->nd_bpos = (char *)(void *)
5488 		    PHYS_TO_DMAP(m->m_epg_pa[nd->nd_bextpg]);
5489 		if (nd->nd_bextpg == 0)
5490 			nd->nd_bpos += m->m_epg_1st_off;
5491 		if (offs > 0) {
5492 			nd->nd_bpos += offs;
5493 			nd->nd_bextpgsiz = rlen - offs;
5494 		} else if (nd->nd_bextpg == 0)
5495 			nd->nd_bextpgsiz = PAGE_SIZE - m->m_epg_1st_off;
5496 		else
5497 			nd->nd_bextpgsiz = PAGE_SIZE;
5498 	} else
5499 		nd->nd_bpos = mtod(m, char *) + offs;
5500 }
5501 
5502 /*
5503  * Grow a ext_pgs mbuf list.  Either allocate another page or add
5504  * an mbuf to the list.
5505  */
5506 struct mbuf *
nfsm_add_ext_pgs(struct mbuf * m,int maxextsiz,int * bextpg)5507 nfsm_add_ext_pgs(struct mbuf *m, int maxextsiz, int *bextpg)
5508 {
5509 	struct mbuf *mp;
5510 	vm_page_t pg;
5511 
5512 	if ((m->m_epg_npgs + 1) * PAGE_SIZE > maxextsiz) {
5513 		mp = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
5514 		*bextpg = 0;
5515 		m->m_next = mp;
5516 	} else {
5517 		pg = vm_page_alloc_noobj(VM_ALLOC_WAITOK | VM_ALLOC_NODUMP |
5518 		    VM_ALLOC_WIRED);
5519 		m->m_epg_pa[m->m_epg_npgs] = VM_PAGE_TO_PHYS(pg);
5520 		*bextpg = m->m_epg_npgs;
5521 		m->m_epg_npgs++;
5522 		m->m_epg_last_len = 0;
5523 		mp = m;
5524 	}
5525 	return (mp);
5526 }
5527 
5528 /*
5529  * Do the NFSv4.1 Destroy Session.
5530  */
5531 int
nfsrpc_destroysession(struct nfsmount * nmp,struct nfsclsession * tsep,struct ucred * cred,NFSPROC_T * p)5532 nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclsession *tsep,
5533     struct ucred *cred, NFSPROC_T *p)
5534 {
5535 	uint32_t *tl;
5536 	struct nfsrv_descript nfsd;
5537 	struct nfsrv_descript *nd = &nfsd;
5538 	int error;
5539 
5540 	if (tsep == NULL)
5541 		tsep = nfsmnt_mdssession(nmp);
5542 	if (tsep == NULL)
5543 		return (0);
5544 	nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL, 0,
5545 	    0, NULL);
5546 	NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
5547 	bcopy(tsep->nfsess_sessionid, tl, NFSX_V4SESSIONID);
5548 	nd->nd_flag |= ND_USEGSSNAME;
5549 	error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
5550 	    NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
5551 	if (error != 0)
5552 		return (error);
5553 	error = nd->nd_repstat;
5554 	m_freem(nd->nd_mrep);
5555 	return (error);
5556 }
5557 
5558 /*
5559  * Determine the true form (the type of ACL stored on the file) for the
5560  * vnode argument.
5561  */
5562 static uint32_t
nfs_trueform(struct vnode * vp)5563 nfs_trueform(struct vnode *vp)
5564 {
5565 	uint32_t trueform;
5566 
5567 	trueform = NFSV4_ACL_MODEL_NONE;
5568 	if ((vp->v_mount->mnt_flag & MNT_NFS4ACLS) != 0)
5569 		trueform = NFSV4_ACL_MODEL_NFS4;
5570 	else if ((vp->v_mount->mnt_flag & MNT_ACLS) != 0)
5571 		trueform = NFSV4_ACL_MODEL_POSIX_DRAFT;
5572 	return (trueform);
5573 }
5574 
5575 /*
5576  * Translate a vnode type into an NFSv4 type, including the named
5577  * attribute types.
5578  */
5579 static uint32_t
vtonfsv4_type(struct vattr * vap)5580 vtonfsv4_type(struct vattr *vap)
5581 {
5582 	nfstype ntyp;
5583 
5584 	if (vap->va_type >= 9)
5585 		ntyp = NFNON;
5586 	else
5587 		ntyp = nfsv34_type[vap->va_type];
5588 	if ((vap->va_bsdflags & SFBSD_NAMEDATTR) != 0) {
5589 		if (ntyp == NFDIR)
5590 			ntyp = NFATTRDIR;
5591 		else if (ntyp == NFREG)
5592 			ntyp = NFNAMEDATTR;
5593 	}
5594 	return (txdr_unsigned((uint32_t)ntyp));
5595 }
5596 
5597 /*
5598  * Translate an NFS type to a vnode type.
5599  */
5600 static __enum_uint8(vtype)
nfsv4tov_type(uint32_t ntyp,uint16_t * bsdflags)5601 nfsv4tov_type(uint32_t ntyp, uint16_t *bsdflags)
5602 {
5603 	__enum_uint8(vtype) vtyp;
5604 
5605 	ntyp = fxdr_unsigned(uint32_t, ntyp) % (NFNAMEDATTR + 1);
5606 	if (ntyp == NFATTRDIR) {
5607 		vtyp = VDIR;
5608 		*bsdflags |= SFBSD_NAMEDATTR;
5609 	} else if (ntyp == NFNAMEDATTR) {
5610 		vtyp = VREG;
5611 		*bsdflags |= SFBSD_NAMEDATTR;
5612 	} else {
5613 		vtyp = nv34tov_type[ntyp];
5614 	}
5615 	return (vtyp);
5616 }
5617