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