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