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