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