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