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