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