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