xref: /freebsd/sys/fs/nfsserver/nfs_nfsdserv.c (revision 03e9e83f358678bab5e4c1ddf9c9d8faa7183cbb)
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 	if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1)
5137 		layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK);
5138 	else if (layouttype == NFSLAYOUT_FLEXFILE)
5139 		layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP,
5140 		    M_WAITOK);
5141 	else
5142 		nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE;
5143 	if (layp != NULL)
5144 		nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype,
5145 		    &iomode, &offset, &len, minlen, &stateid, maxcnt,
5146 		    &retonclose, &layoutlen, layp, nd->nd_cred, p);
5147 	NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat,
5148 	    layoutlen);
5149 	if (nd->nd_repstat == 0) {
5150 		/* For NFSv4.1, set the Current StateID. */
5151 		if ((nd->nd_flag & ND_NFSV41) != 0) {
5152 			nd->nd_curstateid = stateid;
5153 			nd->nd_flag |= ND_CURSTATEID;
5154 		}
5155 		NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID +
5156 		    2 * NFSX_HYPER);
5157 		*tl++ = txdr_unsigned(retonclose);
5158 		*tl++ = txdr_unsigned(stateid.seqid);
5159 		NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
5160 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5161 		*tl++ = txdr_unsigned(1);	/* Only returns one layout. */
5162 		txdr_hyper(offset, tl); tl += 2;
5163 		txdr_hyper(len, tl); tl += 2;
5164 		*tl++ = txdr_unsigned(iomode);
5165 		*tl = txdr_unsigned(layouttype);
5166 		nfsm_strtom(nd, layp, layoutlen);
5167 	} else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) {
5168 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5169 		*tl = newnfs_false;
5170 	}
5171 	free(layp, M_TEMP);
5172 nfsmout:
5173 	vput(vp);
5174 	NFSEXITCODE2(error, nd);
5175 	return (error);
5176 }
5177 
5178 /*
5179  * nfsv4 layoutcommit service
5180  */
5181 int
nfsrvd_layoutcommit(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5182 nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram,
5183     vnode_t vp, struct nfsexstuff *exp)
5184 {
5185 	uint32_t *tl;
5186 	nfsv4stateid_t stateid;
5187 	int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim;
5188 	int hasnewsize;
5189 	uint64_t offset, len, newoff = 0, newsize;
5190 	struct timespec newmtime;
5191 	char *layp;
5192 	struct thread *p = curthread;
5193 
5194 	layp = NULL;
5195 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER +
5196 	    NFSX_STATEID);
5197 	offset = fxdr_hyper(tl); tl += 2;
5198 	len = fxdr_hyper(tl); tl += 2;
5199 	reclaim = fxdr_unsigned(int, *tl++);
5200 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5201 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5202 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5203 	/*
5204 	 * For the special stateid of other all 0s and seqid == 1, set the
5205 	 * stateid to the current stateid, if it is set.
5206 	 */
5207 	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5208 	    stateid.other[1] == 0 && stateid.other[2] == 0) {
5209 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5210 			stateid = nd->nd_curstateid;
5211 			stateid.seqid = 0;
5212 		} else {
5213 			nd->nd_repstat = NFSERR_BADSTATEID;
5214 			goto nfsmout;
5215 		}
5216 	}
5217 
5218 	hasnewoff = fxdr_unsigned(int, *tl);
5219 	if (hasnewoff != 0) {
5220 		NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
5221 		newoff = fxdr_hyper(tl); tl += 2;
5222 	} else
5223 		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5224 	hasnewmtime = fxdr_unsigned(int, *tl);
5225 	if (hasnewmtime != 0) {
5226 		NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED);
5227 		fxdr_nfsv4time(tl, &newmtime);
5228 		tl += (NFSX_V4TIME / NFSX_UNSIGNED);
5229 	} else
5230 		NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5231 	layouttype = fxdr_unsigned(int, *tl++);
5232 	maxcnt = fxdr_unsigned(int, *tl);
5233 	/* There is no limit in the RFC, so use 1000 as a sanity limit. */
5234 	if (maxcnt < 0 || maxcnt > 1000) {
5235 		error = NFSERR_BADXDR;
5236 		goto nfsmout;
5237 	}
5238 	if (maxcnt > 0) {
5239 		layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
5240 		error = nfsrv_mtostr(nd, layp, maxcnt);
5241 		if (error != 0)
5242 			goto nfsmout;
5243 	}
5244 	nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff,
5245 	    newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid,
5246 	    maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p);
5247 	NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat);
5248 	if (nd->nd_repstat == 0) {
5249 		if (hasnewsize != 0) {
5250 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
5251 			*tl++ = newnfs_true;
5252 			txdr_hyper(newsize, tl);
5253 		} else {
5254 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5255 			*tl = newnfs_false;
5256 		}
5257 	}
5258 nfsmout:
5259 	free(layp, M_TEMP);
5260 	vput(vp);
5261 	NFSEXITCODE2(error, nd);
5262 	return (error);
5263 }
5264 
5265 /*
5266  * nfsv4 layoutreturn service
5267  */
5268 int
nfsrvd_layoutreturn(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5269 nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram,
5270     vnode_t vp, struct nfsexstuff *exp)
5271 {
5272 	uint32_t *tl, *layp;
5273 	nfsv4stateid_t stateid;
5274 	int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim;
5275 	uint64_t offset, len;
5276 	struct thread *p = curthread;
5277 
5278 	layp = NULL;
5279 	NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
5280 	reclaim = *tl++;
5281 	layouttype = fxdr_unsigned(int, *tl++);
5282 	iomode = fxdr_unsigned(int, *tl++);
5283 	kind = fxdr_unsigned(int, *tl);
5284 	NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim,
5285 	    layouttype, iomode, kind);
5286 	if (kind == NFSV4LAYOUTRET_FILE) {
5287 		NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
5288 		    NFSX_UNSIGNED);
5289 		offset = fxdr_hyper(tl); tl += 2;
5290 		len = fxdr_hyper(tl); tl += 2;
5291 		stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5292 		NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5293 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5294 
5295 		/*
5296 		 * For the special stateid of other all 0s and seqid == 1, set
5297 		 * the stateid to the current stateid, if it is set.
5298 		 */
5299 		if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5300 		    stateid.other[1] == 0 && stateid.other[2] == 0) {
5301 			if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5302 				stateid = nd->nd_curstateid;
5303 				stateid.seqid = 0;
5304 			} else {
5305 				nd->nd_repstat = NFSERR_BADSTATEID;
5306 				goto nfsmout;
5307 			}
5308 		}
5309 
5310 		maxcnt = fxdr_unsigned(int, *tl);
5311 		/*
5312 		 * There is no fixed upper bound defined in the RFCs,
5313 		 * but 128Kbytes should be more than sufficient.
5314 		 */
5315 		if (maxcnt < 0 || maxcnt > 131072)
5316 			maxcnt = 0;
5317 		if (maxcnt > 0) {
5318 			layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
5319 			error = nfsrv_mtostr(nd, (char *)layp, maxcnt);
5320 			if (error != 0)
5321 				goto nfsmout;
5322 		}
5323 	} else {
5324 		if (reclaim == newnfs_true) {
5325 			nd->nd_repstat = NFSERR_INVAL;
5326 			goto nfsmout;
5327 		}
5328 		offset = len = 0;
5329 		maxcnt = 0;
5330 	}
5331 	nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode,
5332 	    offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd,
5333 	    nd->nd_cred, p);
5334 	NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat,
5335 	    fnd);
5336 	if (nd->nd_repstat == 0) {
5337 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5338 		if (fnd != 0) {
5339 			*tl = newnfs_true;
5340 			NFSM_BUILD(tl, uint32_t *, NFSX_STATEID);
5341 			*tl++ = txdr_unsigned(stateid.seqid);
5342 			NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
5343 		} else
5344 			*tl = newnfs_false;
5345 	}
5346 nfsmout:
5347 	free(layp, M_TEMP);
5348 	vput(vp);
5349 	NFSEXITCODE2(error, nd);
5350 	return (error);
5351 }
5352 
5353 /*
5354  * nfsv4 layout error service
5355  */
5356 int
nfsrvd_layouterror(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5357 nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram,
5358     vnode_t vp, struct nfsexstuff *exp)
5359 {
5360 	uint32_t *tl;
5361 	nfsv4stateid_t stateid;
5362 	int cnt, error = 0, i, stat;
5363 	int opnum __unused;
5364 	char devid[NFSX_V4DEVICEID];
5365 	uint64_t offset, len;
5366 
5367 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
5368 	    NFSX_UNSIGNED);
5369 	offset = fxdr_hyper(tl); tl += 2;
5370 	len = fxdr_hyper(tl); tl += 2;
5371 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5372 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5373 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5374 	cnt = fxdr_unsigned(int, *tl);
5375 	NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset,
5376 	    (uintmax_t)len, cnt);
5377 	/*
5378 	 * For the special stateid of other all 0s and seqid == 1, set
5379 	 * the stateid to the current stateid, if it is set.
5380 	 */
5381 	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5382 	    stateid.other[1] == 0 && stateid.other[2] == 0) {
5383 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5384 			stateid = nd->nd_curstateid;
5385 			stateid.seqid = 0;
5386 		} else {
5387 			nd->nd_repstat = NFSERR_BADSTATEID;
5388 			goto nfsmout;
5389 		}
5390 	}
5391 
5392 	/*
5393 	 * Ignore offset, len and stateid for now.
5394 	 */
5395 	for (i = 0; i < cnt; i++) {
5396 		NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 *
5397 		    NFSX_UNSIGNED);
5398 		NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5399 		tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5400 		stat = fxdr_unsigned(int, *tl++);
5401 		opnum = fxdr_unsigned(int, *tl);
5402 		NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat);
5403 		/*
5404 		 * Except for NFSERR_ACCES, NFSERR_STALE and NFSERR_NOSPC
5405 		 * errors, disable the mirror.
5406 		 */
5407 		if (stat != NFSERR_ACCES && stat != NFSERR_STALE &&
5408 		    stat != NFSERR_NOSPC)
5409 			nfsrv_delds(devid, curthread);
5410 
5411 		/* For NFSERR_NOSPC, mark all deviceids and layouts. */
5412 		if (stat == NFSERR_NOSPC)
5413 			nfsrv_marknospc(devid, true);
5414 	}
5415 nfsmout:
5416 	vput(vp);
5417 	NFSEXITCODE2(error, nd);
5418 	return (error);
5419 }
5420 
5421 /*
5422  * nfsv4 layout stats service
5423  */
5424 int
nfsrvd_layoutstats(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5425 nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram,
5426     vnode_t vp, struct nfsexstuff *exp)
5427 {
5428 	uint32_t *tl;
5429 	nfsv4stateid_t stateid;
5430 	int cnt, error = 0;
5431 	int layouttype __unused;
5432 	char devid[NFSX_V4DEVICEID] __unused;
5433 	uint64_t offset __unused, len __unused, readcount __unused;
5434 	uint64_t readbytes __unused, writecount __unused, writebytes __unused;
5435 
5436 	NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID +
5437 	    NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED);
5438 	offset = fxdr_hyper(tl); tl += 2;
5439 	len = fxdr_hyper(tl); tl += 2;
5440 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5441 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5442 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5443 	readcount = fxdr_hyper(tl); tl += 2;
5444 	readbytes = fxdr_hyper(tl); tl += 2;
5445 	writecount = fxdr_hyper(tl); tl += 2;
5446 	writebytes = fxdr_hyper(tl); tl += 2;
5447 	NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5448 	tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5449 	layouttype = fxdr_unsigned(int, *tl++);
5450 	cnt = fxdr_unsigned(int, *tl);
5451 	error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1);
5452 	if (error != 0)
5453 		goto nfsmout;
5454 	NFSD_DEBUG(4, "layoutstats cnt=%d\n", cnt);
5455 	/*
5456 	 * For the special stateid of other all 0s and seqid == 1, set
5457 	 * the stateid to the current stateid, if it is set.
5458 	 */
5459 	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5460 	    stateid.other[1] == 0 && stateid.other[2] == 0) {
5461 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5462 			stateid = nd->nd_curstateid;
5463 			stateid.seqid = 0;
5464 		} else {
5465 			nd->nd_repstat = NFSERR_BADSTATEID;
5466 			goto nfsmout;
5467 		}
5468 	}
5469 
5470 	/*
5471 	 * No use for the stats for now.
5472 	 */
5473 nfsmout:
5474 	vput(vp);
5475 	NFSEXITCODE2(error, nd);
5476 	return (error);
5477 }
5478 
5479 /*
5480  * nfsv4 io_advise service
5481  */
5482 int
nfsrvd_ioadvise(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5483 nfsrvd_ioadvise(struct nfsrv_descript *nd, __unused int isdgram,
5484     vnode_t vp, struct nfsexstuff *exp)
5485 {
5486 	uint32_t *tl;
5487 	nfsv4stateid_t stateid;
5488 	nfsattrbit_t hints;
5489 	int error = 0, ret;
5490 	off_t offset, len;
5491 
5492 	NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5493 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5494 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5495 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5496 	offset = fxdr_hyper(tl); tl += 2;
5497 	len = fxdr_hyper(tl);
5498 	error = nfsrv_getattrbits(nd, &hints, NULL, NULL);
5499 	if (error != 0)
5500 		goto nfsmout;
5501 	/*
5502 	 * For the special stateid of other all 0s and seqid == 1, set
5503 	 * the stateid to the current stateid, if it is set.
5504 	 */
5505 	if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5506 	    stateid.other[1] == 0 && stateid.other[2] == 0) {
5507 		if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5508 			stateid = nd->nd_curstateid;
5509 			stateid.seqid = 0;
5510 		} else {
5511 			nd->nd_repstat = NFSERR_BADSTATEID;
5512 			goto nfsmout;
5513 		}
5514 	}
5515 
5516 	if (offset < 0) {
5517 		nd->nd_repstat = NFSERR_INVAL;
5518 		goto nfsmout;
5519 	}
5520 	if (len < 0)
5521 		len = 0;
5522 	if (vp->v_type != VREG) {
5523 		if (vp->v_type == VDIR)
5524 			nd->nd_repstat = NFSERR_ISDIR;
5525 		else
5526 			nd->nd_repstat = NFSERR_WRONGTYPE;
5527 		goto nfsmout;
5528 	}
5529 
5530 	/*
5531 	 * For now, we can only handle WILLNEED and DONTNEED and don't use
5532 	 * the stateid.
5533 	 */
5534 	if ((NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED) &&
5535 	    !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED)) ||
5536 	    (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED) &&
5537 	    !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED))) {
5538 		NFSVOPUNLOCK(vp);
5539 		if (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED)) {
5540 			ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_WILLNEED);
5541 			NFSZERO_ATTRBIT(&hints);
5542 			if (ret == 0)
5543 				NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED);
5544 			else
5545 				NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5546 		} else {
5547 			ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_DONTNEED);
5548 			NFSZERO_ATTRBIT(&hints);
5549 			if (ret == 0)
5550 				NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED);
5551 			else
5552 				NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5553 		}
5554 		vrele(vp);
5555 	} else {
5556 		NFSZERO_ATTRBIT(&hints);
5557 		NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5558 		vput(vp);
5559 	}
5560 	nfsrv_putattrbit(nd, &hints);
5561 	NFSEXITCODE2(error, nd);
5562 	return (error);
5563 nfsmout:
5564 	vput(vp);
5565 	NFSEXITCODE2(error, nd);
5566 	return (error);
5567 }
5568 
5569 /*
5570  * nfsv4 getdeviceinfo service
5571  */
5572 int
nfsrvd_getdevinfo(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)5573 nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram,
5574     __unused vnode_t vp, __unused struct nfsexstuff *exp)
5575 {
5576 	uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP];
5577 	int cnt, devaddrlen, error = 0, i, layouttype;
5578 	char devid[NFSX_V4DEVICEID], *devaddr;
5579 	time_t dev_time;
5580 
5581 	NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
5582 	NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5583 	tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5584 	layouttype = fxdr_unsigned(int, *tl++);
5585 	maxcnt = fxdr_unsigned(uint32_t, *tl++);
5586 	cnt = fxdr_unsigned(int, *tl);
5587 	NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype,
5588 	    maxcnt, cnt);
5589 	if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) {
5590 		nd->nd_repstat = NFSERR_INVAL;
5591 		goto nfsmout;
5592 	}
5593 	if (cnt > 0) {
5594 		NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED);
5595 		for (i = 0; i < cnt; i++)
5596 			notify[i] = fxdr_unsigned(uint32_t, *tl++);
5597 	}
5598 	for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++)
5599 		notify[i] = 0;
5600 
5601 	/*
5602 	 * Check that the device id is not stale.  Device ids are recreated
5603 	 * each time the nfsd threads are restarted.
5604 	 */
5605 	NFSBCOPY(devid, &dev_time, sizeof(dev_time));
5606 	if (dev_time != nfsdev_time) {
5607 		nd->nd_repstat = NFSERR_NOENT;
5608 		goto nfsmout;
5609 	}
5610 
5611 	/* Look for the device id. */
5612 	nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt,
5613 	    notify, &devaddrlen, &devaddr);
5614 	NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat);
5615 	if (nd->nd_repstat == 0) {
5616 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5617 		*tl = txdr_unsigned(layouttype);
5618 		nfsm_strtom(nd, devaddr, devaddrlen);
5619 		cnt = 0;
5620 		for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) {
5621 			if (notify[i] != 0)
5622 				cnt = i + 1;
5623 		}
5624 		NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED);
5625 		*tl++ = txdr_unsigned(cnt);
5626 		for (i = 0; i < cnt; i++)
5627 			*tl++ = txdr_unsigned(notify[i]);
5628 	} else if (nd->nd_repstat == NFSERR_TOOSMALL) {
5629 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5630 		*tl = txdr_unsigned(maxcnt);
5631 	}
5632 nfsmout:
5633 	NFSEXITCODE2(error, nd);
5634 	return (error);
5635 }
5636 
5637 /*
5638  * nfsv4 test stateid service
5639  */
5640 int
nfsrvd_teststateid(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)5641 nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram,
5642     __unused vnode_t vp, __unused struct nfsexstuff *exp)
5643 {
5644 	uint32_t *tl;
5645 	nfsv4stateid_t *stateidp = NULL, *tstateidp;
5646 	int cnt, error = 0, i, ret;
5647 	struct thread *p = curthread;
5648 
5649 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5650 	cnt = fxdr_unsigned(int, *tl);
5651 	if (cnt <= 0 || cnt > 1024) {
5652 		nd->nd_repstat = NFSERR_BADXDR;
5653 		goto nfsmout;
5654 	}
5655 	stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK);
5656 	tstateidp = stateidp;
5657 	for (i = 0; i < cnt; i++) {
5658 		NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
5659 		tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
5660 		NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER);
5661 		tstateidp++;
5662 	}
5663 	NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5664 	*tl = txdr_unsigned(cnt);
5665 	tstateidp = stateidp;
5666 	for (i = 0; i < cnt; i++) {
5667 		ret = nfsrv_teststateid(nd, tstateidp, p);
5668 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5669 		*tl = txdr_unsigned(ret);
5670 		tstateidp++;
5671 	}
5672 nfsmout:
5673 	free(stateidp, M_TEMP);
5674 	NFSEXITCODE2(error, nd);
5675 	return (error);
5676 }
5677 
5678 /*
5679  * nfs allocate service
5680  */
5681 int
nfsrvd_allocate(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5682 nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram,
5683     vnode_t vp, struct nfsexstuff *exp)
5684 {
5685 	uint32_t *tl;
5686 	struct nfsvattr forat;
5687 	int error = 0, forat_ret = 1, gotproxystateid;
5688 	off_t off, len;
5689 	struct nfsstate st, *stp = &st;
5690 	struct nfslock lo, *lop = &lo;
5691 	nfsv4stateid_t stateid;
5692 	nfsquad_t clientid;
5693 	nfsattrbit_t attrbits;
5694 
5695 	if (!nfsrv_doallocate) {
5696 		/*
5697 		 * If any exported file system, such as a ZFS one, cannot
5698 		 * do VOP_ALLOCATE(), this operation cannot be supported
5699 		 * for NFSv4.2.  This cannot be done 'per filesystem', but
5700 		 * must be for the entire nfsd NFSv4.2 service.
5701 		 */
5702 		nd->nd_repstat = NFSERR_NOTSUPP;
5703 		goto nfsmout;
5704 	}
5705 	gotproxystateid = 0;
5706 	NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5707 	stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5708 	lop->lo_flags = NFSLCK_WRITE;
5709 	stp->ls_ownerlen = 0;
5710 	stp->ls_op = NULL;
5711 	stp->ls_uid = nd->nd_cred->cr_uid;
5712 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
5713 	clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
5714 	clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
5715 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
5716 		if ((nd->nd_flag & ND_NFSV41) != 0)
5717 			clientid.qval = nd->nd_clientid.qval;
5718 		else if (nd->nd_clientid.qval != clientid.qval)
5719 			printf("EEK2 multiple clids\n");
5720 	} else {
5721 		if ((nd->nd_flag & ND_NFSV41) != 0)
5722 			printf("EEK! no clientid from session\n");
5723 		nd->nd_flag |= ND_IMPLIEDCLID;
5724 		nd->nd_clientid.qval = clientid.qval;
5725 	}
5726 	stp->ls_stateid.other[2] = *tl++;
5727 	/*
5728 	 * Don't allow this to be done for a DS.
5729 	 */
5730 	if ((nd->nd_flag & ND_DSSERVER) != 0)
5731 		nd->nd_repstat = NFSERR_NOTSUPP;
5732 	/* However, allow the proxy stateid. */
5733 	if (stp->ls_stateid.seqid == 0xffffffff &&
5734 	    stp->ls_stateid.other[0] == 0x55555555 &&
5735 	    stp->ls_stateid.other[1] == 0x55555555 &&
5736 	    stp->ls_stateid.other[2] == 0x55555555)
5737 		gotproxystateid = 1;
5738 	off = fxdr_hyper(tl); tl += 2;
5739 	lop->lo_first = off;
5740 	len = fxdr_hyper(tl);
5741 	lop->lo_end = lop->lo_first + len;
5742 	/*
5743 	 * Sanity check the offset and length.
5744 	 * off and len are off_t (signed int64_t) whereas
5745 	 * lo_first and lo_end are uint64_t and, as such,
5746 	 * if off >= 0 && len > 0, lo_end cannot overflow
5747 	 * unless off_t is changed to something other than
5748 	 * int64_t.  Check lo_end < lo_first in case that
5749 	 * is someday the case.
5750 	 */
5751 	if (nd->nd_repstat == 0 && (len <= 0 || off < 0 || lop->lo_end >
5752 	    OFF_MAX || lop->lo_end < lop->lo_first))
5753 		nd->nd_repstat = NFSERR_INVAL;
5754 
5755 	if (nd->nd_repstat == 0 && vp->v_type != VREG)
5756 		nd->nd_repstat = NFSERR_WRONGTYPE;
5757 	NFSZERO_ATTRBIT(&attrbits);
5758 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5759 	forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits);
5760 	if (nd->nd_repstat == 0)
5761 		nd->nd_repstat = forat_ret;
5762 	if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid ||
5763 	     NFSVNO_EXSTRICTACCESS(exp)))
5764 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp,
5765 		    curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5766 		    NULL);
5767 	if (nd->nd_repstat == 0 && gotproxystateid == 0)
5768 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
5769 		    &stateid, exp, nd, curthread);
5770 
5771 	NFSD_DEBUG(4, "nfsrvd_allocate: off=%jd len=%jd stat=%d\n",
5772 	    (intmax_t)off, (intmax_t)len, nd->nd_repstat);
5773 	if (nd->nd_repstat == 0)
5774 		nd->nd_repstat = nfsvno_allocate(vp, off, len, nd->nd_cred,
5775 		    curthread);
5776 	NFSD_DEBUG(4, "nfsrvd_allocate: aft nfsvno_allocate=%d\n",
5777 	    nd->nd_repstat);
5778 	vput(vp);
5779 	NFSEXITCODE2(0, nd);
5780 	return (0);
5781 nfsmout:
5782 	vput(vp);
5783 	NFSEXITCODE2(error, nd);
5784 	return (error);
5785 }
5786 
5787 /*
5788  * nfs deallocate service
5789  */
5790 int
nfsrvd_deallocate(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5791 nfsrvd_deallocate(struct nfsrv_descript *nd, __unused int isdgram,
5792     vnode_t vp, struct nfsexstuff *exp)
5793 {
5794 	uint32_t *tl;
5795 	struct nfsvattr forat;
5796 	int error = 0, forat_ret = 1, gotproxystateid;
5797 	off_t off, len;
5798 	struct nfsstate st, *stp = &st;
5799 	struct nfslock lo, *lop = &lo;
5800 	nfsv4stateid_t stateid;
5801 	nfsquad_t clientid;
5802 	nfsattrbit_t attrbits;
5803 
5804 	gotproxystateid = 0;
5805 	NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5806 	stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5807 	lop->lo_flags = NFSLCK_WRITE;
5808 	stp->ls_ownerlen = 0;
5809 	stp->ls_op = NULL;
5810 	stp->ls_uid = nd->nd_cred->cr_uid;
5811 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
5812 	clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
5813 	clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
5814 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
5815 		if ((nd->nd_flag & ND_NFSV41) != 0)
5816 			clientid.qval = nd->nd_clientid.qval;
5817 		else if (nd->nd_clientid.qval != clientid.qval)
5818 			printf("EEK2 multiple clids\n");
5819 	} else {
5820 		if ((nd->nd_flag & ND_NFSV41) != 0)
5821 			printf("EEK! no clientid from session\n");
5822 		nd->nd_flag |= ND_IMPLIEDCLID;
5823 		nd->nd_clientid.qval = clientid.qval;
5824 	}
5825 	stp->ls_stateid.other[2] = *tl++;
5826 	/*
5827 	 * Don't allow this to be done for a DS.
5828 	 */
5829 	if ((nd->nd_flag & ND_DSSERVER) != 0)
5830 		nd->nd_repstat = NFSERR_NOTSUPP;
5831 	/* However, allow the proxy stateid. */
5832 	if (stp->ls_stateid.seqid == 0xffffffff &&
5833 	    stp->ls_stateid.other[0] == 0x55555555 &&
5834 	    stp->ls_stateid.other[1] == 0x55555555 &&
5835 	    stp->ls_stateid.other[2] == 0x55555555)
5836 		gotproxystateid = 1;
5837 	off = fxdr_hyper(tl); tl += 2;
5838 	lop->lo_first = off;
5839 	len = fxdr_hyper(tl);
5840 	if (len < 0)
5841 		len = OFF_MAX;
5842 	NFSD_DEBUG(4, "dealloc: off=%jd len=%jd\n", (intmax_t)off,
5843 	    (intmax_t)len);
5844 	lop->lo_end = lop->lo_first + len;
5845 	/*
5846 	 * Sanity check the offset and length.
5847 	 * off and len are off_t (signed int64_t) whereas
5848 	 * lo_first and lo_end are uint64_t and, as such,
5849 	 * if off >= 0 && len > 0, lo_end cannot overflow
5850 	 * unless off_t is changed to something other than
5851 	 * int64_t.  Check lo_end < lo_first in case that
5852 	 * is someday the case.
5853 	 * The error to return is not specified by RFC 7862 so I
5854 	 * made this compatible with the Linux knfsd.
5855 	 */
5856 	if (nd->nd_repstat == 0) {
5857 		if (off < 0 || lop->lo_end > NFSRV_MAXFILESIZE)
5858 			nd->nd_repstat = NFSERR_FBIG;
5859 		else if (len == 0 || lop->lo_end < lop->lo_first)
5860 			nd->nd_repstat = NFSERR_INVAL;
5861 	}
5862 
5863 	if (nd->nd_repstat == 0 && vp->v_type != VREG)
5864 		nd->nd_repstat = NFSERR_WRONGTYPE;
5865 	NFSZERO_ATTRBIT(&attrbits);
5866 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5867 	forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits);
5868 	if (nd->nd_repstat == 0)
5869 		nd->nd_repstat = forat_ret;
5870 	if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid ||
5871 	     NFSVNO_EXSTRICTACCESS(exp)))
5872 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp,
5873 		    curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5874 		    NULL);
5875 	if (nd->nd_repstat == 0 && gotproxystateid == 0)
5876 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
5877 		    &stateid, exp, nd, curthread);
5878 
5879 	if (nd->nd_repstat == 0)
5880 		nd->nd_repstat = nfsvno_deallocate(vp, off, len, nd->nd_cred,
5881 		    curthread);
5882 	vput(vp);
5883 	NFSD_DEBUG(4, "eo deallocate=%d\n", nd->nd_repstat);
5884 	NFSEXITCODE2(0, nd);
5885 	return (0);
5886 nfsmout:
5887 	vput(vp);
5888 	NFSEXITCODE2(error, nd);
5889 	return (error);
5890 }
5891 
5892 /*
5893  * nfs copy service
5894  */
5895 int
nfsrvd_copy_file_range(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,vnode_t tovp,struct nfsexstuff * exp,struct nfsexstuff * toexp)5896 nfsrvd_copy_file_range(struct nfsrv_descript *nd, __unused int isdgram,
5897     vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
5898 {
5899 	uint32_t *tl;
5900 	struct nfsvattr at;
5901 	int cnt, error = 0, ret;
5902 	off_t inoff, outoff;
5903 	uint64_t len;
5904 	size_t xfer;
5905 	struct nfsstate inst, outst, *instp = &inst, *outstp = &outst;
5906 	struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo;
5907 	nfsquad_t clientid;
5908 	nfsv4stateid_t stateid;
5909 	nfsattrbit_t attrbits;
5910 	void *rl_rcookie, *rl_wcookie;
5911 
5912 	rl_rcookie = rl_wcookie = NULL;
5913 	if (nfsrv_maxcopyrange == 0 || nfsrv_devidcnt > 0) {
5914 		/*
5915 		 * For a pNFS server, reply NFSERR_NOTSUPP so that the client
5916 		 * will do the copy via I/O on the DS(s).
5917 		 * If vfs.nfsd.maxcopyrange set to 0, disable Copy.
5918 		 */
5919 		nd->nd_repstat = NFSERR_NOTSUPP;
5920 		goto nfsmout;
5921 	}
5922 	if (vp == tovp) {
5923 		/* Copying a byte range within the same file is not allowed. */
5924 		nd->nd_repstat = NFSERR_INVAL;
5925 		goto nfsmout;
5926 	}
5927 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER +
5928 	    3 * NFSX_UNSIGNED);
5929 	instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
5930 	inlop->lo_flags = NFSLCK_READ;
5931 	instp->ls_ownerlen = 0;
5932 	instp->ls_op = NULL;
5933 	instp->ls_uid = nd->nd_cred->cr_uid;
5934 	instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5935 	clientid.lval[0] = instp->ls_stateid.other[0] = *tl++;
5936 	clientid.lval[1] = instp->ls_stateid.other[1] = *tl++;
5937 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0)
5938 		clientid.qval = nd->nd_clientid.qval;
5939 	instp->ls_stateid.other[2] = *tl++;
5940 	outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5941 	outlop->lo_flags = NFSLCK_WRITE;
5942 	outstp->ls_ownerlen = 0;
5943 	outstp->ls_op = NULL;
5944 	outstp->ls_uid = nd->nd_cred->cr_uid;
5945 	outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5946 	outstp->ls_stateid.other[0] = *tl++;
5947 	outstp->ls_stateid.other[1] = *tl++;
5948 	outstp->ls_stateid.other[2] = *tl++;
5949 	inoff = fxdr_hyper(tl); tl += 2;
5950 	inlop->lo_first = inoff;
5951 	outoff = fxdr_hyper(tl); tl += 2;
5952 	outlop->lo_first = outoff;
5953 	len = fxdr_hyper(tl); tl += 2;
5954 	if (len == 0) {
5955 		/* len == 0 means to EOF. */
5956 		inlop->lo_end = OFF_MAX;
5957 		outlop->lo_end = OFF_MAX;
5958 	} else {
5959 		inlop->lo_end = inlop->lo_first + len;
5960 		outlop->lo_end = outlop->lo_first + len;
5961 	}
5962 
5963 	/*
5964 	 * At this time only consecutive, synchronous copy is supported,
5965 	 * so ca_consecutive and ca_synchronous can be ignored.
5966 	 */
5967 	tl += 2;
5968 
5969 	cnt = fxdr_unsigned(int, *tl);
5970 	if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0)
5971 		nd->nd_repstat = NFSERR_NOTSUPP;
5972 	if (nd->nd_repstat == 0 && (inoff > OFF_MAX || outoff > OFF_MAX ||
5973 	    inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX ||
5974 	    inlop->lo_end < inlop->lo_first || outlop->lo_end <
5975 	    outlop->lo_first))
5976 		nd->nd_repstat = NFSERR_INVAL;
5977 
5978 	if (nd->nd_repstat == 0 && vp->v_type != VREG)
5979 		nd->nd_repstat = NFSERR_WRONGTYPE;
5980 
5981 	/* Check permissions for the input file. */
5982 	NFSZERO_ATTRBIT(&attrbits);
5983 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5984 	ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits);
5985 	if (nd->nd_repstat == 0)
5986 		nd->nd_repstat = ret;
5987 	if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5988 	     NFSVNO_EXSTRICTACCESS(exp)))
5989 		nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
5990 		    curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5991 		    NULL);
5992 	if (nd->nd_repstat == 0)
5993 		nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL,
5994 		    clientid, &stateid, exp, nd, curthread);
5995 	NFSVOPUNLOCK(vp);
5996 	if (nd->nd_repstat != 0)
5997 		goto out;
5998 
5999 	error = NFSVOPLOCK(tovp, LK_SHARED);
6000 	if (error != 0)
6001 		goto out;
6002 	if (tovp->v_type != VREG)
6003 		nd->nd_repstat = NFSERR_WRONGTYPE;
6004 
6005 	/* For the output file, we only need the Owner attribute. */
6006 	ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits);
6007 	if (nd->nd_repstat == 0)
6008 		nd->nd_repstat = ret;
6009 	if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
6010 	     NFSVNO_EXSTRICTACCESS(exp)))
6011 		nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp,
6012 		    curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
6013 		    NULL);
6014 	if (nd->nd_repstat == 0)
6015 		nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL,
6016 		    clientid, &stateid, toexp, nd, curthread);
6017 	NFSVOPUNLOCK(tovp);
6018 
6019 	/* Range lock the byte ranges for both invp and outvp. */
6020 	if (nd->nd_repstat == 0) {
6021 		for (;;) {
6022 			if (len == 0) {
6023 				rl_wcookie = vn_rangelock_wlock(tovp, outoff,
6024 				    OFF_MAX);
6025 				rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
6026 				    OFF_MAX);
6027 			} else {
6028 				rl_wcookie = vn_rangelock_wlock(tovp, outoff,
6029 				    outoff + len);
6030 				rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
6031 				    inoff + len);
6032 			}
6033 			if (rl_rcookie != NULL)
6034 				break;
6035 			vn_rangelock_unlock(tovp, rl_wcookie);
6036 			if (len == 0)
6037 				rl_rcookie = vn_rangelock_rlock(vp, inoff,
6038 				    OFF_MAX);
6039 			else
6040 				rl_rcookie = vn_rangelock_rlock(vp, inoff,
6041 				    inoff + len);
6042 			vn_rangelock_unlock(vp, rl_rcookie);
6043 		}
6044 
6045 		error = NFSVOPLOCK(vp, LK_SHARED);
6046 		if (error == 0) {
6047 			ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL);
6048 			if (ret == 0) {
6049 				/*
6050 				 * Since invp is range locked, na_size should
6051 				 * not change.
6052 				 */
6053 				if (len == 0 && at.na_size > inoff) {
6054 					/*
6055 					 * If len == 0, set it based on invp's
6056 					 * size. If offset is past EOF, just
6057 					 * leave len == 0.
6058 					 */
6059 					len = at.na_size - inoff;
6060 				} else if (nfsrv_linux42server == 0 &&
6061 				    inoff + len > at.na_size) {
6062 					/*
6063 					 * RFC-7862 says that NFSERR_INVAL must
6064 					 * be returned when inoff + len exceeds
6065 					 * the file size, however the NFSv4.2
6066 					 * Linux client likes to do this, so
6067 					 * only check if nfsrv_linux42server
6068 					 * is not set.
6069 					 */
6070 					nd->nd_repstat = NFSERR_INVAL;
6071 				}
6072 			}
6073 			NFSVOPUNLOCK(vp);
6074 			if (ret != 0 && nd->nd_repstat == 0)
6075 				nd->nd_repstat = ret;
6076 		} else if (nd->nd_repstat == 0)
6077 			nd->nd_repstat = error;
6078 	}
6079 
6080 	/*
6081 	 * Do the actual copy to an upper limit of vfs.nfsd.maxcopyrange.
6082 	 * This size limit can be set to limit the time a copy RPC will
6083 	 * take.
6084 	 */
6085 	if (len > nfsrv_maxcopyrange)
6086 		xfer = nfsrv_maxcopyrange;
6087 	else
6088 		xfer = len;
6089 	if (nd->nd_repstat == 0) {
6090 		nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff,
6091 		    &xfer, COPY_FILE_RANGE_TIMEO1SEC, nd->nd_cred, nd->nd_cred,
6092 		    NULL);
6093 		if (nd->nd_repstat == 0)
6094 			len = xfer;
6095 	}
6096 
6097 	/* Unlock the ranges. */
6098 	if (rl_rcookie != NULL)
6099 		vn_rangelock_unlock(vp, rl_rcookie);
6100 	if (rl_wcookie != NULL)
6101 		vn_rangelock_unlock(tovp, rl_wcookie);
6102 
6103 	if (nd->nd_repstat == 0) {
6104 		NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER +
6105 		    NFSX_VERF);
6106 		*tl++ = txdr_unsigned(0);	/* No callback ids. */
6107 		txdr_hyper(len, tl); tl += 2;
6108 		*tl++ = txdr_unsigned(NFSWRITE_UNSTABLE);
6109 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
6110 		*tl++ = txdr_unsigned(nfsboottime.tv_usec);
6111 		*tl++ = newnfs_true;
6112 		*tl = newnfs_true;
6113 	}
6114 out:
6115 	vrele(vp);
6116 	vrele(tovp);
6117 	NFSEXITCODE2(error, nd);
6118 	return (error);
6119 nfsmout:
6120 	vput(vp);
6121 	vrele(tovp);
6122 	NFSEXITCODE2(error, nd);
6123 	return (error);
6124 }
6125 
6126 /*
6127  * nfs clone service
6128  */
6129 int
nfsrvd_clone(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,vnode_t tovp,struct nfsexstuff * exp,struct nfsexstuff * toexp)6130 nfsrvd_clone(struct nfsrv_descript *nd, __unused int isdgram,
6131     vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
6132 {
6133 	uint32_t *tl;
6134 	struct nfsvattr at;
6135 	int error = 0, ret;
6136 	off_t inoff, outoff;
6137 	uint64_t len;
6138 	size_t xfer;
6139 	struct nfsstate inst, outst, *instp = &inst, *outstp = &outst;
6140 	struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo;
6141 	nfsquad_t clientid;
6142 	nfsv4stateid_t stateid;
6143 	nfsattrbit_t attrbits;
6144 	void *rl_rcookie, *rl_wcookie;
6145 	long pathval;
6146 
6147 	rl_rcookie = rl_wcookie = NULL;
6148 	pathval = 0;
6149 	if (nfsrv_maxcopyrange == 0 || nfsrv_devidcnt > 0 ||
6150 	    VOP_PATHCONF(vp, _PC_CLONE_BLKSIZE, &pathval) != 0 ||
6151 	    pathval == 0) {
6152 		/*
6153 		 * For a pNFS server, reply NFSERR_NOTSUPP so that the client
6154 		 * will not do the clone and will do I/O on the DS(s).
6155 		 * If vfs.nfsd.maxcopyrange set to 0, disable Clone.
6156 		 */
6157 		nd->nd_repstat = NFSERR_NOTSUPP;
6158 		goto nfsmout;
6159 	}
6160 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER);
6161 	instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
6162 	inlop->lo_flags = NFSLCK_READ;
6163 	instp->ls_ownerlen = 0;
6164 	instp->ls_op = NULL;
6165 	instp->ls_uid = nd->nd_cred->cr_uid;
6166 	instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
6167 	clientid.lval[0] = instp->ls_stateid.other[0] = *tl++;
6168 	clientid.lval[1] = instp->ls_stateid.other[1] = *tl++;
6169 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0)
6170 		clientid.qval = nd->nd_clientid.qval;
6171 	instp->ls_stateid.other[2] = *tl++;
6172 	outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
6173 	outlop->lo_flags = NFSLCK_WRITE;
6174 	outstp->ls_ownerlen = 0;
6175 	outstp->ls_op = NULL;
6176 	outstp->ls_uid = nd->nd_cred->cr_uid;
6177 	outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
6178 	outstp->ls_stateid.other[0] = *tl++;
6179 	outstp->ls_stateid.other[1] = *tl++;
6180 	outstp->ls_stateid.other[2] = *tl++;
6181 	inoff = fxdr_hyper(tl); tl += 2;
6182 	inlop->lo_first = inoff;
6183 	outoff = fxdr_hyper(tl); tl += 2;
6184 	outlop->lo_first = outoff;
6185 	len = fxdr_hyper(tl);
6186 	if (len == 0) {
6187 		/* len == 0 means to EOF. */
6188 		inlop->lo_end = OFF_MAX;
6189 		outlop->lo_end = OFF_MAX;
6190 	} else {
6191 		inlop->lo_end = inlop->lo_first + len;
6192 		outlop->lo_end = outlop->lo_first + len;
6193 	}
6194 
6195 	if ((inoff > OFF_MAX || outoff > OFF_MAX ||
6196 	    inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX ||
6197 	    inlop->lo_end < inlop->lo_first || outlop->lo_end <
6198 	    outlop->lo_first))
6199 		nd->nd_repstat = NFSERR_INVAL;
6200 
6201 	if (nd->nd_repstat == 0 && vp->v_type != VREG)
6202 		nd->nd_repstat = NFSERR_WRONGTYPE;
6203 
6204 	/* Check permissions for the input file. */
6205 	NFSZERO_ATTRBIT(&attrbits);
6206 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
6207 	ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits);
6208 	if (nd->nd_repstat == 0)
6209 		nd->nd_repstat = ret;
6210 	if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
6211 	     NFSVNO_EXSTRICTACCESS(exp)))
6212 		nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
6213 		    curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
6214 		    NULL);
6215 	if (nd->nd_repstat == 0)
6216 		nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL,
6217 		    clientid, &stateid, exp, nd, curthread);
6218 	if (vp != tovp) {
6219 		NFSVOPUNLOCK(vp);
6220 		if (nd->nd_repstat != 0)
6221 			goto out;
6222 
6223 		error = NFSVOPLOCK(tovp, LK_SHARED);
6224 		if (error != 0)
6225 			goto out;
6226 		pathval = 0;
6227 		if (VOP_PATHCONF(tovp, _PC_CLONE_BLKSIZE, &pathval) != 0 ||
6228 		    pathval == 0)
6229 			nd->nd_repstat = NFSERR_NOTSUPP;
6230 		else if (tovp->v_type != VREG)
6231 			nd->nd_repstat = NFSERR_WRONGTYPE;
6232 	}
6233 
6234 	/* For the output file, we only need the Owner attribute. */
6235 	ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits);
6236 	if (nd->nd_repstat == 0)
6237 		nd->nd_repstat = ret;
6238 	if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
6239 	     NFSVNO_EXSTRICTACCESS(exp)))
6240 		nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp,
6241 		    curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
6242 		    NULL);
6243 	if (nd->nd_repstat == 0)
6244 		nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL,
6245 		    clientid, &stateid, toexp, nd, curthread);
6246 	NFSVOPUNLOCK(tovp);
6247 
6248 	/* Range lock the byte ranges for both invp and outvp. */
6249 	if (nd->nd_repstat == 0) {
6250 		for (;;) {
6251 			if (len == 0)
6252 				rl_wcookie = vn_rangelock_wlock(tovp, outoff,
6253 				    OFF_MAX);
6254 			else
6255 				rl_wcookie = vn_rangelock_wlock(tovp, outoff,
6256 				    outoff + len);
6257 			if (vp != tovp) {
6258 				if (len == 0)
6259 					rl_rcookie = vn_rangelock_tryrlock(vp,
6260 					    inoff, OFF_MAX);
6261 				else
6262 					rl_rcookie = vn_rangelock_tryrlock(vp,
6263 					    inoff, inoff + len);
6264 				if (rl_rcookie != NULL)
6265 					break;
6266 			} else {
6267 				rl_rcookie = NULL;
6268 				break;
6269 			}
6270 			vn_rangelock_unlock(tovp, rl_wcookie);
6271 			if (len == 0)
6272 				rl_rcookie = vn_rangelock_rlock(vp, inoff,
6273 				    OFF_MAX);
6274 			else
6275 				rl_rcookie = vn_rangelock_rlock(vp, inoff,
6276 				    inoff + len);
6277 			vn_rangelock_unlock(vp, rl_rcookie);
6278 		}
6279 
6280 		error = NFSVOPLOCK(vp, LK_SHARED);
6281 		if (error == 0) {
6282 			ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL);
6283 			if (ret == 0) {
6284 				/*
6285 				 * Since invp is range locked, na_size should
6286 				 * not change.
6287 				 */
6288 				if (len == 0 && at.na_size > inoff)
6289 					len = SSIZE_MAX;	/* To EOF. */
6290 				else if (inoff + len > at.na_size)
6291 					nd->nd_repstat = NFSERR_INVAL;
6292 			}
6293 			NFSVOPUNLOCK(vp);
6294 			if (ret != 0 && nd->nd_repstat == 0)
6295 				nd->nd_repstat = ret;
6296 		} else if (nd->nd_repstat == 0)
6297 			nd->nd_repstat = error;
6298 	}
6299 
6300 	/*
6301 	 * Do the actual copy to an upper limit of vfs.nfsd.maxcopyrange.
6302 	 * This size limit can be set to limit the time a copy RPC will
6303 	 * take.
6304 	 */
6305 	xfer = len;
6306 	if (nd->nd_repstat == 0) {
6307 		nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff,
6308 		    &xfer, COPY_FILE_RANGE_CLONE, nd->nd_cred, nd->nd_cred,
6309 		    NULL);
6310 		if (nd->nd_repstat == ENOSYS)
6311 			nd->nd_repstat = NFSERR_INVAL;
6312 	}
6313 
6314 	/* Unlock the ranges. */
6315 	if (rl_rcookie != NULL)
6316 		vn_rangelock_unlock(vp, rl_rcookie);
6317 	if (rl_wcookie != NULL)
6318 		vn_rangelock_unlock(tovp, rl_wcookie);
6319 
6320 out:
6321 	vrele(vp);
6322 	vrele(tovp);
6323 	NFSEXITCODE2(error, nd);
6324 	return (error);
6325 nfsmout:
6326 	vput(vp);
6327 	vrele(tovp);
6328 	NFSEXITCODE2(error, nd);
6329 	return (error);
6330 }
6331 
6332 /*
6333  * nfs seek service
6334  */
6335 int
nfsrvd_seek(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)6336 nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram,
6337     vnode_t vp, struct nfsexstuff *exp)
6338 {
6339 	uint32_t *tl;
6340 	struct nfsvattr at;
6341 	int content, error = 0;
6342 	off_t off;
6343 	u_long cmd;
6344 	nfsattrbit_t attrbits;
6345 	bool eof;
6346 
6347 	NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED);
6348 	/* Ignore the stateid for now. */
6349 	tl += (NFSX_STATEID / NFSX_UNSIGNED);
6350 	off = fxdr_hyper(tl); tl += 2;
6351 	content = fxdr_unsigned(int, *tl);
6352 	if (content == NFSV4CONTENT_DATA)
6353 		cmd = FIOSEEKDATA;
6354 	else if (content == NFSV4CONTENT_HOLE)
6355 		cmd = FIOSEEKHOLE;
6356 	else
6357 		nd->nd_repstat = NFSERR_BADXDR;
6358 	if (nd->nd_repstat == 0 && vp->v_type == VDIR)
6359 		nd->nd_repstat = NFSERR_ISDIR;
6360 	if (nd->nd_repstat == 0 && vp->v_type != VREG)
6361 		nd->nd_repstat = NFSERR_WRONGTYPE;
6362 	if (nd->nd_repstat == 0 && off < 0)
6363 		nd->nd_repstat = NFSERR_NXIO;
6364 	if (nd->nd_repstat == 0) {
6365 		/* Check permissions for the input file. */
6366 		NFSZERO_ATTRBIT(&attrbits);
6367 		NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
6368 		nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1,
6369 		    &attrbits);
6370 	}
6371 	if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
6372 	     NFSVNO_EXSTRICTACCESS(exp)))
6373 		nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
6374 		    curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
6375 		    NULL);
6376 	if (nd->nd_repstat != 0)
6377 		goto nfsmout;
6378 
6379 	/* nfsvno_seek() unlocks and vrele()s the vp. */
6380 	nd->nd_repstat = nfsvno_seek(nd, vp, cmd, &off, content, &eof,
6381 	    nd->nd_cred, curthread);
6382 	if (nd->nd_repstat == 0 && eof && content == NFSV4CONTENT_DATA &&
6383 	    nfsrv_linux42server != 0)
6384 		nd->nd_repstat = NFSERR_NXIO;
6385 	if (nd->nd_repstat == 0) {
6386 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
6387 		if (eof)
6388 			*tl++ = newnfs_true;
6389 		else
6390 			*tl++ = newnfs_false;
6391 		txdr_hyper(off, tl);
6392 	}
6393 	NFSEXITCODE2(error, nd);
6394 	return (error);
6395 nfsmout:
6396 	vput(vp);
6397 	NFSEXITCODE2(error, nd);
6398 	return (error);
6399 }
6400 
6401 /*
6402  * nfs get extended attribute service
6403  */
6404 int
nfsrvd_getxattr(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)6405 nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram,
6406     vnode_t vp, __unused struct nfsexstuff *exp)
6407 {
6408 	uint32_t *tl;
6409 	struct mbuf *mp = NULL, *mpend = NULL;
6410 	int error, len;
6411 	char *name;
6412 	struct thread *p = curthread;
6413 	uint16_t off;
6414 
6415 	error = 0;
6416 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6417 	len = fxdr_unsigned(int, *tl);
6418 	if (len <= 0) {
6419 		nd->nd_repstat = NFSERR_BADXDR;
6420 		goto nfsmout;
6421 	}
6422 	if (len > EXTATTR_MAXNAMELEN) {
6423 		nd->nd_repstat = NFSERR_NOXATTR;
6424 		goto nfsmout;
6425 	}
6426 	name = malloc(len + 1, M_TEMP, M_WAITOK);
6427 	nd->nd_repstat = nfsrv_mtostr(nd, name, len);
6428 	if (nd->nd_repstat == 0)
6429 		nd->nd_repstat = nfsvno_getxattr(vp, name,
6430 		    nd->nd_maxresp, nd->nd_cred, nd->nd_flag,
6431 		    nd->nd_maxextsiz, p, &mp, &mpend, &len);
6432 	if (nd->nd_repstat == ENOATTR)
6433 		nd->nd_repstat = NFSERR_NOXATTR;
6434 	else if (nd->nd_repstat == EOPNOTSUPP)
6435 		nd->nd_repstat = NFSERR_NOTSUPP;
6436 	if (nd->nd_repstat == 0) {
6437 		NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
6438 		*tl = txdr_unsigned(len);
6439 		if (len > 0) {
6440 			nd->nd_mb->m_next = mp;
6441 			nd->nd_mb = mpend;
6442 			if ((mpend->m_flags & M_EXTPG) != 0) {
6443 				nd->nd_flag |= ND_EXTPG;
6444 				nd->nd_bextpg = mpend->m_epg_npgs - 1;
6445 				nd->nd_bpos =
6446 				   PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]);
6447 				off = (nd->nd_bextpg == 0) ?
6448 				    mpend->m_epg_1st_off : 0;
6449 				nd->nd_bpos += off + mpend->m_epg_last_len;
6450 				nd->nd_bextpgsiz = PAGE_SIZE -
6451 				    mpend->m_epg_last_len - off;
6452 			} else
6453 				nd->nd_bpos = mtod(mpend, char *) +
6454 				    mpend->m_len;
6455 		}
6456 	}
6457 	free(name, M_TEMP);
6458 
6459 nfsmout:
6460 	if (nd->nd_repstat == 0)
6461 		nd->nd_repstat = error;
6462 	vput(vp);
6463 	NFSEXITCODE2(0, nd);
6464 	return (0);
6465 }
6466 
6467 /*
6468  * nfs set extended attribute service
6469  */
6470 int
nfsrvd_setxattr(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)6471 nfsrvd_setxattr(struct nfsrv_descript *nd, __unused int isdgram,
6472     vnode_t vp, __unused struct nfsexstuff *exp)
6473 {
6474 	uint32_t *tl;
6475 	struct nfsvattr ova, nva;
6476 	nfsattrbit_t attrbits;
6477 	int error, len, opt;
6478 	char *name;
6479 	size_t siz;
6480 	struct thread *p = curthread;
6481 
6482 	error = 0;
6483 	name = NULL;
6484 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
6485 	opt = fxdr_unsigned(int, *tl++);
6486 	len = fxdr_unsigned(int, *tl);
6487 	if (len <= 0) {
6488 		nd->nd_repstat = NFSERR_BADXDR;
6489 		goto nfsmout;
6490 	}
6491 	if (len > EXTATTR_MAXNAMELEN) {
6492 		nd->nd_repstat = NFSERR_NOXATTR;
6493 		goto nfsmout;
6494 	}
6495 	name = malloc(len + 1, M_TEMP, M_WAITOK);
6496 	error = nfsrv_mtostr(nd, name, len);
6497 	if (error != 0)
6498 		goto nfsmout;
6499 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6500 	len = fxdr_unsigned(int, *tl);
6501 	if (len < 0 || len > IOSIZE_MAX) {
6502 		nd->nd_repstat = NFSERR_XATTR2BIG;
6503 		goto nfsmout;
6504 	}
6505 	switch (opt) {
6506 	case NFSV4SXATTR_CREATE:
6507 		error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
6508 		    &siz, nd->nd_cred, p);
6509 		if (error != ENOATTR)
6510 			nd->nd_repstat = NFSERR_EXIST;
6511 		error = 0;
6512 		break;
6513 	case NFSV4SXATTR_REPLACE:
6514 		error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
6515 		    &siz, nd->nd_cred, p);
6516 		if (error != 0)
6517 			nd->nd_repstat = NFSERR_NOXATTR;
6518 		break;
6519 	case NFSV4SXATTR_EITHER:
6520 		break;
6521 	default:
6522 		nd->nd_repstat = NFSERR_BADXDR;
6523 	}
6524 	if (nd->nd_repstat != 0)
6525 		goto nfsmout;
6526 
6527 	/* Now, do the Set Extended attribute, with Change before and after. */
6528 	NFSZERO_ATTRBIT(&attrbits);
6529 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
6530 	nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
6531 	if (nd->nd_repstat == 0) {
6532 		nd->nd_repstat = nfsvno_setxattr(vp, name, len, nd->nd_md,
6533 		    nd->nd_dpos, nd->nd_cred, p);
6534 		if (nd->nd_repstat == ENXIO)
6535 			nd->nd_repstat = NFSERR_XATTR2BIG;
6536 	}
6537 	if (nd->nd_repstat == 0 && len > 0)
6538 		nd->nd_repstat = nfsm_advance(nd, NFSM_RNDUP(len), -1);
6539 	if (nd->nd_repstat == 0)
6540 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
6541 	if (nd->nd_repstat == 0) {
6542 		NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
6543 		*tl++ = newnfs_true;
6544 		txdr_hyper(ova.na_filerev, tl); tl += 2;
6545 		txdr_hyper(nva.na_filerev, tl);
6546 	}
6547 
6548 nfsmout:
6549 	free(name, M_TEMP);
6550 	if (nd->nd_repstat == 0)
6551 		nd->nd_repstat = error;
6552 	vput(vp);
6553 	NFSEXITCODE2(0, nd);
6554 	return (0);
6555 }
6556 
6557 /*
6558  * nfs remove extended attribute service
6559  */
6560 int
nfsrvd_rmxattr(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)6561 nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int isdgram,
6562     vnode_t vp, __unused struct nfsexstuff *exp)
6563 {
6564 	uint32_t *tl;
6565 	struct nfsvattr ova, nva;
6566 	nfsattrbit_t attrbits;
6567 	int error, len;
6568 	char *name;
6569 	struct thread *p = curthread;
6570 
6571 	error = 0;
6572 	name = NULL;
6573 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6574 	len = fxdr_unsigned(int, *tl);
6575 	if (len <= 0) {
6576 		nd->nd_repstat = NFSERR_BADXDR;
6577 		goto nfsmout;
6578 	}
6579 	if (len > EXTATTR_MAXNAMELEN) {
6580 		nd->nd_repstat = NFSERR_NOXATTR;
6581 		goto nfsmout;
6582 	}
6583 	name = malloc(len + 1, M_TEMP, M_WAITOK);
6584 	error = nfsrv_mtostr(nd, name, len);
6585 	if (error != 0)
6586 		goto nfsmout;
6587 
6588 	if ((nd->nd_flag & ND_IMPLIEDCLID) == 0) {
6589 		printf("EEK! nfsrvd_rmxattr: no implied clientid\n");
6590 		error = NFSERR_NOXATTR;
6591 		goto nfsmout;
6592 	}
6593 	/*
6594 	 * Now, do the Remove Extended attribute, with Change before and
6595 	 * after.
6596 	*/
6597 	NFSZERO_ATTRBIT(&attrbits);
6598 	NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
6599 	nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
6600 	if (nd->nd_repstat == 0) {
6601 		nd->nd_repstat = nfsvno_rmxattr(nd, vp, name, nd->nd_cred, p);
6602 		if (nd->nd_repstat == ENOATTR)
6603 			nd->nd_repstat = NFSERR_NOXATTR;
6604 	}
6605 	if (nd->nd_repstat == 0)
6606 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
6607 	if (nd->nd_repstat == 0) {
6608 		NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
6609 		*tl++ = newnfs_true;
6610 		txdr_hyper(ova.na_filerev, tl); tl += 2;
6611 		txdr_hyper(nva.na_filerev, tl);
6612 	}
6613 
6614 nfsmout:
6615 	free(name, M_TEMP);
6616 	if (nd->nd_repstat == 0)
6617 		nd->nd_repstat = error;
6618 	vput(vp);
6619 	NFSEXITCODE2(0, nd);
6620 	return (0);
6621 }
6622 
6623 /*
6624  * nfs list extended attribute service
6625  */
6626 int
nfsrvd_listxattr(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)6627 nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram,
6628     vnode_t vp, __unused struct nfsexstuff *exp)
6629 {
6630 	uint32_t cnt, *tl, len, len2, i, pos, retlen;
6631 	int error;
6632 	uint64_t cookie, cookie2;
6633 	u_char *buf;
6634 	bool eof;
6635 	struct thread *p = curthread;
6636 
6637 	error = 0;
6638 	buf = NULL;
6639 	NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
6640 	/*
6641 	 * The cookie doesn't need to be in net byte order, but FreeBSD
6642 	 * does so to make it more readable in packet traces.
6643 	 */
6644 	cookie = fxdr_hyper(tl); tl += 2;
6645 	len = fxdr_unsigned(uint32_t, *tl);
6646 	if (len == 0 || cookie >= IOSIZE_MAX) {
6647 		nd->nd_repstat = NFSERR_BADXDR;
6648 		goto nfsmout;
6649 	}
6650 	if (len > nd->nd_maxresp - NFS_MAXXDR)
6651 		len = nd->nd_maxresp - NFS_MAXXDR;
6652 	len2 = len;
6653 	nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf,
6654 	    &len, &eof);
6655 	if (nd->nd_repstat == EOPNOTSUPP)
6656 		nd->nd_repstat = NFSERR_NOTSUPP;
6657 	if (nd->nd_repstat == 0) {
6658 		cookie2 = cookie + len;
6659 		if (cookie2 < cookie)
6660 			nd->nd_repstat = NFSERR_BADXDR;
6661 	}
6662 	retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED;
6663 	if (nd->nd_repstat == 0 && len2 < retlen)
6664 		nd->nd_repstat = NFSERR_TOOSMALL;
6665 	if (nd->nd_repstat == 0) {
6666 		/* Now copy the entries out. */
6667 		if (len == 0) {
6668 			/* The cookie was at eof. */
6669 			NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 *
6670 			    NFSX_UNSIGNED);
6671 			txdr_hyper(cookie2, tl); tl += 2;
6672 			*tl++ = txdr_unsigned(0);
6673 			*tl = newnfs_true;
6674 			goto nfsmout;
6675 		}
6676 
6677 		/* Sanity check the cookie. */
6678 		for (pos = 0; pos < len; pos += (i + 1)) {
6679 			if (pos == cookie)
6680 				break;
6681 			i = buf[pos];
6682 		}
6683 		if (pos != cookie) {
6684 			nd->nd_repstat = NFSERR_INVAL;
6685 			goto nfsmout;
6686 		}
6687 
6688 		/* Loop around copying the entrie(s) out. */
6689 		cnt = 0;
6690 		len -= cookie;
6691 		i = buf[pos];
6692 		while (i < len && len2 >= retlen + NFSM_RNDUP(i) +
6693 		    NFSX_UNSIGNED) {
6694 			if (cnt == 0) {
6695 				NFSM_BUILD(tl, uint32_t *, NFSX_HYPER +
6696 				    NFSX_UNSIGNED);
6697 				txdr_hyper(cookie2, tl); tl += 2;
6698 			}
6699 			retlen += nfsm_strtom(nd, &buf[pos + 1], i);
6700 			len -= (i + 1);
6701 			pos += (i + 1);
6702 			i = buf[pos];
6703 			cnt++;
6704 		}
6705 		/*
6706 		 * eof is set true/false by nfsvno_listxattr(), but if we
6707 		 * can't copy all entries returned by nfsvno_listxattr(),
6708 		 * we are not at eof.
6709 		 */
6710 		if (len > 0)
6711 			eof = false;
6712 		if (cnt > 0) {
6713 			/* *tl is set above. */
6714 			*tl = txdr_unsigned(cnt);
6715 			NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
6716 			if (eof)
6717 				*tl = newnfs_true;
6718 			else
6719 				*tl = newnfs_false;
6720 		} else
6721 			nd->nd_repstat = NFSERR_TOOSMALL;
6722 	}
6723 
6724 nfsmout:
6725 	free(buf, M_TEMP);
6726 	if (nd->nd_repstat == 0)
6727 		nd->nd_repstat = error;
6728 	vput(vp);
6729 	NFSEXITCODE2(0, nd);
6730 	return (0);
6731 }
6732 
6733 /*
6734  * nfsv4 service not supported
6735  */
6736 int
nfsrvd_notsupp(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)6737 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
6738     __unused vnode_t vp, __unused struct nfsexstuff *exp)
6739 {
6740 
6741 	nd->nd_repstat = NFSERR_NOTSUPP;
6742 	NFSEXITCODE2(0, nd);
6743 	return (0);
6744 }
6745