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