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