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