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