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