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