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