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