xref: /freebsd/sys/fs/nfsserver/nfs_nfsdserv.c (revision cce64f2e68511652a0edc3e3482d801115e91b43)
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 #include "opt_inet.h"
38 #include "opt_inet6.h"
39 /*
40  * nfs version 2, 3 and 4 server calls to vnode ops
41  * - these routines generally have 3 phases
42  *   1 - break down and validate rpc request in mbuf list
43  *   2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
44  *       function in nfsd_port.c
45  *   3 - build the rpc reply in an mbuf list
46  * For nfsv4, these functions are called for each Op within the Compound RPC.
47  */
48 
49 #include <fs/nfs/nfsport.h>
50 #include <sys/extattr.h>
51 #include <sys/filio.h>
52 
53 /* Global vars */
54 extern u_int32_t newnfs_false, newnfs_true;
55 extern __enum_uint8(vtype) nv34tov_type[8];
56 extern struct timeval nfsboottime;
57 extern int nfsrv_enable_crossmntpt;
58 extern int nfsrv_statehashsize;
59 extern int nfsrv_layouthashsize;
60 extern time_t nfsdev_time;
61 extern volatile int nfsrv_devidcnt;
62 extern int nfsd_debuglevel;
63 extern u_long sb_max_adj;
64 extern int nfsrv_pnfsatime;
65 extern int nfsrv_maxpnfsmirror;
66 extern uint32_t nfs_srvmaxio;
67 extern int nfsrv_issuedelegs;
68 
69 static int	nfs_async = 0;
70 SYSCTL_DECL(_vfs_nfsd);
71 SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
72     "Tell client that writes were synced even though they were not");
73 extern int	nfsrv_doflexfile;
74 SYSCTL_INT(_vfs_nfsd, OID_AUTO, default_flexfile, CTLFLAG_RW,
75     &nfsrv_doflexfile, 0, "Make Flex File Layout the default for pNFS");
76 static int	nfsrv_linux42server = 1;
77 SYSCTL_INT(_vfs_nfsd, OID_AUTO, linux42server, CTLFLAG_RW,
78     &nfsrv_linux42server, 0,
79     "Enable Linux style NFSv4.2 server (non-RFC compliant)");
80 static bool	nfsrv_openaccess = true;
81 SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, v4openaccess, CTLFLAG_RW,
82     &nfsrv_openaccess, 0,
83     "Enable Linux style NFSv4 Open access check");
84 static char nfsrv_scope[NFSV4_OPAQUELIMIT];
85 SYSCTL_STRING(_vfs_nfsd, OID_AUTO, scope, CTLFLAG_RWTUN,
86     &nfsrv_scope, NFSV4_OPAQUELIMIT, "Server scope");
87 static char nfsrv_owner_major[NFSV4_OPAQUELIMIT];
88 SYSCTL_STRING(_vfs_nfsd, OID_AUTO, owner_major, CTLFLAG_RWTUN,
89     &nfsrv_owner_major, NFSV4_OPAQUELIMIT, "Server owner major");
90 static uint64_t nfsrv_owner_minor;
91 SYSCTL_U64(_vfs_nfsd, OID_AUTO, owner_minor, CTLFLAG_RWTUN,
92     &nfsrv_owner_minor, 0, "Server owner minor");
93 /*
94  * Only enable this if all your exported file systems
95  * (or pNFS DSs for the pNFS case) support VOP_ALLOCATE.
96  */
97 static bool	nfsrv_doallocate = false;
98 SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, enable_v42allocate, CTLFLAG_RW,
99     &nfsrv_doallocate, 0,
100     "Enable NFSv4.2 Allocate operation");
101 static uint64_t nfsrv_maxcopyrange = SSIZE_MAX;
102 SYSCTL_U64(_vfs_nfsd, OID_AUTO, maxcopyrange, CTLFLAG_RW,
103     &nfsrv_maxcopyrange, 0, "Max size of a Copy so RPC times reasonable");
104 
105 /*
106  * This list defines the GSS mechanisms supported.
107  * (Don't ask me how you get these strings from the RFC stuff like
108  *  iso(1), org(3)... but someone did it, so I don't need to know.)
109  */
110 static struct nfsgss_mechlist nfsgss_mechlist[] = {
111 	{ 9, "\052\206\110\206\367\022\001\002\002", 11 },
112 	{ 0, "", 0 },
113 };
114 
115 /* local functions */
116 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
117     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
118     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
119     int *diraft_retp, nfsattrbit_t *attrbitp,
120     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
121     int pathlen);
122 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
123     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
124     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
125     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
126     NFSPROC_T *p, struct nfsexstuff *exp);
127 
128 /*
129  * nfs access service (not a part of NFS V2)
130  */
131 int
nfsrvd_access(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)132 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
133     vnode_t vp, struct nfsexstuff *exp)
134 {
135 	u_int32_t *tl;
136 	int getret, error = 0;
137 	struct nfsvattr nva;
138 	u_int32_t testmode, nfsmode, supported = 0;
139 	accmode_t deletebit;
140 	struct thread *p = curthread;
141 
142 	if (nd->nd_repstat) {
143 		nfsrv_postopattr(nd, 1, &nva);
144 		goto out;
145 	}
146 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
147 	nfsmode = fxdr_unsigned(u_int32_t, *tl);
148 	if ((nd->nd_flag & ND_NFSV4) &&
149 	    (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
150 	     NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
151 	     NFSACCESS_EXECUTE | NFSACCESS_XAREAD | NFSACCESS_XAWRITE |
152 	     NFSACCESS_XALIST))) {
153 		nd->nd_repstat = NFSERR_INVAL;
154 		vput(vp);
155 		goto out;
156 	}
157 	if (nfsmode & NFSACCESS_READ) {
158 		supported |= NFSACCESS_READ;
159 		if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
160 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
161 			nfsmode &= ~NFSACCESS_READ;
162 	}
163 	if (nfsmode & NFSACCESS_MODIFY) {
164 		supported |= NFSACCESS_MODIFY;
165 		if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
166 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
167 			nfsmode &= ~NFSACCESS_MODIFY;
168 	}
169 	if (nfsmode & NFSACCESS_EXTEND) {
170 		supported |= NFSACCESS_EXTEND;
171 		if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
172 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
173 			nfsmode &= ~NFSACCESS_EXTEND;
174 	}
175 	if (nfsmode & NFSACCESS_XAREAD) {
176 		supported |= NFSACCESS_XAREAD;
177 		if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
178 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
179 			nfsmode &= ~NFSACCESS_XAREAD;
180 	}
181 	if (nfsmode & NFSACCESS_XAWRITE) {
182 		supported |= NFSACCESS_XAWRITE;
183 		if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
184 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
185 			nfsmode &= ~NFSACCESS_XAWRITE;
186 	}
187 	if (nfsmode & NFSACCESS_XALIST) {
188 		supported |= NFSACCESS_XALIST;
189 		if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
190 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
191 			nfsmode &= ~NFSACCESS_XALIST;
192 	}
193 	if (nfsmode & NFSACCESS_DELETE) {
194 		supported |= NFSACCESS_DELETE;
195 		if (vp->v_type == VDIR)
196 			deletebit = VDELETE_CHILD;
197 		else
198 			deletebit = VDELETE;
199 		if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
200 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
201 			nfsmode &= ~NFSACCESS_DELETE;
202 	}
203 	if (vp->v_type == VDIR)
204 		testmode = NFSACCESS_LOOKUP;
205 	else
206 		testmode = NFSACCESS_EXECUTE;
207 	if (nfsmode & testmode) {
208 		supported |= (nfsmode & testmode);
209 		if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
210 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
211 			nfsmode &= ~testmode;
212 	}
213 	nfsmode &= supported;
214 	if (nd->nd_flag & ND_NFSV3) {
215 		getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
216 		nfsrv_postopattr(nd, getret, &nva);
217 	}
218 	vput(vp);
219 	if (nd->nd_flag & ND_NFSV4) {
220 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
221 		*tl++ = txdr_unsigned(supported);
222 	} else
223 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
224 	*tl = txdr_unsigned(nfsmode);
225 
226 out:
227 	NFSEXITCODE2(0, nd);
228 	return (0);
229 nfsmout:
230 	vput(vp);
231 	NFSEXITCODE2(error, nd);
232 	return (error);
233 }
234 
235 /*
236  * nfs getattr service
237  */
238 int
nfsrvd_getattr(struct nfsrv_descript * nd,int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)239 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
240     vnode_t vp, __unused struct nfsexstuff *exp)
241 {
242 	struct nfsvattr nva;
243 	fhandle_t fh;
244 	int at_root = 0, error = 0, ret, supports_nfsv4acls;
245 	struct nfsreferral *refp;
246 	nfsattrbit_t attrbits, tmpbits;
247 	struct mount *mp;
248 	struct vnode *tvp = NULL;
249 	struct vattr va;
250 	uint64_t mounted_on_fileno = 0;
251 	accmode_t accmode;
252 	struct thread *p = curthread;
253 	size_t atsiz;
254 	long pathval;
255 	bool has_hiddensystem, has_namedattr, xattrsupp;
256 	uint32_t clone_blksize;
257 
258 	if (nd->nd_repstat)
259 		goto out;
260 	if (nd->nd_flag & ND_NFSV4) {
261 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
262 		if (error) {
263 			vput(vp);
264 			goto out;
265 		}
266 
267 		/*
268 		 * Check for a referral.
269 		 */
270 		refp = nfsv4root_getreferral(vp, NULL, 0);
271 		if (refp != NULL) {
272 			(void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
273 			    &nd->nd_repstat);
274 			vput(vp);
275 			goto out;
276 		}
277 		if (nd->nd_repstat == 0) {
278 			accmode = 0;
279 			NFSSET_ATTRBIT(&tmpbits, &attrbits);
280 
281 			/*
282 			 * GETATTR with write-only attr time_access_set and time_modify_set
283 			 * should return NFS4ERR_INVAL.
284 			 */
285 			if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) ||
286 					NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){
287 				error = NFSERR_INVAL;
288 				vput(vp);
289 				goto out;
290 			}
291 			if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
292 				NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
293 				accmode |= VREAD_ACL;
294 			}
295 			if (NFSNONZERO_ATTRBIT(&tmpbits))
296 				accmode |= VREAD_ATTRIBUTES;
297 			if (accmode != 0)
298 				nd->nd_repstat = nfsvno_accchk(vp, accmode,
299 				    nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
300 				    NFSACCCHK_VPISLOCKED, NULL);
301 		}
302 	}
303 	if (!nd->nd_repstat)
304 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
305 	if (!nd->nd_repstat) {
306 		if (nd->nd_flag & ND_NFSV4) {
307 			if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
308 				nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
309 			if (!nd->nd_repstat)
310 				nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
311 				    &nva, &attrbits, p);
312 			if (nd->nd_repstat == 0) {
313 				supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
314 				xattrsupp = false;
315 				if (NFSISSET_ATTRBIT(&attrbits,
316 				    NFSATTRBIT_XATTRSUPPORT)) {
317 					ret = VOP_GETEXTATTR(vp,
318 					    EXTATTR_NAMESPACE_USER,
319 					    "xxx", NULL, &atsiz, nd->nd_cred,
320 					    p);
321 					xattrsupp = ret != EOPNOTSUPP;
322 				}
323 				if (VOP_PATHCONF(vp, _PC_HAS_HIDDENSYSTEM,
324 				    &pathval) != 0)
325 					pathval = 0;
326 				has_hiddensystem = pathval > 0;
327 				pathval = 0;
328 				if (NFSISSET_ATTRBIT(&attrbits,
329 				    NFSATTRBIT_NAMEDATTR) &&
330 				    VOP_PATHCONF(vp, _PC_HAS_NAMEDATTR,
331 				    &pathval) != 0)
332 					pathval = 0;
333 				has_namedattr = pathval > 0;
334 				pathval = 0;
335 				if (VOP_PATHCONF(vp, _PC_CLONE_BLKSIZE,
336 				    &pathval) != 0)
337 					pathval = 0;
338 				clone_blksize = pathval;
339 				mp = vp->v_mount;
340 				if (nfsrv_enable_crossmntpt != 0 &&
341 				    vp->v_type == VDIR &&
342 				    (vp->v_vflag & VV_ROOT) != 0 &&
343 				    vp != rootvnode) {
344 					tvp = mp->mnt_vnodecovered;
345 					VREF(tvp);
346 					at_root = 1;
347 				} else
348 					at_root = 0;
349 				vfs_ref(mp);
350 				NFSVOPUNLOCK(vp);
351 				if (at_root != 0) {
352 					if ((nd->nd_repstat =
353 					     NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
354 						nd->nd_repstat = VOP_GETATTR(
355 						    tvp, &va, nd->nd_cred);
356 						vput(tvp);
357 					} else
358 						vrele(tvp);
359 					if (nd->nd_repstat == 0)
360 						mounted_on_fileno = (uint64_t)
361 						    va.va_fileid;
362 					else
363 						at_root = 0;
364 				}
365 				if (nd->nd_repstat == 0)
366 					nd->nd_repstat = vfs_busy(mp, 0);
367 				vfs_rel(mp);
368 				if (nd->nd_repstat == 0) {
369 					(void)nfsvno_fillattr(nd, mp, vp, &nva,
370 					    &fh, 0, &attrbits, nd->nd_cred, p,
371 					    isdgram, 1, supports_nfsv4acls,
372 					    at_root, mounted_on_fileno,
373 					    xattrsupp, has_hiddensystem,
374 					    has_namedattr, clone_blksize);
375 					vfs_unbusy(mp);
376 				}
377 				vrele(vp);
378 			} else
379 				vput(vp);
380 		} else {
381 			nfsrv_fillattr(nd, &nva);
382 			vput(vp);
383 		}
384 	} else {
385 		vput(vp);
386 	}
387 
388 out:
389 	NFSEXITCODE2(error, nd);
390 	return (error);
391 }
392 
393 /*
394  * nfs setattr service
395  */
396 int
nfsrvd_setattr(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)397 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
398     vnode_t vp, struct nfsexstuff *exp)
399 {
400 	struct nfsvattr nva, nva2;
401 	u_int32_t *tl;
402 	int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
403 	int gotproxystateid;
404 	struct timespec guard = { 0, 0 };
405 	nfsattrbit_t attrbits, retbits;
406 	nfsv4stateid_t stateid;
407 	NFSACL_T *aclp = NULL;
408 	struct thread *p = curthread;
409 
410 	NFSZERO_ATTRBIT(&retbits);
411 	if (nd->nd_repstat) {
412 		nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
413 		goto out;
414 	}
415 #ifdef NFS4_ACL_EXTATTR_NAME
416 	aclp = acl_alloc(M_WAITOK);
417 	aclp->acl_cnt = 0;
418 #endif
419 	gotproxystateid = 0;
420 	NFSVNO_ATTRINIT(&nva);
421 	if (nd->nd_flag & ND_NFSV4) {
422 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
423 		stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
424 		stateid.other[0] = *tl++;
425 		stateid.other[1] = *tl++;
426 		stateid.other[2] = *tl;
427 		if (stateid.other[0] == 0x55555555 &&
428 		    stateid.other[1] == 0x55555555 &&
429 		    stateid.other[2] == 0x55555555 &&
430 		    stateid.seqid == 0xffffffff)
431 			gotproxystateid = 1;
432 	}
433 	error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p);
434 	if (error)
435 		goto nfsmout;
436 
437 	/* For NFSv4, only va_uid and va_flags is used from nva2. */
438 	NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
439 	NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_HIDDEN);
440 	NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SYSTEM);
441 	preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits);
442 	if (!nd->nd_repstat)
443 		nd->nd_repstat = preat_ret;
444 
445 	NFSZERO_ATTRBIT(&retbits);
446 	if (nd->nd_flag & ND_NFSV3) {
447 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
448 		gcheck = fxdr_unsigned(int, *tl);
449 		if (gcheck) {
450 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
451 			fxdr_nfsv3time(tl, &guard);
452 		}
453 		if (!nd->nd_repstat && gcheck &&
454 		    (nva2.na_ctime.tv_sec != guard.tv_sec ||
455 		     nva2.na_ctime.tv_nsec != guard.tv_nsec))
456 			nd->nd_repstat = NFSERR_NOT_SYNC;
457 		if (nd->nd_repstat) {
458 			vput(vp);
459 #ifdef NFS4_ACL_EXTATTR_NAME
460 			acl_free(aclp);
461 #endif
462 			nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
463 			goto out;
464 		}
465 	} else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
466 		nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
467 
468 	/*
469 	 * Now that we have all the fields, lets do it.
470 	 * If the size is being changed write access is required, otherwise
471 	 * just check for a read only file system.
472 	 */
473 	if (!nd->nd_repstat) {
474 		if (NFSVNO_NOTSETSIZE(&nva)) {
475 			if (NFSVNO_EXRDONLY(exp) ||
476 			    (vp->v_mount->mnt_flag & MNT_RDONLY))
477 				nd->nd_repstat = EROFS;
478 		} else {
479 			if (vp->v_type != VREG)
480 				nd->nd_repstat = EINVAL;
481 			else if (nva2.na_uid != nd->nd_cred->cr_uid ||
482 			    NFSVNO_EXSTRICTACCESS(exp))
483 				nd->nd_repstat = nfsvno_accchk(vp,
484 				    VWRITE, nd->nd_cred, exp, p,
485 				    NFSACCCHK_NOOVERRIDE,
486 				    NFSACCCHK_VPISLOCKED, NULL);
487 		}
488 	}
489 	/*
490 	 * Proxy operations from the MDS are allowed via the all 0s special
491 	 * stateid.
492 	 */
493 	if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0 &&
494 	    gotproxystateid == 0)
495 		nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
496 		    &nva, &attrbits, exp, p);
497 
498 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
499 	    u_long oldflags;
500 
501 	    oldflags = nva2.na_flags;
502 	    /*
503 	     * For V4, try setting the attributes in sets, so that the
504 	     * reply bitmap will be correct for an error case.
505 	     */
506 	    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
507 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
508 		NFSVNO_ATTRINIT(&nva2);
509 		NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
510 		NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
511 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
512 		    exp);
513 		if (!nd->nd_repstat) {
514 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
515 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
516 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
517 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
518 		}
519 	    }
520 	    if (!nd->nd_repstat &&
521 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
522 		NFSVNO_ATTRINIT(&nva2);
523 		NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
524 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
525 		    exp);
526 		if (!nd->nd_repstat)
527 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
528 	    }
529 	    if (!nd->nd_repstat &&
530 		(NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
531 		 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
532 		NFSVNO_ATTRINIT(&nva2);
533 		NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
534 		NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
535 		if (nva.na_vaflags & VA_UTIMES_NULL) {
536 			nva2.na_vaflags |= VA_UTIMES_NULL;
537 			NFSVNO_SETACTIVE(&nva2, vaflags);
538 		}
539 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
540 		    exp);
541 		if (!nd->nd_repstat) {
542 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
543 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
544 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
545 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
546 		}
547 	    }
548 	    if (!nd->nd_repstat &&
549 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE)) {
550 		NFSVNO_ATTRINIT(&nva2);
551 		NFSVNO_SETATTRVAL(&nva2, btime, nva.na_btime);
552 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
553 		    exp);
554 		if (!nd->nd_repstat)
555 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMECREATE);
556 	    }
557 	    if (!nd->nd_repstat &&
558 		(NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE) ||
559 		 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))) {
560 		NFSVNO_ATTRINIT(&nva2);
561 		NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
562 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
563 		    exp);
564 		if (!nd->nd_repstat) {
565 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE))
566 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
567 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))
568 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODESETMASKED);
569 		}
570 	    }
571 	    if (!nd->nd_repstat &&
572 		(NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN) ||
573 		 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM))) {
574 		if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN)) {
575 		    if ((nva.na_flags & UF_HIDDEN) != 0)
576 			oldflags |= UF_HIDDEN;
577 		    else
578 			oldflags &= ~UF_HIDDEN;
579 		}
580 		if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM)) {
581 		    if ((nva.na_flags & UF_SYSTEM) != 0)
582 			oldflags |= UF_SYSTEM;
583 		    else
584 			oldflags &= ~UF_SYSTEM;
585 		}
586 		NFSVNO_ATTRINIT(&nva2);
587 		NFSVNO_SETATTRVAL(&nva2, flags, oldflags);
588 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
589 		    exp);
590 		if (!nd->nd_repstat) {
591 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN))
592 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_HIDDEN);
593 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM))
594 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SYSTEM);
595 		}
596 	    }
597 
598 #ifdef NFS4_ACL_EXTATTR_NAME
599 	    if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
600 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
601 		nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
602 		if (!nd->nd_repstat)
603 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
604 	    }
605 #endif
606 	} else if (!nd->nd_repstat) {
607 		nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
608 		    exp);
609 	}
610 	if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
611 		postat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
612 		if (!nd->nd_repstat)
613 			nd->nd_repstat = postat_ret;
614 	}
615 	vput(vp);
616 #ifdef NFS4_ACL_EXTATTR_NAME
617 	acl_free(aclp);
618 #endif
619 	if (nd->nd_flag & ND_NFSV3)
620 		nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
621 	else if (nd->nd_flag & ND_NFSV4)
622 		(void) nfsrv_putattrbit(nd, &retbits);
623 	else if (!nd->nd_repstat)
624 		nfsrv_fillattr(nd, &nva);
625 
626 out:
627 	NFSEXITCODE2(0, nd);
628 	return (0);
629 nfsmout:
630 	vput(vp);
631 #ifdef NFS4_ACL_EXTATTR_NAME
632 	acl_free(aclp);
633 #endif
634 	if (nd->nd_flag & ND_NFSV4) {
635 		/*
636 		 * For all nd_repstat, the V4 reply includes a bitmap,
637 		 * even NFSERR_BADXDR, which is what this will end up
638 		 * returning.
639 		 */
640 		(void) nfsrv_putattrbit(nd, &retbits);
641 	}
642 	NFSEXITCODE2(error, nd);
643 	return (error);
644 }
645 
646 /*
647  * nfs lookup rpc
648  * (Also performs lookup parent for v4)
649  */
650 int
nfsrvd_lookup(struct nfsrv_descript * nd,__unused int isdgram,vnode_t dp,vnode_t * vpp,fhandle_t * fhp,struct nfsexstuff * exp)651 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
652     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
653 {
654 	struct nameidata named;
655 	vnode_t vp, dirp = NULL;
656 	int error = 0, dattr_ret = 1;
657 	struct nfsvattr nva, dattr;
658 	char *bufp;
659 	u_long *hashp;
660 	struct thread *p = curthread;
661 	struct componentname *cnp;
662 	short irflag;
663 
664 	if (nd->nd_repstat) {
665 		nfsrv_postopattr(nd, dattr_ret, &dattr);
666 		goto out;
667 	}
668 
669 	/*
670 	 * For some reason, if dp is a symlink, the error
671 	 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
672 	 */
673 	if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
674 		nd->nd_repstat = NFSERR_SYMLINK;
675 		vrele(dp);
676 		goto out;
677 	}
678 
679 	cnp = &named.ni_cnd;
680 	irflag = vn_irflag_read(dp);
681 	if ((irflag & VIRF_NAMEDDIR) != 0)
682 		NFSNAMEICNDSET(cnp, nd->nd_cred, LOOKUP, LOCKLEAF | OPENNAMED);
683 	else
684 		NFSNAMEICNDSET(cnp, nd->nd_cred, LOOKUP, LOCKLEAF);
685 	nfsvno_setpathbuf(&named, &bufp, &hashp);
686 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
687 	if (error) {
688 		vrele(dp);
689 		nfsvno_relpathbuf(&named);
690 		goto out;
691 	}
692 	if (!nd->nd_repstat) {
693 		/* Don't set OPENNAMED for Lookupp (".."). */
694 		if (cnp->cn_namelen == 2 && *cnp->cn_pnbuf == '.' &&
695 		    *(cnp->cn_pnbuf + 1) == '.')
696 			cnp->cn_flags &= ~OPENNAMED;
697 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp);
698 	} else {
699 		vrele(dp);
700 		nfsvno_relpathbuf(&named);
701 	}
702 	if (nd->nd_repstat) {
703 		if (dirp) {
704 			if (nd->nd_flag & ND_NFSV3)
705 				dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p,
706 				    0, NULL);
707 			vrele(dirp);
708 		}
709 		if (nd->nd_flag & ND_NFSV3)
710 			nfsrv_postopattr(nd, dattr_ret, &dattr);
711 		goto out;
712 	}
713 	nfsvno_relpathbuf(&named);
714 	vp = named.ni_vp;
715 	if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
716 	    vp->v_type != VDIR && vp->v_type != VLNK)
717 		/*
718 		 * Only allow lookup of VDIR and VLNK for traversal of
719 		 * non-exported volumes during NFSv4 mounting.
720 		 */
721 		nd->nd_repstat = ENOENT;
722 	if (nd->nd_repstat == 0) {
723 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
724 		/*
725 		 * EOPNOTSUPP indicates the file system cannot be exported,
726 		 * so just pretend the entry does not exist.
727 		 */
728 		if (nd->nd_repstat == EOPNOTSUPP)
729 			nd->nd_repstat = ENOENT;
730 	}
731 	if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
732 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
733 	if (vpp != NULL && nd->nd_repstat == 0)
734 		*vpp = vp;
735 	else
736 		vput(vp);
737 	if (dirp) {
738 		if (nd->nd_flag & ND_NFSV3)
739 			dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0,
740 			    NULL);
741 		vrele(dirp);
742 	}
743 	if (nd->nd_repstat) {
744 		if (nd->nd_flag & ND_NFSV3)
745 			nfsrv_postopattr(nd, dattr_ret, &dattr);
746 		goto out;
747 	}
748 	if (nd->nd_flag & ND_NFSV2) {
749 		(void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
750 		nfsrv_fillattr(nd, &nva);
751 	} else if (nd->nd_flag & ND_NFSV3) {
752 		(void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
753 		nfsrv_postopattr(nd, 0, &nva);
754 		nfsrv_postopattr(nd, dattr_ret, &dattr);
755 	}
756 
757 out:
758 	NFSEXITCODE2(error, nd);
759 	return (error);
760 }
761 
762 /*
763  * nfs readlink service
764  */
765 int
nfsrvd_readlink(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)766 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
767     vnode_t vp, __unused struct nfsexstuff *exp)
768 {
769 	u_int32_t *tl;
770 	struct mbuf *mp = NULL, *mpend = NULL;
771 	int getret = 1, len;
772 	struct nfsvattr nva;
773 	struct thread *p = curthread;
774 	uint16_t off;
775 
776 	if (nd->nd_repstat) {
777 		nfsrv_postopattr(nd, getret, &nva);
778 		goto out;
779 	}
780 	if (vp->v_type != VLNK) {
781 		if (nd->nd_flag & ND_NFSV2)
782 			nd->nd_repstat = ENXIO;
783 		else
784 			nd->nd_repstat = EINVAL;
785 	}
786 	if (nd->nd_repstat == 0) {
787 		if ((nd->nd_flag & ND_EXTPG) != 0)
788 			nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred,
789 			    nd->nd_maxextsiz, p, &mp, &mpend, &len);
790 		else
791 			nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred,
792 			    0, p, &mp, &mpend, &len);
793 	}
794 	if (nd->nd_flag & ND_NFSV3)
795 		getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
796 	vput(vp);
797 	if (nd->nd_flag & ND_NFSV3)
798 		nfsrv_postopattr(nd, getret, &nva);
799 	if (nd->nd_repstat)
800 		goto out;
801 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
802 	*tl = txdr_unsigned(len);
803 	if (mp != NULL) {
804 		nd->nd_mb->m_next = mp;
805 		nd->nd_mb = mpend;
806 		if ((mpend->m_flags & M_EXTPG) != 0) {
807 			nd->nd_bextpg = mpend->m_epg_npgs - 1;
808 			nd->nd_bpos = (char *)(void *)
809 			    PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]);
810 			off = (nd->nd_bextpg == 0) ? mpend->m_epg_1st_off : 0;
811 			nd->nd_bpos += off + mpend->m_epg_last_len;
812 			nd->nd_bextpgsiz = PAGE_SIZE - mpend->m_epg_last_len -
813 			    off;
814 		} else
815 			nd->nd_bpos = mtod(mpend, char *) + mpend->m_len;
816 	}
817 
818 out:
819 	NFSEXITCODE2(0, nd);
820 	return (0);
821 }
822 
823 /*
824  * nfs read service
825  */
826 int
nfsrvd_read(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)827 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
828     vnode_t vp, struct nfsexstuff *exp)
829 {
830 	u_int32_t *tl;
831 	int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0;
832 	struct mbuf *m2, *m3;
833 	struct nfsvattr nva;
834 	off_t off = 0x0;
835 	struct nfsstate st, *stp = &st;
836 	struct nfslock lo, *lop = &lo;
837 	nfsv4stateid_t stateid;
838 	nfsquad_t clientid;
839 	struct thread *p = curthread;
840 	uint16_t poff;
841 
842 	if (nd->nd_repstat) {
843 		nfsrv_postopattr(nd, getret, &nva);
844 		goto out;
845 	}
846 	if (nd->nd_flag & ND_NFSV2) {
847 		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
848 		off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
849 		reqlen = fxdr_unsigned(int, *tl);
850 	} else if (nd->nd_flag & ND_NFSV3) {
851 		NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
852 		off = fxdr_hyper(tl);
853 		tl += 2;
854 		reqlen = fxdr_unsigned(int, *tl);
855 	} else {
856 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
857 		reqlen = fxdr_unsigned(int, *(tl + 6));
858 	}
859 	if (reqlen > NFS_SRVMAXDATA(nd)) {
860 		reqlen = NFS_SRVMAXDATA(nd);
861 	} else if (reqlen < 0) {
862 		error = EBADRPC;
863 		goto nfsmout;
864 	}
865 	gotproxystateid = 0;
866 	if (nd->nd_flag & ND_NFSV4) {
867 		stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
868 		lop->lo_flags = NFSLCK_READ;
869 		stp->ls_ownerlen = 0;
870 		stp->ls_op = NULL;
871 		stp->ls_uid = nd->nd_cred->cr_uid;
872 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
873 		clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
874 		clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
875 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
876 			if ((nd->nd_flag & ND_NFSV41) != 0)
877 				clientid.qval = nd->nd_clientid.qval;
878 			else if (nd->nd_clientid.qval != clientid.qval)
879 				printf("EEK1 multiple clids\n");
880 		} else {
881 			if ((nd->nd_flag & ND_NFSV41) != 0)
882 				printf("EEK! no clientid from session\n");
883 			nd->nd_flag |= ND_IMPLIEDCLID;
884 			nd->nd_clientid.qval = clientid.qval;
885 		}
886 		stp->ls_stateid.other[2] = *tl++;
887 		/*
888 		 * Don't allow the client to use a special stateid for a DS op.
889 		 */
890 		if ((nd->nd_flag & ND_DSSERVER) != 0 &&
891 		    ((stp->ls_stateid.other[0] == 0x0 &&
892 		    stp->ls_stateid.other[1] == 0x0 &&
893 		    stp->ls_stateid.other[2] == 0x0) ||
894 		    (stp->ls_stateid.other[0] == 0xffffffff &&
895 		    stp->ls_stateid.other[1] == 0xffffffff &&
896 		    stp->ls_stateid.other[2] == 0xffffffff) ||
897 		    stp->ls_stateid.seqid != 0))
898 			nd->nd_repstat = NFSERR_BADSTATEID;
899 		/* However, allow the proxy stateid. */
900 		if (stp->ls_stateid.seqid == 0xffffffff &&
901 		    stp->ls_stateid.other[0] == 0x55555555 &&
902 		    stp->ls_stateid.other[1] == 0x55555555 &&
903 		    stp->ls_stateid.other[2] == 0x55555555)
904 			gotproxystateid = 1;
905 		off = fxdr_hyper(tl);
906 		lop->lo_first = off;
907 		tl += 2;
908 		lop->lo_end = off + reqlen;
909 		/*
910 		 * Paranoia, just in case it wraps around.
911 		 */
912 		if (lop->lo_end < off)
913 			lop->lo_end = NFS64BITSSET;
914 	}
915 	if (vp->v_type != VREG) {
916 		if (nd->nd_flag & ND_NFSV3)
917 			nd->nd_repstat = EINVAL;
918 		else
919 			nd->nd_repstat = (vp->v_type == VDIR) ? EISDIR :
920 			    EINVAL;
921 	}
922 	getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
923 	if (!nd->nd_repstat)
924 		nd->nd_repstat = getret;
925 	if (!nd->nd_repstat &&
926 	    (nva.na_uid != nd->nd_cred->cr_uid ||
927 	     NFSVNO_EXSTRICTACCESS(exp))) {
928 		nd->nd_repstat = nfsvno_accchk(vp, VREAD,
929 		    nd->nd_cred, exp, p,
930 		    NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
931 		if (nd->nd_repstat)
932 			nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
933 			    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
934 			    NFSACCCHK_VPISLOCKED, NULL);
935 	}
936 	/*
937 	 * DS reads are marked by ND_DSSERVER or use the proxy special
938 	 * stateid.
939 	 */
940 	if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
941 	    ND_NFSV4 && gotproxystateid == 0)
942 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
943 		    &stateid, exp, nd, p);
944 	if (nd->nd_repstat) {
945 		vput(vp);
946 		if (nd->nd_flag & ND_NFSV3)
947 			nfsrv_postopattr(nd, getret, &nva);
948 		goto out;
949 	}
950 	if (off >= nva.na_size) {
951 		cnt = 0;
952 		eof = 1;
953 	} else if (reqlen == 0)
954 		cnt = 0;
955 	else if ((off + reqlen) >= nva.na_size) {
956 		cnt = nva.na_size - off;
957 		eof = 1;
958 	} else
959 		cnt = reqlen;
960 	m3 = NULL;
961 	if (cnt > 0) {
962 		/*
963 		 * If cnt > MCLBYTES and the reply will not be saved, use
964 		 * ext_pgs mbufs for TLS.
965 		 * For NFSv4.0, we do not know for sure if the reply will
966 		 * be saved, so do not use ext_pgs mbufs for NFSv4.0.
967 		 * Always use ext_pgs mbufs if ND_EXTPG is set.
968 		 */
969 		if ((nd->nd_flag & ND_EXTPG) != 0 || (cnt > MCLBYTES &&
970 		    (nd->nd_flag & (ND_TLS | ND_SAVEREPLY)) == ND_TLS &&
971 		    (nd->nd_flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4))
972 			nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred,
973 			    nd->nd_maxextsiz, p, &m3, &m2);
974 		else
975 			nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred,
976 			    0, p, &m3, &m2);
977 		if (!(nd->nd_flag & ND_NFSV4)) {
978 			getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
979 			if (!nd->nd_repstat)
980 				nd->nd_repstat = getret;
981 		}
982 		if (nd->nd_repstat) {
983 			vput(vp);
984 			if (m3)
985 				m_freem(m3);
986 			if (nd->nd_flag & ND_NFSV3)
987 				nfsrv_postopattr(nd, getret, &nva);
988 			goto out;
989 		}
990 	}
991 	vput(vp);
992 	if (nd->nd_flag & ND_NFSV2) {
993 		nfsrv_fillattr(nd, &nva);
994 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
995 	} else {
996 		if (nd->nd_flag & ND_NFSV3) {
997 			nfsrv_postopattr(nd, getret, &nva);
998 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
999 			*tl++ = txdr_unsigned(cnt);
1000 		} else
1001 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1002 		if (eof)
1003 			*tl++ = newnfs_true;
1004 		else
1005 			*tl++ = newnfs_false;
1006 	}
1007 	*tl = txdr_unsigned(cnt);
1008 	if (m3) {
1009 		nd->nd_mb->m_next = m3;
1010 		nd->nd_mb = m2;
1011 		if ((m2->m_flags & M_EXTPG) != 0) {
1012 			nd->nd_flag |= ND_EXTPG;
1013 			nd->nd_bextpg = m2->m_epg_npgs - 1;
1014 			nd->nd_bpos = (char *)(void *)
1015 			    PHYS_TO_DMAP(m2->m_epg_pa[nd->nd_bextpg]);
1016 			poff = (nd->nd_bextpg == 0) ? m2->m_epg_1st_off : 0;
1017 			nd->nd_bpos += poff + m2->m_epg_last_len;
1018 			nd->nd_bextpgsiz = PAGE_SIZE - m2->m_epg_last_len -
1019 			    poff;
1020 		} else
1021 			nd->nd_bpos = mtod(m2, char *) + m2->m_len;
1022 	}
1023 
1024 out:
1025 	NFSEXITCODE2(0, nd);
1026 	return (0);
1027 nfsmout:
1028 	vput(vp);
1029 	NFSEXITCODE2(error, nd);
1030 	return (error);
1031 }
1032 
1033 /*
1034  * nfs write service
1035  */
1036 int
nfsrvd_write(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)1037 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
1038     vnode_t vp, struct nfsexstuff *exp)
1039 {
1040 	u_int32_t *tl;
1041 	struct nfsvattr nva, forat;
1042 	int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
1043 	int gotproxystateid, stable = NFSWRITE_FILESYNC;
1044 	off_t off;
1045 	struct nfsstate st, *stp = &st;
1046 	struct nfslock lo, *lop = &lo;
1047 	nfsv4stateid_t stateid;
1048 	nfsquad_t clientid;
1049 	nfsattrbit_t attrbits;
1050 	struct thread *p = curthread;
1051 
1052 	if (nd->nd_repstat) {
1053 		nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1054 		goto out;
1055 	}
1056 	gotproxystateid = 0;
1057 	if (nd->nd_flag & ND_NFSV2) {
1058 		NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1059 		off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
1060 		tl += 2;
1061 		retlen = len = fxdr_unsigned(int32_t, *tl);
1062 	} else if (nd->nd_flag & ND_NFSV3) {
1063 		NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1064 		off = fxdr_hyper(tl);
1065 		tl += 3;
1066 		stable = fxdr_unsigned(int, *tl++);
1067 		retlen = len = fxdr_unsigned(int32_t, *tl);
1068 	} else {
1069 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
1070 		stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
1071 		lop->lo_flags = NFSLCK_WRITE;
1072 		stp->ls_ownerlen = 0;
1073 		stp->ls_op = NULL;
1074 		stp->ls_uid = nd->nd_cred->cr_uid;
1075 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
1076 		clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
1077 		clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
1078 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
1079 			if ((nd->nd_flag & ND_NFSV41) != 0)
1080 				clientid.qval = nd->nd_clientid.qval;
1081 			else if (nd->nd_clientid.qval != clientid.qval)
1082 				printf("EEK2 multiple clids\n");
1083 		} else {
1084 			if ((nd->nd_flag & ND_NFSV41) != 0)
1085 				printf("EEK! no clientid from session\n");
1086 			nd->nd_flag |= ND_IMPLIEDCLID;
1087 			nd->nd_clientid.qval = clientid.qval;
1088 		}
1089 		stp->ls_stateid.other[2] = *tl++;
1090 		/*
1091 		 * Don't allow the client to use a special stateid for a DS op.
1092 		 */
1093 		if ((nd->nd_flag & ND_DSSERVER) != 0 &&
1094 		    ((stp->ls_stateid.other[0] == 0x0 &&
1095 		    stp->ls_stateid.other[1] == 0x0 &&
1096 		    stp->ls_stateid.other[2] == 0x0) ||
1097 		    (stp->ls_stateid.other[0] == 0xffffffff &&
1098 		    stp->ls_stateid.other[1] == 0xffffffff &&
1099 		    stp->ls_stateid.other[2] == 0xffffffff) ||
1100 		    stp->ls_stateid.seqid != 0))
1101 			nd->nd_repstat = NFSERR_BADSTATEID;
1102 		/* However, allow the proxy stateid. */
1103 		if (stp->ls_stateid.seqid == 0xffffffff &&
1104 		    stp->ls_stateid.other[0] == 0x55555555 &&
1105 		    stp->ls_stateid.other[1] == 0x55555555 &&
1106 		    stp->ls_stateid.other[2] == 0x55555555)
1107 			gotproxystateid = 1;
1108 		off = fxdr_hyper(tl);
1109 		lop->lo_first = off;
1110 		tl += 2;
1111 		stable = fxdr_unsigned(int, *tl++);
1112 		retlen = len = fxdr_unsigned(int32_t, *tl);
1113 		lop->lo_end = off + len;
1114 		/*
1115 		 * Paranoia, just in case it wraps around, which shouldn't
1116 		 * ever happen anyhow.
1117 		 */
1118 		if (lop->lo_end < lop->lo_first)
1119 			lop->lo_end = NFS64BITSSET;
1120 	}
1121 
1122 	if (retlen > nfs_srvmaxio || retlen < 0)
1123 		nd->nd_repstat = EIO;
1124 	if (vp->v_type != VREG && !nd->nd_repstat) {
1125 		if (nd->nd_flag & ND_NFSV3)
1126 			nd->nd_repstat = EINVAL;
1127 		else
1128 			nd->nd_repstat = (vp->v_type == VDIR) ? EISDIR :
1129 			    EINVAL;
1130 	}
1131 	NFSZERO_ATTRBIT(&attrbits);
1132 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
1133 	forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits);
1134 	if (!nd->nd_repstat)
1135 		nd->nd_repstat = forat_ret;
1136 	if (!nd->nd_repstat &&
1137 	    (forat.na_uid != nd->nd_cred->cr_uid ||
1138 	     NFSVNO_EXSTRICTACCESS(exp)))
1139 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
1140 		    nd->nd_cred, exp, p,
1141 		    NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
1142 	/*
1143 	 * DS reads are marked by ND_DSSERVER or use the proxy special
1144 	 * stateid.
1145 	 */
1146 	if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
1147 	    ND_NFSV4 && gotproxystateid == 0)
1148 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
1149 		    &stateid, exp, nd, p);
1150 	if (nd->nd_repstat) {
1151 		vput(vp);
1152 		if (nd->nd_flag & ND_NFSV3)
1153 			nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1154 		goto out;
1155 	}
1156 
1157 	/*
1158 	 * For NFS Version 2, it is not obvious what a write of zero length
1159 	 * should do, but I might as well be consistent with Version 3,
1160 	 * which is to return ok so long as there are no permission problems.
1161 	 */
1162 	if (retlen > 0) {
1163 		nd->nd_repstat = nfsvno_write(vp, off, retlen, &stable,
1164 		    nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
1165 		error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
1166 		if (error)
1167 			goto nfsmout;
1168 	}
1169 	if (nd->nd_flag & ND_NFSV4)
1170 		aftat_ret = 0;
1171 	else
1172 		aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
1173 	vput(vp);
1174 	if (!nd->nd_repstat)
1175 		nd->nd_repstat = aftat_ret;
1176 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1177 		if (nd->nd_flag & ND_NFSV3)
1178 			nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1179 		if (nd->nd_repstat)
1180 			goto out;
1181 		NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1182 		*tl++ = txdr_unsigned(retlen);
1183 		/*
1184 		 * If nfs_async is set, then pretend the write was FILESYNC.
1185 		 * Warning: Doing this violates RFC1813 and runs a risk
1186 		 * of data written by a client being lost when the server
1187 		 * crashes/reboots.
1188 		 */
1189 		if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
1190 			*tl++ = txdr_unsigned(stable);
1191 		else
1192 			*tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
1193 		/*
1194 		 * Actually, there is no need to txdr these fields,
1195 		 * but it may make the values more human readable,
1196 		 * for debugging purposes.
1197 		 */
1198 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
1199 		*tl = txdr_unsigned(nfsboottime.tv_usec);
1200 	} else if (!nd->nd_repstat)
1201 		nfsrv_fillattr(nd, &nva);
1202 
1203 out:
1204 	NFSEXITCODE2(0, nd);
1205 	return (0);
1206 nfsmout:
1207 	vput(vp);
1208 	NFSEXITCODE2(error, nd);
1209 	return (error);
1210 }
1211 
1212 /*
1213  * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
1214  * now does a truncate to 0 length via. setattr if it already exists
1215  * The core creation routine has been extracted out into nfsrv_creatsub(),
1216  * so it can also be used by nfsrv_open() for V4.
1217  */
1218 int
nfsrvd_create(struct nfsrv_descript * nd,__unused int isdgram,vnode_t dp,struct nfsexstuff * exp)1219 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
1220     vnode_t dp, struct nfsexstuff *exp)
1221 {
1222 	struct nfsvattr nva, dirfor, diraft;
1223 	struct nfsv2_sattr *sp;
1224 	struct nameidata named;
1225 	u_int32_t *tl;
1226 	int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
1227 	int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
1228 	NFSDEV_T rdev = 0;
1229 	vnode_t vp = NULL, dirp = NULL;
1230 	fhandle_t fh;
1231 	char *bufp;
1232 	u_long *hashp;
1233 	__enum_uint8(vtype) vtyp;
1234 	int32_t cverf[2], tverf[2] = { 0, 0 };
1235 	struct thread *p = curthread;
1236 
1237 	if (nd->nd_repstat) {
1238 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1239 		goto out;
1240 	}
1241 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1242 	    LOCKPARENT | LOCKLEAF | NOCACHE);
1243 	nfsvno_setpathbuf(&named, &bufp, &hashp);
1244 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1245 	if (error)
1246 		goto nfsmout;
1247 	if (!nd->nd_repstat) {
1248 		NFSVNO_ATTRINIT(&nva);
1249 		if (nd->nd_flag & ND_NFSV2) {
1250 			NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1251 			vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
1252 			if (vtyp == VNON)
1253 				vtyp = VREG;
1254 			NFSVNO_SETATTRVAL(&nva, type, vtyp);
1255 			NFSVNO_SETATTRVAL(&nva, mode,
1256 			    nfstov_mode(sp->sa_mode));
1257 			switch (nva.na_type) {
1258 			case VREG:
1259 				tsize = fxdr_unsigned(int32_t, sp->sa_size);
1260 				if (tsize != -1)
1261 					NFSVNO_SETATTRVAL(&nva, size,
1262 					    (u_quad_t)tsize);
1263 				break;
1264 			case VCHR:
1265 			case VBLK:
1266 			case VFIFO:
1267 				rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
1268 				break;
1269 			default:
1270 				break;
1271 			}
1272 		} else {
1273 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1274 			how = fxdr_unsigned(int, *tl);
1275 			switch (how) {
1276 			case NFSCREATE_GUARDED:
1277 			case NFSCREATE_UNCHECKED:
1278 				error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1279 				if (error)
1280 					goto nfsmout;
1281 				break;
1282 			case NFSCREATE_EXCLUSIVE:
1283 				NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1284 				cverf[0] = *tl++;
1285 				cverf[1] = *tl;
1286 				exclusive_flag = 1;
1287 				break;
1288 			}
1289 			NFSVNO_SETATTRVAL(&nva, type, VREG);
1290 		}
1291 	}
1292 	if (nd->nd_repstat) {
1293 		nfsvno_relpathbuf(&named);
1294 		if (nd->nd_flag & ND_NFSV3) {
1295 			dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1,
1296 			    NULL);
1297 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1298 			    &diraft);
1299 		}
1300 		vput(dp);
1301 		goto out;
1302 	}
1303 
1304 	nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp);
1305 	if (dirp) {
1306 		if (nd->nd_flag & ND_NFSV2) {
1307 			vrele(dirp);
1308 			dirp = NULL;
1309 		} else {
1310 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1311 			    NULL);
1312 		}
1313 	}
1314 	if (nd->nd_repstat) {
1315 		if (nd->nd_flag & ND_NFSV3)
1316 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1317 			    &diraft);
1318 		if (dirp)
1319 			vrele(dirp);
1320 		goto out;
1321 	}
1322 
1323 	if (!(nd->nd_flag & ND_NFSV2)) {
1324 		switch (how) {
1325 		case NFSCREATE_GUARDED:
1326 			if (named.ni_vp)
1327 				nd->nd_repstat = EEXIST;
1328 			break;
1329 		case NFSCREATE_UNCHECKED:
1330 			break;
1331 		case NFSCREATE_EXCLUSIVE:
1332 			if (named.ni_vp == NULL)
1333 				NFSVNO_SETATTRVAL(&nva, mode, 0);
1334 			break;
1335 		}
1336 	}
1337 
1338 	/*
1339 	 * Iff doesn't exist, create it
1340 	 * otherwise just truncate to 0 length
1341 	 *   should I set the mode too ?
1342 	 */
1343 	nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1344 	    &exclusive_flag, cverf, rdev, exp);
1345 
1346 	if (!nd->nd_repstat) {
1347 		nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1348 		if (!nd->nd_repstat)
1349 			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1350 			    NULL);
1351 		vput(vp);
1352 		if (!nd->nd_repstat) {
1353 			tverf[0] = nva.na_atime.tv_sec;
1354 			tverf[1] = nva.na_atime.tv_nsec;
1355 		}
1356 	}
1357 	if (nd->nd_flag & ND_NFSV2) {
1358 		if (!nd->nd_repstat) {
1359 			(void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 0);
1360 			nfsrv_fillattr(nd, &nva);
1361 		}
1362 	} else {
1363 		if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1364 		    || cverf[1] != tverf[1]))
1365 			nd->nd_repstat = EEXIST;
1366 		diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1367 		vrele(dirp);
1368 		if (!nd->nd_repstat) {
1369 			(void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 1);
1370 			nfsrv_postopattr(nd, 0, &nva);
1371 		}
1372 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1373 	}
1374 
1375 out:
1376 	NFSEXITCODE2(0, nd);
1377 	return (0);
1378 nfsmout:
1379 	vput(dp);
1380 	nfsvno_relpathbuf(&named);
1381 	NFSEXITCODE2(error, nd);
1382 	return (error);
1383 }
1384 
1385 /*
1386  * nfs v3 mknod service (and v4 create)
1387  */
1388 int
nfsrvd_mknod(struct nfsrv_descript * nd,__unused int isdgram,vnode_t dp,vnode_t * vpp,fhandle_t * fhp,struct nfsexstuff * exp)1389 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1390     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1391 {
1392 	struct nfsvattr nva, dirfor, diraft;
1393 	u_int32_t *tl;
1394 	struct nameidata named;
1395 	int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1396 	u_int32_t major, minor;
1397 	__enum_uint8(vtype) vtyp = VNON;
1398 	nfstype nfs4type = NFNON;
1399 	vnode_t vp, dirp = NULL;
1400 	nfsattrbit_t attrbits;
1401 	char *bufp = NULL, *pathcp = NULL;
1402 	u_long *hashp, cnflags;
1403 	NFSACL_T *aclp = NULL;
1404 	struct thread *p = curthread;
1405 
1406 	NFSVNO_ATTRINIT(&nva);
1407 	cnflags = LOCKPARENT;
1408 	if (nd->nd_repstat) {
1409 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1410 		goto out;
1411 	}
1412 #ifdef NFS4_ACL_EXTATTR_NAME
1413 	aclp = acl_alloc(M_WAITOK);
1414 	aclp->acl_cnt = 0;
1415 #endif
1416 
1417 	/*
1418 	 * For V4, the creation stuff is here, Yuck!
1419 	 */
1420 	if (nd->nd_flag & ND_NFSV4) {
1421 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1422 		vtyp = nfsv34tov_type(*tl);
1423 		nfs4type = fxdr_unsigned(nfstype, *tl);
1424 		if ((vn_irflag_read(dp) & VIRF_NAMEDDIR) != 0) {
1425 			/*
1426 			 * Don't allow creation of non-regular file objects
1427 			 * in a named attribute directory.
1428 			 */
1429 			nd->nd_repstat = NFSERR_INVAL;
1430 			vrele(dp);
1431 #ifdef NFS4_ACL_EXTATTR_NAME
1432 			acl_free(aclp);
1433 #endif
1434 			goto out;
1435 		}
1436 		switch (nfs4type) {
1437 		case NFLNK:
1438 			error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1439 			    &pathlen);
1440 			if (error)
1441 				goto nfsmout;
1442 			break;
1443 		case NFCHR:
1444 		case NFBLK:
1445 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1446 			major = fxdr_unsigned(u_int32_t, *tl++);
1447 			minor = fxdr_unsigned(u_int32_t, *tl);
1448 			nva.na_rdev = NFSMAKEDEV(major, minor);
1449 			break;
1450 		case NFSOCK:
1451 		case NFFIFO:
1452 			break;
1453 		case NFDIR:
1454 			cnflags = LOCKPARENT;
1455 			break;
1456 		default:
1457 			nd->nd_repstat = NFSERR_BADTYPE;
1458 			vrele(dp);
1459 #ifdef NFS4_ACL_EXTATTR_NAME
1460 			acl_free(aclp);
1461 #endif
1462 			goto out;
1463 		}
1464 	}
1465 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE);
1466 	nfsvno_setpathbuf(&named, &bufp, &hashp);
1467 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1468 	if (error)
1469 		goto nfsmout;
1470 	if (!nd->nd_repstat) {
1471 		if (nd->nd_flag & ND_NFSV3) {
1472 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1473 			vtyp = nfsv34tov_type(*tl);
1474 		}
1475 		error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p);
1476 		if (error)
1477 			goto nfsmout;
1478 		nva.na_type = vtyp;
1479 		if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1480 		    (vtyp == VCHR || vtyp == VBLK)) {
1481 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1482 			major = fxdr_unsigned(u_int32_t, *tl++);
1483 			minor = fxdr_unsigned(u_int32_t, *tl);
1484 			nva.na_rdev = NFSMAKEDEV(major, minor);
1485 		}
1486 	}
1487 
1488 	dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
1489 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1490 		if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1491 		    dirfor.na_gid == nva.na_gid)
1492 			NFSVNO_UNSET(&nva, gid);
1493 		nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1494 	}
1495 	if (nd->nd_repstat) {
1496 		vrele(dp);
1497 #ifdef NFS4_ACL_EXTATTR_NAME
1498 		acl_free(aclp);
1499 #endif
1500 		nfsvno_relpathbuf(&named);
1501 		if (pathcp)
1502 			free(pathcp, M_TEMP);
1503 		if (nd->nd_flag & ND_NFSV3)
1504 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1505 			    &diraft);
1506 		goto out;
1507 	}
1508 
1509 	/*
1510 	 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1511 	 * in va_mode, so we'll have to set a default here.
1512 	 */
1513 	if (NFSVNO_NOTSETMODE(&nva)) {
1514 		if (vtyp == VLNK)
1515 			nva.na_mode = 0755;
1516 		else
1517 			nva.na_mode = 0400;
1518 	}
1519 
1520 	if (vtyp == VDIR)
1521 		named.ni_cnd.cn_flags |= WILLBEDIR;
1522 	nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp);
1523 	if (nd->nd_repstat) {
1524 		if (dirp) {
1525 			if (nd->nd_flag & ND_NFSV3)
1526 				dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd,
1527 				    p, 0, NULL);
1528 			vrele(dirp);
1529 		}
1530 #ifdef NFS4_ACL_EXTATTR_NAME
1531 		acl_free(aclp);
1532 #endif
1533 		if (nd->nd_flag & ND_NFSV3)
1534 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1535 			    &diraft);
1536 		goto out;
1537 	}
1538 	if (dirp)
1539 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1540 
1541 	if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1542 		if (vtyp == VDIR) {
1543 			nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1544 			    &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1545 			    exp);
1546 #ifdef NFS4_ACL_EXTATTR_NAME
1547 			acl_free(aclp);
1548 #endif
1549 			goto out;
1550 		} else if (vtyp == VLNK) {
1551 			nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1552 			    &dirfor, &diraft, &diraft_ret, &attrbits,
1553 			    aclp, p, exp, pathcp, pathlen);
1554 #ifdef NFS4_ACL_EXTATTR_NAME
1555 			acl_free(aclp);
1556 #endif
1557 			free(pathcp, M_TEMP);
1558 			goto out;
1559 		}
1560 	}
1561 
1562 	nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1563 	if (!nd->nd_repstat) {
1564 		vp = named.ni_vp;
1565 		nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1566 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1567 		if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1568 			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1569 			    NULL);
1570 		if (vpp != NULL && nd->nd_repstat == 0) {
1571 			NFSVOPUNLOCK(vp);
1572 			*vpp = vp;
1573 		} else
1574 			vput(vp);
1575 	}
1576 
1577 	diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1578 	vrele(dirp);
1579 	if (!nd->nd_repstat) {
1580 		if (nd->nd_flag & ND_NFSV3) {
1581 			(void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1);
1582 			nfsrv_postopattr(nd, 0, &nva);
1583 		} else {
1584 			NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1585 			*tl++ = newnfs_false;
1586 			txdr_hyper(dirfor.na_filerev, tl);
1587 			tl += 2;
1588 			txdr_hyper(diraft.na_filerev, tl);
1589 			(void) nfsrv_putattrbit(nd, &attrbits);
1590 		}
1591 	}
1592 	if (nd->nd_flag & ND_NFSV3)
1593 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1594 #ifdef NFS4_ACL_EXTATTR_NAME
1595 	acl_free(aclp);
1596 #endif
1597 
1598 out:
1599 	NFSEXITCODE2(0, nd);
1600 	return (0);
1601 nfsmout:
1602 	vrele(dp);
1603 #ifdef NFS4_ACL_EXTATTR_NAME
1604 	acl_free(aclp);
1605 #endif
1606 	if (bufp)
1607 		nfsvno_relpathbuf(&named);
1608 	if (pathcp)
1609 		free(pathcp, M_TEMP);
1610 
1611 	NFSEXITCODE2(error, nd);
1612 	return (error);
1613 }
1614 
1615 /*
1616  * nfs remove service
1617  */
1618 int
nfsrvd_remove(struct nfsrv_descript * nd,__unused int isdgram,vnode_t dp,struct nfsexstuff * exp)1619 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1620     vnode_t dp, struct nfsexstuff *exp)
1621 {
1622 	struct nameidata named;
1623 	u_int32_t *tl;
1624 	int error = 0, dirfor_ret = 1, diraft_ret = 1;
1625 	vnode_t dirp = NULL;
1626 	struct nfsvattr dirfor, diraft;
1627 	char *bufp;
1628 	u_long *hashp;
1629 	struct thread *p = curthread;
1630 
1631 	if (nd->nd_repstat) {
1632 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1633 		goto out;
1634 	}
1635 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1636 	    LOCKPARENT | LOCKLEAF);
1637 	nfsvno_setpathbuf(&named, &bufp, &hashp);
1638 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1639 	if (error) {
1640 		vput(dp);
1641 		nfsvno_relpathbuf(&named);
1642 		goto out;
1643 	}
1644 	if (!nd->nd_repstat) {
1645 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp);
1646 	} else {
1647 		vput(dp);
1648 		nfsvno_relpathbuf(&named);
1649 	}
1650 	if (dirp) {
1651 		if (!(nd->nd_flag & ND_NFSV2)) {
1652 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1653 			    NULL);
1654 		} else {
1655 			vrele(dirp);
1656 			dirp = NULL;
1657 		}
1658 	}
1659 	if (!nd->nd_repstat) {
1660 		if (nd->nd_flag & ND_NFSV4) {
1661 			if (named.ni_vp->v_type == VDIR)
1662 				nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1663 				    nd->nd_cred, p, exp);
1664 			else
1665 				nd->nd_repstat = nfsvno_removesub(&named, true,
1666 				    nd, p, exp);
1667 		} else if (nd->nd_procnum == NFSPROC_RMDIR) {
1668 			nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1669 			    nd->nd_cred, p, exp);
1670 		} else {
1671 			nd->nd_repstat = nfsvno_removesub(&named, false, nd, p,
1672 			    exp);
1673 		}
1674 	}
1675 	if (!(nd->nd_flag & ND_NFSV2)) {
1676 		if (dirp) {
1677 			diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0,
1678 			    NULL);
1679 			vrele(dirp);
1680 		}
1681 		if (nd->nd_flag & ND_NFSV3) {
1682 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1683 			    &diraft);
1684 		} else if (!nd->nd_repstat) {
1685 			NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1686 			*tl++ = newnfs_false;
1687 			txdr_hyper(dirfor.na_filerev, tl);
1688 			tl += 2;
1689 			txdr_hyper(diraft.na_filerev, tl);
1690 		}
1691 	}
1692 
1693 out:
1694 	NFSEXITCODE2(error, nd);
1695 	return (error);
1696 }
1697 
1698 /*
1699  * nfs rename service
1700  */
1701 int
nfsrvd_rename(struct nfsrv_descript * nd,int isdgram,vnode_t dp,vnode_t todp,struct nfsexstuff * exp,struct nfsexstuff * toexp)1702 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1703     vnode_t dp, vnode_t todp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1704 {
1705 	u_int32_t *tl;
1706 	int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
1707 	int tdirfor_ret = 1, tdiraft_ret = 1;
1708 	struct nameidata fromnd, tond;
1709 	vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1710 	struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1711 	struct nfsexstuff tnes;
1712 	struct nfsrvfh tfh;
1713 	char *bufp, *tbufp = NULL;
1714 	u_long *hashp;
1715 	fhandle_t fh;
1716 	struct thread *p = curthread;
1717 
1718 	if (nd->nd_repstat) {
1719 		nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1720 		nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1721 		goto out;
1722 	}
1723 	if (!(nd->nd_flag & ND_NFSV2))
1724 		fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL);
1725 	tond.ni_cnd.cn_nameiop = 0;
1726 	tond.ni_startdir = NULL;
1727 	NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT);
1728 	nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1729 	error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1730 	if (error) {
1731 		vput(dp);
1732 		if (todp)
1733 			vrele(todp);
1734 		nfsvno_relpathbuf(&fromnd);
1735 		goto out;
1736 	}
1737 	/*
1738 	 * Unlock dp in this code section, so it is unlocked before
1739 	 * tdp gets locked. This avoids a potential LOR if tdp is the
1740 	 * parent directory of dp.
1741 	 */
1742 	if (nd->nd_flag & ND_NFSV4) {
1743 		tdp = todp;
1744 		tnes = *toexp;
1745 		if (dp != tdp) {
1746 			NFSVOPUNLOCK(dp);
1747 			/* Might lock tdp. */
1748 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0,
1749 			    NULL);
1750 		} else {
1751 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1752 			    NULL);
1753 			NFSVOPUNLOCK(dp);
1754 		}
1755 	} else {
1756 		tfh.nfsrvfh_len = 0;
1757 		error = nfsrv_mtofh(nd, &tfh);
1758 		if (error == 0)
1759 			error = nfsvno_getfh(dp, &fh, p);
1760 		if (error) {
1761 			vput(dp);
1762 			/* todp is always NULL except NFSv4 */
1763 			nfsvno_relpathbuf(&fromnd);
1764 			goto out;
1765 		}
1766 
1767 		/* If this is the same file handle, just VREF() the vnode. */
1768 		if (!NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1769 			VREF(dp);
1770 			tdp = dp;
1771 			tnes = *exp;
1772 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1773 			    NULL);
1774 			NFSVOPUNLOCK(dp);
1775 		} else {
1776 			NFSVOPUNLOCK(dp);
1777 			nd->nd_cred->cr_uid = nd->nd_saveduid;
1778 			nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1779 			    0, -1);	/* Locks tdp. */
1780 			if (tdp) {
1781 				tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd,
1782 				    p, 1, NULL);
1783 				NFSVOPUNLOCK(tdp);
1784 			}
1785 		}
1786 	}
1787 	NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE);
1788 	nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1789 	if (!nd->nd_repstat) {
1790 		error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1791 		if (error) {
1792 			if (tdp)
1793 				vrele(tdp);
1794 			vrele(dp);
1795 			nfsvno_relpathbuf(&fromnd);
1796 			nfsvno_relpathbuf(&tond);
1797 			goto out;
1798 		}
1799 	}
1800 	if (nd->nd_repstat) {
1801 		if (nd->nd_flag & ND_NFSV3) {
1802 			nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1803 			    &fdiraft);
1804 			nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1805 			    &tdiraft);
1806 		}
1807 		if (tdp)
1808 			vrele(tdp);
1809 		vrele(dp);
1810 		nfsvno_relpathbuf(&fromnd);
1811 		nfsvno_relpathbuf(&tond);
1812 		goto out;
1813 	}
1814 
1815 	/*
1816 	 * Done parsing, now down to business.
1817 	 */
1818 	nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, &fdirp);
1819 	if (nd->nd_repstat) {
1820 		if (nd->nd_flag & ND_NFSV3) {
1821 			nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1822 			    &fdiraft);
1823 			nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1824 			    &tdiraft);
1825 		}
1826 		if (fdirp)
1827 			vrele(fdirp);
1828 		if (tdp)
1829 			vrele(tdp);
1830 		nfsvno_relpathbuf(&tond);
1831 		goto out;
1832 	}
1833 	if (fromnd.ni_vp->v_type == VDIR)
1834 		tond.ni_cnd.cn_flags |= WILLBEDIR;
1835 	nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, &tdirp);
1836 	nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd, p);
1837 	if (fdirp)
1838 		fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL);
1839 	if (tdirp)
1840 		tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL);
1841 	if (fdirp)
1842 		vrele(fdirp);
1843 	if (tdirp)
1844 		vrele(tdirp);
1845 	if (nd->nd_flag & ND_NFSV3) {
1846 		nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1847 		nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1848 	} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1849 		NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1850 		*tl++ = newnfs_false;
1851 		txdr_hyper(fdirfor.na_filerev, tl);
1852 		tl += 2;
1853 		txdr_hyper(fdiraft.na_filerev, tl);
1854 		tl += 2;
1855 		*tl++ = newnfs_false;
1856 		txdr_hyper(tdirfor.na_filerev, tl);
1857 		tl += 2;
1858 		txdr_hyper(tdiraft.na_filerev, tl);
1859 	}
1860 
1861 out:
1862 	NFSEXITCODE2(error, nd);
1863 	return (error);
1864 }
1865 
1866 /*
1867  * nfs link service
1868  */
1869 int
nfsrvd_link(struct nfsrv_descript * nd,int isdgram,vnode_t vp,vnode_t tovp,struct nfsexstuff * exp,struct nfsexstuff * toexp)1870 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1871     vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1872 {
1873 	struct nameidata named;
1874 	u_int32_t *tl;
1875 	int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1876 	vnode_t dirp = NULL, dp = NULL;
1877 	struct nfsvattr dirfor, diraft, at;
1878 	struct nfsexstuff tnes;
1879 	struct nfsrvfh dfh;
1880 	char *bufp;
1881 	u_long *hashp;
1882 	struct thread *p = curthread;
1883 	nfsquad_t clientid;
1884 
1885 	if (nd->nd_repstat) {
1886 		nfsrv_postopattr(nd, getret, &at);
1887 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1888 		goto out;
1889 	}
1890 	if ((vn_irflag_read(vp) & (VIRF_NAMEDDIR | VIRF_NAMEDATTR)) != 0 ||
1891 	    (tovp != NULL &&
1892 	     (vn_irflag_read(tovp) & (VIRF_NAMEDDIR | VIRF_NAMEDATTR)) != 0)) {
1893 		nd->nd_repstat = NFSERR_INVAL;
1894 		if (tovp != NULL)
1895 			vrele(tovp);
1896 	}
1897 	NFSVOPUNLOCK(vp);
1898 	if (!nd->nd_repstat && vp->v_type == VDIR) {
1899 		if (nd->nd_flag & ND_NFSV4)
1900 			nd->nd_repstat = NFSERR_ISDIR;
1901 		else
1902 			nd->nd_repstat = NFSERR_INVAL;
1903 		if (tovp)
1904 			vrele(tovp);
1905 	}
1906 	if (!nd->nd_repstat) {
1907 		if (nd->nd_flag & ND_NFSV4) {
1908 			dp = tovp;
1909 			tnes = *toexp;
1910 		} else {
1911 			error = nfsrv_mtofh(nd, &dfh);
1912 			if (error) {
1913 				vrele(vp);
1914 				/* tovp is always NULL unless NFSv4 */
1915 				goto out;
1916 			}
1917 			nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL,
1918 			    0, -1);
1919 			if (dp)
1920 				NFSVOPUNLOCK(dp);
1921 		}
1922 	}
1923 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT | NOCACHE);
1924 	if (!nd->nd_repstat) {
1925 		nfsvno_setpathbuf(&named, &bufp, &hashp);
1926 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1927 		if (error) {
1928 			vrele(vp);
1929 			if (dp)
1930 				vrele(dp);
1931 			nfsvno_relpathbuf(&named);
1932 			goto out;
1933 		}
1934 		if (!nd->nd_repstat) {
1935 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1936 			    &dirp);
1937 		} else {
1938 			if (dp)
1939 				vrele(dp);
1940 			nfsvno_relpathbuf(&named);
1941 		}
1942 	}
1943 	if (dirp) {
1944 		if (nd->nd_flag & ND_NFSV2) {
1945 			vrele(dirp);
1946 			dirp = NULL;
1947 		} else {
1948 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1949 			    NULL);
1950 		}
1951 	}
1952 	if (!nd->nd_repstat) {
1953 		clientid.qval = 0;
1954 		if ((nd->nd_flag & (ND_IMPLIEDCLID | ND_NFSV41)) ==
1955 		    (ND_IMPLIEDCLID | ND_NFSV41))
1956 			clientid.qval = nd->nd_clientid.qval;
1957 		nd->nd_repstat = nfsvno_link(&named, vp, clientid, nd->nd_cred,
1958 		    p, exp);
1959 	}
1960 	if (nd->nd_flag & ND_NFSV3)
1961 		getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL);
1962 	if (dirp) {
1963 		diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1964 		vrele(dirp);
1965 	}
1966 	vrele(vp);
1967 	if (nd->nd_flag & ND_NFSV3) {
1968 		nfsrv_postopattr(nd, getret, &at);
1969 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1970 	} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1971 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1972 		*tl++ = newnfs_false;
1973 		txdr_hyper(dirfor.na_filerev, tl);
1974 		tl += 2;
1975 		txdr_hyper(diraft.na_filerev, tl);
1976 	}
1977 
1978 out:
1979 	NFSEXITCODE2(error, nd);
1980 	return (error);
1981 }
1982 
1983 /*
1984  * nfs symbolic link service
1985  */
1986 int
nfsrvd_symlink(struct nfsrv_descript * nd,__unused int isdgram,vnode_t dp,vnode_t * vpp,fhandle_t * fhp,struct nfsexstuff * exp)1987 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1988     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1989 {
1990 	struct nfsvattr nva, dirfor, diraft;
1991 	struct nameidata named;
1992 	int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1993 	vnode_t dirp = NULL;
1994 	char *bufp, *pathcp = NULL;
1995 	u_long *hashp;
1996 	struct thread *p = curthread;
1997 
1998 	if (nd->nd_repstat) {
1999 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
2000 		goto out;
2001 	}
2002 	if (vpp)
2003 		*vpp = NULL;
2004 	NFSVNO_ATTRINIT(&nva);
2005 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2006 	    LOCKPARENT | NOCACHE);
2007 	nfsvno_setpathbuf(&named, &bufp, &hashp);
2008 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2009 	if (!error && !nd->nd_repstat)
2010 		error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
2011 	if (error) {
2012 		vrele(dp);
2013 		nfsvno_relpathbuf(&named);
2014 		goto out;
2015 	}
2016 	if (!nd->nd_repstat) {
2017 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp);
2018 	} else {
2019 		vrele(dp);
2020 		nfsvno_relpathbuf(&named);
2021 	}
2022 	if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
2023 		vrele(dirp);
2024 		dirp = NULL;
2025 	}
2026 
2027 	/*
2028 	 * And call nfsrvd_symlinksub() to do the common code. It will
2029 	 * return EBADRPC upon a parsing error, 0 otherwise.
2030 	 */
2031 	if (!nd->nd_repstat) {
2032 		if (dirp != NULL)
2033 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
2034 			    NULL);
2035 		nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
2036 		    &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
2037 		    pathcp, pathlen);
2038 	} else if (dirp != NULL) {
2039 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
2040 		vrele(dirp);
2041 	}
2042 	if (pathcp)
2043 		free(pathcp, M_TEMP);
2044 
2045 	if (nd->nd_flag & ND_NFSV3) {
2046 		if (!nd->nd_repstat) {
2047 			(void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1);
2048 			nfsrv_postopattr(nd, 0, &nva);
2049 		}
2050 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
2051 	}
2052 
2053 out:
2054 	NFSEXITCODE2(error, nd);
2055 	return (error);
2056 }
2057 
2058 /*
2059  * Common code for creating a symbolic link.
2060  */
2061 static void
nfsrvd_symlinksub(struct nfsrv_descript * nd,struct nameidata * ndp,struct nfsvattr * nvap,fhandle_t * fhp,vnode_t * vpp,vnode_t dirp,struct nfsvattr * dirforp,struct nfsvattr * diraftp,int * diraft_retp,nfsattrbit_t * attrbitp,NFSACL_T * aclp,NFSPROC_T * p,struct nfsexstuff * exp,char * pathcp,int pathlen)2062 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
2063     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
2064     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
2065     int *diraft_retp, nfsattrbit_t *attrbitp,
2066     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
2067     int pathlen)
2068 {
2069 	u_int32_t *tl;
2070 
2071 	nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
2072 	    !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
2073 	if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
2074 		nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
2075 		if (nd->nd_flag & ND_NFSV3) {
2076 			nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
2077 			if (!nd->nd_repstat)
2078 				nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
2079 				    nvap, nd, p, 1, NULL);
2080 		}
2081 		if (vpp != NULL && nd->nd_repstat == 0) {
2082 			NFSVOPUNLOCK(ndp->ni_vp);
2083 			*vpp = ndp->ni_vp;
2084 		} else
2085 			vput(ndp->ni_vp);
2086 	}
2087 	if (dirp) {
2088 		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
2089 		vrele(dirp);
2090 	}
2091 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
2092 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2093 		*tl++ = newnfs_false;
2094 		txdr_hyper(dirforp->na_filerev, tl);
2095 		tl += 2;
2096 		txdr_hyper(diraftp->na_filerev, tl);
2097 		(void) nfsrv_putattrbit(nd, attrbitp);
2098 	}
2099 
2100 	NFSEXITCODE2(0, nd);
2101 }
2102 
2103 /*
2104  * nfs mkdir service
2105  */
2106 int
nfsrvd_mkdir(struct nfsrv_descript * nd,__unused int isdgram,vnode_t dp,vnode_t * vpp,fhandle_t * fhp,struct nfsexstuff * exp)2107 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
2108     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
2109 {
2110 	struct nfsvattr nva, dirfor, diraft;
2111 	struct nameidata named;
2112 	u_int32_t *tl;
2113 	int error = 0, dirfor_ret = 1, diraft_ret = 1;
2114 	vnode_t dirp = NULL;
2115 	char *bufp;
2116 	u_long *hashp;
2117 	struct thread *p = curthread;
2118 
2119 	if (nd->nd_repstat) {
2120 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
2121 		goto out;
2122 	}
2123 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT | NOCACHE);
2124 	nfsvno_setpathbuf(&named, &bufp, &hashp);
2125 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2126 	if (error)
2127 		goto nfsmout;
2128 	if (!nd->nd_repstat) {
2129 		NFSVNO_ATTRINIT(&nva);
2130 		if (nd->nd_flag & ND_NFSV3) {
2131 			error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
2132 			if (error)
2133 				goto nfsmout;
2134 		} else {
2135 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2136 			nva.na_mode = nfstov_mode(*tl++);
2137 		}
2138 	}
2139 	if (!nd->nd_repstat) {
2140 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp);
2141 	} else {
2142 		vrele(dp);
2143 		nfsvno_relpathbuf(&named);
2144 	}
2145 	if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
2146 		vrele(dirp);
2147 		dirp = NULL;
2148 	}
2149 	if (nd->nd_repstat) {
2150 		if (dirp != NULL) {
2151 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
2152 			    NULL);
2153 			vrele(dirp);
2154 		}
2155 		if (nd->nd_flag & ND_NFSV3)
2156 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
2157 			    &diraft);
2158 		goto out;
2159 	}
2160 	if (dirp != NULL)
2161 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
2162 
2163 	/*
2164 	 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
2165 	 */
2166 	nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
2167 	    &diraft_ret, NULL, NULL, p, exp);
2168 
2169 	if (nd->nd_flag & ND_NFSV3) {
2170 		if (!nd->nd_repstat) {
2171 			(void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1);
2172 			nfsrv_postopattr(nd, 0, &nva);
2173 		}
2174 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
2175 	} else if (!nd->nd_repstat) {
2176 		(void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
2177 		nfsrv_fillattr(nd, &nva);
2178 	}
2179 
2180 out:
2181 	NFSEXITCODE2(0, nd);
2182 	return (0);
2183 nfsmout:
2184 	vrele(dp);
2185 	nfsvno_relpathbuf(&named);
2186 	NFSEXITCODE2(error, nd);
2187 	return (error);
2188 }
2189 
2190 /*
2191  * Code common to mkdir for V2,3 and 4.
2192  */
2193 static void
nfsrvd_mkdirsub(struct nfsrv_descript * nd,struct nameidata * ndp,struct nfsvattr * nvap,fhandle_t * fhp,vnode_t * vpp,vnode_t dirp,struct nfsvattr * dirforp,struct nfsvattr * diraftp,int * diraft_retp,nfsattrbit_t * attrbitp,NFSACL_T * aclp,NFSPROC_T * p,struct nfsexstuff * exp)2194 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
2195     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
2196     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
2197     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
2198     NFSPROC_T *p, struct nfsexstuff *exp)
2199 {
2200 	vnode_t vp;
2201 	u_int32_t *tl;
2202 
2203 	NFSVNO_SETATTRVAL(nvap, type, VDIR);
2204 	nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
2205 	    nd->nd_cred, p, exp);
2206 	if (!nd->nd_repstat) {
2207 		vp = ndp->ni_vp;
2208 		nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
2209 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
2210 		if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
2211 			nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1,
2212 			    NULL);
2213 		if (vpp && !nd->nd_repstat) {
2214 			NFSVOPUNLOCK(vp);
2215 			*vpp = vp;
2216 		} else {
2217 			vput(vp);
2218 		}
2219 	}
2220 	if (dirp) {
2221 		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
2222 		vrele(dirp);
2223 	}
2224 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
2225 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2226 		*tl++ = newnfs_false;
2227 		txdr_hyper(dirforp->na_filerev, tl);
2228 		tl += 2;
2229 		txdr_hyper(diraftp->na_filerev, tl);
2230 		(void) nfsrv_putattrbit(nd, attrbitp);
2231 	}
2232 
2233 	NFSEXITCODE2(0, nd);
2234 }
2235 
2236 /*
2237  * nfs commit service
2238  */
2239 int
nfsrvd_commit(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)2240 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
2241     vnode_t vp, __unused struct nfsexstuff *exp)
2242 {
2243 	struct nfsvattr bfor, aft;
2244 	u_int32_t *tl;
2245 	int error = 0, for_ret = 1, aft_ret = 1, cnt;
2246 	u_int64_t off;
2247 	struct thread *p = curthread;
2248 
2249        if (nd->nd_repstat) {
2250 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2251 		goto out;
2252 	}
2253 
2254 	/* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */
2255 	if (vp->v_type != VREG) {
2256 		if (nd->nd_flag & ND_NFSV3)
2257 			error = NFSERR_NOTSUPP;
2258 		else
2259 			error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL;
2260 		goto nfsmout;
2261 	}
2262 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2263 
2264 	/*
2265 	 * XXX At this time VOP_FSYNC() does not accept offset and byte
2266 	 * count parameters, so these arguments are useless (someday maybe).
2267 	 */
2268 	off = fxdr_hyper(tl);
2269 	tl += 2;
2270 	cnt = fxdr_unsigned(int, *tl);
2271 	if (nd->nd_flag & ND_NFSV3)
2272 		for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL);
2273 	nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
2274 	if (nd->nd_flag & ND_NFSV3) {
2275 		aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL);
2276 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2277 	}
2278 	vput(vp);
2279 	if (!nd->nd_repstat) {
2280 		NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2281 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
2282 		*tl = txdr_unsigned(nfsboottime.tv_usec);
2283 	}
2284 
2285 out:
2286 	NFSEXITCODE2(0, nd);
2287 	return (0);
2288 nfsmout:
2289 	vput(vp);
2290 	NFSEXITCODE2(error, nd);
2291 	return (error);
2292 }
2293 
2294 /*
2295  * nfs statfs service
2296  */
2297 int
nfsrvd_statfs(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)2298 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
2299     vnode_t vp, __unused struct nfsexstuff *exp)
2300 {
2301 	struct statfs *sf;
2302 	u_int32_t *tl;
2303 	int getret = 1;
2304 	struct nfsvattr at;
2305 	u_quad_t tval;
2306 	struct thread *p = curthread;
2307 
2308 	sf = NULL;
2309 	if (nd->nd_repstat) {
2310 		nfsrv_postopattr(nd, getret, &at);
2311 		goto out;
2312 	}
2313 	sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2314 	nd->nd_repstat = nfsvno_statfs(vp, sf);
2315 	getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2316 	vput(vp);
2317 	if (nd->nd_flag & ND_NFSV3)
2318 		nfsrv_postopattr(nd, getret, &at);
2319 	if (nd->nd_repstat)
2320 		goto out;
2321 	if (nd->nd_flag & ND_NFSV2) {
2322 		NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2323 		*tl++ = txdr_unsigned(NFS_V2MAXDATA);
2324 		*tl++ = txdr_unsigned(sf->f_bsize);
2325 		*tl++ = txdr_unsigned(sf->f_blocks);
2326 		*tl++ = txdr_unsigned(sf->f_bfree);
2327 		*tl = txdr_unsigned(sf->f_bavail);
2328 	} else {
2329 		NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2330 		tval = (u_quad_t)sf->f_blocks;
2331 		tval *= (u_quad_t)sf->f_bsize;
2332 		txdr_hyper(tval, tl); tl += 2;
2333 		tval = (u_quad_t)sf->f_bfree;
2334 		tval *= (u_quad_t)sf->f_bsize;
2335 		txdr_hyper(tval, tl); tl += 2;
2336 		tval = (u_quad_t)sf->f_bavail;
2337 		tval *= (u_quad_t)sf->f_bsize;
2338 		txdr_hyper(tval, tl); tl += 2;
2339 		tval = (u_quad_t)sf->f_files;
2340 		txdr_hyper(tval, tl); tl += 2;
2341 		tval = (u_quad_t)sf->f_ffree;
2342 		txdr_hyper(tval, tl); tl += 2;
2343 		tval = (u_quad_t)sf->f_ffree;
2344 		txdr_hyper(tval, tl); tl += 2;
2345 		*tl = 0;
2346 	}
2347 
2348 out:
2349 	free(sf, M_STATFS);
2350 	NFSEXITCODE2(0, nd);
2351 	return (0);
2352 }
2353 
2354 /*
2355  * nfs fsinfo service
2356  */
2357 int
nfsrvd_fsinfo(struct nfsrv_descript * nd,int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)2358 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2359     vnode_t vp, __unused struct nfsexstuff *exp)
2360 {
2361 	u_int32_t *tl;
2362 	struct nfsfsinfo fs;
2363 	int getret = 1;
2364 	struct nfsvattr at;
2365 	struct thread *p = curthread;
2366 
2367 	if (nd->nd_repstat) {
2368 		nfsrv_postopattr(nd, getret, &at);
2369 		goto out;
2370 	}
2371 	getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2372 	nfsvno_getfs(&fs, isdgram);
2373 	vput(vp);
2374 	nfsrv_postopattr(nd, getret, &at);
2375 	NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2376 	*tl++ = txdr_unsigned(fs.fs_rtmax);
2377 	*tl++ = txdr_unsigned(fs.fs_rtpref);
2378 	*tl++ = txdr_unsigned(fs.fs_rtmult);
2379 	*tl++ = txdr_unsigned(fs.fs_wtmax);
2380 	*tl++ = txdr_unsigned(fs.fs_wtpref);
2381 	*tl++ = txdr_unsigned(fs.fs_wtmult);
2382 	*tl++ = txdr_unsigned(fs.fs_dtpref);
2383 	txdr_hyper(fs.fs_maxfilesize, tl);
2384 	tl += 2;
2385 	txdr_nfsv3time(&fs.fs_timedelta, tl);
2386 	tl += 2;
2387 	*tl = txdr_unsigned(fs.fs_properties);
2388 
2389 out:
2390 	NFSEXITCODE2(0, nd);
2391 	return (0);
2392 }
2393 
2394 /*
2395  * nfs pathconf service
2396  */
2397 int
nfsrvd_pathconf(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)2398 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2399     vnode_t vp, __unused struct nfsexstuff *exp)
2400 {
2401 	struct nfsv3_pathconf *pc;
2402 	int getret = 1;
2403 	long linkmax, namemax, chownres, notrunc;
2404 	struct nfsvattr at;
2405 	struct thread *p = curthread;
2406 
2407 	if (nd->nd_repstat) {
2408 		nfsrv_postopattr(nd, getret, &at);
2409 		goto out;
2410 	}
2411 	nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2412 	    nd->nd_cred, p);
2413 	if (!nd->nd_repstat)
2414 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2415 		    nd->nd_cred, p);
2416 	if (!nd->nd_repstat)
2417 		nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2418 		    &chownres, nd->nd_cred, p);
2419 	if (!nd->nd_repstat)
2420 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, &notrunc,
2421 		    nd->nd_cred, p);
2422 	getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2423 	vput(vp);
2424 	nfsrv_postopattr(nd, getret, &at);
2425 	if (!nd->nd_repstat) {
2426 		NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2427 		pc->pc_linkmax = txdr_unsigned(linkmax);
2428 		pc->pc_namemax = txdr_unsigned(namemax);
2429 		pc->pc_notrunc = txdr_unsigned(notrunc);
2430 		pc->pc_chownrestricted = txdr_unsigned(chownres);
2431 
2432 		/*
2433 		 * These should probably be supported by VOP_PATHCONF(), but
2434 		 * until msdosfs is exportable (why would you want to?), the
2435 		 * Unix defaults should be ok.
2436 		 */
2437 		pc->pc_caseinsensitive = newnfs_false;
2438 		pc->pc_casepreserving = newnfs_true;
2439 	}
2440 
2441 out:
2442 	NFSEXITCODE2(0, nd);
2443 	return (0);
2444 }
2445 
2446 /*
2447  * nfsv4 lock service
2448  */
2449 int
nfsrvd_lock(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)2450 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2451     vnode_t vp, struct nfsexstuff *exp)
2452 {
2453 	u_int32_t *tl;
2454 	int i;
2455 	struct nfsstate *stp = NULL;
2456 	struct nfslock *lop;
2457 	struct nfslockconflict cf;
2458 	int error = 0;
2459 	u_short flags = NFSLCK_LOCK, lflags;
2460 	u_int64_t offset, len;
2461 	nfsv4stateid_t stateid;
2462 	nfsquad_t clientid;
2463 	struct thread *p = curthread;
2464 
2465 	NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2466 	i = fxdr_unsigned(int, *tl++);
2467 	switch (i) {
2468 	case NFSV4LOCKT_READW:
2469 		flags |= NFSLCK_BLOCKING;
2470 	case NFSV4LOCKT_READ:
2471 		lflags = NFSLCK_READ;
2472 		break;
2473 	case NFSV4LOCKT_WRITEW:
2474 		flags |= NFSLCK_BLOCKING;
2475 	case NFSV4LOCKT_WRITE:
2476 		lflags = NFSLCK_WRITE;
2477 		break;
2478 	default:
2479 		nd->nd_repstat = NFSERR_BADXDR;
2480 		goto nfsmout;
2481 	}
2482 	if (*tl++ == newnfs_true)
2483 		flags |= NFSLCK_RECLAIM;
2484 	offset = fxdr_hyper(tl);
2485 	tl += 2;
2486 	len = fxdr_hyper(tl);
2487 	tl += 2;
2488 	if (*tl == newnfs_true)
2489 		flags |= NFSLCK_OPENTOLOCK;
2490 	if (flags & NFSLCK_OPENTOLOCK) {
2491 		NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2492 		i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2493 		if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2494 			nd->nd_repstat = NFSERR_BADXDR;
2495 			goto nfsmout;
2496 		}
2497 		stp = malloc(sizeof (struct nfsstate) + i,
2498 			M_NFSDSTATE, M_WAITOK);
2499 		stp->ls_ownerlen = i;
2500 		stp->ls_op = nd->nd_rp;
2501 		stp->ls_seq = fxdr_unsigned(int, *tl++);
2502 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2503 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2504 			NFSX_STATEIDOTHER);
2505 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2506 
2507 		/*
2508 		 * For the special stateid of other all 0s and seqid == 1, set
2509 		 * the stateid to the current stateid, if it is set.
2510 		 */
2511 		if ((nd->nd_flag & ND_NFSV41) != 0 &&
2512 		    stp->ls_stateid.seqid == 1 &&
2513 		    stp->ls_stateid.other[0] == 0 &&
2514 		    stp->ls_stateid.other[1] == 0 &&
2515 		    stp->ls_stateid.other[2] == 0) {
2516 			if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2517 				stp->ls_stateid = nd->nd_curstateid;
2518 				stp->ls_stateid.seqid = 0;
2519 			} else {
2520 				nd->nd_repstat = NFSERR_BADSTATEID;
2521 				goto nfsmout;
2522 			}
2523 		}
2524 
2525 		stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2526 		clientid.lval[0] = *tl++;
2527 		clientid.lval[1] = *tl++;
2528 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2529 			if ((nd->nd_flag & ND_NFSV41) != 0)
2530 				clientid.qval = nd->nd_clientid.qval;
2531 			else if (nd->nd_clientid.qval != clientid.qval)
2532 				printf("EEK3 multiple clids\n");
2533 		} else {
2534 			if ((nd->nd_flag & ND_NFSV41) != 0)
2535 				printf("EEK! no clientid from session\n");
2536 			nd->nd_flag |= ND_IMPLIEDCLID;
2537 			nd->nd_clientid.qval = clientid.qval;
2538 		}
2539 		error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2540 		if (error)
2541 			goto nfsmout;
2542 	} else {
2543 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2544 		stp = malloc(sizeof (struct nfsstate),
2545 			M_NFSDSTATE, M_WAITOK);
2546 		stp->ls_ownerlen = 0;
2547 		stp->ls_op = nd->nd_rp;
2548 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2549 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2550 			NFSX_STATEIDOTHER);
2551 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2552 
2553 		/*
2554 		 * For the special stateid of other all 0s and seqid == 1, set
2555 		 * the stateid to the current stateid, if it is set.
2556 		 */
2557 		if ((nd->nd_flag & ND_NFSV41) != 0 &&
2558 		    stp->ls_stateid.seqid == 1 &&
2559 		    stp->ls_stateid.other[0] == 0 &&
2560 		    stp->ls_stateid.other[1] == 0 &&
2561 		    stp->ls_stateid.other[2] == 0) {
2562 			if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2563 				stp->ls_stateid = nd->nd_curstateid;
2564 				stp->ls_stateid.seqid = 0;
2565 			} else {
2566 				nd->nd_repstat = NFSERR_BADSTATEID;
2567 				goto nfsmout;
2568 			}
2569 		}
2570 
2571 		stp->ls_seq = fxdr_unsigned(int, *tl);
2572 		clientid.lval[0] = stp->ls_stateid.other[0];
2573 		clientid.lval[1] = stp->ls_stateid.other[1];
2574 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2575 			if ((nd->nd_flag & ND_NFSV41) != 0)
2576 				clientid.qval = nd->nd_clientid.qval;
2577 			else if (nd->nd_clientid.qval != clientid.qval)
2578 				printf("EEK4 multiple clids\n");
2579 		} else {
2580 			if ((nd->nd_flag & ND_NFSV41) != 0)
2581 				printf("EEK! no clientid from session\n");
2582 			nd->nd_flag |= ND_IMPLIEDCLID;
2583 			nd->nd_clientid.qval = clientid.qval;
2584 		}
2585 	}
2586 	lop = malloc(sizeof (struct nfslock),
2587 		M_NFSDLOCK, M_WAITOK);
2588 	lop->lo_first = offset;
2589 	if (len == NFS64BITSSET) {
2590 		lop->lo_end = NFS64BITSSET;
2591 	} else {
2592 		lop->lo_end = offset + len;
2593 		if (lop->lo_end <= lop->lo_first)
2594 			nd->nd_repstat = NFSERR_INVAL;
2595 	}
2596 	lop->lo_flags = lflags;
2597 	stp->ls_flags = flags;
2598 	stp->ls_uid = nd->nd_cred->cr_uid;
2599 
2600 	/*
2601 	 * Do basic access checking.
2602 	 */
2603 	if (!nd->nd_repstat && vp->v_type != VREG) {
2604 	    if (vp->v_type == VDIR)
2605 		nd->nd_repstat = NFSERR_ISDIR;
2606 	    else
2607 		nd->nd_repstat = NFSERR_INVAL;
2608 	}
2609 	if (!nd->nd_repstat) {
2610 	    if (lflags & NFSLCK_WRITE) {
2611 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2612 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2613 		    NFSACCCHK_VPISLOCKED, NULL);
2614 	    } else {
2615 		nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2616 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2617 		    NFSACCCHK_VPISLOCKED, NULL);
2618 		if (nd->nd_repstat)
2619 		    nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2620 			nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2621 			NFSACCCHK_VPISLOCKED, NULL);
2622 	    }
2623 	}
2624 
2625 	/*
2626 	 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2627 	 * seqid# gets updated. nfsrv_lockctrl() will return the value
2628 	 * of nd_repstat, if it gets that far.
2629 	 */
2630 	nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2631 		&stateid, exp, nd, p);
2632 	if (lop)
2633 		free(lop, M_NFSDLOCK);
2634 	if (stp)
2635 		free(stp, M_NFSDSTATE);
2636 	if (!nd->nd_repstat) {
2637 		/* For NFSv4.1, set the Current StateID. */
2638 		if ((nd->nd_flag & ND_NFSV41) != 0) {
2639 			nd->nd_curstateid = stateid;
2640 			nd->nd_flag |= ND_CURSTATEID;
2641 		}
2642 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2643 		*tl++ = txdr_unsigned(stateid.seqid);
2644 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2645 	} else if (nd->nd_repstat == NFSERR_DENIED) {
2646 		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2647 		txdr_hyper(cf.cl_first, tl);
2648 		tl += 2;
2649 		if (cf.cl_end == NFS64BITSSET)
2650 			len = NFS64BITSSET;
2651 		else
2652 			len = cf.cl_end - cf.cl_first;
2653 		txdr_hyper(len, tl);
2654 		tl += 2;
2655 		if (cf.cl_flags == NFSLCK_WRITE)
2656 			*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2657 		else
2658 			*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2659 		*tl++ = stateid.other[0];
2660 		*tl = stateid.other[1];
2661 		(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2662 	}
2663 	vput(vp);
2664 	NFSEXITCODE2(0, nd);
2665 	return (0);
2666 nfsmout:
2667 	vput(vp);
2668 	if (stp)
2669 		free(stp, M_NFSDSTATE);
2670 	NFSEXITCODE2(error, nd);
2671 	return (error);
2672 }
2673 
2674 /*
2675  * nfsv4 lock test service
2676  */
2677 int
nfsrvd_lockt(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)2678 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2679     vnode_t vp, struct nfsexstuff *exp)
2680 {
2681 	u_int32_t *tl;
2682 	int i;
2683 	struct nfsstate *stp = NULL;
2684 	struct nfslock lo, *lop = &lo;
2685 	struct nfslockconflict cf;
2686 	int error = 0;
2687 	nfsv4stateid_t stateid;
2688 	nfsquad_t clientid;
2689 	u_int64_t len;
2690 	struct thread *p = curthread;
2691 
2692 	NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2693 	i = fxdr_unsigned(int, *(tl + 7));
2694 	if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2695 		nd->nd_repstat = NFSERR_BADXDR;
2696 		goto nfsmout;
2697 	}
2698 	stp = malloc(sizeof (struct nfsstate) + i,
2699 	    M_NFSDSTATE, M_WAITOK);
2700 	stp->ls_ownerlen = i;
2701 	stp->ls_op = NULL;
2702 	stp->ls_flags = NFSLCK_TEST;
2703 	stp->ls_uid = nd->nd_cred->cr_uid;
2704 	i = fxdr_unsigned(int, *tl++);
2705 	switch (i) {
2706 	case NFSV4LOCKT_READW:
2707 		stp->ls_flags |= NFSLCK_BLOCKING;
2708 	case NFSV4LOCKT_READ:
2709 		lo.lo_flags = NFSLCK_READ;
2710 		break;
2711 	case NFSV4LOCKT_WRITEW:
2712 		stp->ls_flags |= NFSLCK_BLOCKING;
2713 	case NFSV4LOCKT_WRITE:
2714 		lo.lo_flags = NFSLCK_WRITE;
2715 		break;
2716 	default:
2717 		nd->nd_repstat = NFSERR_BADXDR;
2718 		goto nfsmout;
2719 	}
2720 	lo.lo_first = fxdr_hyper(tl);
2721 	tl += 2;
2722 	len = fxdr_hyper(tl);
2723 	if (len == NFS64BITSSET) {
2724 		lo.lo_end = NFS64BITSSET;
2725 	} else {
2726 		lo.lo_end = lo.lo_first + len;
2727 		if (lo.lo_end <= lo.lo_first)
2728 			nd->nd_repstat = NFSERR_INVAL;
2729 	}
2730 	tl += 2;
2731 	clientid.lval[0] = *tl++;
2732 	clientid.lval[1] = *tl;
2733 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2734 		if ((nd->nd_flag & ND_NFSV41) != 0)
2735 			clientid.qval = nd->nd_clientid.qval;
2736 		else if (nd->nd_clientid.qval != clientid.qval)
2737 			printf("EEK5 multiple clids\n");
2738 	} else {
2739 		if ((nd->nd_flag & ND_NFSV41) != 0)
2740 			printf("EEK! no clientid from session\n");
2741 		nd->nd_flag |= ND_IMPLIEDCLID;
2742 		nd->nd_clientid.qval = clientid.qval;
2743 	}
2744 	error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2745 	if (error)
2746 		goto nfsmout;
2747 	if (!nd->nd_repstat && vp->v_type != VREG) {
2748 	    if (vp->v_type == VDIR)
2749 		nd->nd_repstat = NFSERR_ISDIR;
2750 	    else
2751 		nd->nd_repstat = NFSERR_INVAL;
2752 	}
2753 	if (!nd->nd_repstat)
2754 	  nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2755 	    &stateid, exp, nd, p);
2756 	if (nd->nd_repstat) {
2757 	    if (nd->nd_repstat == NFSERR_DENIED) {
2758 		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2759 		txdr_hyper(cf.cl_first, tl);
2760 		tl += 2;
2761 		if (cf.cl_end == NFS64BITSSET)
2762 			len = NFS64BITSSET;
2763 		else
2764 			len = cf.cl_end - cf.cl_first;
2765 		txdr_hyper(len, tl);
2766 		tl += 2;
2767 		if (cf.cl_flags == NFSLCK_WRITE)
2768 			*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2769 		else
2770 			*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2771 		*tl++ = stp->ls_stateid.other[0];
2772 		*tl = stp->ls_stateid.other[1];
2773 		(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2774 	    }
2775 	}
2776 	vput(vp);
2777 	if (stp)
2778 		free(stp, M_NFSDSTATE);
2779 	NFSEXITCODE2(0, nd);
2780 	return (0);
2781 nfsmout:
2782 	vput(vp);
2783 	if (stp)
2784 		free(stp, M_NFSDSTATE);
2785 	NFSEXITCODE2(error, nd);
2786 	return (error);
2787 }
2788 
2789 /*
2790  * nfsv4 unlock service
2791  */
2792 int
nfsrvd_locku(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)2793 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2794     vnode_t vp, struct nfsexstuff *exp)
2795 {
2796 	u_int32_t *tl;
2797 	int i;
2798 	struct nfsstate *stp;
2799 	struct nfslock *lop;
2800 	int error = 0;
2801 	nfsv4stateid_t stateid;
2802 	nfsquad_t clientid;
2803 	u_int64_t len;
2804 	struct thread *p = curthread;
2805 
2806 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2807 	stp = malloc(sizeof (struct nfsstate),
2808 	    M_NFSDSTATE, M_WAITOK);
2809 	lop = malloc(sizeof (struct nfslock),
2810 	    M_NFSDLOCK, M_WAITOK);
2811 	stp->ls_flags = NFSLCK_UNLOCK;
2812 	lop->lo_flags = NFSLCK_UNLOCK;
2813 	stp->ls_op = nd->nd_rp;
2814 	i = fxdr_unsigned(int, *tl++);
2815 	switch (i) {
2816 	case NFSV4LOCKT_READW:
2817 		stp->ls_flags |= NFSLCK_BLOCKING;
2818 	case NFSV4LOCKT_READ:
2819 		break;
2820 	case NFSV4LOCKT_WRITEW:
2821 		stp->ls_flags |= NFSLCK_BLOCKING;
2822 	case NFSV4LOCKT_WRITE:
2823 		break;
2824 	default:
2825 		nd->nd_repstat = NFSERR_BADXDR;
2826 		free(stp, M_NFSDSTATE);
2827 		free(lop, M_NFSDLOCK);
2828 		goto nfsmout;
2829 	}
2830 	stp->ls_ownerlen = 0;
2831 	stp->ls_uid = nd->nd_cred->cr_uid;
2832 	stp->ls_seq = fxdr_unsigned(int, *tl++);
2833 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2834 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2835 	    NFSX_STATEIDOTHER);
2836 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2837 
2838 	/*
2839 	 * For the special stateid of other all 0s and seqid == 1, set the
2840 	 * stateid to the current stateid, if it is set.
2841 	 */
2842 	if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
2843 	    stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
2844 	    stp->ls_stateid.other[2] == 0) {
2845 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2846 			stp->ls_stateid = nd->nd_curstateid;
2847 			stp->ls_stateid.seqid = 0;
2848 		} else {
2849 			nd->nd_repstat = NFSERR_BADSTATEID;
2850 			free(stp, M_NFSDSTATE);
2851 			free(lop, M_NFSDLOCK);
2852 			goto nfsmout;
2853 		}
2854 	}
2855 
2856 	lop->lo_first = fxdr_hyper(tl);
2857 	tl += 2;
2858 	len = fxdr_hyper(tl);
2859 	if (len == NFS64BITSSET) {
2860 		lop->lo_end = NFS64BITSSET;
2861 	} else {
2862 		lop->lo_end = lop->lo_first + len;
2863 		if (lop->lo_end <= lop->lo_first)
2864 			nd->nd_repstat = NFSERR_INVAL;
2865 	}
2866 	clientid.lval[0] = stp->ls_stateid.other[0];
2867 	clientid.lval[1] = stp->ls_stateid.other[1];
2868 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2869 		if ((nd->nd_flag & ND_NFSV41) != 0)
2870 			clientid.qval = nd->nd_clientid.qval;
2871 		else if (nd->nd_clientid.qval != clientid.qval)
2872 			printf("EEK6 multiple clids\n");
2873 	} else {
2874 		if ((nd->nd_flag & ND_NFSV41) != 0)
2875 			printf("EEK! no clientid from session\n");
2876 		nd->nd_flag |= ND_IMPLIEDCLID;
2877 		nd->nd_clientid.qval = clientid.qval;
2878 	}
2879 	if (!nd->nd_repstat && vp->v_type != VREG) {
2880 	    if (vp->v_type == VDIR)
2881 		nd->nd_repstat = NFSERR_ISDIR;
2882 	    else
2883 		nd->nd_repstat = NFSERR_INVAL;
2884 	}
2885 	/*
2886 	 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2887 	 * seqid# gets incremented. nfsrv_lockctrl() will return the
2888 	 * value of nd_repstat, if it gets that far.
2889 	 */
2890 	nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2891 	    &stateid, exp, nd, p);
2892 	if (stp)
2893 		free(stp, M_NFSDSTATE);
2894 	if (lop)
2895 		free(lop, M_NFSDLOCK);
2896 	if (!nd->nd_repstat) {
2897 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2898 		*tl++ = txdr_unsigned(stateid.seqid);
2899 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2900 	}
2901 nfsmout:
2902 	vput(vp);
2903 	NFSEXITCODE2(error, nd);
2904 	return (error);
2905 }
2906 
2907 /*
2908  * nfsv4 open service
2909  */
2910 int
nfsrvd_open(struct nfsrv_descript * nd,__unused int isdgram,vnode_t dp,vnode_t * vpp,__unused fhandle_t * fhp,struct nfsexstuff * exp)2911 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2912     vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp)
2913 {
2914 	u_int32_t *tl;
2915 	int i, retext;
2916 	struct nfsstate *stp = NULL;
2917 	int error = 0, create, claim, exclusive_flag = 0, override;
2918 	u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2919 	int how = NFSCREATE_UNCHECKED;
2920 	int32_t cverf[2], tverf[2] = { 0, 0 };
2921 	vnode_t vp = NULL, dirp = NULL;
2922 	struct nfsvattr nva, dirfor, diraft, nva2;
2923 	struct nameidata named;
2924 	nfsv4stateid_t stateid, delegstateid;
2925 	nfsattrbit_t attrbits;
2926 	nfsquad_t clientid;
2927 	char *bufp = NULL;
2928 	u_long *hashp;
2929 	NFSACL_T *aclp = NULL;
2930 	struct thread *p = curthread;
2931 	bool done_namei;
2932 	__enum_uint8_decl(wdelegace) { USENONE, USEMODE, USENFSV4ACL }
2933 	    delegace;
2934 
2935 #ifdef NFS4_ACL_EXTATTR_NAME
2936 	aclp = acl_alloc(M_WAITOK);
2937 	aclp->acl_cnt = 0;
2938 #endif
2939 	NFSZERO_ATTRBIT(&attrbits);
2940 	done_namei = false;
2941 	delegace = USEMODE;
2942 	named.ni_cnd.cn_nameiop = 0;
2943 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2944 	i = fxdr_unsigned(int, *(tl + 5));
2945 	if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2946 		nd->nd_repstat = NFSERR_BADXDR;
2947 		goto nfsmout;
2948 	}
2949 	stp = malloc(sizeof (struct nfsstate) + i,
2950 	    M_NFSDSTATE, M_WAITOK);
2951 	stp->ls_ownerlen = i;
2952 	stp->ls_op = nd->nd_rp;
2953 	stp->ls_flags = NFSLCK_OPEN;
2954 	stp->ls_uid = nd->nd_cred->cr_uid;
2955 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2956 	i = fxdr_unsigned(int, *tl++);
2957 	retext = 0;
2958 	if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
2959 	    NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
2960 		retext = 1;
2961 		/* For now, ignore these. */
2962 		i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
2963 		switch (i & NFSV4OPEN_WANTDELEGMASK) {
2964 		case NFSV4OPEN_WANTANYDELEG:
2965 			stp->ls_flags |= (NFSLCK_WANTRDELEG |
2966 			    NFSLCK_WANTWDELEG);
2967 			i &= ~NFSV4OPEN_WANTDELEGMASK;
2968 			break;
2969 		case NFSV4OPEN_WANTREADDELEG:
2970 			stp->ls_flags |= NFSLCK_WANTRDELEG;
2971 			i &= ~NFSV4OPEN_WANTDELEGMASK;
2972 			break;
2973 		case NFSV4OPEN_WANTWRITEDELEG:
2974 			stp->ls_flags |= NFSLCK_WANTWDELEG;
2975 			i &= ~NFSV4OPEN_WANTDELEGMASK;
2976 			break;
2977 		case NFSV4OPEN_WANTNODELEG:
2978 			stp->ls_flags |= NFSLCK_WANTNODELEG;
2979 			i &= ~NFSV4OPEN_WANTDELEGMASK;
2980 			break;
2981 		case NFSV4OPEN_WANTCANCEL:
2982 			printf("NFSv4: ignore Open WantCancel\n");
2983 			i &= ~NFSV4OPEN_WANTDELEGMASK;
2984 			break;
2985 		default:
2986 			/* nd_repstat will be set to NFSERR_INVAL below. */
2987 			break;
2988 		}
2989 	}
2990 	switch (i) {
2991 	case NFSV4OPEN_ACCESSREAD:
2992 		stp->ls_flags |= NFSLCK_READACCESS;
2993 		break;
2994 	case NFSV4OPEN_ACCESSWRITE:
2995 		stp->ls_flags |= NFSLCK_WRITEACCESS;
2996 		break;
2997 	case NFSV4OPEN_ACCESSBOTH:
2998 		stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2999 		break;
3000 	default:
3001 		nd->nd_repstat = NFSERR_INVAL;
3002 	}
3003 	i = fxdr_unsigned(int, *tl++);
3004 	switch (i) {
3005 	case NFSV4OPEN_DENYNONE:
3006 		break;
3007 	case NFSV4OPEN_DENYREAD:
3008 		stp->ls_flags |= NFSLCK_READDENY;
3009 		break;
3010 	case NFSV4OPEN_DENYWRITE:
3011 		stp->ls_flags |= NFSLCK_WRITEDENY;
3012 		break;
3013 	case NFSV4OPEN_DENYBOTH:
3014 		stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3015 		break;
3016 	default:
3017 		nd->nd_repstat = NFSERR_INVAL;
3018 	}
3019 	clientid.lval[0] = *tl++;
3020 	clientid.lval[1] = *tl;
3021 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3022 		if ((nd->nd_flag & ND_NFSV41) != 0)
3023 			clientid.qval = nd->nd_clientid.qval;
3024 		else if (nd->nd_clientid.qval != clientid.qval)
3025 			printf("EEK7 multiple clids\n");
3026 	} else {
3027 		if ((nd->nd_flag & ND_NFSV41) != 0)
3028 			printf("EEK! no clientid from session\n");
3029 		nd->nd_flag |= ND_IMPLIEDCLID;
3030 		nd->nd_clientid.qval = clientid.qval;
3031 	}
3032 	error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
3033 	if (error)
3034 		goto nfsmout;
3035 	NFSVNO_ATTRINIT(&nva);
3036 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3037 	create = fxdr_unsigned(int, *tl);
3038 	if (!nd->nd_repstat)
3039 		nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
3040 	if (create == NFSV4OPEN_CREATE) {
3041 		nva.na_type = VREG;
3042 		nva.na_mode = 0;
3043 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3044 		how = fxdr_unsigned(int, *tl);
3045 		switch (how) {
3046 		case NFSCREATE_UNCHECKED:
3047 		case NFSCREATE_GUARDED:
3048 			error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
3049 			if (error)
3050 				goto nfsmout;
3051 			/*
3052 			 * If the na_gid being set is the same as that of
3053 			 * the directory it is going in, clear it, since
3054 			 * that is what will be set by default. This allows
3055 			 * a user that isn't in that group to do the create.
3056 			 */
3057 			if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
3058 			    nva.na_gid == dirfor.na_gid)
3059 				NFSVNO_UNSET(&nva, gid);
3060 			if (!nd->nd_repstat)
3061 				nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
3062 			break;
3063 		case NFSCREATE_EXCLUSIVE:
3064 			NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
3065 			cverf[0] = *tl++;
3066 			cverf[1] = *tl;
3067 			if ((vn_irflag_read(dp) & VIRF_NAMEDDIR) != 0)
3068 				nd->nd_repstat = NFSERR_INVAL;
3069 			break;
3070 		case NFSCREATE_EXCLUSIVE41:
3071 			NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
3072 			cverf[0] = *tl++;
3073 			cverf[1] = *tl;
3074 			error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
3075 			if (error != 0)
3076 				goto nfsmout;
3077 			if ((vn_irflag_read(dp) & VIRF_NAMEDDIR) != 0 ||
3078 			    NFSISSET_ATTRBIT(&attrbits,
3079 			    NFSATTRBIT_TIMEACCESSSET))
3080 				nd->nd_repstat = NFSERR_INVAL;
3081 			/*
3082 			 * If the na_gid being set is the same as that of
3083 			 * the directory it is going in, clear it, since
3084 			 * that is what will be set by default. This allows
3085 			 * a user that isn't in that group to do the create.
3086 			 */
3087 			if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
3088 			    nva.na_gid == dirfor.na_gid)
3089 				NFSVNO_UNSET(&nva, gid);
3090 			if (nd->nd_repstat == 0)
3091 				nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
3092 			break;
3093 		default:
3094 			nd->nd_repstat = NFSERR_BADXDR;
3095 			goto nfsmout;
3096 		}
3097 	} else if (create != NFSV4OPEN_NOCREATE) {
3098 		nd->nd_repstat = NFSERR_BADXDR;
3099 		goto nfsmout;
3100 	}
3101 
3102 	/*
3103 	 * Now, handle the claim, which usually includes looking up a
3104 	 * name in the directory referenced by dp. The exception is
3105 	 * NFSV4OPEN_CLAIMPREVIOUS.
3106 	 */
3107 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3108 	claim = fxdr_unsigned(int, *tl);
3109 	if (claim == NFSV4OPEN_CLAIMDELEGATECUR || claim ==
3110 	    NFSV4OPEN_CLAIMDELEGATECURFH) {
3111 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3112 		stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3113 		NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
3114 		stp->ls_flags |= NFSLCK_DELEGCUR;
3115 	} else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV || claim ==
3116 	    NFSV4OPEN_CLAIMDELEGATEPREVFH) {
3117 		stp->ls_flags |= NFSLCK_DELEGPREV;
3118 	}
3119 	if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
3120 	    || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
3121 		if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
3122 		    claim != NFSV4OPEN_CLAIMNULL)
3123 			nd->nd_repstat = NFSERR_INVAL;
3124 		if (nd->nd_repstat) {
3125 			nd->nd_repstat = nfsrv_opencheck(clientid,
3126 			    &stateid, stp, NULL, nd, p, nd->nd_repstat);
3127 			goto nfsmout;
3128 		}
3129 		if (create == NFSV4OPEN_CREATE)
3130 		    NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
3131 			LOCKPARENT | LOCKLEAF | NOCACHE);
3132 		else
3133 		    NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3134 			LOCKLEAF);
3135 		nfsvno_setpathbuf(&named, &bufp, &hashp);
3136 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3137 		if (error) {
3138 			vrele(dp);
3139 #ifdef NFS4_ACL_EXTATTR_NAME
3140 			acl_free(aclp);
3141 #endif
3142 			free(stp, M_NFSDSTATE);
3143 			nfsvno_relpathbuf(&named);
3144 			NFSEXITCODE2(error, nd);
3145 			return (error);
3146 		}
3147 		if (!nd->nd_repstat) {
3148 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
3149 			    &dirp);
3150 		} else {
3151 			vrele(dp);
3152 			nfsvno_relpathbuf(&named);
3153 		}
3154 		if (create == NFSV4OPEN_CREATE) {
3155 		    switch (how) {
3156 		    case NFSCREATE_UNCHECKED:
3157 			if (nd->nd_repstat == 0 && named.ni_vp != NULL) {
3158 				/*
3159 				 * Clear the setable attribute bits, except
3160 				 * for Size, if it is being truncated.
3161 				 */
3162 				NFSZERO_ATTRBIT(&attrbits);
3163 				if (NFSVNO_ISSETSIZE(&nva))
3164 					NFSSETBIT_ATTRBIT(&attrbits,
3165 					    NFSATTRBIT_SIZE);
3166 			}
3167 			break;
3168 		    case NFSCREATE_GUARDED:
3169 			if (nd->nd_repstat == 0 && named.ni_vp != NULL) {
3170 				nd->nd_repstat = EEXIST;
3171 				done_namei = true;
3172 			}
3173 			break;
3174 		    case NFSCREATE_EXCLUSIVE:
3175 			if (nd->nd_repstat == 0 && named.ni_vp == NULL)
3176 				nva.na_mode = 0;
3177 			/* FALLTHROUGH */
3178 		    case NFSCREATE_EXCLUSIVE41:
3179 			if (nd->nd_repstat == 0 && named.ni_vp != NULL) {
3180 				nd->nd_repstat = nfsvno_getattr(named.ni_vp,
3181 				    &nva2, nd, p, 1, NULL);
3182 				if (nd->nd_repstat == 0) {
3183 					tverf[0] = nva2.na_atime.tv_sec;
3184 					tverf[1] = nva2.na_atime.tv_nsec;
3185 					if (cverf[0] != tverf[0] ||
3186 					     cverf[1] != tverf[1])
3187 						nd->nd_repstat = EEXIST;
3188 				}
3189 				if (nd->nd_repstat != 0)
3190 					done_namei = true;
3191 			}
3192 			exclusive_flag = 1;
3193 			break;
3194 		    }
3195 		}
3196 		nfsvno_open(nd, &named, clientid, &stateid, stp,
3197 		    &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
3198 		    nd->nd_cred, done_namei, exp, &vp);
3199 	} else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
3200 	    NFSV4OPEN_CLAIMFH || claim == NFSV4OPEN_CLAIMDELEGATECURFH ||
3201 	    claim == NFSV4OPEN_CLAIMDELEGATEPREVFH) {
3202 		if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3203 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3204 			i = fxdr_unsigned(int, *tl);
3205 			switch (i) {
3206 			case NFSV4OPEN_DELEGATEREAD:
3207 				stp->ls_flags |= NFSLCK_DELEGREAD;
3208 				break;
3209 			case NFSV4OPEN_DELEGATEWRITE:
3210 				stp->ls_flags |= NFSLCK_DELEGWRITE;
3211 			case NFSV4OPEN_DELEGATENONE:
3212 				break;
3213 			default:
3214 				nd->nd_repstat = NFSERR_BADXDR;
3215 				goto nfsmout;
3216 			}
3217 			stp->ls_flags |= NFSLCK_RECLAIM;
3218 		} else {
3219 			if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
3220 				nd->nd_repstat = NFSERR_INVAL;
3221 		}
3222 		vp = dp;
3223 		NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
3224 		if (!VN_IS_DOOMED(vp))
3225 			nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
3226 			    stp, vp, nd, p, nd->nd_repstat);
3227 		else
3228 			nd->nd_repstat = NFSERR_PERM;
3229 	} else {
3230 		nd->nd_repstat = NFSERR_BADXDR;
3231 		goto nfsmout;
3232 	}
3233 
3234 	/*
3235 	 * Do basic access checking.
3236 	 */
3237 	if (!nd->nd_repstat && vp->v_type != VREG) {
3238 		/*
3239 		 * The IETF working group decided that this is the correct
3240 		 * error return for all non-regular files.
3241 		 */
3242 		nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
3243 	}
3244 
3245 	/*
3246 	 * If the Open is being done for a file that already exists, apply
3247 	 * normal permission checking including for the file owner, if
3248 	 * vfs.nfsd.v4openaccess is set.
3249 	 * Previously, the owner was always allowed to open the file to
3250 	 * be consistent with the NFS tradition of always allowing the
3251 	 * owner of the file to write to the file regardless of permissions.
3252 	 * It now appears that the Linux client expects the owner
3253 	 * permissions to be checked for opens that are not creating the
3254 	 * file.  I believe the correct approach is to use the Access
3255 	 * operation's results to be consistent with NFSv3, but that is
3256 	 * not what the current Linux client appears to be doing.
3257 	 * Since both the Linux and OpenSolaris NFSv4 servers do this check,
3258 	 * I have enabled it by default.  Since Linux does not apply this
3259 	 * check for claim_delegate_cur, this code does the same.
3260 	 * If this semantic change causes a problem, it can be disabled by
3261 	 * setting the sysctl vfs.nfsd.v4openaccess to 0 to re-enable the
3262 	 * previous semantics.
3263 	 */
3264 	if (nfsrv_openaccess && create == NFSV4OPEN_NOCREATE &&
3265 	    (stp->ls_flags & NFSLCK_DELEGCUR) == 0)
3266 		override = NFSACCCHK_NOOVERRIDE;
3267 	else
3268 		override = NFSACCCHK_ALLOWOWNER;
3269 	if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
3270 	    nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
3271 	        exp, p, override, NFSACCCHK_VPISLOCKED, NULL);
3272 	if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
3273 	    nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
3274 	        exp, p, override, NFSACCCHK_VPISLOCKED, NULL);
3275 	    if (nd->nd_repstat)
3276 		nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
3277 		    nd->nd_cred, exp, p, override,
3278 		    NFSACCCHK_VPISLOCKED, NULL);
3279 	}
3280 
3281 	if (!nd->nd_repstat)
3282 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3283 
3284 	if (nd->nd_repstat == 0 && aclp != NULL && nfsrv_issuedelegs != 0 &&
3285 	    (dp->v_mount->mnt_flag & MNT_NFS4ACLS) != 0) {
3286 		if (aclp->acl_cnt == 0 && create == NFSV4OPEN_NOCREATE) {
3287 			int retacl;
3288 
3289 			/* We do not yet have an ACL, so try and get one. */
3290 			retacl = VOP_GETACL(vp, ACL_TYPE_NFS4, aclp,
3291 			    nd->nd_cred, p);
3292 			if (retacl != 0 && retacl != ENOATTR &&
3293 			    retacl != EOPNOTSUPP && retacl != EINVAL)
3294 				delegace = USENONE;
3295 			else if (retacl == 0 && aclp->acl_cnt > 0)
3296 				delegace = USENFSV4ACL;
3297 		} else if (aclp->acl_cnt > 0 && create == NFSV4OPEN_CREATE) {
3298 			delegace = USENFSV4ACL;
3299 		}
3300 	}
3301 
3302 	/*
3303 	 * Do the open locking/delegation stuff.
3304 	 */
3305 	if (!nd->nd_repstat)
3306 	    nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
3307 		&delegstateid, &rflags, exp, p, nva.na_filerev);
3308 
3309 	/*
3310 	 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
3311 	 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
3312 	 * (ie: Leave the NFSVOPUNLOCK() about here.)
3313 	 */
3314 	if (vp)
3315 		NFSVOPUNLOCK(vp);
3316 	if (stp)
3317 		free(stp, M_NFSDSTATE);
3318 	if (!nd->nd_repstat && dirp)
3319 		nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
3320 	if (!nd->nd_repstat) {
3321 		/* For NFSv4.1, set the Current StateID. */
3322 		if ((nd->nd_flag & ND_NFSV41) != 0) {
3323 			nd->nd_curstateid = stateid;
3324 			nd->nd_flag |= ND_CURSTATEID;
3325 		}
3326 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
3327 		*tl++ = txdr_unsigned(stateid.seqid);
3328 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3329 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3330 		if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3331 			*tl++ = newnfs_true;
3332 			*tl++ = 0;
3333 			*tl++ = 0;
3334 			*tl++ = 0;
3335 			*tl++ = 0;
3336 		} else {
3337 			*tl++ = newnfs_false;	/* Since dirp is not locked */
3338 			txdr_hyper(dirfor.na_filerev, tl);
3339 			tl += 2;
3340 			txdr_hyper(diraft.na_filerev, tl);
3341 			tl += 2;
3342 		}
3343 		*tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
3344 		(void) nfsrv_putattrbit(nd, &attrbits);
3345 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3346 		if (rflags & NFSV4OPEN_READDELEGATE)
3347 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
3348 		else if (rflags & NFSV4OPEN_WRITEDELEGATE)
3349 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
3350 		else if (retext != 0) {
3351 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
3352 			if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) {
3353 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3354 				*tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3355 			} else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) {
3356 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3357 				*tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE);
3358 			} else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
3359 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3360 				*tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
3361 				*tl = newnfs_false;
3362 			} else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
3363 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3364 				*tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
3365 				*tl = newnfs_false;
3366 			} else if ((rflags &
3367 			    NFSV4OPEN_WDNOTSUPPDOWNGRADE) != 0) {
3368 				NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3369 				*tl = txdr_unsigned(NFSV4OPEN_NOTSUPPDOWNGRADE);
3370 			} else if ((rflags & NFSV4OPEN_WDNOTSUPPUPGRADE) != 0) {
3371 				NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3372 				*tl = txdr_unsigned(NFSV4OPEN_NOTSUPPUPGRADE);
3373 			} else {
3374 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3375 				*tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3376 			}
3377 		} else
3378 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
3379 		if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
3380 			NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
3381 			*tl++ = txdr_unsigned(delegstateid.seqid);
3382 			NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
3383 			    NFSX_STATEIDOTHER);
3384 			tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3385 			if (rflags & NFSV4OPEN_RECALL)
3386 				*tl = newnfs_true;
3387 			else
3388 				*tl = newnfs_false;
3389 			if (rflags & NFSV4OPEN_WRITEDELEGATE) {
3390 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3391 				*tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
3392 				txdr_hyper(nva.na_size, tl);
3393 			}
3394 
3395 			/* Set up the write delegation ACE. */
3396 			NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3397 			if (delegace == USENFSV4ACL) {
3398 				int j;
3399 
3400 				for (j = 0; j < aclp->acl_cnt; j++) {
3401 					if (aclp->acl_entry[j].ae_tag ==
3402 					    ACL_USER_OBJ ||
3403 					    aclp->acl_entry[j].ae_entry_type !=
3404 					    ACL_ENTRY_TYPE_ALLOW)
3405 						break;
3406 				}
3407 				if (j < aclp->acl_cnt &&
3408 				    aclp->acl_entry[j].ae_tag ==
3409 				    ACL_USER_OBJ &&
3410 				    aclp->acl_entry[j].ae_entry_type ==
3411 				    ACL_ENTRY_TYPE_ALLOW) {
3412 					/* Use this ACE. */
3413 					*tl++ = txdr_unsigned(
3414 					    NFSV4ACE_ALLOWEDTYPE);
3415 					*tl++ = txdr_unsigned(0x0);
3416 					*tl = txdr_unsigned(
3417 					    nfs_aceperm(
3418 					    aclp->acl_entry[j].ae_perm));
3419 					(void)nfsm_strtom(nd, "OWNER@", 6);
3420 				} else
3421 					delegace = USENONE;
3422 			}
3423 			if (delegace == USENONE) {
3424 				/* Don't allow anything. */
3425 				*tl++ = 0x0;
3426 				*tl++ = 0x0;
3427 				*tl = 0x0;
3428 				NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3429 				*tl = 0;
3430 			} else if (delegace == USEMODE) {
3431 				/* Build from mode. */
3432 				*tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
3433 				*tl++ = txdr_unsigned(0x0);
3434 				acemask = NFSV4ACE_ALLFILESMASK;
3435 				if (nva.na_mode & S_IRUSR)
3436 					acemask |= NFSV4ACE_READMASK;
3437 				if (nva.na_mode & S_IWUSR)
3438 					acemask |= NFSV4ACE_WRITEMASK;
3439 				if (nva.na_mode & S_IXUSR)
3440 					acemask |= NFSV4ACE_EXECUTEMASK;
3441 				*tl = txdr_unsigned(acemask);
3442 				(void)nfsm_strtom(nd, "OWNER@", 6);
3443 			}
3444 		}
3445 		*vpp = vp;
3446 	} else if (vp) {
3447 		vrele(vp);
3448 	}
3449 	if (dirp)
3450 		vrele(dirp);
3451 #ifdef NFS4_ACL_EXTATTR_NAME
3452 	acl_free(aclp);
3453 #endif
3454 	NFSEXITCODE2(0, nd);
3455 	return (0);
3456 nfsmout:
3457 	vrele(dp);
3458 #ifdef NFS4_ACL_EXTATTR_NAME
3459 	acl_free(aclp);
3460 #endif
3461 	if (stp)
3462 		free(stp, M_NFSDSTATE);
3463 	NFSEXITCODE2(error, nd);
3464 	return (error);
3465 }
3466 
3467 /*
3468  * nfsv4 close service
3469  */
3470 int
nfsrvd_close(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)3471 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
3472     vnode_t vp, __unused struct nfsexstuff *exp)
3473 {
3474 	u_int32_t *tl;
3475 	struct nfsstate st, *stp = &st;
3476 	int error = 0, writeacc;
3477 	nfsv4stateid_t stateid;
3478 	nfsquad_t clientid;
3479 	struct nfsvattr na;
3480 	struct thread *p = curthread;
3481 
3482 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
3483 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3484 	stp->ls_ownerlen = 0;
3485 	stp->ls_op = nd->nd_rp;
3486 	stp->ls_uid = nd->nd_cred->cr_uid;
3487 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3488 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3489 	    NFSX_STATEIDOTHER);
3490 
3491 	/*
3492 	 * For the special stateid of other all 0s and seqid == 1, set the
3493 	 * stateid to the current stateid, if it is set.
3494 	 */
3495 	if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3496 	    stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3497 	    stp->ls_stateid.other[2] == 0) {
3498 		if ((nd->nd_flag & ND_CURSTATEID) != 0)
3499 			stp->ls_stateid = nd->nd_curstateid;
3500 		else {
3501 			nd->nd_repstat = NFSERR_BADSTATEID;
3502 			goto nfsmout;
3503 		}
3504 	}
3505 
3506 	stp->ls_flags = NFSLCK_CLOSE;
3507 	clientid.lval[0] = stp->ls_stateid.other[0];
3508 	clientid.lval[1] = stp->ls_stateid.other[1];
3509 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3510 		if ((nd->nd_flag & ND_NFSV41) != 0)
3511 			clientid.qval = nd->nd_clientid.qval;
3512 		else if (nd->nd_clientid.qval != clientid.qval)
3513 			printf("EEK8 multiple clids\n");
3514 	} else {
3515 		if ((nd->nd_flag & ND_NFSV41) != 0)
3516 			printf("EEK! no clientid from session\n");
3517 		nd->nd_flag |= ND_IMPLIEDCLID;
3518 		nd->nd_clientid.qval = clientid.qval;
3519 	}
3520 	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3521 	    &writeacc);
3522 	/* For pNFS, update the attributes. */
3523 	if (writeacc != 0 || nfsrv_pnfsatime != 0)
3524 		nfsrv_updatemdsattr(vp, &na, p);
3525 	vput(vp);
3526 	if (!nd->nd_repstat) {
3527 		/*
3528 		 * If the stateid that has been closed is the current stateid,
3529 		 * unset it.
3530 		 */
3531 		if ((nd->nd_flag & ND_CURSTATEID) != 0 &&
3532 		    stateid.other[0] == nd->nd_curstateid.other[0] &&
3533 		    stateid.other[1] == nd->nd_curstateid.other[1] &&
3534 		    stateid.other[2] == nd->nd_curstateid.other[2])
3535 			nd->nd_flag &= ~ND_CURSTATEID;
3536 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3537 		*tl++ = txdr_unsigned(stateid.seqid);
3538 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3539 	}
3540 	NFSEXITCODE2(0, nd);
3541 	return (0);
3542 nfsmout:
3543 	vput(vp);
3544 	NFSEXITCODE2(error, nd);
3545 	return (error);
3546 }
3547 
3548 /*
3549  * nfsv4 delegpurge service
3550  */
3551 int
nfsrvd_delegpurge(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)3552 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
3553     __unused vnode_t vp, __unused struct nfsexstuff *exp)
3554 {
3555 	u_int32_t *tl;
3556 	int error = 0;
3557 	nfsquad_t clientid;
3558 	struct thread *p = curthread;
3559 
3560 	if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
3561 		goto nfsmout;
3562 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3563 	clientid.lval[0] = *tl++;
3564 	clientid.lval[1] = *tl;
3565 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3566 		if ((nd->nd_flag & ND_NFSV41) != 0)
3567 			clientid.qval = nd->nd_clientid.qval;
3568 		else if (nd->nd_clientid.qval != clientid.qval)
3569 			printf("EEK9 multiple clids\n");
3570 	} else {
3571 		if ((nd->nd_flag & ND_NFSV41) != 0)
3572 			printf("EEK! no clientid from session\n");
3573 		nd->nd_flag |= ND_IMPLIEDCLID;
3574 		nd->nd_clientid.qval = clientid.qval;
3575 	}
3576 	nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
3577 	    NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL);
3578 nfsmout:
3579 	NFSEXITCODE2(error, nd);
3580 	return (error);
3581 }
3582 
3583 /*
3584  * nfsv4 delegreturn service
3585  */
3586 int
nfsrvd_delegreturn(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)3587 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
3588     vnode_t vp, __unused struct nfsexstuff *exp)
3589 {
3590 	u_int32_t *tl;
3591 	int error = 0, writeacc;
3592 	nfsv4stateid_t stateid;
3593 	nfsquad_t clientid;
3594 	struct nfsvattr na;
3595 	struct thread *p = curthread;
3596 
3597 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3598 	stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3599 	NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
3600 	clientid.lval[0] = stateid.other[0];
3601 	clientid.lval[1] = stateid.other[1];
3602 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3603 		if ((nd->nd_flag & ND_NFSV41) != 0)
3604 			clientid.qval = nd->nd_clientid.qval;
3605 		else if (nd->nd_clientid.qval != clientid.qval)
3606 			printf("EEK10 multiple clids\n");
3607 	} else {
3608 		if ((nd->nd_flag & ND_NFSV41) != 0)
3609 			printf("EEK! no clientid from session\n");
3610 		nd->nd_flag |= ND_IMPLIEDCLID;
3611 		nd->nd_clientid.qval = clientid.qval;
3612 	}
3613 	nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
3614 	    NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc);
3615 	/* For pNFS, update the attributes. */
3616 	if (writeacc != 0 || nfsrv_pnfsatime != 0)
3617 		nfsrv_updatemdsattr(vp, &na, p);
3618 nfsmout:
3619 	vput(vp);
3620 	NFSEXITCODE2(error, nd);
3621 	return (error);
3622 }
3623 
3624 /*
3625  * nfsv4 get file handle service
3626  */
3627 int
nfsrvd_getfh(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)3628 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3629     vnode_t vp, __unused struct nfsexstuff *exp)
3630 {
3631 	fhandle_t fh;
3632 	struct thread *p = curthread;
3633 	int siz;
3634 	short irflag;
3635 
3636 	nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3637 	irflag = vn_irflag_read(vp);
3638 	vput(vp);
3639 	if (nd->nd_repstat == 0) {
3640 		siz = 0;
3641 		if ((irflag & VIRF_NAMEDDIR) != 0)
3642 			siz = NFSX_FHMAX + NFSX_V4NAMEDDIRFH;
3643 		else if ((irflag & VIRF_NAMEDATTR) != 0)
3644 			siz = NFSX_FHMAX + NFSX_V4NAMEDATTRFH;
3645 		(void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, siz, 0);
3646 	}
3647 	NFSEXITCODE2(0, nd);
3648 	return (0);
3649 }
3650 
3651 /*
3652  * nfsv4 open confirm service
3653  */
3654 int
nfsrvd_openconfirm(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)3655 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3656     vnode_t vp, __unused struct nfsexstuff *exp)
3657 {
3658 	u_int32_t *tl;
3659 	struct nfsstate st, *stp = &st;
3660 	int error = 0;
3661 	nfsv4stateid_t stateid;
3662 	nfsquad_t clientid;
3663 	struct thread *p = curthread;
3664 
3665 	if ((nd->nd_flag & ND_NFSV41) != 0) {
3666 		nd->nd_repstat = NFSERR_NOTSUPP;
3667 		goto nfsmout;
3668 	}
3669 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3670 	stp->ls_ownerlen = 0;
3671 	stp->ls_op = nd->nd_rp;
3672 	stp->ls_uid = nd->nd_cred->cr_uid;
3673 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3674 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3675 	    NFSX_STATEIDOTHER);
3676 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3677 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3678 	stp->ls_flags = NFSLCK_CONFIRM;
3679 	clientid.lval[0] = stp->ls_stateid.other[0];
3680 	clientid.lval[1] = stp->ls_stateid.other[1];
3681 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3682 		if ((nd->nd_flag & ND_NFSV41) != 0)
3683 			clientid.qval = nd->nd_clientid.qval;
3684 		else if (nd->nd_clientid.qval != clientid.qval)
3685 			printf("EEK11 multiple clids\n");
3686 	} else {
3687 		if ((nd->nd_flag & ND_NFSV41) != 0)
3688 			printf("EEK! no clientid from session\n");
3689 		nd->nd_flag |= ND_IMPLIEDCLID;
3690 		nd->nd_clientid.qval = clientid.qval;
3691 	}
3692 	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3693 	    NULL);
3694 	if (!nd->nd_repstat) {
3695 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3696 		*tl++ = txdr_unsigned(stateid.seqid);
3697 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3698 	}
3699 nfsmout:
3700 	vput(vp);
3701 	NFSEXITCODE2(error, nd);
3702 	return (error);
3703 }
3704 
3705 /*
3706  * nfsv4 open downgrade service
3707  */
3708 int
nfsrvd_opendowngrade(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)3709 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3710     vnode_t vp, __unused struct nfsexstuff *exp)
3711 {
3712 	u_int32_t *tl;
3713 	int i;
3714 	struct nfsstate st, *stp = &st;
3715 	int error = 0;
3716 	nfsv4stateid_t stateid;
3717 	nfsquad_t clientid;
3718 	struct thread *p = curthread;
3719 
3720 	/* opendowngrade can only work on a file object.*/
3721 	if (vp->v_type != VREG) {
3722 		error = NFSERR_INVAL;
3723 		goto nfsmout;
3724 	}
3725 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3726 	stp->ls_ownerlen = 0;
3727 	stp->ls_op = nd->nd_rp;
3728 	stp->ls_uid = nd->nd_cred->cr_uid;
3729 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3730 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3731 	    NFSX_STATEIDOTHER);
3732 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3733 
3734 	/*
3735 	 * For the special stateid of other all 0s and seqid == 1, set the
3736 	 * stateid to the current stateid, if it is set.
3737 	 */
3738 	if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3739 	    stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3740 	    stp->ls_stateid.other[2] == 0) {
3741 		if ((nd->nd_flag & ND_CURSTATEID) != 0)
3742 			stp->ls_stateid = nd->nd_curstateid;
3743 		else {
3744 			nd->nd_repstat = NFSERR_BADSTATEID;
3745 			goto nfsmout;
3746 		}
3747 	}
3748 
3749 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3750 	i = fxdr_unsigned(int, *tl++);
3751 	if ((nd->nd_flag & ND_NFSV41) != 0)
3752 		i &= ~NFSV4OPEN_WANTDELEGMASK;
3753 	switch (i) {
3754 	case NFSV4OPEN_ACCESSREAD:
3755 		stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3756 		break;
3757 	case NFSV4OPEN_ACCESSWRITE:
3758 		stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3759 		break;
3760 	case NFSV4OPEN_ACCESSBOTH:
3761 		stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3762 		    NFSLCK_DOWNGRADE);
3763 		break;
3764 	default:
3765 		nd->nd_repstat = NFSERR_INVAL;
3766 	}
3767 	i = fxdr_unsigned(int, *tl);
3768 	switch (i) {
3769 	case NFSV4OPEN_DENYNONE:
3770 		break;
3771 	case NFSV4OPEN_DENYREAD:
3772 		stp->ls_flags |= NFSLCK_READDENY;
3773 		break;
3774 	case NFSV4OPEN_DENYWRITE:
3775 		stp->ls_flags |= NFSLCK_WRITEDENY;
3776 		break;
3777 	case NFSV4OPEN_DENYBOTH:
3778 		stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3779 		break;
3780 	default:
3781 		nd->nd_repstat = NFSERR_INVAL;
3782 	}
3783 
3784 	clientid.lval[0] = stp->ls_stateid.other[0];
3785 	clientid.lval[1] = stp->ls_stateid.other[1];
3786 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3787 		if ((nd->nd_flag & ND_NFSV41) != 0)
3788 			clientid.qval = nd->nd_clientid.qval;
3789 		else if (nd->nd_clientid.qval != clientid.qval)
3790 			printf("EEK12 multiple clids\n");
3791 	} else {
3792 		if ((nd->nd_flag & ND_NFSV41) != 0)
3793 			printf("EEK! no clientid from session\n");
3794 		nd->nd_flag |= ND_IMPLIEDCLID;
3795 		nd->nd_clientid.qval = clientid.qval;
3796 	}
3797 	if (!nd->nd_repstat)
3798 		nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3799 		    nd, p, NULL);
3800 	if (!nd->nd_repstat) {
3801 		/* For NFSv4.1, set the Current StateID. */
3802 		if ((nd->nd_flag & ND_NFSV41) != 0) {
3803 			nd->nd_curstateid = stateid;
3804 			nd->nd_flag |= ND_CURSTATEID;
3805 		}
3806 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3807 		*tl++ = txdr_unsigned(stateid.seqid);
3808 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3809 	}
3810 nfsmout:
3811 	vput(vp);
3812 	NFSEXITCODE2(error, nd);
3813 	return (error);
3814 }
3815 
3816 /*
3817  * nfsv4 renew lease service
3818  */
3819 int
nfsrvd_renew(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)3820 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3821     __unused vnode_t vp, __unused struct nfsexstuff *exp)
3822 {
3823 	u_int32_t *tl;
3824 	int error = 0;
3825 	nfsquad_t clientid;
3826 	struct thread *p = curthread;
3827 
3828 	if ((nd->nd_flag & ND_NFSV41) != 0) {
3829 		nd->nd_repstat = NFSERR_NOTSUPP;
3830 		goto nfsmout;
3831 	}
3832 	if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
3833 		goto nfsmout;
3834 	NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3835 	clientid.lval[0] = *tl++;
3836 	clientid.lval[1] = *tl;
3837 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3838 		if ((nd->nd_flag & ND_NFSV41) != 0)
3839 			clientid.qval = nd->nd_clientid.qval;
3840 		else if (nd->nd_clientid.qval != clientid.qval)
3841 			printf("EEK13 multiple clids\n");
3842 	} else {
3843 		if ((nd->nd_flag & ND_NFSV41) != 0)
3844 			printf("EEK! no clientid from session\n");
3845 		nd->nd_flag |= ND_IMPLIEDCLID;
3846 		nd->nd_clientid.qval = clientid.qval;
3847 	}
3848 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3849 	    NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
3850 nfsmout:
3851 	NFSEXITCODE2(error, nd);
3852 	return (error);
3853 }
3854 
3855 /*
3856  * nfsv4 security info service
3857  */
3858 int
nfsrvd_secinfo(struct nfsrv_descript * nd,int isdgram,vnode_t dp,struct nfsexstuff * exp)3859 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3860     vnode_t dp, struct nfsexstuff *exp)
3861 {
3862 	u_int32_t *tl;
3863 	int len;
3864 	struct nameidata named;
3865 	vnode_t dirp = NULL, vp;
3866 	struct nfsrvfh fh;
3867 	struct nfsexstuff retnes;
3868 	u_int32_t *sizp;
3869 	int error = 0, i;
3870 	uint64_t savflag;
3871 	char *bufp;
3872 	u_long *hashp;
3873 	struct thread *p = curthread;
3874 
3875 	/*
3876 	 * All this just to get the export flags for the name.
3877 	 */
3878 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3879 	    LOCKLEAF);
3880 	nfsvno_setpathbuf(&named, &bufp, &hashp);
3881 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3882 	if (error) {
3883 		vput(dp);
3884 		nfsvno_relpathbuf(&named);
3885 		goto out;
3886 	}
3887 	if (!nd->nd_repstat) {
3888 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp);
3889 	} else {
3890 		vput(dp);
3891 		nfsvno_relpathbuf(&named);
3892 	}
3893 	if (dirp)
3894 		vrele(dirp);
3895 	if (nd->nd_repstat)
3896 		goto out;
3897 	nfsvno_relpathbuf(&named);
3898 	fh.nfsrvfh_len = NFSX_MYFH;
3899 	vp = named.ni_vp;
3900 	nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3901 	vput(vp);
3902 	savflag = nd->nd_flag;
3903 	if (!nd->nd_repstat) {
3904 		/*
3905 		 * Pretend the next op is Secinfo, so that no wrongsec
3906 		 * test will be done.
3907 		 */
3908 		nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0,
3909 		    NFSV4OP_SECINFO);
3910 		if (vp)
3911 			vput(vp);
3912 	}
3913 	nd->nd_flag = savflag;
3914 	if (nd->nd_repstat)
3915 		goto out;
3916 
3917 	/*
3918 	 * Finally have the export flags for name, so we can create
3919 	 * the security info.
3920 	 */
3921 	len = 0;
3922 	NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3923 
3924 	/* If nes_numsecflavor == 0, all are allowed. */
3925 	if (retnes.nes_numsecflavor == 0) {
3926 		NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3927 		*tl++ = txdr_unsigned(RPCAUTH_UNIX);
3928 		*tl = txdr_unsigned(RPCAUTH_GSS);
3929 		nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3930 		    nfsgss_mechlist[KERBV_MECH].len);
3931 		NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3932 		*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3933 		*tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3934 		*tl = txdr_unsigned(RPCAUTH_GSS);
3935 		nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3936 		    nfsgss_mechlist[KERBV_MECH].len);
3937 		NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3938 		*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3939 		*tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3940 		*tl = txdr_unsigned(RPCAUTH_GSS);
3941 		nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3942 		    nfsgss_mechlist[KERBV_MECH].len);
3943 		NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3944 		*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3945 		*tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3946 		len = 4;
3947 	}
3948 	for (i = 0; i < retnes.nes_numsecflavor; i++) {
3949 		if (retnes.nes_secflavors[i] == AUTH_SYS) {
3950 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3951 			*tl = txdr_unsigned(RPCAUTH_UNIX);
3952 			len++;
3953 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3954 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3955 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
3956 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3957 			    nfsgss_mechlist[KERBV_MECH].len);
3958 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3959 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3960 			*tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3961 			len++;
3962 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3963 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3964 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
3965 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3966 			    nfsgss_mechlist[KERBV_MECH].len);
3967 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3968 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3969 			*tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3970 			len++;
3971 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3972 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3973 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
3974 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3975 			    nfsgss_mechlist[KERBV_MECH].len);
3976 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3977 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3978 			*tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3979 			len++;
3980 		}
3981 	}
3982 	*sizp = txdr_unsigned(len);
3983 
3984 out:
3985 	NFSEXITCODE2(error, nd);
3986 	return (error);
3987 }
3988 
3989 /*
3990  * nfsv4 security info no name service
3991  */
3992 int
nfsrvd_secinfononame(struct nfsrv_descript * nd,int isdgram,vnode_t dp,struct nfsexstuff * exp)3993 nfsrvd_secinfononame(struct nfsrv_descript *nd, int isdgram,
3994     vnode_t dp, struct nfsexstuff *exp)
3995 {
3996 	uint32_t *tl, *sizp;
3997 	struct nameidata named;
3998 	vnode_t dirp = NULL, vp;
3999 	struct nfsrvfh fh;
4000 	struct nfsexstuff retnes;
4001 	int error = 0, fhstyle, i, len;
4002 	uint64_t savflag;
4003 	char *bufp;
4004 	u_long *hashp;
4005 	struct thread *p = curthread;
4006 
4007 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4008 	fhstyle = fxdr_unsigned(int, *tl);
4009 	switch (fhstyle) {
4010 	case NFSSECINFONONAME_PARENT:
4011 		if (dp->v_type != VDIR) {
4012 			vput(dp);
4013 			nd->nd_repstat = NFSERR_NOTDIR;
4014 			goto nfsmout;
4015 		}
4016 		NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
4017 		    LOCKLEAF);
4018 		nfsvno_setpathbuf(&named, &bufp, &hashp);
4019 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
4020 		if (error != 0) {
4021 			vput(dp);
4022 			nfsvno_relpathbuf(&named);
4023 			goto nfsmout;
4024 		}
4025 		if (nd->nd_repstat == 0)
4026 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp);
4027 		else
4028 			vput(dp);
4029 		if (dirp != NULL)
4030 			vrele(dirp);
4031 		nfsvno_relpathbuf(&named);
4032 		vp = named.ni_vp;
4033 		break;
4034 	case NFSSECINFONONAME_CURFH:
4035 		vp = dp;
4036 		break;
4037 	default:
4038 		nd->nd_repstat = NFSERR_INVAL;
4039 		vput(dp);
4040 	}
4041 	if (nd->nd_repstat != 0)
4042 		goto nfsmout;
4043 	fh.nfsrvfh_len = NFSX_MYFH;
4044 	nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
4045 	vput(vp);
4046 	savflag = nd->nd_flag;
4047 	if (nd->nd_repstat == 0) {
4048 		/*
4049 		 * Pretend the next op is Secinfo, so that no wrongsec
4050 		 * test will be done.
4051 		 */
4052 		nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0,
4053 		    NFSV4OP_SECINFO);
4054 		if (vp != NULL)
4055 			vput(vp);
4056 	}
4057 	nd->nd_flag = savflag;
4058 	if (nd->nd_repstat != 0)
4059 		goto nfsmout;
4060 
4061 	/*
4062 	 * Finally have the export flags for fh/parent, so we can create
4063 	 * the security info.
4064 	 */
4065 	len = 0;
4066 	NFSM_BUILD(sizp, uint32_t *, NFSX_UNSIGNED);
4067 
4068 	/* If nes_numsecflavor == 0, all are allowed. */
4069 	if (retnes.nes_numsecflavor == 0) {
4070 		NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4071 		*tl++ = txdr_unsigned(RPCAUTH_UNIX);
4072 		*tl = txdr_unsigned(RPCAUTH_GSS);
4073 		nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4074 		    nfsgss_mechlist[KERBV_MECH].len);
4075 		NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
4076 		*tl++ = txdr_unsigned(GSS_KERBV_QOP);
4077 		*tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE);
4078 		*tl = txdr_unsigned(RPCAUTH_GSS);
4079 		nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4080 		    nfsgss_mechlist[KERBV_MECH].len);
4081 		NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
4082 		*tl++ = txdr_unsigned(GSS_KERBV_QOP);
4083 		*tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
4084 		*tl = txdr_unsigned(RPCAUTH_GSS);
4085 		nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4086 		    nfsgss_mechlist[KERBV_MECH].len);
4087 		NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4088 		*tl++ = txdr_unsigned(GSS_KERBV_QOP);
4089 		*tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
4090 		len = 4;
4091 	}
4092 	for (i = 0; i < retnes.nes_numsecflavor; i++) {
4093 		if (retnes.nes_secflavors[i] == AUTH_SYS) {
4094 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4095 			*tl = txdr_unsigned(RPCAUTH_UNIX);
4096 			len++;
4097 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
4098 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4099 			*tl = txdr_unsigned(RPCAUTH_GSS);
4100 			nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4101 			    nfsgss_mechlist[KERBV_MECH].len);
4102 			NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4103 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
4104 			*tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
4105 			len++;
4106 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
4107 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4108 			*tl = txdr_unsigned(RPCAUTH_GSS);
4109 			nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4110 			    nfsgss_mechlist[KERBV_MECH].len);
4111 			NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4112 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
4113 			*tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
4114 			len++;
4115 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
4116 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4117 			*tl = txdr_unsigned(RPCAUTH_GSS);
4118 			nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4119 			    nfsgss_mechlist[KERBV_MECH].len);
4120 			NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4121 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
4122 			*tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
4123 			len++;
4124 		}
4125 	}
4126 	*sizp = txdr_unsigned(len);
4127 
4128 nfsmout:
4129 	NFSEXITCODE2(error, nd);
4130 	return (error);
4131 }
4132 
4133 /*
4134  * nfsv4 set client id service
4135  */
4136 int
nfsrvd_setclientid(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4137 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
4138     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4139 {
4140 	u_int32_t *tl;
4141 	int i;
4142 	int error = 0, idlen;
4143 	struct nfsclient *clp = NULL;
4144 #ifdef INET
4145 	struct sockaddr_in *rin;
4146 #endif
4147 #ifdef INET6
4148 	struct sockaddr_in6 *rin6;
4149 #endif
4150 #if defined(INET) || defined(INET6)
4151 	u_char *ucp, *ucp2;
4152 #endif
4153 	u_char *verf, *addrbuf;
4154 	nfsquad_t clientid, confirm;
4155 	struct thread *p = curthread;
4156 
4157 	if ((nd->nd_flag & ND_NFSV41) != 0) {
4158 		nd->nd_repstat = NFSERR_NOTSUPP;
4159 		goto nfsmout;
4160 	}
4161 	if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4162 		goto out;
4163 	NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
4164 	verf = (u_char *)tl;
4165 	tl += (NFSX_VERF / NFSX_UNSIGNED);
4166 	i = fxdr_unsigned(int, *tl);
4167 	if (i > NFSV4_OPAQUELIMIT || i <= 0) {
4168 		nd->nd_repstat = NFSERR_BADXDR;
4169 		goto nfsmout;
4170 	}
4171 	idlen = i;
4172 	if (nd->nd_flag & ND_GSS)
4173 		i += nd->nd_princlen;
4174 	clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
4175 	    M_ZERO);
4176 	clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
4177 	    nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
4178 	NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
4179 	/* Allocated large enough for an AF_INET or AF_INET6 socket. */
4180 	clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
4181 	    M_WAITOK | M_ZERO);
4182 	clp->lc_req.nr_cred = NULL;
4183 	NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4184 	clp->lc_idlen = idlen;
4185 	error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4186 	if (error)
4187 		goto nfsmout;
4188 	if (nd->nd_flag & ND_GSS) {
4189 		clp->lc_flags = LCL_GSS;
4190 		if (nd->nd_flag & ND_GSSINTEGRITY)
4191 			clp->lc_flags |= LCL_GSSINTEGRITY;
4192 		else if (nd->nd_flag & ND_GSSPRIVACY)
4193 			clp->lc_flags |= LCL_GSSPRIVACY;
4194 	} else {
4195 		clp->lc_flags = 0;
4196 	}
4197 	if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
4198 		clp->lc_flags |= LCL_NAME;
4199 		clp->lc_namelen = nd->nd_princlen;
4200 		clp->lc_name = &clp->lc_id[idlen];
4201 		NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4202 	} else {
4203 		clp->lc_uid = nd->nd_cred->cr_uid;
4204 		clp->lc_gid = nd->nd_cred->cr_gid;
4205 	}
4206 
4207 	/* If the client is using TLS, do so for the callback connection. */
4208 	if (nd->nd_flag & ND_TLS)
4209 		clp->lc_flags |= LCL_TLSCB;
4210 
4211 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4212 	clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
4213 	error = nfsrv_getclientipaddr(nd, clp);
4214 	if (error)
4215 		goto nfsmout;
4216 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4217 	clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
4218 
4219 	/*
4220 	 * nfsrv_setclient() does the actual work of adding it to the
4221 	 * client list. If there is no error, the structure has been
4222 	 * linked into the client list and clp should no longer be used
4223 	 * here. When an error is returned, it has not been linked in,
4224 	 * so it should be free'd.
4225 	 */
4226 	nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4227 	if (nd->nd_repstat == NFSERR_CLIDINUSE) {
4228 		/*
4229 		 * 8 is the maximum length of the port# string.
4230 		 */
4231 		addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK);
4232 		switch (clp->lc_req.nr_nam->sa_family) {
4233 #ifdef INET
4234 		case AF_INET:
4235 			if (clp->lc_flags & LCL_TCPCALLBACK)
4236 				(void) nfsm_strtom(nd, "tcp", 3);
4237 			else
4238 				(void) nfsm_strtom(nd, "udp", 3);
4239 			rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
4240 			ucp = (u_char *)&rin->sin_addr.s_addr;
4241 			ucp2 = (u_char *)&rin->sin_port;
4242 			sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
4243 			    ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
4244 			    ucp2[0] & 0xff, ucp2[1] & 0xff);
4245 			break;
4246 #endif
4247 #ifdef INET6
4248 		case AF_INET6:
4249 			if (clp->lc_flags & LCL_TCPCALLBACK)
4250 				(void) nfsm_strtom(nd, "tcp6", 4);
4251 			else
4252 				(void) nfsm_strtom(nd, "udp6", 4);
4253 			rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
4254 			ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf,
4255 			    INET6_ADDRSTRLEN);
4256 			if (ucp != NULL)
4257 				i = strlen(ucp);
4258 			else
4259 				i = 0;
4260 			ucp2 = (u_char *)&rin6->sin6_port;
4261 			sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff,
4262 			    ucp2[1] & 0xff);
4263 			break;
4264 #endif
4265 		}
4266 		(void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
4267 		free(addrbuf, M_TEMP);
4268 	}
4269 	if (clp) {
4270 		free(clp->lc_req.nr_nam, M_SONAME);
4271 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4272 		free(clp->lc_stateid, M_NFSDCLIENT);
4273 		free(clp, M_NFSDCLIENT);
4274 	}
4275 	if (!nd->nd_repstat) {
4276 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
4277 		*tl++ = clientid.lval[0];
4278 		*tl++ = clientid.lval[1];
4279 		*tl++ = confirm.lval[0];
4280 		*tl = confirm.lval[1];
4281 	}
4282 
4283 out:
4284 	NFSEXITCODE2(0, nd);
4285 	return (0);
4286 nfsmout:
4287 	if (clp) {
4288 		free(clp->lc_req.nr_nam, M_SONAME);
4289 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4290 		free(clp->lc_stateid, M_NFSDCLIENT);
4291 		free(clp, M_NFSDCLIENT);
4292 	}
4293 	NFSEXITCODE2(error, nd);
4294 	return (error);
4295 }
4296 
4297 /*
4298  * nfsv4 set client id confirm service
4299  */
4300 int
nfsrvd_setclientidcfrm(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4301 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
4302     __unused int isdgram, __unused vnode_t vp,
4303     __unused struct nfsexstuff *exp)
4304 {
4305 	u_int32_t *tl;
4306 	int error = 0;
4307 	nfsquad_t clientid, confirm;
4308 	struct thread *p = curthread;
4309 
4310 	if ((nd->nd_flag & ND_NFSV41) != 0) {
4311 		nd->nd_repstat = NFSERR_NOTSUPP;
4312 		goto nfsmout;
4313 	}
4314 	if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4315 		goto nfsmout;
4316 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
4317 	clientid.lval[0] = *tl++;
4318 	clientid.lval[1] = *tl++;
4319 	confirm.lval[0] = *tl++;
4320 	confirm.lval[1] = *tl;
4321 
4322 	/*
4323 	 * nfsrv_getclient() searches the client list for a match and
4324 	 * returns the appropriate NFSERR status.
4325 	 */
4326 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
4327 	    NULL, NULL, confirm, 0, nd, p);
4328 nfsmout:
4329 	NFSEXITCODE2(error, nd);
4330 	return (error);
4331 }
4332 
4333 /*
4334  * nfsv4 verify service
4335  */
4336 int
nfsrvd_verify(struct nfsrv_descript * nd,int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)4337 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
4338     vnode_t vp, __unused struct nfsexstuff *exp)
4339 {
4340 	int error = 0, ret, fhsize = NFSX_MYFH;
4341 	struct nfsvattr nva;
4342 	struct statfs *sf;
4343 	struct nfsfsinfo fs;
4344 	fhandle_t fh;
4345 	struct thread *p = curthread;
4346 
4347 	sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
4348 	nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
4349 	if (!nd->nd_repstat)
4350 		nd->nd_repstat = nfsvno_statfs(vp, sf);
4351 	if (!nd->nd_repstat)
4352 		nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
4353 	if (!nd->nd_repstat) {
4354 		nfsvno_getfs(&fs, isdgram);
4355 		error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
4356 		    sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, NULL, NULL, p,
4357 		    nd->nd_cred);
4358 		if (!error) {
4359 			if (nd->nd_procnum == NFSV4OP_NVERIFY) {
4360 				if (ret == 0)
4361 					nd->nd_repstat = NFSERR_SAME;
4362 				else if (ret != NFSERR_NOTSAME)
4363 					nd->nd_repstat = ret;
4364 			} else if (ret)
4365 				nd->nd_repstat = ret;
4366 		}
4367 	}
4368 	vput(vp);
4369 	free(sf, M_STATFS);
4370 	NFSEXITCODE2(error, nd);
4371 	return (error);
4372 }
4373 
4374 /*
4375  * nfs openattr rpc
4376  */
4377 int
nfsrvd_openattr(struct nfsrv_descript * nd,__unused int isdgram,struct vnode * dp,struct vnode ** vpp,__unused fhandle_t * fhp,__unused struct nfsexstuff * exp)4378 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
4379     struct vnode *dp, struct vnode **vpp, __unused fhandle_t *fhp,
4380     __unused struct nfsexstuff *exp)
4381 {
4382 	uint32_t *tl;
4383 	struct componentname cn;
4384 	int error = 0;
4385 
4386 	NFSNAMEICNDSET(&cn, nd->nd_cred, LOOKUP, OPENNAMED | ISLASTCN |
4387 	    NOFOLLOW | LOCKLEAF);
4388 	cn.cn_nameptr = ".";
4389 	cn.cn_namelen = 1;
4390 	cn.cn_lkflags = LK_SHARED;
4391 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4392 	if (*tl == newnfs_true)
4393 		cn.cn_flags |= CREATENAMED;
4394 
4395 	nd->nd_repstat = vn_lock(dp, LK_SHARED);
4396 	if (nd->nd_repstat != 0)
4397 		goto nfsmout;
4398 
4399 	if ((dp->v_mount->mnt_flag & MNT_NAMEDATTR) == 0)
4400 		nd->nd_repstat = NFSERR_NOTSUPP;
4401 	if (nd->nd_repstat == 0 && (vn_irflag_read(dp) & (VIRF_NAMEDDIR |
4402 	    VIRF_NAMEDATTR)) != 0)
4403 		nd->nd_repstat = NFSERR_WRONGTYPE;
4404 	if (nd->nd_repstat == 0) {
4405 		nd->nd_repstat = VOP_LOOKUP(dp, vpp, &cn);
4406 		if (nd->nd_repstat == ENOATTR)
4407 			nd->nd_repstat = NFSERR_NOENT;
4408 	}
4409 	if (nd->nd_repstat == 0)
4410 		NFSVOPUNLOCK(*vpp);
4411 
4412 	vput(dp);
4413 	NFSEXITCODE2(0, nd);
4414 	return (0);
4415 nfsmout:
4416 	vrele(dp);
4417 	NFSEXITCODE2(error, nd);
4418 	return (error);
4419 }
4420 
4421 /*
4422  * nfsv4 release lock owner service
4423  */
4424 int
nfsrvd_releaselckown(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4425 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
4426     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4427 {
4428 	u_int32_t *tl;
4429 	struct nfsstate *stp = NULL;
4430 	int error = 0, len;
4431 	nfsquad_t clientid;
4432 	struct thread *p = curthread;
4433 
4434 	if ((nd->nd_flag & ND_NFSV41) != 0) {
4435 		nd->nd_repstat = NFSERR_NOTSUPP;
4436 		goto nfsmout;
4437 	}
4438 	if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4439 		goto nfsmout;
4440 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
4441 	len = fxdr_unsigned(int, *(tl + 2));
4442 	if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
4443 		nd->nd_repstat = NFSERR_BADXDR;
4444 		goto nfsmout;
4445 	}
4446 	stp = malloc(sizeof (struct nfsstate) + len,
4447 	    M_NFSDSTATE, M_WAITOK);
4448 	stp->ls_ownerlen = len;
4449 	stp->ls_op = NULL;
4450 	stp->ls_flags = NFSLCK_RELEASE;
4451 	stp->ls_uid = nd->nd_cred->cr_uid;
4452 	clientid.lval[0] = *tl++;
4453 	clientid.lval[1] = *tl;
4454 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
4455 		if ((nd->nd_flag & ND_NFSV41) != 0)
4456 			clientid.qval = nd->nd_clientid.qval;
4457 		else if (nd->nd_clientid.qval != clientid.qval)
4458 			printf("EEK14 multiple clids\n");
4459 	} else {
4460 		if ((nd->nd_flag & ND_NFSV41) != 0)
4461 			printf("EEK! no clientid from session\n");
4462 		nd->nd_flag |= ND_IMPLIEDCLID;
4463 		nd->nd_clientid.qval = clientid.qval;
4464 	}
4465 	error = nfsrv_mtostr(nd, stp->ls_owner, len);
4466 	if (error)
4467 		goto nfsmout;
4468 	nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
4469 	free(stp, M_NFSDSTATE);
4470 
4471 	NFSEXITCODE2(0, nd);
4472 	return (0);
4473 nfsmout:
4474 	if (stp)
4475 		free(stp, M_NFSDSTATE);
4476 	NFSEXITCODE2(error, nd);
4477 	return (error);
4478 }
4479 
4480 /*
4481  * nfsv4 exchange_id service
4482  */
4483 int
nfsrvd_exchangeid(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4484 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
4485     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4486 {
4487 	uint32_t *tl;
4488 	int error = 0, i, idlen;
4489 	struct nfsclient *clp = NULL;
4490 	nfsquad_t clientid, confirm;
4491 	uint8_t *verf;
4492 	uint32_t sp4type, v41flags;
4493 	struct timespec verstime;
4494 	nfsopbit_t mustops, allowops;
4495 #ifdef INET
4496 	struct sockaddr_in *sin, *rin;
4497 #endif
4498 #ifdef INET6
4499 	struct sockaddr_in6 *sin6, *rin6;
4500 #endif
4501 	struct thread *p = curthread;
4502 	char *s;
4503 
4504 	if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4505 		goto nfsmout;
4506 	NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
4507 	verf = (uint8_t *)tl;
4508 	tl += (NFSX_VERF / NFSX_UNSIGNED);
4509 	i = fxdr_unsigned(int, *tl);
4510 	if (i > NFSV4_OPAQUELIMIT || i <= 0) {
4511 		nd->nd_repstat = NFSERR_BADXDR;
4512 		goto nfsmout;
4513 	}
4514 	idlen = i;
4515 	if (nd->nd_flag & ND_GSS)
4516 		i += nd->nd_princlen;
4517 	clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
4518 	    M_ZERO);
4519 	clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
4520 	    nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
4521 	NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
4522 	/* Allocated large enough for an AF_INET or AF_INET6 socket. */
4523 	clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
4524 	    M_WAITOK | M_ZERO);
4525 	switch (nd->nd_nam->sa_family) {
4526 #ifdef INET
4527 	case AF_INET:
4528 		rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
4529 		sin = (struct sockaddr_in *)nd->nd_nam;
4530 		rin->sin_family = AF_INET;
4531 		rin->sin_len = sizeof(struct sockaddr_in);
4532 		rin->sin_port = 0;
4533 		rin->sin_addr.s_addr = sin->sin_addr.s_addr;
4534 		break;
4535 #endif
4536 #ifdef INET6
4537 	case AF_INET6:
4538 		rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
4539 		sin6 = (struct sockaddr_in6 *)nd->nd_nam;
4540 		rin6->sin6_family = AF_INET6;
4541 		rin6->sin6_len = sizeof(struct sockaddr_in6);
4542 		rin6->sin6_port = 0;
4543 		rin6->sin6_addr = sin6->sin6_addr;
4544 		break;
4545 #endif
4546 	}
4547 	clp->lc_req.nr_cred = NULL;
4548 	NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4549 	clp->lc_idlen = idlen;
4550 	error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4551 	if (error != 0)
4552 		goto nfsmout;
4553 	if ((nd->nd_flag & ND_GSS) != 0) {
4554 		clp->lc_flags = LCL_GSS | LCL_NFSV41;
4555 		if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
4556 			clp->lc_flags |= LCL_GSSINTEGRITY;
4557 		else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
4558 			clp->lc_flags |= LCL_GSSPRIVACY;
4559 	} else
4560 		clp->lc_flags = LCL_NFSV41;
4561 	if ((nd->nd_flag & ND_NFSV42) != 0)
4562 		clp->lc_flags |= LCL_NFSV42;
4563 	if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
4564 		clp->lc_flags |= LCL_NAME;
4565 		clp->lc_namelen = nd->nd_princlen;
4566 		clp->lc_name = &clp->lc_id[idlen];
4567 		NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4568 	} else {
4569 		clp->lc_uid = nd->nd_cred->cr_uid;
4570 		clp->lc_gid = nd->nd_cred->cr_gid;
4571 	}
4572 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4573 	v41flags = fxdr_unsigned(uint32_t, *tl++);
4574 	if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
4575 	    NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
4576 	    NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
4577 		nd->nd_repstat = NFSERR_INVAL;
4578 		goto nfsmout;
4579 	}
4580 	if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
4581 		confirm.lval[1] = 1;
4582 	else
4583 		confirm.lval[1] = 0;
4584 	if (nfsrv_devidcnt == 0)
4585 		v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS;
4586  	else
4587  		v41flags = NFSV4EXCH_USEPNFSMDS;
4588 	sp4type = fxdr_unsigned(uint32_t, *tl);
4589 	if (sp4type == NFSV4EXCH_SP4MACHCRED) {
4590 		if ((nd->nd_flag & (ND_GSSINTEGRITY | ND_GSSPRIVACY)) == 0 ||
4591 		    nd->nd_princlen == 0)
4592 			nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
4593 		if (nd->nd_repstat == 0)
4594 			nd->nd_repstat = nfsrv_getopbits(nd, &mustops, NULL);
4595 		if (nd->nd_repstat == 0)
4596 			nd->nd_repstat = nfsrv_getopbits(nd, &allowops, NULL);
4597 		if (nd->nd_repstat != 0)
4598 			goto nfsmout;
4599 		NFSOPBIT_CLRNOTMUST(&mustops);
4600 		NFSSET_OPBIT(&clp->lc_mustops, &mustops);
4601 		NFSOPBIT_CLRNOTALLOWED(&allowops);
4602 		NFSSET_OPBIT(&clp->lc_allowops, &allowops);
4603 		clp->lc_flags |= LCL_MACHCRED;
4604 	} else if (sp4type != NFSV4EXCH_SP4NONE) {
4605 		nd->nd_repstat = NFSERR_NOTSUPP;
4606 		goto nfsmout;
4607 	}
4608 
4609 	/*
4610 	 * nfsrv_setclient() does the actual work of adding it to the
4611 	 * client list. If there is no error, the structure has been
4612 	 * linked into the client list and clp should no longer be used
4613 	 * here. When an error is returned, it has not been linked in,
4614 	 * so it should be free'd.
4615 	 */
4616 	nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4617 	if (clp != NULL) {
4618 		free(clp->lc_req.nr_nam, M_SONAME);
4619 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4620 		free(clp->lc_stateid, M_NFSDCLIENT);
4621 		free(clp, M_NFSDCLIENT);
4622 	}
4623 	if (nd->nd_repstat == 0) {
4624 		if (confirm.lval[1] != 0)
4625 			v41flags |= NFSV4EXCH_CONFIRMEDR;
4626 		NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED);
4627 		*tl++ = clientid.lval[0];			/* ClientID */
4628 		*tl++ = clientid.lval[1];
4629 		*tl++ = txdr_unsigned(confirm.lval[0]);		/* SequenceID */
4630 		*tl++ = txdr_unsigned(v41flags);		/* Exch flags */
4631 		*tl = txdr_unsigned(sp4type);			/* No SSV */
4632 		if (sp4type == NFSV4EXCH_SP4MACHCRED) {
4633 			nfsrv_putopbit(nd, &mustops);
4634 			nfsrv_putopbit(nd, &allowops);
4635 		}
4636 		NFSM_BUILD(tl, uint32_t *, NFSX_HYPER);
4637 		txdr_hyper(nfsrv_owner_minor, tl);	/* Owner Minor */
4638 		if (nfsrv_owner_major[0] != 0)
4639 			s = nfsrv_owner_major;
4640 		else
4641 			s = nd->nd_cred->cr_prison->pr_hostuuid;
4642 		nfsm_strtom(nd, s, strlen(s));		/* Owner Major */
4643 		if (nfsrv_scope[0] != 0)
4644 			s = nfsrv_scope;
4645 		else
4646 			s = nd->nd_cred->cr_prison->pr_hostuuid;
4647 		nfsm_strtom(nd, s, strlen(s)	);		/* Scope */
4648 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4649 		*tl = txdr_unsigned(1);
4650 		(void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4651 		(void)nfsm_strtom(nd, version, strlen(version));
4652 		NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4653 		verstime.tv_sec = 1293840000;		/* Jan 1, 2011 */
4654 		verstime.tv_nsec = 0;
4655 		txdr_nfsv4time(&verstime, tl);
4656 	}
4657 	NFSEXITCODE2(0, nd);
4658 	return (0);
4659 nfsmout:
4660 	if (clp != NULL) {
4661 		free(clp->lc_req.nr_nam, M_SONAME);
4662 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4663 		free(clp->lc_stateid, M_NFSDCLIENT);
4664 		free(clp, M_NFSDCLIENT);
4665 	}
4666 	NFSEXITCODE2(error, nd);
4667 	return (error);
4668 }
4669 
4670 /*
4671  * nfsv4 create session service
4672  */
4673 int
nfsrvd_createsession(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4674 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
4675     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4676 {
4677 	uint32_t *tl;
4678 	int error = 0;
4679 	nfsquad_t clientid, confirm;
4680 	struct nfsdsession *sep = NULL;
4681 	uint32_t rdmacnt;
4682 	struct thread *p = curthread;
4683 	static bool do_printf = true;
4684 
4685 	if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4686 		goto nfsmout;
4687 	sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
4688 	    M_NFSDSESSION, M_WAITOK | M_ZERO);
4689 	sep->sess_refcnt = 1;
4690 	mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
4691 	NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
4692 	clientid.lval[0] = *tl++;
4693 	clientid.lval[1] = *tl++;
4694 	confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
4695 	sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
4696 	/* Persistent sessions and RDMA are not supported. */
4697 	sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
4698 
4699 	/* Fore channel attributes. */
4700 	NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4701 	tl++;					/* Header pad always 0. */
4702 	sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
4703 	if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) {
4704 		sep->sess_maxreq = sb_max_adj - NFS_MAXXDR;
4705 		if (do_printf)
4706 			printf("Consider increasing kern.ipc.maxsockbuf\n");
4707 		do_printf = false;
4708 	}
4709 	sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
4710 	if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) {
4711 		sep->sess_maxresp = sb_max_adj - NFS_MAXXDR;
4712 		if (do_printf)
4713 			printf("Consider increasing kern.ipc.maxsockbuf\n");
4714 		do_printf = false;
4715 	}
4716 	sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
4717 	sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
4718 	sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
4719 	if (sep->sess_maxslots > NFSV4_SLOTS)
4720 		sep->sess_maxslots = NFSV4_SLOTS;
4721 	rdmacnt = fxdr_unsigned(uint32_t, *tl);
4722 	if (rdmacnt > 1) {
4723 		nd->nd_repstat = NFSERR_BADXDR;
4724 		goto nfsmout;
4725 	} else if (rdmacnt == 1)
4726 		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4727 
4728 	/* Back channel attributes. */
4729 	NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4730 	tl++;					/* Header pad always 0. */
4731 	sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
4732 	sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
4733 	sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
4734 	sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
4735 	sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
4736 	rdmacnt = fxdr_unsigned(uint32_t, *tl);
4737 	if (rdmacnt > 1) {
4738 		nd->nd_repstat = NFSERR_BADXDR;
4739 		goto nfsmout;
4740 	} else if (rdmacnt == 1)
4741 		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4742 
4743 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4744 	sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
4745 
4746 	/*
4747 	 * nfsrv_getclient() searches the client list for a match and
4748 	 * returns the appropriate NFSERR status.
4749 	 */
4750 	nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
4751 	    NULL, sep, confirm, sep->sess_cbprogram, nd, p);
4752 	if (nd->nd_repstat == 0) {
4753 		NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4754 		NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
4755 		NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
4756 		*tl++ = txdr_unsigned(confirm.lval[0]);	/* sequenceid */
4757 		*tl++ = txdr_unsigned(sep->sess_crflags);
4758 
4759 		/* Fore channel attributes. */
4760 		*tl++ = 0;
4761 		*tl++ = txdr_unsigned(sep->sess_maxreq);
4762 		*tl++ = txdr_unsigned(sep->sess_maxresp);
4763 		*tl++ = txdr_unsigned(sep->sess_maxrespcached);
4764 		*tl++ = txdr_unsigned(sep->sess_maxops);
4765 		*tl++ = txdr_unsigned(sep->sess_maxslots);
4766 		*tl++ = txdr_unsigned(1);
4767 		*tl++ = txdr_unsigned(0);			/* No RDMA. */
4768 
4769 		/* Back channel attributes. */
4770 		*tl++ = 0;
4771 		*tl++ = txdr_unsigned(sep->sess_cbmaxreq);
4772 		*tl++ = txdr_unsigned(sep->sess_cbmaxresp);
4773 		*tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
4774 		*tl++ = txdr_unsigned(sep->sess_cbmaxops);
4775 		*tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
4776 		*tl++ = txdr_unsigned(1);
4777 		*tl = txdr_unsigned(0);			/* No RDMA. */
4778 	}
4779 nfsmout:
4780 	if (nd->nd_repstat != 0 && sep != NULL)
4781 		free(sep, M_NFSDSESSION);
4782 	NFSEXITCODE2(error, nd);
4783 	return (error);
4784 }
4785 
4786 /*
4787  * nfsv4 sequence service
4788  */
4789 int
nfsrvd_sequence(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4790 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
4791     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4792 {
4793 	uint32_t *tl;
4794 	uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
4795 	int cache_this, error = 0;
4796 	struct thread *p = curthread;
4797 
4798 	if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4799 		goto nfsmout;
4800 	NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
4801 	NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
4802 	NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4803 	sequenceid = fxdr_unsigned(uint32_t, *tl++);
4804 	nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
4805 	highest_slotid = fxdr_unsigned(uint32_t, *tl++);
4806 	if (*tl == newnfs_true)
4807 		cache_this = 1;
4808 	else
4809 		cache_this = 0;
4810 	nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
4811 	    &target_highest_slotid, cache_this, &sflags, p);
4812 	if (nd->nd_repstat != NFSERR_BADSLOT)
4813 		nd->nd_flag |= ND_HASSEQUENCE;
4814 	if (nd->nd_repstat == 0) {
4815 		NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4816 		NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
4817 		NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
4818 		*tl++ = txdr_unsigned(sequenceid);
4819 		*tl++ = txdr_unsigned(nd->nd_slotid);
4820 		*tl++ = txdr_unsigned(highest_slotid);
4821 		*tl++ = txdr_unsigned(target_highest_slotid);
4822 		*tl = txdr_unsigned(sflags);
4823 	}
4824 nfsmout:
4825 	NFSEXITCODE2(error, nd);
4826 	return (error);
4827 }
4828 
4829 /*
4830  * nfsv4 reclaim complete service
4831  */
4832 int
nfsrvd_reclaimcomplete(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4833 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
4834     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4835 {
4836 	uint32_t *tl;
4837 	int error = 0, onefs;
4838 
4839 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4840 	/*
4841 	 * I believe that a ReclaimComplete with rca_one_fs == TRUE is only
4842 	 * to be used after a file system has been transferred to a different
4843 	 * file server.  However, RFC5661 is somewhat vague w.r.t. this and
4844 	 * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs
4845 	 * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE.
4846 	 * Therefore, just ignore the rca_one_fs == TRUE operation and return
4847 	 * NFS_OK without doing anything.
4848 	 */
4849 	onefs = 0;
4850 	if (*tl == newnfs_true)
4851 		onefs = 1;
4852 	nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs);
4853 nfsmout:
4854 	NFSEXITCODE2(error, nd);
4855 	return (error);
4856 }
4857 
4858 /*
4859  * nfsv4 destroy clientid service
4860  */
4861 int
nfsrvd_destroyclientid(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4862 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
4863     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4864 {
4865 	uint32_t *tl;
4866 	nfsquad_t clientid;
4867 	int error = 0;
4868 	struct thread *p = curthread;
4869 
4870 	if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4871 		goto nfsmout;
4872 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4873 	clientid.lval[0] = *tl++;
4874 	clientid.lval[1] = *tl;
4875 	nd->nd_repstat = nfsrv_destroyclient(nd, clientid, p);
4876 nfsmout:
4877 	NFSEXITCODE2(error, nd);
4878 	return (error);
4879 }
4880 
4881 /*
4882  * nfsv4 bind connection to session service
4883  */
4884 int
nfsrvd_bindconnsess(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4885 nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram,
4886     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4887 {
4888 	uint32_t *tl;
4889 	uint8_t sessid[NFSX_V4SESSIONID];
4890 	int error = 0, foreaft;
4891 
4892 	if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4893 		goto nfsmout;
4894 	NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED);
4895 	NFSBCOPY(tl, sessid, NFSX_V4SESSIONID);
4896 	tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4897 	foreaft = fxdr_unsigned(int, *tl++);
4898 	if (*tl == newnfs_true) {
4899 		/* RDMA is not supported. */
4900 		nd->nd_repstat = NFSERR_NOTSUPP;
4901 		goto nfsmout;
4902 	}
4903 
4904 	nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft);
4905 	if (nd->nd_repstat == 0) {
4906 		NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 *
4907 		    NFSX_UNSIGNED);
4908 		NFSBCOPY(sessid, tl, NFSX_V4SESSIONID);
4909 		tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4910 		*tl++ = txdr_unsigned(foreaft);
4911 		*tl = newnfs_false;
4912 	}
4913 nfsmout:
4914 	NFSEXITCODE2(error, nd);
4915 	return (error);
4916 }
4917 
4918 /*
4919  * nfsv4 destroy session service
4920  */
4921 int
nfsrvd_destroysession(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4922 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4923     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4924 {
4925 	uint8_t *cp, sessid[NFSX_V4SESSIONID];
4926 	int error = 0;
4927 
4928 	if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4929 		goto nfsmout;
4930 	NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4931 	NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4932 	nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4933 nfsmout:
4934 	NFSEXITCODE2(error, nd);
4935 	return (error);
4936 }
4937 
4938 /*
4939  * nfsv4 free stateid service
4940  */
4941 int
nfsrvd_freestateid(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4942 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
4943     __unused vnode_t vp, __unused struct nfsexstuff *exp)
4944 {
4945 	uint32_t *tl;
4946 	nfsv4stateid_t stateid;
4947 	int error = 0;
4948 	struct thread *p = curthread;
4949 
4950 	NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4951 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4952 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4953 
4954 	/*
4955 	 * For the special stateid of other all 0s and seqid == 1, set the
4956 	 * stateid to the current stateid, if it is set.
4957 	 */
4958 	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4959 	    stateid.other[1] == 0 && stateid.other[2] == 0) {
4960 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4961 			stateid = nd->nd_curstateid;
4962 			stateid.seqid = 0;
4963 		} else {
4964 			nd->nd_repstat = NFSERR_BADSTATEID;
4965 			goto nfsmout;
4966 		}
4967 	}
4968 
4969 	nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
4970 
4971 	/* If the current stateid has been free'd, unset it. */
4972 	if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 &&
4973 	    stateid.other[0] == nd->nd_curstateid.other[0] &&
4974 	    stateid.other[1] == nd->nd_curstateid.other[1] &&
4975 	    stateid.other[2] == nd->nd_curstateid.other[2])
4976 		nd->nd_flag &= ~ND_CURSTATEID;
4977 nfsmout:
4978 	NFSEXITCODE2(error, nd);
4979 	return (error);
4980 }
4981 
4982 /*
4983  * nfsv4 layoutget service
4984  */
4985 int
nfsrvd_layoutget(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)4986 nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram,
4987     vnode_t vp, struct nfsexstuff *exp)
4988 {
4989 	uint32_t *tl;
4990 	nfsv4stateid_t stateid;
4991 	int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose;
4992 	uint64_t offset, len, minlen;
4993 	char *layp;
4994 	struct thread *p = curthread;
4995 
4996 	NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
4997 	    NFSX_STATEID);
4998 	tl++;		/* Signal layout available. Ignore for now. */
4999 	layouttype = fxdr_unsigned(int, *tl++);
5000 	iomode = fxdr_unsigned(int, *tl++);
5001 	offset = fxdr_hyper(tl); tl += 2;
5002 	len = fxdr_hyper(tl); tl += 2;
5003 	minlen = fxdr_hyper(tl); tl += 2;
5004 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5005 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5006 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5007 	maxcnt = fxdr_unsigned(int, *tl);
5008 	NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n",
5009 	    layouttype, iomode, (uintmax_t)offset, (uintmax_t)len,
5010 	    (uintmax_t)minlen);
5011 	if (len < minlen ||
5012 	    (minlen != UINT64_MAX && offset + minlen < offset) ||
5013 	    (len != UINT64_MAX && offset + len < offset)) {
5014 		nd->nd_repstat = NFSERR_INVAL;
5015 		goto nfsmout;
5016 	}
5017 
5018 	/*
5019 	 * For the special stateid of other all 0s and seqid == 1, set the
5020 	 * stateid to the current stateid, if it is set.
5021 	 */
5022 	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5023 	    stateid.other[1] == 0 && stateid.other[2] == 0) {
5024 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5025 			stateid = nd->nd_curstateid;
5026 			stateid.seqid = 0;
5027 		} else {
5028 			nd->nd_repstat = NFSERR_BADSTATEID;
5029 			goto nfsmout;
5030 		}
5031 	}
5032 
5033 	layp = NULL;
5034 	if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1)
5035 		layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK);
5036 	else if (layouttype == NFSLAYOUT_FLEXFILE)
5037 		layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP,
5038 		    M_WAITOK);
5039 	else
5040 		nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE;
5041 	if (layp != NULL)
5042 		nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype,
5043 		    &iomode, &offset, &len, minlen, &stateid, maxcnt,
5044 		    &retonclose, &layoutlen, layp, nd->nd_cred, p);
5045 	NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat,
5046 	    layoutlen);
5047 	if (nd->nd_repstat == 0) {
5048 		/* For NFSv4.1, set the Current StateID. */
5049 		if ((nd->nd_flag & ND_NFSV41) != 0) {
5050 			nd->nd_curstateid = stateid;
5051 			nd->nd_flag |= ND_CURSTATEID;
5052 		}
5053 		NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID +
5054 		    2 * NFSX_HYPER);
5055 		*tl++ = txdr_unsigned(retonclose);
5056 		*tl++ = txdr_unsigned(stateid.seqid);
5057 		NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
5058 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5059 		*tl++ = txdr_unsigned(1);	/* Only returns one layout. */
5060 		txdr_hyper(offset, tl); tl += 2;
5061 		txdr_hyper(len, tl); tl += 2;
5062 		*tl++ = txdr_unsigned(iomode);
5063 		*tl = txdr_unsigned(layouttype);
5064 		nfsm_strtom(nd, layp, layoutlen);
5065 	} else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) {
5066 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5067 		*tl = newnfs_false;
5068 	}
5069 	free(layp, M_TEMP);
5070 nfsmout:
5071 	vput(vp);
5072 	NFSEXITCODE2(error, nd);
5073 	return (error);
5074 }
5075 
5076 /*
5077  * nfsv4 layoutcommit service
5078  */
5079 int
nfsrvd_layoutcommit(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5080 nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram,
5081     vnode_t vp, struct nfsexstuff *exp)
5082 {
5083 	uint32_t *tl;
5084 	nfsv4stateid_t stateid;
5085 	int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim;
5086 	int hasnewsize;
5087 	uint64_t offset, len, newoff = 0, newsize;
5088 	struct timespec newmtime;
5089 	char *layp;
5090 	struct thread *p = curthread;
5091 
5092 	layp = NULL;
5093 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER +
5094 	    NFSX_STATEID);
5095 	offset = fxdr_hyper(tl); tl += 2;
5096 	len = fxdr_hyper(tl); tl += 2;
5097 	reclaim = fxdr_unsigned(int, *tl++);
5098 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5099 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5100 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5101 	/*
5102 	 * For the special stateid of other all 0s and seqid == 1, set the
5103 	 * stateid to the current stateid, if it is set.
5104 	 */
5105 	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5106 	    stateid.other[1] == 0 && stateid.other[2] == 0) {
5107 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5108 			stateid = nd->nd_curstateid;
5109 			stateid.seqid = 0;
5110 		} else {
5111 			nd->nd_repstat = NFSERR_BADSTATEID;
5112 			goto nfsmout;
5113 		}
5114 	}
5115 
5116 	hasnewoff = fxdr_unsigned(int, *tl);
5117 	if (hasnewoff != 0) {
5118 		NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
5119 		newoff = fxdr_hyper(tl); tl += 2;
5120 	} else
5121 		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5122 	hasnewmtime = fxdr_unsigned(int, *tl);
5123 	if (hasnewmtime != 0) {
5124 		NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED);
5125 		fxdr_nfsv4time(tl, &newmtime);
5126 		tl += (NFSX_V4TIME / NFSX_UNSIGNED);
5127 	} else
5128 		NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5129 	layouttype = fxdr_unsigned(int, *tl++);
5130 	maxcnt = fxdr_unsigned(int, *tl);
5131 	if (maxcnt > 0) {
5132 		layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
5133 		error = nfsrv_mtostr(nd, layp, maxcnt);
5134 		if (error != 0)
5135 			goto nfsmout;
5136 	}
5137 	nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff,
5138 	    newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid,
5139 	    maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p);
5140 	NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat);
5141 	if (nd->nd_repstat == 0) {
5142 		if (hasnewsize != 0) {
5143 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
5144 			*tl++ = newnfs_true;
5145 			txdr_hyper(newsize, tl);
5146 		} else {
5147 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5148 			*tl = newnfs_false;
5149 		}
5150 	}
5151 nfsmout:
5152 	free(layp, M_TEMP);
5153 	vput(vp);
5154 	NFSEXITCODE2(error, nd);
5155 	return (error);
5156 }
5157 
5158 /*
5159  * nfsv4 layoutreturn service
5160  */
5161 int
nfsrvd_layoutreturn(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5162 nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram,
5163     vnode_t vp, struct nfsexstuff *exp)
5164 {
5165 	uint32_t *tl, *layp;
5166 	nfsv4stateid_t stateid;
5167 	int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim;
5168 	uint64_t offset, len;
5169 	struct thread *p = curthread;
5170 
5171 	layp = NULL;
5172 	NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
5173 	reclaim = *tl++;
5174 	layouttype = fxdr_unsigned(int, *tl++);
5175 	iomode = fxdr_unsigned(int, *tl++);
5176 	kind = fxdr_unsigned(int, *tl);
5177 	NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim,
5178 	    layouttype, iomode, kind);
5179 	if (kind == NFSV4LAYOUTRET_FILE) {
5180 		NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
5181 		    NFSX_UNSIGNED);
5182 		offset = fxdr_hyper(tl); tl += 2;
5183 		len = fxdr_hyper(tl); tl += 2;
5184 		stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5185 		NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5186 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5187 
5188 		/*
5189 		 * For the special stateid of other all 0s and seqid == 1, set
5190 		 * the stateid to the current stateid, if it is set.
5191 		 */
5192 		if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5193 		    stateid.other[1] == 0 && stateid.other[2] == 0) {
5194 			if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5195 				stateid = nd->nd_curstateid;
5196 				stateid.seqid = 0;
5197 			} else {
5198 				nd->nd_repstat = NFSERR_BADSTATEID;
5199 				goto nfsmout;
5200 			}
5201 		}
5202 
5203 		maxcnt = fxdr_unsigned(int, *tl);
5204 		/*
5205 		 * There is no fixed upper bound defined in the RFCs,
5206 		 * but 128Kbytes should be more than sufficient.
5207 		 */
5208 		if (maxcnt < 0 || maxcnt > 131072)
5209 			maxcnt = 0;
5210 		if (maxcnt > 0) {
5211 			layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
5212 			error = nfsrv_mtostr(nd, (char *)layp, maxcnt);
5213 			if (error != 0)
5214 				goto nfsmout;
5215 		}
5216 	} else {
5217 		if (reclaim == newnfs_true) {
5218 			nd->nd_repstat = NFSERR_INVAL;
5219 			goto nfsmout;
5220 		}
5221 		offset = len = 0;
5222 		maxcnt = 0;
5223 	}
5224 	nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode,
5225 	    offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd,
5226 	    nd->nd_cred, p);
5227 	NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat,
5228 	    fnd);
5229 	if (nd->nd_repstat == 0) {
5230 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5231 		if (fnd != 0) {
5232 			*tl = newnfs_true;
5233 			NFSM_BUILD(tl, uint32_t *, NFSX_STATEID);
5234 			*tl++ = txdr_unsigned(stateid.seqid);
5235 			NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
5236 		} else
5237 			*tl = newnfs_false;
5238 	}
5239 nfsmout:
5240 	free(layp, M_TEMP);
5241 	vput(vp);
5242 	NFSEXITCODE2(error, nd);
5243 	return (error);
5244 }
5245 
5246 /*
5247  * nfsv4 layout error service
5248  */
5249 int
nfsrvd_layouterror(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5250 nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram,
5251     vnode_t vp, struct nfsexstuff *exp)
5252 {
5253 	uint32_t *tl;
5254 	nfsv4stateid_t stateid;
5255 	int cnt, error = 0, i, stat;
5256 	int opnum __unused;
5257 	char devid[NFSX_V4DEVICEID];
5258 	uint64_t offset, len;
5259 
5260 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
5261 	    NFSX_UNSIGNED);
5262 	offset = fxdr_hyper(tl); tl += 2;
5263 	len = fxdr_hyper(tl); tl += 2;
5264 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5265 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5266 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5267 	cnt = fxdr_unsigned(int, *tl);
5268 	NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset,
5269 	    (uintmax_t)len, cnt);
5270 	/*
5271 	 * For the special stateid of other all 0s and seqid == 1, set
5272 	 * the stateid to the current stateid, if it is set.
5273 	 */
5274 	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5275 	    stateid.other[1] == 0 && stateid.other[2] == 0) {
5276 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5277 			stateid = nd->nd_curstateid;
5278 			stateid.seqid = 0;
5279 		} else {
5280 			nd->nd_repstat = NFSERR_BADSTATEID;
5281 			goto nfsmout;
5282 		}
5283 	}
5284 
5285 	/*
5286 	 * Ignore offset, len and stateid for now.
5287 	 */
5288 	for (i = 0; i < cnt; i++) {
5289 		NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 *
5290 		    NFSX_UNSIGNED);
5291 		NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5292 		tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5293 		stat = fxdr_unsigned(int, *tl++);
5294 		opnum = fxdr_unsigned(int, *tl);
5295 		NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat);
5296 		/*
5297 		 * Except for NFSERR_ACCES, NFSERR_STALE and NFSERR_NOSPC
5298 		 * errors, disable the mirror.
5299 		 */
5300 		if (stat != NFSERR_ACCES && stat != NFSERR_STALE &&
5301 		    stat != NFSERR_NOSPC)
5302 			nfsrv_delds(devid, curthread);
5303 
5304 		/* For NFSERR_NOSPC, mark all deviceids and layouts. */
5305 		if (stat == NFSERR_NOSPC)
5306 			nfsrv_marknospc(devid, true);
5307 	}
5308 nfsmout:
5309 	vput(vp);
5310 	NFSEXITCODE2(error, nd);
5311 	return (error);
5312 }
5313 
5314 /*
5315  * nfsv4 layout stats service
5316  */
5317 int
nfsrvd_layoutstats(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5318 nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram,
5319     vnode_t vp, struct nfsexstuff *exp)
5320 {
5321 	uint32_t *tl;
5322 	nfsv4stateid_t stateid;
5323 	int cnt, error = 0;
5324 	int layouttype __unused;
5325 	char devid[NFSX_V4DEVICEID] __unused;
5326 	uint64_t offset __unused, len __unused, readcount __unused;
5327 	uint64_t readbytes __unused, writecount __unused, writebytes __unused;
5328 
5329 	NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID +
5330 	    NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED);
5331 	offset = fxdr_hyper(tl); tl += 2;
5332 	len = fxdr_hyper(tl); tl += 2;
5333 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5334 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5335 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5336 	readcount = fxdr_hyper(tl); tl += 2;
5337 	readbytes = fxdr_hyper(tl); tl += 2;
5338 	writecount = fxdr_hyper(tl); tl += 2;
5339 	writebytes = fxdr_hyper(tl); tl += 2;
5340 	NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5341 	tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5342 	layouttype = fxdr_unsigned(int, *tl++);
5343 	cnt = fxdr_unsigned(int, *tl);
5344 	error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1);
5345 	if (error != 0)
5346 		goto nfsmout;
5347 	NFSD_DEBUG(4, "layoutstats cnt=%d\n", cnt);
5348 	/*
5349 	 * For the special stateid of other all 0s and seqid == 1, set
5350 	 * the stateid to the current stateid, if it is set.
5351 	 */
5352 	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5353 	    stateid.other[1] == 0 && stateid.other[2] == 0) {
5354 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5355 			stateid = nd->nd_curstateid;
5356 			stateid.seqid = 0;
5357 		} else {
5358 			nd->nd_repstat = NFSERR_BADSTATEID;
5359 			goto nfsmout;
5360 		}
5361 	}
5362 
5363 	/*
5364 	 * No use for the stats for now.
5365 	 */
5366 nfsmout:
5367 	vput(vp);
5368 	NFSEXITCODE2(error, nd);
5369 	return (error);
5370 }
5371 
5372 /*
5373  * nfsv4 io_advise service
5374  */
5375 int
nfsrvd_ioadvise(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5376 nfsrvd_ioadvise(struct nfsrv_descript *nd, __unused int isdgram,
5377     vnode_t vp, struct nfsexstuff *exp)
5378 {
5379 	uint32_t *tl;
5380 	nfsv4stateid_t stateid;
5381 	nfsattrbit_t hints;
5382 	int error = 0, ret;
5383 	off_t offset, len;
5384 
5385 	NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5386 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5387 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5388 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5389 	offset = fxdr_hyper(tl); tl += 2;
5390 	len = fxdr_hyper(tl);
5391 	error = nfsrv_getattrbits(nd, &hints, NULL, NULL);
5392 	if (error != 0)
5393 		goto nfsmout;
5394 	/*
5395 	 * For the special stateid of other all 0s and seqid == 1, set
5396 	 * the stateid to the current stateid, if it is set.
5397 	 */
5398 	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5399 	    stateid.other[1] == 0 && stateid.other[2] == 0) {
5400 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5401 			stateid = nd->nd_curstateid;
5402 			stateid.seqid = 0;
5403 		} else {
5404 			nd->nd_repstat = NFSERR_BADSTATEID;
5405 			goto nfsmout;
5406 		}
5407 	}
5408 
5409 	if (offset < 0) {
5410 		nd->nd_repstat = NFSERR_INVAL;
5411 		goto nfsmout;
5412 	}
5413 	if (len < 0)
5414 		len = 0;
5415 	if (vp->v_type != VREG) {
5416 		if (vp->v_type == VDIR)
5417 			nd->nd_repstat = NFSERR_ISDIR;
5418 		else
5419 			nd->nd_repstat = NFSERR_WRONGTYPE;
5420 		goto nfsmout;
5421 	}
5422 
5423 	/*
5424 	 * For now, we can only handle WILLNEED and DONTNEED and don't use
5425 	 * the stateid.
5426 	 */
5427 	if ((NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED) &&
5428 	    !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED)) ||
5429 	    (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED) &&
5430 	    !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED))) {
5431 		NFSVOPUNLOCK(vp);
5432 		if (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED)) {
5433 			ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_WILLNEED);
5434 			NFSZERO_ATTRBIT(&hints);
5435 			if (ret == 0)
5436 				NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED);
5437 			else
5438 				NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5439 		} else {
5440 			ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_DONTNEED);
5441 			NFSZERO_ATTRBIT(&hints);
5442 			if (ret == 0)
5443 				NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED);
5444 			else
5445 				NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5446 		}
5447 		vrele(vp);
5448 	} else {
5449 		NFSZERO_ATTRBIT(&hints);
5450 		NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5451 		vput(vp);
5452 	}
5453 	nfsrv_putattrbit(nd, &hints);
5454 	NFSEXITCODE2(error, nd);
5455 	return (error);
5456 nfsmout:
5457 	vput(vp);
5458 	NFSEXITCODE2(error, nd);
5459 	return (error);
5460 }
5461 
5462 /*
5463  * nfsv4 getdeviceinfo service
5464  */
5465 int
nfsrvd_getdevinfo(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)5466 nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram,
5467     __unused vnode_t vp, __unused struct nfsexstuff *exp)
5468 {
5469 	uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP];
5470 	int cnt, devaddrlen, error = 0, i, layouttype;
5471 	char devid[NFSX_V4DEVICEID], *devaddr;
5472 	time_t dev_time;
5473 
5474 	NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
5475 	NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5476 	tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5477 	layouttype = fxdr_unsigned(int, *tl++);
5478 	maxcnt = fxdr_unsigned(uint32_t, *tl++);
5479 	cnt = fxdr_unsigned(int, *tl);
5480 	NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype,
5481 	    maxcnt, cnt);
5482 	if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) {
5483 		nd->nd_repstat = NFSERR_INVAL;
5484 		goto nfsmout;
5485 	}
5486 	if (cnt > 0) {
5487 		NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED);
5488 		for (i = 0; i < cnt; i++)
5489 			notify[i] = fxdr_unsigned(uint32_t, *tl++);
5490 	}
5491 	for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++)
5492 		notify[i] = 0;
5493 
5494 	/*
5495 	 * Check that the device id is not stale.  Device ids are recreated
5496 	 * each time the nfsd threads are restarted.
5497 	 */
5498 	NFSBCOPY(devid, &dev_time, sizeof(dev_time));
5499 	if (dev_time != nfsdev_time) {
5500 		nd->nd_repstat = NFSERR_NOENT;
5501 		goto nfsmout;
5502 	}
5503 
5504 	/* Look for the device id. */
5505 	nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt,
5506 	    notify, &devaddrlen, &devaddr);
5507 	NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat);
5508 	if (nd->nd_repstat == 0) {
5509 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5510 		*tl = txdr_unsigned(layouttype);
5511 		nfsm_strtom(nd, devaddr, devaddrlen);
5512 		cnt = 0;
5513 		for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) {
5514 			if (notify[i] != 0)
5515 				cnt = i + 1;
5516 		}
5517 		NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED);
5518 		*tl++ = txdr_unsigned(cnt);
5519 		for (i = 0; i < cnt; i++)
5520 			*tl++ = txdr_unsigned(notify[i]);
5521 	} else if (nd->nd_repstat == NFSERR_TOOSMALL) {
5522 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5523 		*tl = txdr_unsigned(maxcnt);
5524 	}
5525 nfsmout:
5526 	NFSEXITCODE2(error, nd);
5527 	return (error);
5528 }
5529 
5530 /*
5531  * nfsv4 test stateid service
5532  */
5533 int
nfsrvd_teststateid(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)5534 nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram,
5535     __unused vnode_t vp, __unused struct nfsexstuff *exp)
5536 {
5537 	uint32_t *tl;
5538 	nfsv4stateid_t *stateidp = NULL, *tstateidp;
5539 	int cnt, error = 0, i, ret;
5540 	struct thread *p = curthread;
5541 
5542 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5543 	cnt = fxdr_unsigned(int, *tl);
5544 	if (cnt <= 0 || cnt > 1024) {
5545 		nd->nd_repstat = NFSERR_BADXDR;
5546 		goto nfsmout;
5547 	}
5548 	stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK);
5549 	tstateidp = stateidp;
5550 	for (i = 0; i < cnt; i++) {
5551 		NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
5552 		tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
5553 		NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER);
5554 		tstateidp++;
5555 	}
5556 	NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5557 	*tl = txdr_unsigned(cnt);
5558 	tstateidp = stateidp;
5559 	for (i = 0; i < cnt; i++) {
5560 		ret = nfsrv_teststateid(nd, tstateidp, p);
5561 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5562 		*tl = txdr_unsigned(ret);
5563 		tstateidp++;
5564 	}
5565 nfsmout:
5566 	free(stateidp, M_TEMP);
5567 	NFSEXITCODE2(error, nd);
5568 	return (error);
5569 }
5570 
5571 /*
5572  * nfs allocate service
5573  */
5574 int
nfsrvd_allocate(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5575 nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram,
5576     vnode_t vp, struct nfsexstuff *exp)
5577 {
5578 	uint32_t *tl;
5579 	struct nfsvattr forat;
5580 	int error = 0, forat_ret = 1, gotproxystateid;
5581 	off_t off, len;
5582 	struct nfsstate st, *stp = &st;
5583 	struct nfslock lo, *lop = &lo;
5584 	nfsv4stateid_t stateid;
5585 	nfsquad_t clientid;
5586 	nfsattrbit_t attrbits;
5587 
5588 	if (!nfsrv_doallocate) {
5589 		/*
5590 		 * If any exported file system, such as a ZFS one, cannot
5591 		 * do VOP_ALLOCATE(), this operation cannot be supported
5592 		 * for NFSv4.2.  This cannot be done 'per filesystem', but
5593 		 * must be for the entire nfsd NFSv4.2 service.
5594 		 */
5595 		nd->nd_repstat = NFSERR_NOTSUPP;
5596 		goto nfsmout;
5597 	}
5598 	gotproxystateid = 0;
5599 	NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5600 	stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5601 	lop->lo_flags = NFSLCK_WRITE;
5602 	stp->ls_ownerlen = 0;
5603 	stp->ls_op = NULL;
5604 	stp->ls_uid = nd->nd_cred->cr_uid;
5605 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
5606 	clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
5607 	clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
5608 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
5609 		if ((nd->nd_flag & ND_NFSV41) != 0)
5610 			clientid.qval = nd->nd_clientid.qval;
5611 		else if (nd->nd_clientid.qval != clientid.qval)
5612 			printf("EEK2 multiple clids\n");
5613 	} else {
5614 		if ((nd->nd_flag & ND_NFSV41) != 0)
5615 			printf("EEK! no clientid from session\n");
5616 		nd->nd_flag |= ND_IMPLIEDCLID;
5617 		nd->nd_clientid.qval = clientid.qval;
5618 	}
5619 	stp->ls_stateid.other[2] = *tl++;
5620 	/*
5621 	 * Don't allow this to be done for a DS.
5622 	 */
5623 	if ((nd->nd_flag & ND_DSSERVER) != 0)
5624 		nd->nd_repstat = NFSERR_NOTSUPP;
5625 	/* However, allow the proxy stateid. */
5626 	if (stp->ls_stateid.seqid == 0xffffffff &&
5627 	    stp->ls_stateid.other[0] == 0x55555555 &&
5628 	    stp->ls_stateid.other[1] == 0x55555555 &&
5629 	    stp->ls_stateid.other[2] == 0x55555555)
5630 		gotproxystateid = 1;
5631 	off = fxdr_hyper(tl); tl += 2;
5632 	lop->lo_first = off;
5633 	len = fxdr_hyper(tl);
5634 	lop->lo_end = lop->lo_first + len;
5635 	/*
5636 	 * Sanity check the offset and length.
5637 	 * off and len are off_t (signed int64_t) whereas
5638 	 * lo_first and lo_end are uint64_t and, as such,
5639 	 * if off >= 0 && len > 0, lo_end cannot overflow
5640 	 * unless off_t is changed to something other than
5641 	 * int64_t.  Check lo_end < lo_first in case that
5642 	 * is someday the case.
5643 	 */
5644 	if (nd->nd_repstat == 0 && (len <= 0 || off < 0 || lop->lo_end >
5645 	    OFF_MAX || lop->lo_end < lop->lo_first))
5646 		nd->nd_repstat = NFSERR_INVAL;
5647 
5648 	if (nd->nd_repstat == 0 && vp->v_type != VREG)
5649 		nd->nd_repstat = NFSERR_WRONGTYPE;
5650 	NFSZERO_ATTRBIT(&attrbits);
5651 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5652 	forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits);
5653 	if (nd->nd_repstat == 0)
5654 		nd->nd_repstat = forat_ret;
5655 	if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid ||
5656 	     NFSVNO_EXSTRICTACCESS(exp)))
5657 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp,
5658 		    curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5659 		    NULL);
5660 	if (nd->nd_repstat == 0 && gotproxystateid == 0)
5661 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
5662 		    &stateid, exp, nd, curthread);
5663 
5664 	NFSD_DEBUG(4, "nfsrvd_allocate: off=%jd len=%jd stat=%d\n",
5665 	    (intmax_t)off, (intmax_t)len, nd->nd_repstat);
5666 	if (nd->nd_repstat == 0)
5667 		nd->nd_repstat = nfsvno_allocate(vp, off, len, nd->nd_cred,
5668 		    curthread);
5669 	NFSD_DEBUG(4, "nfsrvd_allocate: aft nfsvno_allocate=%d\n",
5670 	    nd->nd_repstat);
5671 	vput(vp);
5672 	NFSEXITCODE2(0, nd);
5673 	return (0);
5674 nfsmout:
5675 	vput(vp);
5676 	NFSEXITCODE2(error, nd);
5677 	return (error);
5678 }
5679 
5680 /*
5681  * nfs deallocate service
5682  */
5683 int
nfsrvd_deallocate(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5684 nfsrvd_deallocate(struct nfsrv_descript *nd, __unused int isdgram,
5685     vnode_t vp, struct nfsexstuff *exp)
5686 {
5687 	uint32_t *tl;
5688 	struct nfsvattr forat;
5689 	int error = 0, forat_ret = 1, gotproxystateid;
5690 	off_t off, len;
5691 	struct nfsstate st, *stp = &st;
5692 	struct nfslock lo, *lop = &lo;
5693 	nfsv4stateid_t stateid;
5694 	nfsquad_t clientid;
5695 	nfsattrbit_t attrbits;
5696 
5697 	gotproxystateid = 0;
5698 	NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5699 	stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5700 	lop->lo_flags = NFSLCK_WRITE;
5701 	stp->ls_ownerlen = 0;
5702 	stp->ls_op = NULL;
5703 	stp->ls_uid = nd->nd_cred->cr_uid;
5704 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
5705 	clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
5706 	clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
5707 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
5708 		if ((nd->nd_flag & ND_NFSV41) != 0)
5709 			clientid.qval = nd->nd_clientid.qval;
5710 		else if (nd->nd_clientid.qval != clientid.qval)
5711 			printf("EEK2 multiple clids\n");
5712 	} else {
5713 		if ((nd->nd_flag & ND_NFSV41) != 0)
5714 			printf("EEK! no clientid from session\n");
5715 		nd->nd_flag |= ND_IMPLIEDCLID;
5716 		nd->nd_clientid.qval = clientid.qval;
5717 	}
5718 	stp->ls_stateid.other[2] = *tl++;
5719 	/*
5720 	 * Don't allow this to be done for a DS.
5721 	 */
5722 	if ((nd->nd_flag & ND_DSSERVER) != 0)
5723 		nd->nd_repstat = NFSERR_NOTSUPP;
5724 	/* However, allow the proxy stateid. */
5725 	if (stp->ls_stateid.seqid == 0xffffffff &&
5726 	    stp->ls_stateid.other[0] == 0x55555555 &&
5727 	    stp->ls_stateid.other[1] == 0x55555555 &&
5728 	    stp->ls_stateid.other[2] == 0x55555555)
5729 		gotproxystateid = 1;
5730 	off = fxdr_hyper(tl); tl += 2;
5731 	lop->lo_first = off;
5732 	len = fxdr_hyper(tl);
5733 	if (len < 0)
5734 		len = OFF_MAX;
5735 	NFSD_DEBUG(4, "dealloc: off=%jd len=%jd\n", (intmax_t)off,
5736 	    (intmax_t)len);
5737 	lop->lo_end = lop->lo_first + len;
5738 	/*
5739 	 * Sanity check the offset and length.
5740 	 * off and len are off_t (signed int64_t) whereas
5741 	 * lo_first and lo_end are uint64_t and, as such,
5742 	 * if off >= 0 && len > 0, lo_end cannot overflow
5743 	 * unless off_t is changed to something other than
5744 	 * int64_t.  Check lo_end < lo_first in case that
5745 	 * is someday the case.
5746 	 * The error to return is not specified by RFC 7862 so I
5747 	 * made this compatible with the Linux knfsd.
5748 	 */
5749 	if (nd->nd_repstat == 0) {
5750 		if (off < 0 || lop->lo_end > NFSRV_MAXFILESIZE)
5751 			nd->nd_repstat = NFSERR_FBIG;
5752 		else if (len == 0 || lop->lo_end < lop->lo_first)
5753 			nd->nd_repstat = NFSERR_INVAL;
5754 	}
5755 
5756 	if (nd->nd_repstat == 0 && vp->v_type != VREG)
5757 		nd->nd_repstat = NFSERR_WRONGTYPE;
5758 	NFSZERO_ATTRBIT(&attrbits);
5759 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5760 	forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits);
5761 	if (nd->nd_repstat == 0)
5762 		nd->nd_repstat = forat_ret;
5763 	if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid ||
5764 	     NFSVNO_EXSTRICTACCESS(exp)))
5765 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp,
5766 		    curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5767 		    NULL);
5768 	if (nd->nd_repstat == 0 && gotproxystateid == 0)
5769 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
5770 		    &stateid, exp, nd, curthread);
5771 
5772 	if (nd->nd_repstat == 0)
5773 		nd->nd_repstat = nfsvno_deallocate(vp, off, len, nd->nd_cred,
5774 		    curthread);
5775 	vput(vp);
5776 	NFSD_DEBUG(4, "eo deallocate=%d\n", nd->nd_repstat);
5777 	NFSEXITCODE2(0, nd);
5778 	return (0);
5779 nfsmout:
5780 	vput(vp);
5781 	NFSEXITCODE2(error, nd);
5782 	return (error);
5783 }
5784 
5785 /*
5786  * nfs copy service
5787  */
5788 int
nfsrvd_copy_file_range(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,vnode_t tovp,struct nfsexstuff * exp,struct nfsexstuff * toexp)5789 nfsrvd_copy_file_range(struct nfsrv_descript *nd, __unused int isdgram,
5790     vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
5791 {
5792 	uint32_t *tl;
5793 	struct nfsvattr at;
5794 	int cnt, error = 0, ret;
5795 	off_t inoff, outoff;
5796 	uint64_t len;
5797 	size_t xfer;
5798 	struct nfsstate inst, outst, *instp = &inst, *outstp = &outst;
5799 	struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo;
5800 	nfsquad_t clientid;
5801 	nfsv4stateid_t stateid;
5802 	nfsattrbit_t attrbits;
5803 	void *rl_rcookie, *rl_wcookie;
5804 
5805 	rl_rcookie = rl_wcookie = NULL;
5806 	if (nfsrv_maxcopyrange == 0 || nfsrv_devidcnt > 0) {
5807 		/*
5808 		 * For a pNFS server, reply NFSERR_NOTSUPP so that the client
5809 		 * will do the copy via I/O on the DS(s).
5810 		 * If vfs.nfsd.maxcopyrange set to 0, disable Copy.
5811 		 */
5812 		nd->nd_repstat = NFSERR_NOTSUPP;
5813 		goto nfsmout;
5814 	}
5815 	if (vp == tovp) {
5816 		/* Copying a byte range within the same file is not allowed. */
5817 		nd->nd_repstat = NFSERR_INVAL;
5818 		goto nfsmout;
5819 	}
5820 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER +
5821 	    3 * NFSX_UNSIGNED);
5822 	instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
5823 	inlop->lo_flags = NFSLCK_READ;
5824 	instp->ls_ownerlen = 0;
5825 	instp->ls_op = NULL;
5826 	instp->ls_uid = nd->nd_cred->cr_uid;
5827 	instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5828 	clientid.lval[0] = instp->ls_stateid.other[0] = *tl++;
5829 	clientid.lval[1] = instp->ls_stateid.other[1] = *tl++;
5830 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0)
5831 		clientid.qval = nd->nd_clientid.qval;
5832 	instp->ls_stateid.other[2] = *tl++;
5833 	outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5834 	outlop->lo_flags = NFSLCK_WRITE;
5835 	outstp->ls_ownerlen = 0;
5836 	outstp->ls_op = NULL;
5837 	outstp->ls_uid = nd->nd_cred->cr_uid;
5838 	outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5839 	outstp->ls_stateid.other[0] = *tl++;
5840 	outstp->ls_stateid.other[1] = *tl++;
5841 	outstp->ls_stateid.other[2] = *tl++;
5842 	inoff = fxdr_hyper(tl); tl += 2;
5843 	inlop->lo_first = inoff;
5844 	outoff = fxdr_hyper(tl); tl += 2;
5845 	outlop->lo_first = outoff;
5846 	len = fxdr_hyper(tl); tl += 2;
5847 	if (len == 0) {
5848 		/* len == 0 means to EOF. */
5849 		inlop->lo_end = OFF_MAX;
5850 		outlop->lo_end = OFF_MAX;
5851 	} else {
5852 		inlop->lo_end = inlop->lo_first + len;
5853 		outlop->lo_end = outlop->lo_first + len;
5854 	}
5855 
5856 	/*
5857 	 * At this time only consecutive, synchronous copy is supported,
5858 	 * so ca_consecutive and ca_synchronous can be ignored.
5859 	 */
5860 	tl += 2;
5861 
5862 	cnt = fxdr_unsigned(int, *tl);
5863 	if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0)
5864 		nd->nd_repstat = NFSERR_NOTSUPP;
5865 	if (nd->nd_repstat == 0 && (inoff > OFF_MAX || outoff > OFF_MAX ||
5866 	    inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX ||
5867 	    inlop->lo_end < inlop->lo_first || outlop->lo_end <
5868 	    outlop->lo_first))
5869 		nd->nd_repstat = NFSERR_INVAL;
5870 
5871 	if (nd->nd_repstat == 0 && vp->v_type != VREG)
5872 		nd->nd_repstat = NFSERR_WRONGTYPE;
5873 
5874 	/* Check permissions for the input file. */
5875 	NFSZERO_ATTRBIT(&attrbits);
5876 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5877 	ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits);
5878 	if (nd->nd_repstat == 0)
5879 		nd->nd_repstat = ret;
5880 	if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5881 	     NFSVNO_EXSTRICTACCESS(exp)))
5882 		nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
5883 		    curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5884 		    NULL);
5885 	if (nd->nd_repstat == 0)
5886 		nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL,
5887 		    clientid, &stateid, exp, nd, curthread);
5888 	NFSVOPUNLOCK(vp);
5889 	if (nd->nd_repstat != 0)
5890 		goto out;
5891 
5892 	error = NFSVOPLOCK(tovp, LK_SHARED);
5893 	if (error != 0)
5894 		goto out;
5895 	if (tovp->v_type != VREG)
5896 		nd->nd_repstat = NFSERR_WRONGTYPE;
5897 
5898 	/* For the output file, we only need the Owner attribute. */
5899 	ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits);
5900 	if (nd->nd_repstat == 0)
5901 		nd->nd_repstat = ret;
5902 	if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5903 	     NFSVNO_EXSTRICTACCESS(exp)))
5904 		nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp,
5905 		    curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5906 		    NULL);
5907 	if (nd->nd_repstat == 0)
5908 		nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL,
5909 		    clientid, &stateid, toexp, nd, curthread);
5910 	NFSVOPUNLOCK(tovp);
5911 
5912 	/* Range lock the byte ranges for both invp and outvp. */
5913 	if (nd->nd_repstat == 0) {
5914 		for (;;) {
5915 			if (len == 0) {
5916 				rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5917 				    OFF_MAX);
5918 				rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5919 				    OFF_MAX);
5920 			} else {
5921 				rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5922 				    outoff + len);
5923 				rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5924 				    inoff + len);
5925 			}
5926 			if (rl_rcookie != NULL)
5927 				break;
5928 			vn_rangelock_unlock(tovp, rl_wcookie);
5929 			if (len == 0)
5930 				rl_rcookie = vn_rangelock_rlock(vp, inoff,
5931 				    OFF_MAX);
5932 			else
5933 				rl_rcookie = vn_rangelock_rlock(vp, inoff,
5934 				    inoff + len);
5935 			vn_rangelock_unlock(vp, rl_rcookie);
5936 		}
5937 
5938 		error = NFSVOPLOCK(vp, LK_SHARED);
5939 		if (error == 0) {
5940 			ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL);
5941 			if (ret == 0) {
5942 				/*
5943 				 * Since invp is range locked, na_size should
5944 				 * not change.
5945 				 */
5946 				if (len == 0 && at.na_size > inoff) {
5947 					/*
5948 					 * If len == 0, set it based on invp's
5949 					 * size. If offset is past EOF, just
5950 					 * leave len == 0.
5951 					 */
5952 					len = at.na_size - inoff;
5953 				} else if (nfsrv_linux42server == 0 &&
5954 				    inoff + len > at.na_size) {
5955 					/*
5956 					 * RFC-7862 says that NFSERR_INVAL must
5957 					 * be returned when inoff + len exceeds
5958 					 * the file size, however the NFSv4.2
5959 					 * Linux client likes to do this, so
5960 					 * only check if nfsrv_linux42server
5961 					 * is not set.
5962 					 */
5963 					nd->nd_repstat = NFSERR_INVAL;
5964 				}
5965 			}
5966 			NFSVOPUNLOCK(vp);
5967 			if (ret != 0 && nd->nd_repstat == 0)
5968 				nd->nd_repstat = ret;
5969 		} else if (nd->nd_repstat == 0)
5970 			nd->nd_repstat = error;
5971 	}
5972 
5973 	/*
5974 	 * Do the actual copy to an upper limit of vfs.nfsd.maxcopyrange.
5975 	 * This size limit can be set to limit the time a copy RPC will
5976 	 * take.
5977 	 */
5978 	if (len > nfsrv_maxcopyrange)
5979 		xfer = nfsrv_maxcopyrange;
5980 	else
5981 		xfer = len;
5982 	if (nd->nd_repstat == 0) {
5983 		nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff,
5984 		    &xfer, COPY_FILE_RANGE_TIMEO1SEC, nd->nd_cred, nd->nd_cred,
5985 		    NULL);
5986 		if (nd->nd_repstat == 0)
5987 			len = xfer;
5988 	}
5989 
5990 	/* Unlock the ranges. */
5991 	if (rl_rcookie != NULL)
5992 		vn_rangelock_unlock(vp, rl_rcookie);
5993 	if (rl_wcookie != NULL)
5994 		vn_rangelock_unlock(tovp, rl_wcookie);
5995 
5996 	if (nd->nd_repstat == 0) {
5997 		NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER +
5998 		    NFSX_VERF);
5999 		*tl++ = txdr_unsigned(0);	/* No callback ids. */
6000 		txdr_hyper(len, tl); tl += 2;
6001 		*tl++ = txdr_unsigned(NFSWRITE_UNSTABLE);
6002 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
6003 		*tl++ = txdr_unsigned(nfsboottime.tv_usec);
6004 		*tl++ = newnfs_true;
6005 		*tl = newnfs_true;
6006 	}
6007 out:
6008 	vrele(vp);
6009 	vrele(tovp);
6010 	NFSEXITCODE2(error, nd);
6011 	return (error);
6012 nfsmout:
6013 	vput(vp);
6014 	vrele(tovp);
6015 	NFSEXITCODE2(error, nd);
6016 	return (error);
6017 }
6018 
6019 /*
6020  * nfs clone service
6021  */
6022 int
nfsrvd_clone(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,vnode_t tovp,struct nfsexstuff * exp,struct nfsexstuff * toexp)6023 nfsrvd_clone(struct nfsrv_descript *nd, __unused int isdgram,
6024     vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
6025 {
6026 	uint32_t *tl;
6027 	struct nfsvattr at;
6028 	int error = 0, ret;
6029 	off_t inoff, outoff;
6030 	uint64_t len;
6031 	size_t xfer;
6032 	struct nfsstate inst, outst, *instp = &inst, *outstp = &outst;
6033 	struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo;
6034 	nfsquad_t clientid;
6035 	nfsv4stateid_t stateid;
6036 	nfsattrbit_t attrbits;
6037 	void *rl_rcookie, *rl_wcookie;
6038 	long pathval;
6039 
6040 	rl_rcookie = rl_wcookie = NULL;
6041 	pathval = 0;
6042 	if (nfsrv_maxcopyrange == 0 || nfsrv_devidcnt > 0 ||
6043 	    VOP_PATHCONF(vp, _PC_CLONE_BLKSIZE, &pathval) != 0 ||
6044 	    pathval == 0) {
6045 		/*
6046 		 * For a pNFS server, reply NFSERR_NOTSUPP so that the client
6047 		 * will not do the clone and will do I/O on the DS(s).
6048 		 * If vfs.nfsd.maxcopyrange set to 0, disable Clone.
6049 		 */
6050 		nd->nd_repstat = NFSERR_NOTSUPP;
6051 		goto nfsmout;
6052 	}
6053 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER);
6054 	instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
6055 	inlop->lo_flags = NFSLCK_READ;
6056 	instp->ls_ownerlen = 0;
6057 	instp->ls_op = NULL;
6058 	instp->ls_uid = nd->nd_cred->cr_uid;
6059 	instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
6060 	clientid.lval[0] = instp->ls_stateid.other[0] = *tl++;
6061 	clientid.lval[1] = instp->ls_stateid.other[1] = *tl++;
6062 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0)
6063 		clientid.qval = nd->nd_clientid.qval;
6064 	instp->ls_stateid.other[2] = *tl++;
6065 	outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
6066 	outlop->lo_flags = NFSLCK_WRITE;
6067 	outstp->ls_ownerlen = 0;
6068 	outstp->ls_op = NULL;
6069 	outstp->ls_uid = nd->nd_cred->cr_uid;
6070 	outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
6071 	outstp->ls_stateid.other[0] = *tl++;
6072 	outstp->ls_stateid.other[1] = *tl++;
6073 	outstp->ls_stateid.other[2] = *tl++;
6074 	inoff = fxdr_hyper(tl); tl += 2;
6075 	inlop->lo_first = inoff;
6076 	outoff = fxdr_hyper(tl); tl += 2;
6077 	outlop->lo_first = outoff;
6078 	len = fxdr_hyper(tl);
6079 	if (len == 0) {
6080 		/* len == 0 means to EOF. */
6081 		inlop->lo_end = OFF_MAX;
6082 		outlop->lo_end = OFF_MAX;
6083 	} else {
6084 		inlop->lo_end = inlop->lo_first + len;
6085 		outlop->lo_end = outlop->lo_first + len;
6086 	}
6087 
6088 	if ((inoff > OFF_MAX || outoff > OFF_MAX ||
6089 	    inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX ||
6090 	    inlop->lo_end < inlop->lo_first || outlop->lo_end <
6091 	    outlop->lo_first))
6092 		nd->nd_repstat = NFSERR_INVAL;
6093 
6094 	if (nd->nd_repstat == 0 && vp->v_type != VREG)
6095 		nd->nd_repstat = NFSERR_WRONGTYPE;
6096 
6097 	/* Check permissions for the input file. */
6098 	NFSZERO_ATTRBIT(&attrbits);
6099 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
6100 	ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits);
6101 	if (nd->nd_repstat == 0)
6102 		nd->nd_repstat = ret;
6103 	if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
6104 	     NFSVNO_EXSTRICTACCESS(exp)))
6105 		nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
6106 		    curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
6107 		    NULL);
6108 	if (nd->nd_repstat == 0)
6109 		nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL,
6110 		    clientid, &stateid, exp, nd, curthread);
6111 	if (vp != tovp) {
6112 		NFSVOPUNLOCK(vp);
6113 		if (nd->nd_repstat != 0)
6114 			goto out;
6115 
6116 		error = NFSVOPLOCK(tovp, LK_SHARED);
6117 		if (error != 0)
6118 			goto out;
6119 		pathval = 0;
6120 		if (VOP_PATHCONF(tovp, _PC_CLONE_BLKSIZE, &pathval) != 0 ||
6121 		    pathval == 0)
6122 			nd->nd_repstat = NFSERR_NOTSUPP;
6123 		else if (tovp->v_type != VREG)
6124 			nd->nd_repstat = NFSERR_WRONGTYPE;
6125 	}
6126 
6127 	/* For the output file, we only need the Owner attribute. */
6128 	ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits);
6129 	if (nd->nd_repstat == 0)
6130 		nd->nd_repstat = ret;
6131 	if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
6132 	     NFSVNO_EXSTRICTACCESS(exp)))
6133 		nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp,
6134 		    curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
6135 		    NULL);
6136 	if (nd->nd_repstat == 0)
6137 		nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL,
6138 		    clientid, &stateid, toexp, nd, curthread);
6139 	NFSVOPUNLOCK(tovp);
6140 
6141 	/* Range lock the byte ranges for both invp and outvp. */
6142 	if (nd->nd_repstat == 0) {
6143 		for (;;) {
6144 			if (len == 0)
6145 				rl_wcookie = vn_rangelock_wlock(tovp, outoff,
6146 				    OFF_MAX);
6147 			else
6148 				rl_wcookie = vn_rangelock_wlock(tovp, outoff,
6149 				    outoff + len);
6150 			if (vp != tovp) {
6151 				if (len == 0)
6152 					rl_rcookie = vn_rangelock_tryrlock(vp,
6153 					    inoff, OFF_MAX);
6154 				else
6155 					rl_rcookie = vn_rangelock_tryrlock(vp,
6156 					    inoff, inoff + len);
6157 				if (rl_rcookie != NULL)
6158 					break;
6159 			} else {
6160 				rl_rcookie = NULL;
6161 				break;
6162 			}
6163 			vn_rangelock_unlock(tovp, rl_wcookie);
6164 			if (len == 0)
6165 				rl_rcookie = vn_rangelock_rlock(vp, inoff,
6166 				    OFF_MAX);
6167 			else
6168 				rl_rcookie = vn_rangelock_rlock(vp, inoff,
6169 				    inoff + len);
6170 			vn_rangelock_unlock(vp, rl_rcookie);
6171 		}
6172 
6173 		error = NFSVOPLOCK(vp, LK_SHARED);
6174 		if (error == 0) {
6175 			ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL);
6176 			if (ret == 0) {
6177 				/*
6178 				 * Since invp is range locked, na_size should
6179 				 * not change.
6180 				 */
6181 				if (len == 0 && at.na_size > inoff)
6182 					len = SSIZE_MAX;	/* To EOF. */
6183 				else if (inoff + len > at.na_size)
6184 					nd->nd_repstat = NFSERR_INVAL;
6185 			}
6186 			NFSVOPUNLOCK(vp);
6187 			if (ret != 0 && nd->nd_repstat == 0)
6188 				nd->nd_repstat = ret;
6189 		} else if (nd->nd_repstat == 0)
6190 			nd->nd_repstat = error;
6191 	}
6192 
6193 	/*
6194 	 * Do the actual copy to an upper limit of vfs.nfsd.maxcopyrange.
6195 	 * This size limit can be set to limit the time a copy RPC will
6196 	 * take.
6197 	 */
6198 	xfer = len;
6199 	if (nd->nd_repstat == 0) {
6200 		nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff,
6201 		    &xfer, COPY_FILE_RANGE_CLONE, nd->nd_cred, nd->nd_cred,
6202 		    NULL);
6203 		if (nd->nd_repstat == ENOSYS)
6204 			nd->nd_repstat = NFSERR_INVAL;
6205 	}
6206 
6207 	/* Unlock the ranges. */
6208 	if (rl_rcookie != NULL)
6209 		vn_rangelock_unlock(vp, rl_rcookie);
6210 	if (rl_wcookie != NULL)
6211 		vn_rangelock_unlock(tovp, rl_wcookie);
6212 
6213 out:
6214 	vrele(vp);
6215 	vrele(tovp);
6216 	NFSEXITCODE2(error, nd);
6217 	return (error);
6218 nfsmout:
6219 	vput(vp);
6220 	vrele(tovp);
6221 	NFSEXITCODE2(error, nd);
6222 	return (error);
6223 }
6224 
6225 /*
6226  * nfs seek service
6227  */
6228 int
nfsrvd_seek(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)6229 nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram,
6230     vnode_t vp, struct nfsexstuff *exp)
6231 {
6232 	uint32_t *tl;
6233 	struct nfsvattr at;
6234 	int content, error = 0;
6235 	off_t off;
6236 	u_long cmd;
6237 	nfsattrbit_t attrbits;
6238 	bool eof;
6239 
6240 	NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED);
6241 	/* Ignore the stateid for now. */
6242 	tl += (NFSX_STATEID / NFSX_UNSIGNED);
6243 	off = fxdr_hyper(tl); tl += 2;
6244 	content = fxdr_unsigned(int, *tl);
6245 	if (content == NFSV4CONTENT_DATA)
6246 		cmd = FIOSEEKDATA;
6247 	else if (content == NFSV4CONTENT_HOLE)
6248 		cmd = FIOSEEKHOLE;
6249 	else
6250 		nd->nd_repstat = NFSERR_BADXDR;
6251 	if (nd->nd_repstat == 0 && vp->v_type == VDIR)
6252 		nd->nd_repstat = NFSERR_ISDIR;
6253 	if (nd->nd_repstat == 0 && vp->v_type != VREG)
6254 		nd->nd_repstat = NFSERR_WRONGTYPE;
6255 	if (nd->nd_repstat == 0 && off < 0)
6256 		nd->nd_repstat = NFSERR_NXIO;
6257 	if (nd->nd_repstat == 0) {
6258 		/* Check permissions for the input file. */
6259 		NFSZERO_ATTRBIT(&attrbits);
6260 		NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
6261 		nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1,
6262 		    &attrbits);
6263 	}
6264 	if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
6265 	     NFSVNO_EXSTRICTACCESS(exp)))
6266 		nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
6267 		    curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
6268 		    NULL);
6269 	if (nd->nd_repstat != 0)
6270 		goto nfsmout;
6271 
6272 	/* nfsvno_seek() unlocks and vrele()s the vp. */
6273 	nd->nd_repstat = nfsvno_seek(nd, vp, cmd, &off, content, &eof,
6274 	    nd->nd_cred, curthread);
6275 	if (nd->nd_repstat == 0 && eof && content == NFSV4CONTENT_DATA &&
6276 	    nfsrv_linux42server != 0)
6277 		nd->nd_repstat = NFSERR_NXIO;
6278 	if (nd->nd_repstat == 0) {
6279 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
6280 		if (eof)
6281 			*tl++ = newnfs_true;
6282 		else
6283 			*tl++ = newnfs_false;
6284 		txdr_hyper(off, tl);
6285 	}
6286 	NFSEXITCODE2(error, nd);
6287 	return (error);
6288 nfsmout:
6289 	vput(vp);
6290 	NFSEXITCODE2(error, nd);
6291 	return (error);
6292 }
6293 
6294 /*
6295  * nfs get extended attribute service
6296  */
6297 int
nfsrvd_getxattr(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)6298 nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram,
6299     vnode_t vp, __unused struct nfsexstuff *exp)
6300 {
6301 	uint32_t *tl;
6302 	struct mbuf *mp = NULL, *mpend = NULL;
6303 	int error, len;
6304 	char *name;
6305 	struct thread *p = curthread;
6306 	uint16_t off;
6307 
6308 	error = 0;
6309 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6310 	len = fxdr_unsigned(int, *tl);
6311 	if (len <= 0) {
6312 		nd->nd_repstat = NFSERR_BADXDR;
6313 		goto nfsmout;
6314 	}
6315 	if (len > EXTATTR_MAXNAMELEN) {
6316 		nd->nd_repstat = NFSERR_NOXATTR;
6317 		goto nfsmout;
6318 	}
6319 	name = malloc(len + 1, M_TEMP, M_WAITOK);
6320 	nd->nd_repstat = nfsrv_mtostr(nd, name, len);
6321 	if (nd->nd_repstat == 0)
6322 		nd->nd_repstat = nfsvno_getxattr(vp, name,
6323 		    nd->nd_maxresp, nd->nd_cred, nd->nd_flag,
6324 		    nd->nd_maxextsiz, p, &mp, &mpend, &len);
6325 	if (nd->nd_repstat == ENOATTR)
6326 		nd->nd_repstat = NFSERR_NOXATTR;
6327 	else if (nd->nd_repstat == EOPNOTSUPP)
6328 		nd->nd_repstat = NFSERR_NOTSUPP;
6329 	if (nd->nd_repstat == 0) {
6330 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
6331 		*tl = txdr_unsigned(len);
6332 		if (len > 0) {
6333 			nd->nd_mb->m_next = mp;
6334 			nd->nd_mb = mpend;
6335 			if ((mpend->m_flags & M_EXTPG) != 0) {
6336 				nd->nd_flag |= ND_EXTPG;
6337 				nd->nd_bextpg = mpend->m_epg_npgs - 1;
6338 				nd->nd_bpos = (char *)(void *)
6339 				   PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]);
6340 				off = (nd->nd_bextpg == 0) ?
6341 				    mpend->m_epg_1st_off : 0;
6342 				nd->nd_bpos += off + mpend->m_epg_last_len;
6343 				nd->nd_bextpgsiz = PAGE_SIZE -
6344 				    mpend->m_epg_last_len - off;
6345 			} else
6346 				nd->nd_bpos = mtod(mpend, char *) +
6347 				    mpend->m_len;
6348 		}
6349 	}
6350 	free(name, M_TEMP);
6351 
6352 nfsmout:
6353 	if (nd->nd_repstat == 0)
6354 		nd->nd_repstat = error;
6355 	vput(vp);
6356 	NFSEXITCODE2(0, nd);
6357 	return (0);
6358 }
6359 
6360 /*
6361  * nfs set extended attribute service
6362  */
6363 int
nfsrvd_setxattr(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)6364 nfsrvd_setxattr(struct nfsrv_descript *nd, __unused int isdgram,
6365     vnode_t vp, __unused struct nfsexstuff *exp)
6366 {
6367 	uint32_t *tl;
6368 	struct nfsvattr ova, nva;
6369 	nfsattrbit_t attrbits;
6370 	int error, len, opt;
6371 	char *name;
6372 	size_t siz;
6373 	struct thread *p = curthread;
6374 
6375 	error = 0;
6376 	name = NULL;
6377 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
6378 	opt = fxdr_unsigned(int, *tl++);
6379 	len = fxdr_unsigned(int, *tl);
6380 	if (len <= 0) {
6381 		nd->nd_repstat = NFSERR_BADXDR;
6382 		goto nfsmout;
6383 	}
6384 	if (len > EXTATTR_MAXNAMELEN) {
6385 		nd->nd_repstat = NFSERR_NOXATTR;
6386 		goto nfsmout;
6387 	}
6388 	name = malloc(len + 1, M_TEMP, M_WAITOK);
6389 	error = nfsrv_mtostr(nd, name, len);
6390 	if (error != 0)
6391 		goto nfsmout;
6392 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6393 	len = fxdr_unsigned(int, *tl);
6394 	if (len < 0 || len > IOSIZE_MAX) {
6395 		nd->nd_repstat = NFSERR_XATTR2BIG;
6396 		goto nfsmout;
6397 	}
6398 	switch (opt) {
6399 	case NFSV4SXATTR_CREATE:
6400 		error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
6401 		    &siz, nd->nd_cred, p);
6402 		if (error != ENOATTR)
6403 			nd->nd_repstat = NFSERR_EXIST;
6404 		error = 0;
6405 		break;
6406 	case NFSV4SXATTR_REPLACE:
6407 		error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
6408 		    &siz, nd->nd_cred, p);
6409 		if (error != 0)
6410 			nd->nd_repstat = NFSERR_NOXATTR;
6411 		break;
6412 	case NFSV4SXATTR_EITHER:
6413 		break;
6414 	default:
6415 		nd->nd_repstat = NFSERR_BADXDR;
6416 	}
6417 	if (nd->nd_repstat != 0)
6418 		goto nfsmout;
6419 
6420 	/* Now, do the Set Extended attribute, with Change before and after. */
6421 	NFSZERO_ATTRBIT(&attrbits);
6422 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
6423 	nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
6424 	if (nd->nd_repstat == 0) {
6425 		nd->nd_repstat = nfsvno_setxattr(vp, name, len, nd->nd_md,
6426 		    nd->nd_dpos, nd->nd_cred, p);
6427 		if (nd->nd_repstat == ENXIO)
6428 			nd->nd_repstat = NFSERR_XATTR2BIG;
6429 	}
6430 	if (nd->nd_repstat == 0 && len > 0)
6431 		nd->nd_repstat = nfsm_advance(nd, NFSM_RNDUP(len), -1);
6432 	if (nd->nd_repstat == 0)
6433 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
6434 	if (nd->nd_repstat == 0) {
6435 		NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
6436 		*tl++ = newnfs_true;
6437 		txdr_hyper(ova.na_filerev, tl); tl += 2;
6438 		txdr_hyper(nva.na_filerev, tl);
6439 	}
6440 
6441 nfsmout:
6442 	free(name, M_TEMP);
6443 	if (nd->nd_repstat == 0)
6444 		nd->nd_repstat = error;
6445 	vput(vp);
6446 	NFSEXITCODE2(0, nd);
6447 	return (0);
6448 }
6449 
6450 /*
6451  * nfs remove extended attribute service
6452  */
6453 int
nfsrvd_rmxattr(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)6454 nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int isdgram,
6455     vnode_t vp, __unused struct nfsexstuff *exp)
6456 {
6457 	uint32_t *tl;
6458 	struct nfsvattr ova, nva;
6459 	nfsattrbit_t attrbits;
6460 	int error, len;
6461 	char *name;
6462 	struct thread *p = curthread;
6463 
6464 	error = 0;
6465 	name = NULL;
6466 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6467 	len = fxdr_unsigned(int, *tl);
6468 	if (len <= 0) {
6469 		nd->nd_repstat = NFSERR_BADXDR;
6470 		goto nfsmout;
6471 	}
6472 	if (len > EXTATTR_MAXNAMELEN) {
6473 		nd->nd_repstat = NFSERR_NOXATTR;
6474 		goto nfsmout;
6475 	}
6476 	name = malloc(len + 1, M_TEMP, M_WAITOK);
6477 	error = nfsrv_mtostr(nd, name, len);
6478 	if (error != 0)
6479 		goto nfsmout;
6480 
6481 	if ((nd->nd_flag & ND_IMPLIEDCLID) == 0) {
6482 		printf("EEK! nfsrvd_rmxattr: no implied clientid\n");
6483 		error = NFSERR_NOXATTR;
6484 		goto nfsmout;
6485 	}
6486 	/*
6487 	 * Now, do the Remove Extended attribute, with Change before and
6488 	 * after.
6489 	*/
6490 	NFSZERO_ATTRBIT(&attrbits);
6491 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
6492 	nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
6493 	if (nd->nd_repstat == 0) {
6494 		nd->nd_repstat = nfsvno_rmxattr(nd, vp, name, nd->nd_cred, p);
6495 		if (nd->nd_repstat == ENOATTR)
6496 			nd->nd_repstat = NFSERR_NOXATTR;
6497 	}
6498 	if (nd->nd_repstat == 0)
6499 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
6500 	if (nd->nd_repstat == 0) {
6501 		NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
6502 		*tl++ = newnfs_true;
6503 		txdr_hyper(ova.na_filerev, tl); tl += 2;
6504 		txdr_hyper(nva.na_filerev, tl);
6505 	}
6506 
6507 nfsmout:
6508 	free(name, M_TEMP);
6509 	if (nd->nd_repstat == 0)
6510 		nd->nd_repstat = error;
6511 	vput(vp);
6512 	NFSEXITCODE2(0, nd);
6513 	return (0);
6514 }
6515 
6516 /*
6517  * nfs list extended attribute service
6518  */
6519 int
nfsrvd_listxattr(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)6520 nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram,
6521     vnode_t vp, __unused struct nfsexstuff *exp)
6522 {
6523 	uint32_t cnt, *tl, len, len2, i, pos, retlen;
6524 	int error;
6525 	uint64_t cookie, cookie2;
6526 	u_char *buf;
6527 	bool eof;
6528 	struct thread *p = curthread;
6529 
6530 	error = 0;
6531 	buf = NULL;
6532 	NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
6533 	/*
6534 	 * The cookie doesn't need to be in net byte order, but FreeBSD
6535 	 * does so to make it more readable in packet traces.
6536 	 */
6537 	cookie = fxdr_hyper(tl); tl += 2;
6538 	len = fxdr_unsigned(uint32_t, *tl);
6539 	if (len == 0 || cookie >= IOSIZE_MAX) {
6540 		nd->nd_repstat = NFSERR_BADXDR;
6541 		goto nfsmout;
6542 	}
6543 	if (len > nd->nd_maxresp - NFS_MAXXDR)
6544 		len = nd->nd_maxresp - NFS_MAXXDR;
6545 	len2 = len;
6546 	nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf,
6547 	    &len, &eof);
6548 	if (nd->nd_repstat == EOPNOTSUPP)
6549 		nd->nd_repstat = NFSERR_NOTSUPP;
6550 	if (nd->nd_repstat == 0) {
6551 		cookie2 = cookie + len;
6552 		if (cookie2 < cookie)
6553 			nd->nd_repstat = NFSERR_BADXDR;
6554 	}
6555 	retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED;
6556 	if (nd->nd_repstat == 0 && len2 < retlen)
6557 		nd->nd_repstat = NFSERR_TOOSMALL;
6558 	if (nd->nd_repstat == 0) {
6559 		/* Now copy the entries out. */
6560 		if (len == 0) {
6561 			/* The cookie was at eof. */
6562 			NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 *
6563 			    NFSX_UNSIGNED);
6564 			txdr_hyper(cookie2, tl); tl += 2;
6565 			*tl++ = txdr_unsigned(0);
6566 			*tl = newnfs_true;
6567 			goto nfsmout;
6568 		}
6569 
6570 		/* Sanity check the cookie. */
6571 		for (pos = 0; pos < len; pos += (i + 1)) {
6572 			if (pos == cookie)
6573 				break;
6574 			i = buf[pos];
6575 		}
6576 		if (pos != cookie) {
6577 			nd->nd_repstat = NFSERR_INVAL;
6578 			goto nfsmout;
6579 		}
6580 
6581 		/* Loop around copying the entrie(s) out. */
6582 		cnt = 0;
6583 		len -= cookie;
6584 		i = buf[pos];
6585 		while (i < len && len2 >= retlen + NFSM_RNDUP(i) +
6586 		    NFSX_UNSIGNED) {
6587 			if (cnt == 0) {
6588 				NFSM_BUILD(tl, uint32_t *, NFSX_HYPER +
6589 				    NFSX_UNSIGNED);
6590 				txdr_hyper(cookie2, tl); tl += 2;
6591 			}
6592 			retlen += nfsm_strtom(nd, &buf[pos + 1], i);
6593 			len -= (i + 1);
6594 			pos += (i + 1);
6595 			i = buf[pos];
6596 			cnt++;
6597 		}
6598 		/*
6599 		 * eof is set true/false by nfsvno_listxattr(), but if we
6600 		 * can't copy all entries returned by nfsvno_listxattr(),
6601 		 * we are not at eof.
6602 		 */
6603 		if (len > 0)
6604 			eof = false;
6605 		if (cnt > 0) {
6606 			/* *tl is set above. */
6607 			*tl = txdr_unsigned(cnt);
6608 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
6609 			if (eof)
6610 				*tl = newnfs_true;
6611 			else
6612 				*tl = newnfs_false;
6613 		} else
6614 			nd->nd_repstat = NFSERR_TOOSMALL;
6615 	}
6616 
6617 nfsmout:
6618 	free(buf, M_TEMP);
6619 	if (nd->nd_repstat == 0)
6620 		nd->nd_repstat = error;
6621 	vput(vp);
6622 	NFSEXITCODE2(0, nd);
6623 	return (0);
6624 }
6625 
6626 /*
6627  * nfsv4 service not supported
6628  */
6629 int
nfsrvd_notsupp(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)6630 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
6631     __unused vnode_t vp, __unused struct nfsexstuff *exp)
6632 {
6633 
6634 	nd->nd_repstat = NFSERR_NOTSUPP;
6635 	NFSEXITCODE2(0, nd);
6636 	return (0);
6637 }
6638