xref: /freebsd/sys/fs/nfsserver/nfs_nfsdserv.c (revision b97b91b5477bd5ddf78c1a35ade9cf71630f5069)
19ec7b004SRick Macklem /*-
251369649SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni  *
49ec7b004SRick Macklem  * Copyright (c) 1989, 1993
59ec7b004SRick Macklem  *	The Regents of the University of California.  All rights reserved.
69ec7b004SRick Macklem  *
79ec7b004SRick Macklem  * This code is derived from software contributed to Berkeley by
89ec7b004SRick Macklem  * Rick Macklem at The University of Guelph.
99ec7b004SRick Macklem  *
109ec7b004SRick Macklem  * Redistribution and use in source and binary forms, with or without
119ec7b004SRick Macklem  * modification, are permitted provided that the following conditions
129ec7b004SRick Macklem  * are met:
139ec7b004SRick Macklem  * 1. Redistributions of source code must retain the above copyright
149ec7b004SRick Macklem  *    notice, this list of conditions and the following disclaimer.
159ec7b004SRick Macklem  * 2. Redistributions in binary form must reproduce the above copyright
169ec7b004SRick Macklem  *    notice, this list of conditions and the following disclaimer in the
179ec7b004SRick Macklem  *    documentation and/or other materials provided with the distribution.
18fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
199ec7b004SRick Macklem  *    may be used to endorse or promote products derived from this software
209ec7b004SRick Macklem  *    without specific prior written permission.
219ec7b004SRick Macklem  *
229ec7b004SRick Macklem  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
239ec7b004SRick Macklem  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
249ec7b004SRick Macklem  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
259ec7b004SRick Macklem  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
269ec7b004SRick Macklem  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
279ec7b004SRick Macklem  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
289ec7b004SRick Macklem  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
299ec7b004SRick Macklem  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
309ec7b004SRick Macklem  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
319ec7b004SRick Macklem  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
329ec7b004SRick Macklem  * SUCH DAMAGE.
339ec7b004SRick Macklem  *
349ec7b004SRick Macklem  */
359ec7b004SRick Macklem 
369ec7b004SRick Macklem #include <sys/cdefs.h>
379ec7b004SRick Macklem __FBSDID("$FreeBSD$");
389ec7b004SRick Macklem 
399ec7b004SRick Macklem /*
409ec7b004SRick Macklem  * nfs version 2, 3 and 4 server calls to vnode ops
419ec7b004SRick Macklem  * - these routines generally have 3 phases
429ec7b004SRick Macklem  *   1 - break down and validate rpc request in mbuf list
439ec7b004SRick Macklem  *   2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
449ec7b004SRick Macklem  *       function in nfsd_port.c
459ec7b004SRick Macklem  *   3 - build the rpc reply in an mbuf list
469ec7b004SRick Macklem  * For nfsv4, these functions are called for each Op within the Compound RPC.
479ec7b004SRick Macklem  */
489ec7b004SRick Macklem 
499ec7b004SRick Macklem #ifndef APPLEKEXT
509ec7b004SRick Macklem #include <fs/nfs/nfsport.h>
519ec7b004SRick Macklem 
529ec7b004SRick Macklem /* Global vars */
539ec7b004SRick Macklem extern u_int32_t newnfs_false, newnfs_true;
549ec7b004SRick Macklem extern enum vtype nv34tov_type[8];
559ec7b004SRick Macklem extern struct timeval nfsboottime;
56c9aad40fSRick Macklem extern int nfs_rootfhset;
5707c0c166SRick Macklem extern int nfsrv_enable_crossmntpt;
581f54e596SRick Macklem extern int nfsrv_statehashsize;
599ec7b004SRick Macklem #endif	/* !APPLEKEXT */
609ec7b004SRick Macklem 
61e4558aacSXin LI static int	nfs_async = 0;
62e4558aacSXin LI SYSCTL_DECL(_vfs_nfsd);
63e4558aacSXin LI SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
64e4558aacSXin LI     "Tell client that writes were synced even though they were not");
65e4558aacSXin LI 
669ec7b004SRick Macklem /*
679ec7b004SRick Macklem  * This list defines the GSS mechanisms supported.
689ec7b004SRick Macklem  * (Don't ask me how you get these strings from the RFC stuff like
699ec7b004SRick Macklem  *  iso(1), org(3)... but someone did it, so I don't need to know.)
709ec7b004SRick Macklem  */
719ec7b004SRick Macklem static struct nfsgss_mechlist nfsgss_mechlist[] = {
729ec7b004SRick Macklem 	{ 9, "\052\206\110\206\367\022\001\002\002", 11 },
739ec7b004SRick Macklem 	{ 0, "", 0 },
749ec7b004SRick Macklem };
759ec7b004SRick Macklem 
769ec7b004SRick Macklem /* local functions */
779ec7b004SRick Macklem static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
789ec7b004SRick Macklem     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
799ec7b004SRick Macklem     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
809ec7b004SRick Macklem     int *diraft_retp, nfsattrbit_t *attrbitp,
819ec7b004SRick Macklem     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
829ec7b004SRick Macklem     int pathlen);
839ec7b004SRick Macklem static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
849ec7b004SRick Macklem     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
859ec7b004SRick Macklem     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
869ec7b004SRick Macklem     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
879ec7b004SRick Macklem     NFSPROC_T *p, struct nfsexstuff *exp);
889ec7b004SRick Macklem 
899ec7b004SRick Macklem /*
909ec7b004SRick Macklem  * nfs access service (not a part of NFS V2)
919ec7b004SRick Macklem  */
929ec7b004SRick Macklem APPLESTATIC int
939ec7b004SRick Macklem nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
949ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
959ec7b004SRick Macklem {
969ec7b004SRick Macklem 	u_int32_t *tl;
979ec7b004SRick Macklem 	int getret, error = 0;
989ec7b004SRick Macklem 	struct nfsvattr nva;
999ec7b004SRick Macklem 	u_int32_t testmode, nfsmode, supported = 0;
1008da45f2cSRick Macklem 	accmode_t deletebit;
1019ec7b004SRick Macklem 
1029ec7b004SRick Macklem 	if (nd->nd_repstat) {
1039ec7b004SRick Macklem 		nfsrv_postopattr(nd, 1, &nva);
104a9285ae5SZack Kirsch 		goto out;
1059ec7b004SRick Macklem 	}
1069ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1079ec7b004SRick Macklem 	nfsmode = fxdr_unsigned(u_int32_t, *tl);
1089ec7b004SRick Macklem 	if ((nd->nd_flag & ND_NFSV4) &&
1099ec7b004SRick Macklem 	    (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
1109ec7b004SRick Macklem 	     NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
1119ec7b004SRick Macklem 	     NFSACCESS_EXECUTE))) {
1129ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
1139ec7b004SRick Macklem 		vput(vp);
114a9285ae5SZack Kirsch 		goto out;
1159ec7b004SRick Macklem 	}
1169ec7b004SRick Macklem 	if (nfsmode & NFSACCESS_READ) {
1179ec7b004SRick Macklem 		supported |= NFSACCESS_READ;
1188da45f2cSRick Macklem 		if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
1198da45f2cSRick Macklem 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
1209ec7b004SRick Macklem 			nfsmode &= ~NFSACCESS_READ;
1219ec7b004SRick Macklem 	}
1229ec7b004SRick Macklem 	if (nfsmode & NFSACCESS_MODIFY) {
1239ec7b004SRick Macklem 		supported |= NFSACCESS_MODIFY;
1248da45f2cSRick Macklem 		if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
1258da45f2cSRick Macklem 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
1269ec7b004SRick Macklem 			nfsmode &= ~NFSACCESS_MODIFY;
1279ec7b004SRick Macklem 	}
1289ec7b004SRick Macklem 	if (nfsmode & NFSACCESS_EXTEND) {
1299ec7b004SRick Macklem 		supported |= NFSACCESS_EXTEND;
1308da45f2cSRick Macklem 		if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
1318da45f2cSRick Macklem 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
1329ec7b004SRick Macklem 			nfsmode &= ~NFSACCESS_EXTEND;
1339ec7b004SRick Macklem 	}
1349ec7b004SRick Macklem 	if (nfsmode & NFSACCESS_DELETE) {
1359ec7b004SRick Macklem 		supported |= NFSACCESS_DELETE;
1368da45f2cSRick Macklem 		if (vp->v_type == VDIR)
1378da45f2cSRick Macklem 			deletebit = VDELETE_CHILD;
1388da45f2cSRick Macklem 		else
1398da45f2cSRick Macklem 			deletebit = VDELETE;
1408da45f2cSRick Macklem 		if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
1418da45f2cSRick Macklem 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
1429ec7b004SRick Macklem 			nfsmode &= ~NFSACCESS_DELETE;
1439ec7b004SRick Macklem 	}
1449ec7b004SRick Macklem 	if (vnode_vtype(vp) == VDIR)
1459ec7b004SRick Macklem 		testmode = NFSACCESS_LOOKUP;
1469ec7b004SRick Macklem 	else
1479ec7b004SRick Macklem 		testmode = NFSACCESS_EXECUTE;
1489ec7b004SRick Macklem 	if (nfsmode & testmode) {
1499ec7b004SRick Macklem 		supported |= (nfsmode & testmode);
1508da45f2cSRick Macklem 		if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
1518da45f2cSRick Macklem 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
1529ec7b004SRick Macklem 			nfsmode &= ~testmode;
1539ec7b004SRick Macklem 	}
1549ec7b004SRick Macklem 	nfsmode &= supported;
1559ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
1560cf42b62SRick Macklem 		getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
1579ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &nva);
1589ec7b004SRick Macklem 	}
1599ec7b004SRick Macklem 	vput(vp);
1609ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
1619ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1629ec7b004SRick Macklem 		*tl++ = txdr_unsigned(supported);
1639ec7b004SRick Macklem 	} else
1649ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1659ec7b004SRick Macklem 	*tl = txdr_unsigned(nfsmode);
166a9285ae5SZack Kirsch 
167a9285ae5SZack Kirsch out:
168a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
1699ec7b004SRick Macklem 	return (0);
1709ec7b004SRick Macklem nfsmout:
1719ec7b004SRick Macklem 	vput(vp);
172a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
1739ec7b004SRick Macklem 	return (error);
1749ec7b004SRick Macklem }
1759ec7b004SRick Macklem 
1769ec7b004SRick Macklem /*
1779ec7b004SRick Macklem  * nfs getattr service
1789ec7b004SRick Macklem  */
1799ec7b004SRick Macklem APPLESTATIC int
1809ec7b004SRick Macklem nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
1819ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1829ec7b004SRick Macklem {
1839ec7b004SRick Macklem 	struct nfsvattr nva;
1849ec7b004SRick Macklem 	fhandle_t fh;
185a09001a8SRick Macklem 	int at_root = 0, error = 0, supports_nfsv4acls;
1869ec7b004SRick Macklem 	struct nfsreferral *refp;
18753f476caSRick Macklem 	nfsattrbit_t attrbits, tmpbits;
18807c0c166SRick Macklem 	struct mount *mp;
18907c0c166SRick Macklem 	struct vnode *tvp = NULL;
19007c0c166SRick Macklem 	struct vattr va;
19107c0c166SRick Macklem 	uint64_t mounted_on_fileno = 0;
19253f476caSRick Macklem 	accmode_t accmode;
1939ec7b004SRick Macklem 
1949ec7b004SRick Macklem 	if (nd->nd_repstat)
195a9285ae5SZack Kirsch 		goto out;
1969ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
1979ec7b004SRick Macklem 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1989ec7b004SRick Macklem 		if (error) {
1999ec7b004SRick Macklem 			vput(vp);
200a9285ae5SZack Kirsch 			goto out;
2019ec7b004SRick Macklem 		}
2029ec7b004SRick Macklem 
2039ec7b004SRick Macklem 		/*
2049ec7b004SRick Macklem 		 * Check for a referral.
2059ec7b004SRick Macklem 		 */
2069ec7b004SRick Macklem 		refp = nfsv4root_getreferral(vp, NULL, 0);
2079ec7b004SRick Macklem 		if (refp != NULL) {
2089ec7b004SRick Macklem 			(void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
2099ec7b004SRick Macklem 			    &nd->nd_repstat);
2109ec7b004SRick Macklem 			vput(vp);
211a9285ae5SZack Kirsch 			goto out;
2129ec7b004SRick Macklem 		}
21353f476caSRick Macklem 		if (nd->nd_repstat == 0) {
21453f476caSRick Macklem 			accmode = 0;
21553f476caSRick Macklem 			NFSSET_ATTRBIT(&tmpbits, &attrbits);
216d8a5961fSMarcelo Araujo 
217d8a5961fSMarcelo Araujo 			/*
218d8a5961fSMarcelo Araujo 			 * GETATTR with write-only attr time_access_set and time_modify_set
219d8a5961fSMarcelo Araujo 			 * should return NFS4ERR_INVAL.
220d8a5961fSMarcelo Araujo 			 */
221d8a5961fSMarcelo Araujo 			if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) ||
222d8a5961fSMarcelo Araujo 					NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){
223d8a5961fSMarcelo Araujo 				error = NFSERR_INVAL;
224d8a5961fSMarcelo Araujo 				vput(vp);
225d8a5961fSMarcelo Araujo 				goto out;
226d8a5961fSMarcelo Araujo 			}
22753f476caSRick Macklem 			if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
22853f476caSRick Macklem 				NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
22953f476caSRick Macklem 				accmode |= VREAD_ACL;
23053f476caSRick Macklem 			}
23153f476caSRick Macklem 			if (NFSNONZERO_ATTRBIT(&tmpbits))
23253f476caSRick Macklem 				accmode |= VREAD_ATTRIBUTES;
23353f476caSRick Macklem 			if (accmode != 0)
23453f476caSRick Macklem 				nd->nd_repstat = nfsvno_accchk(vp, accmode,
2358da45f2cSRick Macklem 				    nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
2368da45f2cSRick Macklem 				    NFSACCCHK_VPISLOCKED, NULL);
2379ec7b004SRick Macklem 		}
23853f476caSRick Macklem 	}
2399ec7b004SRick Macklem 	if (!nd->nd_repstat)
2400cf42b62SRick Macklem 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2419ec7b004SRick Macklem 	if (!nd->nd_repstat) {
2429ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV4) {
2439ec7b004SRick Macklem 			if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
2449ec7b004SRick Macklem 				nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
2459ec7b004SRick Macklem 			if (!nd->nd_repstat)
2469ec7b004SRick Macklem 				nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
2479ec7b004SRick Macklem 				    &nva, &attrbits, nd->nd_cred, p);
24807c0c166SRick Macklem 			if (nd->nd_repstat == 0) {
249a09001a8SRick Macklem 				supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
25007c0c166SRick Macklem 				mp = vp->v_mount;
25107c0c166SRick Macklem 				if (nfsrv_enable_crossmntpt != 0 &&
25207c0c166SRick Macklem 				    vp->v_type == VDIR &&
25307c0c166SRick Macklem 				    (vp->v_vflag & VV_ROOT) != 0 &&
25407c0c166SRick Macklem 				    vp != rootvnode) {
25507c0c166SRick Macklem 					tvp = mp->mnt_vnodecovered;
25607c0c166SRick Macklem 					VREF(tvp);
25707c0c166SRick Macklem 					at_root = 1;
25807c0c166SRick Macklem 				} else
25907c0c166SRick Macklem 					at_root = 0;
26007c0c166SRick Macklem 				vfs_ref(mp);
261a9989634SZack Kirsch 				NFSVOPUNLOCK(vp, 0);
26207c0c166SRick Macklem 				if (at_root != 0) {
26307c0c166SRick Macklem 					if ((nd->nd_repstat =
26498f234f3SZack Kirsch 					     NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
26507c0c166SRick Macklem 						nd->nd_repstat = VOP_GETATTR(
26607c0c166SRick Macklem 						    tvp, &va, nd->nd_cred);
26707c0c166SRick Macklem 						vput(tvp);
26807c0c166SRick Macklem 					} else
26907c0c166SRick Macklem 						vrele(tvp);
27007c0c166SRick Macklem 					if (nd->nd_repstat == 0)
27107c0c166SRick Macklem 						mounted_on_fileno = (uint64_t)
27207c0c166SRick Macklem 						    va.va_fileid;
27307c0c166SRick Macklem 					else
27407c0c166SRick Macklem 						at_root = 0;
27507c0c166SRick Macklem 				}
27607c0c166SRick Macklem 				if (nd->nd_repstat == 0)
27707c0c166SRick Macklem 					nd->nd_repstat = vfs_busy(mp, 0);
27807c0c166SRick Macklem 				vfs_rel(mp);
27907c0c166SRick Macklem 				if (nd->nd_repstat == 0) {
28007c0c166SRick Macklem 					(void)nfsvno_fillattr(nd, mp, vp, &nva,
28107c0c166SRick Macklem 					    &fh, 0, &attrbits, nd->nd_cred, p,
282a09001a8SRick Macklem 					    isdgram, 1, supports_nfsv4acls,
283a09001a8SRick Macklem 					    at_root, mounted_on_fileno);
28407c0c166SRick Macklem 					vfs_unbusy(mp);
28507c0c166SRick Macklem 				}
2869ec7b004SRick Macklem 				vrele(vp);
28707c0c166SRick Macklem 			} else
28807c0c166SRick Macklem 				vput(vp);
2899ec7b004SRick Macklem 		} else {
2909ec7b004SRick Macklem 			nfsrv_fillattr(nd, &nva);
2919ec7b004SRick Macklem 			vput(vp);
2929ec7b004SRick Macklem 		}
2939ec7b004SRick Macklem 	} else {
2949ec7b004SRick Macklem 		vput(vp);
2959ec7b004SRick Macklem 	}
296a9285ae5SZack Kirsch 
297a9285ae5SZack Kirsch out:
298a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
299a9285ae5SZack Kirsch 	return (error);
3009ec7b004SRick Macklem }
3019ec7b004SRick Macklem 
3029ec7b004SRick Macklem /*
3039ec7b004SRick Macklem  * nfs setattr service
3049ec7b004SRick Macklem  */
3059ec7b004SRick Macklem APPLESTATIC int
3069ec7b004SRick Macklem nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
3079ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
3089ec7b004SRick Macklem {
3099ec7b004SRick Macklem 	struct nfsvattr nva, nva2;
3109ec7b004SRick Macklem 	u_int32_t *tl;
3119ec7b004SRick Macklem 	int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
3129ec7b004SRick Macklem 	struct timespec guard = { 0, 0 };
3139ec7b004SRick Macklem 	nfsattrbit_t attrbits, retbits;
3149ec7b004SRick Macklem 	nfsv4stateid_t stateid;
3159ec7b004SRick Macklem 	NFSACL_T *aclp = NULL;
3169ec7b004SRick Macklem 
3179ec7b004SRick Macklem 	if (nd->nd_repstat) {
3189ec7b004SRick Macklem 		nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
319a9285ae5SZack Kirsch 		goto out;
3209ec7b004SRick Macklem 	}
3219ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
322c3e22f83SRick Macklem 	aclp = acl_alloc(M_WAITOK);
3239ec7b004SRick Macklem 	aclp->acl_cnt = 0;
3249ec7b004SRick Macklem #endif
3259ec7b004SRick Macklem 	NFSVNO_ATTRINIT(&nva);
3269ec7b004SRick Macklem 	NFSZERO_ATTRBIT(&retbits);
3279ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
3289ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3299ec7b004SRick Macklem 		stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3309ec7b004SRick Macklem 		NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
3319ec7b004SRick Macklem 	}
332d8a5961fSMarcelo Araujo 	error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p);
3339ec7b004SRick Macklem 	if (error)
3349ec7b004SRick Macklem 		goto nfsmout;
3350cf42b62SRick Macklem 	preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1);
3369ec7b004SRick Macklem 	if (!nd->nd_repstat)
3379ec7b004SRick Macklem 		nd->nd_repstat = preat_ret;
3389ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
3399ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3409ec7b004SRick Macklem 		gcheck = fxdr_unsigned(int, *tl);
3419ec7b004SRick Macklem 		if (gcheck) {
3429ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3439ec7b004SRick Macklem 			fxdr_nfsv3time(tl, &guard);
3449ec7b004SRick Macklem 		}
3459ec7b004SRick Macklem 		if (!nd->nd_repstat && gcheck &&
3469ec7b004SRick Macklem 		    (nva2.na_ctime.tv_sec != guard.tv_sec ||
3479ec7b004SRick Macklem 		     nva2.na_ctime.tv_nsec != guard.tv_nsec))
3489ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_NOT_SYNC;
3499ec7b004SRick Macklem 		if (nd->nd_repstat) {
3509ec7b004SRick Macklem 			vput(vp);
3519ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
3529ec7b004SRick Macklem 			acl_free(aclp);
3539ec7b004SRick Macklem #endif
3549ec7b004SRick Macklem 			nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
355a9285ae5SZack Kirsch 			goto out;
3569ec7b004SRick Macklem 		}
3579ec7b004SRick Macklem 	} else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
3589ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
3599ec7b004SRick Macklem 
3609ec7b004SRick Macklem 	/*
3619ec7b004SRick Macklem 	 * Now that we have all the fields, lets do it.
3629ec7b004SRick Macklem 	 * If the size is being changed write access is required, otherwise
3639ec7b004SRick Macklem 	 * just check for a read only file system.
3649ec7b004SRick Macklem 	 */
3659ec7b004SRick Macklem 	if (!nd->nd_repstat) {
3669ec7b004SRick Macklem 		if (NFSVNO_NOTSETSIZE(&nva)) {
3679ec7b004SRick Macklem 			if (NFSVNO_EXRDONLY(exp) ||
3689ec7b004SRick Macklem 			    (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
3699ec7b004SRick Macklem 				nd->nd_repstat = EROFS;
3709ec7b004SRick Macklem 		} else {
3719ec7b004SRick Macklem 			if (vnode_vtype(vp) != VREG)
3729ec7b004SRick Macklem 				nd->nd_repstat = EINVAL;
3739ec7b004SRick Macklem 			else if (nva2.na_uid != nd->nd_cred->cr_uid ||
3749ec7b004SRick Macklem 			    NFSVNO_EXSTRICTACCESS(exp))
3759ec7b004SRick Macklem 				nd->nd_repstat = nfsvno_accchk(vp,
3768da45f2cSRick Macklem 				    VWRITE, nd->nd_cred, exp, p,
3778da45f2cSRick Macklem 				    NFSACCCHK_NOOVERRIDE,
3788da45f2cSRick Macklem 				    NFSACCCHK_VPISLOCKED, NULL);
3799ec7b004SRick Macklem 		}
3809ec7b004SRick Macklem 	}
3819ec7b004SRick Macklem 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
3829ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
3839ec7b004SRick Macklem 		    &nva, &attrbits, exp, p);
3849ec7b004SRick Macklem 
3859ec7b004SRick Macklem 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
3869ec7b004SRick Macklem 	    /*
3879ec7b004SRick Macklem 	     * For V4, try setting the attrbutes in sets, so that the
3889ec7b004SRick Macklem 	     * reply bitmap will be correct for an error case.
3899ec7b004SRick Macklem 	     */
3909ec7b004SRick Macklem 	    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
3919ec7b004SRick Macklem 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
3929ec7b004SRick Macklem 		NFSVNO_ATTRINIT(&nva2);
3939ec7b004SRick Macklem 		NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
3949ec7b004SRick Macklem 		NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
3959ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
3969ec7b004SRick Macklem 		    exp);
3979ec7b004SRick Macklem 		if (!nd->nd_repstat) {
3989ec7b004SRick Macklem 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
3999ec7b004SRick Macklem 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
4009ec7b004SRick Macklem 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
4019ec7b004SRick Macklem 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
4029ec7b004SRick Macklem 		}
4039ec7b004SRick Macklem 	    }
4049ec7b004SRick Macklem 	    if (!nd->nd_repstat &&
4059ec7b004SRick Macklem 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
4069ec7b004SRick Macklem 		NFSVNO_ATTRINIT(&nva2);
4079ec7b004SRick Macklem 		NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
4089ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
4099ec7b004SRick Macklem 		    exp);
4109ec7b004SRick Macklem 		if (!nd->nd_repstat)
4119ec7b004SRick Macklem 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
4129ec7b004SRick Macklem 	    }
4139ec7b004SRick Macklem 	    if (!nd->nd_repstat &&
4149ec7b004SRick Macklem 		(NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
4159ec7b004SRick Macklem 		 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
4169ec7b004SRick Macklem 		NFSVNO_ATTRINIT(&nva2);
4179ec7b004SRick Macklem 		NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
4189ec7b004SRick Macklem 		NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
4199ec7b004SRick Macklem 		if (nva.na_vaflags & VA_UTIMES_NULL) {
4209ec7b004SRick Macklem 			nva2.na_vaflags |= VA_UTIMES_NULL;
4219ec7b004SRick Macklem 			NFSVNO_SETACTIVE(&nva2, vaflags);
4229ec7b004SRick Macklem 		}
4239ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
4249ec7b004SRick Macklem 		    exp);
4259ec7b004SRick Macklem 		if (!nd->nd_repstat) {
4269ec7b004SRick Macklem 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
4279ec7b004SRick Macklem 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
4289ec7b004SRick Macklem 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
4299ec7b004SRick Macklem 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
4309ec7b004SRick Macklem 		}
4319ec7b004SRick Macklem 	    }
4329ec7b004SRick Macklem 	    if (!nd->nd_repstat &&
4339ec7b004SRick Macklem 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) {
4349ec7b004SRick Macklem 		NFSVNO_ATTRINIT(&nva2);
4359ec7b004SRick Macklem 		NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
4369ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
4379ec7b004SRick Macklem 		    exp);
4389ec7b004SRick Macklem 		if (!nd->nd_repstat)
4399ec7b004SRick Macklem 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
4409ec7b004SRick Macklem 	    }
4419ec7b004SRick Macklem 
4429ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
4439ec7b004SRick Macklem 	    if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
4449ec7b004SRick Macklem 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
4459ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
4469ec7b004SRick Macklem 		if (!nd->nd_repstat)
4479ec7b004SRick Macklem 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
4489ec7b004SRick Macklem 	    }
4499ec7b004SRick Macklem #endif
4509ec7b004SRick Macklem 	} else if (!nd->nd_repstat) {
4519ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
4529ec7b004SRick Macklem 		    exp);
4539ec7b004SRick Macklem 	}
4549ec7b004SRick Macklem 	if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
4550cf42b62SRick Macklem 		postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
4569ec7b004SRick Macklem 		if (!nd->nd_repstat)
4579ec7b004SRick Macklem 			nd->nd_repstat = postat_ret;
4589ec7b004SRick Macklem 	}
4599ec7b004SRick Macklem 	vput(vp);
4609ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
4619ec7b004SRick Macklem 	acl_free(aclp);
4629ec7b004SRick Macklem #endif
4639ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
4649ec7b004SRick Macklem 		nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
4659ec7b004SRick Macklem 	else if (nd->nd_flag & ND_NFSV4)
4669ec7b004SRick Macklem 		(void) nfsrv_putattrbit(nd, &retbits);
4679ec7b004SRick Macklem 	else if (!nd->nd_repstat)
4689ec7b004SRick Macklem 		nfsrv_fillattr(nd, &nva);
469a9285ae5SZack Kirsch 
470a9285ae5SZack Kirsch out:
471a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
4729ec7b004SRick Macklem 	return (0);
4739ec7b004SRick Macklem nfsmout:
4749ec7b004SRick Macklem 	vput(vp);
4759ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
4769ec7b004SRick Macklem 	acl_free(aclp);
4779ec7b004SRick Macklem #endif
4789ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
4799ec7b004SRick Macklem 		/*
4809ec7b004SRick Macklem 		 * For all nd_repstat, the V4 reply includes a bitmap,
4819ec7b004SRick Macklem 		 * even NFSERR_BADXDR, which is what this will end up
4829ec7b004SRick Macklem 		 * returning.
4839ec7b004SRick Macklem 		 */
4849ec7b004SRick Macklem 		(void) nfsrv_putattrbit(nd, &retbits);
4859ec7b004SRick Macklem 	}
486a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
4879ec7b004SRick Macklem 	return (error);
4889ec7b004SRick Macklem }
4899ec7b004SRick Macklem 
4909ec7b004SRick Macklem /*
4919ec7b004SRick Macklem  * nfs lookup rpc
4929ec7b004SRick Macklem  * (Also performs lookup parent for v4)
4939ec7b004SRick Macklem  */
4949ec7b004SRick Macklem APPLESTATIC int
4959ec7b004SRick Macklem nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
4969ec7b004SRick Macklem     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
49737b88c2dSRick Macklem     struct nfsexstuff *exp)
4989ec7b004SRick Macklem {
4999ec7b004SRick Macklem 	struct nameidata named;
5009ec7b004SRick Macklem 	vnode_t vp, dirp = NULL;
501a9285ae5SZack Kirsch 	int error = 0, dattr_ret = 1;
5029ec7b004SRick Macklem 	struct nfsvattr nva, dattr;
5039ec7b004SRick Macklem 	char *bufp;
5049ec7b004SRick Macklem 	u_long *hashp;
5059ec7b004SRick Macklem 
5069ec7b004SRick Macklem 	if (nd->nd_repstat) {
5079ec7b004SRick Macklem 		nfsrv_postopattr(nd, dattr_ret, &dattr);
508a9285ae5SZack Kirsch 		goto out;
5099ec7b004SRick Macklem 	}
5109ec7b004SRick Macklem 
5119ec7b004SRick Macklem 	/*
5129ec7b004SRick Macklem 	 * For some reason, if dp is a symlink, the error
5139ec7b004SRick Macklem 	 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
5149ec7b004SRick Macklem 	 */
5159ec7b004SRick Macklem 	if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
5169ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_SYMLINK;
5179ec7b004SRick Macklem 		vrele(dp);
518a9285ae5SZack Kirsch 		goto out;
5199ec7b004SRick Macklem 	}
5209ec7b004SRick Macklem 
5219ec7b004SRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
5229ec7b004SRick Macklem 	    LOCKLEAF | SAVESTART);
5239ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
5249ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
5259ec7b004SRick Macklem 	if (error) {
5269ec7b004SRick Macklem 		vrele(dp);
5279ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
528a9285ae5SZack Kirsch 		goto out;
5299ec7b004SRick Macklem 	}
5309ec7b004SRick Macklem 	if (!nd->nd_repstat) {
5319ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
5329ec7b004SRick Macklem 	} else {
5339ec7b004SRick Macklem 		vrele(dp);
5349ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
5359ec7b004SRick Macklem 	}
5369ec7b004SRick Macklem 	if (nd->nd_repstat) {
5379ec7b004SRick Macklem 		if (dirp) {
5389ec7b004SRick Macklem 			if (nd->nd_flag & ND_NFSV3)
5399ec7b004SRick Macklem 				dattr_ret = nfsvno_getattr(dirp, &dattr,
5400cf42b62SRick Macklem 				    nd->nd_cred, p, 0);
5419ec7b004SRick Macklem 			vrele(dirp);
5429ec7b004SRick Macklem 		}
5439ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
5449ec7b004SRick Macklem 			nfsrv_postopattr(nd, dattr_ret, &dattr);
545a9285ae5SZack Kirsch 		goto out;
5469ec7b004SRick Macklem 	}
5479ec7b004SRick Macklem 	if (named.ni_startdir)
5489ec7b004SRick Macklem 		vrele(named.ni_startdir);
5499ec7b004SRick Macklem 	nfsvno_relpathbuf(&named);
5509ec7b004SRick Macklem 	vp = named.ni_vp;
55137b88c2dSRick Macklem 	if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
55237b88c2dSRick Macklem 	    vp->v_type != VDIR && vp->v_type != VLNK)
55337b88c2dSRick Macklem 		/*
55437b88c2dSRick Macklem 		 * Only allow lookup of VDIR and VLNK for traversal of
55537b88c2dSRick Macklem 		 * non-exported volumes during NFSv4 mounting.
55637b88c2dSRick Macklem 		 */
55737b88c2dSRick Macklem 		nd->nd_repstat = ENOENT;
55837b88c2dSRick Macklem 	if (nd->nd_repstat == 0)
5599ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
5609ec7b004SRick Macklem 	if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
5610cf42b62SRick Macklem 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
56281f78d99SRick Macklem 	if (vpp != NULL && nd->nd_repstat == 0)
5639ec7b004SRick Macklem 		*vpp = vp;
56481f78d99SRick Macklem 	else
5659ec7b004SRick Macklem 		vput(vp);
5669ec7b004SRick Macklem 	if (dirp) {
5679ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
5689ec7b004SRick Macklem 			dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred,
5690cf42b62SRick Macklem 			    p, 0);
5709ec7b004SRick Macklem 		vrele(dirp);
5719ec7b004SRick Macklem 	}
5729ec7b004SRick Macklem 	if (nd->nd_repstat) {
5739ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
5749ec7b004SRick Macklem 			nfsrv_postopattr(nd, dattr_ret, &dattr);
575a9285ae5SZack Kirsch 		goto out;
5769ec7b004SRick Macklem 	}
5779ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV2) {
5789ec7b004SRick Macklem 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
5799ec7b004SRick Macklem 		nfsrv_fillattr(nd, &nva);
5809ec7b004SRick Macklem 	} else if (nd->nd_flag & ND_NFSV3) {
5819ec7b004SRick Macklem 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
5829ec7b004SRick Macklem 		nfsrv_postopattr(nd, 0, &nva);
5839ec7b004SRick Macklem 		nfsrv_postopattr(nd, dattr_ret, &dattr);
5849ec7b004SRick Macklem 	}
585a9285ae5SZack Kirsch 
586a9285ae5SZack Kirsch out:
587a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
588a9285ae5SZack Kirsch 	return (error);
5899ec7b004SRick Macklem }
5909ec7b004SRick Macklem 
5919ec7b004SRick Macklem /*
5929ec7b004SRick Macklem  * nfs readlink service
5939ec7b004SRick Macklem  */
5949ec7b004SRick Macklem APPLESTATIC int
5959ec7b004SRick Macklem nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
5969ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
5979ec7b004SRick Macklem {
5989ec7b004SRick Macklem 	u_int32_t *tl;
5999ec7b004SRick Macklem 	mbuf_t mp = NULL, mpend = NULL;
6009ec7b004SRick Macklem 	int getret = 1, len;
6019ec7b004SRick Macklem 	struct nfsvattr nva;
6029ec7b004SRick Macklem 
6039ec7b004SRick Macklem 	if (nd->nd_repstat) {
6049ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &nva);
605a9285ae5SZack Kirsch 		goto out;
6069ec7b004SRick Macklem 	}
6079ec7b004SRick Macklem 	if (vnode_vtype(vp) != VLNK) {
6089ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV2)
6099ec7b004SRick Macklem 			nd->nd_repstat = ENXIO;
6109ec7b004SRick Macklem 		else
6119ec7b004SRick Macklem 			nd->nd_repstat = EINVAL;
6129ec7b004SRick Macklem 	}
6139ec7b004SRick Macklem 	if (!nd->nd_repstat)
6149ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
6159ec7b004SRick Macklem 		    &mp, &mpend, &len);
6169ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
6170cf42b62SRick Macklem 		getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
6189ec7b004SRick Macklem 	vput(vp);
6199ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
6209ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &nva);
6219ec7b004SRick Macklem 	if (nd->nd_repstat)
622a9285ae5SZack Kirsch 		goto out;
6239ec7b004SRick Macklem 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
6249ec7b004SRick Macklem 	*tl = txdr_unsigned(len);
6259ec7b004SRick Macklem 	mbuf_setnext(nd->nd_mb, mp);
6269ec7b004SRick Macklem 	nd->nd_mb = mpend;
6279ec7b004SRick Macklem 	nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
628a9285ae5SZack Kirsch 
629a9285ae5SZack Kirsch out:
630a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
6319ec7b004SRick Macklem 	return (0);
6329ec7b004SRick Macklem }
6339ec7b004SRick Macklem 
6349ec7b004SRick Macklem /*
6359ec7b004SRick Macklem  * nfs read service
6369ec7b004SRick Macklem  */
6379ec7b004SRick Macklem APPLESTATIC int
6389ec7b004SRick Macklem nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
6399ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
6409ec7b004SRick Macklem {
6419ec7b004SRick Macklem 	u_int32_t *tl;
64206521fbbSZack Kirsch 	int error = 0, cnt, getret = 1, reqlen, eof = 0;
6439ec7b004SRick Macklem 	mbuf_t m2, m3;
6449ec7b004SRick Macklem 	struct nfsvattr nva;
6459ec7b004SRick Macklem 	off_t off = 0x0;
6469ec7b004SRick Macklem 	struct nfsstate st, *stp = &st;
6479ec7b004SRick Macklem 	struct nfslock lo, *lop = &lo;
6489ec7b004SRick Macklem 	nfsv4stateid_t stateid;
6499ec7b004SRick Macklem 	nfsquad_t clientid;
6509ec7b004SRick Macklem 
6519ec7b004SRick Macklem 	if (nd->nd_repstat) {
6529ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &nva);
653a9285ae5SZack Kirsch 		goto out;
6549ec7b004SRick Macklem 	}
6559ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV2) {
6569ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
6579ec7b004SRick Macklem 		off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
6589ec7b004SRick Macklem 		reqlen = fxdr_unsigned(int, *tl);
6599ec7b004SRick Macklem 	} else if (nd->nd_flag & ND_NFSV3) {
6609ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
6619ec7b004SRick Macklem 		off = fxdr_hyper(tl);
6629ec7b004SRick Macklem 		tl += 2;
6639ec7b004SRick Macklem 		reqlen = fxdr_unsigned(int, *tl);
6649ec7b004SRick Macklem 	} else {
6659ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
6669ec7b004SRick Macklem 		reqlen = fxdr_unsigned(int, *(tl + 6));
6679ec7b004SRick Macklem 	}
6689ec7b004SRick Macklem 	if (reqlen > NFS_SRVMAXDATA(nd)) {
6699ec7b004SRick Macklem 		reqlen = NFS_SRVMAXDATA(nd);
6709ec7b004SRick Macklem 	} else if (reqlen < 0) {
6719ec7b004SRick Macklem 		error = EBADRPC;
6729ec7b004SRick Macklem 		goto nfsmout;
6739ec7b004SRick Macklem 	}
6749ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
6759ec7b004SRick Macklem 		stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
6769ec7b004SRick Macklem 		lop->lo_flags = NFSLCK_READ;
6779ec7b004SRick Macklem 		stp->ls_ownerlen = 0;
6789ec7b004SRick Macklem 		stp->ls_op = NULL;
6799ec7b004SRick Macklem 		stp->ls_uid = nd->nd_cred->cr_uid;
6809ec7b004SRick Macklem 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
6819ec7b004SRick Macklem 		clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
6829ec7b004SRick Macklem 		clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
683c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
684c59e4cc3SRick Macklem 			if ((nd->nd_flag & ND_NFSV41) != 0)
685c59e4cc3SRick Macklem 				clientid.qval = nd->nd_clientid.qval;
686c59e4cc3SRick Macklem 			else if (nd->nd_clientid.qval != clientid.qval)
687c59e4cc3SRick Macklem 				printf("EEK1 multiple clids\n");
6889ec7b004SRick Macklem 		} else {
689c59e4cc3SRick Macklem 			if ((nd->nd_flag & ND_NFSV41) != 0)
690c59e4cc3SRick Macklem 				printf("EEK! no clientid from session\n");
6919ec7b004SRick Macklem 			nd->nd_flag |= ND_IMPLIEDCLID;
6929ec7b004SRick Macklem 			nd->nd_clientid.qval = clientid.qval;
6939ec7b004SRick Macklem 		}
6949ec7b004SRick Macklem 		stp->ls_stateid.other[2] = *tl++;
6959ec7b004SRick Macklem 		off = fxdr_hyper(tl);
6969ec7b004SRick Macklem 		lop->lo_first = off;
6979ec7b004SRick Macklem 		tl += 2;
6989ec7b004SRick Macklem 		lop->lo_end = off + reqlen;
6999ec7b004SRick Macklem 		/*
7009ec7b004SRick Macklem 		 * Paranoia, just in case it wraps around.
7019ec7b004SRick Macklem 		 */
7029ec7b004SRick Macklem 		if (lop->lo_end < off)
7039ec7b004SRick Macklem 			lop->lo_end = NFS64BITSSET;
7049ec7b004SRick Macklem 	}
7059ec7b004SRick Macklem 	if (vnode_vtype(vp) != VREG) {
7069ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
7079ec7b004SRick Macklem 			nd->nd_repstat = EINVAL;
7089ec7b004SRick Macklem 		else
7099ec7b004SRick Macklem 			nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
7109ec7b004SRick Macklem 			    EINVAL;
7119ec7b004SRick Macklem 	}
7120cf42b62SRick Macklem 	getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
7139ec7b004SRick Macklem 	if (!nd->nd_repstat)
7149ec7b004SRick Macklem 		nd->nd_repstat = getret;
7159ec7b004SRick Macklem 	if (!nd->nd_repstat &&
7169ec7b004SRick Macklem 	    (nva.na_uid != nd->nd_cred->cr_uid ||
7179ec7b004SRick Macklem 	     NFSVNO_EXSTRICTACCESS(exp))) {
7188da45f2cSRick Macklem 		nd->nd_repstat = nfsvno_accchk(vp, VREAD,
7199ec7b004SRick Macklem 		    nd->nd_cred, exp, p,
7208da45f2cSRick Macklem 		    NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
7219ec7b004SRick Macklem 		if (nd->nd_repstat)
7228da45f2cSRick Macklem 			nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
7238da45f2cSRick Macklem 			    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
7248da45f2cSRick Macklem 			    NFSACCCHK_VPISLOCKED, NULL);
7259ec7b004SRick Macklem 	}
7269ec7b004SRick Macklem 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
7279ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
7289ec7b004SRick Macklem 		    &stateid, exp, nd, p);
7299ec7b004SRick Macklem 	if (nd->nd_repstat) {
7309ec7b004SRick Macklem 		vput(vp);
7319ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
7329ec7b004SRick Macklem 			nfsrv_postopattr(nd, getret, &nva);
733a9285ae5SZack Kirsch 		goto out;
7349ec7b004SRick Macklem 	}
7359ec7b004SRick Macklem 	if (off >= nva.na_size) {
7369ec7b004SRick Macklem 		cnt = 0;
7379ec7b004SRick Macklem 		eof = 1;
7389ec7b004SRick Macklem 	} else if (reqlen == 0)
7399ec7b004SRick Macklem 		cnt = 0;
74006521fbbSZack Kirsch 	else if ((off + reqlen) >= nva.na_size) {
7419ec7b004SRick Macklem 		cnt = nva.na_size - off;
74206521fbbSZack Kirsch 		eof = 1;
74306521fbbSZack Kirsch 	} else
7449ec7b004SRick Macklem 		cnt = reqlen;
7459ec7b004SRick Macklem 	m3 = NULL;
7469ec7b004SRick Macklem 	if (cnt > 0) {
7479ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
7489ec7b004SRick Macklem 		    &m3, &m2);
7499ec7b004SRick Macklem 		if (!(nd->nd_flag & ND_NFSV4)) {
7500cf42b62SRick Macklem 			getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
7519ec7b004SRick Macklem 			if (!nd->nd_repstat)
7529ec7b004SRick Macklem 				nd->nd_repstat = getret;
7539ec7b004SRick Macklem 		}
7549ec7b004SRick Macklem 		if (nd->nd_repstat) {
7559ec7b004SRick Macklem 			vput(vp);
7569ec7b004SRick Macklem 			if (m3)
7579ec7b004SRick Macklem 				mbuf_freem(m3);
7589ec7b004SRick Macklem 			if (nd->nd_flag & ND_NFSV3)
7599ec7b004SRick Macklem 				nfsrv_postopattr(nd, getret, &nva);
760a9285ae5SZack Kirsch 			goto out;
7619ec7b004SRick Macklem 		}
7629ec7b004SRick Macklem 	}
7639ec7b004SRick Macklem 	vput(vp);
7649ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV2) {
7659ec7b004SRick Macklem 		nfsrv_fillattr(nd, &nva);
7669ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
7679ec7b004SRick Macklem 	} else {
7689ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
7699ec7b004SRick Macklem 			nfsrv_postopattr(nd, getret, &nva);
7709ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
7719ec7b004SRick Macklem 			*tl++ = txdr_unsigned(cnt);
7729ec7b004SRick Macklem 		} else
7739ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
77406521fbbSZack Kirsch 		if (eof)
7759ec7b004SRick Macklem 			*tl++ = newnfs_true;
7769ec7b004SRick Macklem 		else
7779ec7b004SRick Macklem 			*tl++ = newnfs_false;
7789ec7b004SRick Macklem 	}
7799ec7b004SRick Macklem 	*tl = txdr_unsigned(cnt);
7809ec7b004SRick Macklem 	if (m3) {
7819ec7b004SRick Macklem 		mbuf_setnext(nd->nd_mb, m3);
7829ec7b004SRick Macklem 		nd->nd_mb = m2;
7839ec7b004SRick Macklem 		nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
7849ec7b004SRick Macklem 	}
785a9285ae5SZack Kirsch 
786a9285ae5SZack Kirsch out:
787a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
7889ec7b004SRick Macklem 	return (0);
7899ec7b004SRick Macklem nfsmout:
7909ec7b004SRick Macklem 	vput(vp);
791a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
7929ec7b004SRick Macklem 	return (error);
7939ec7b004SRick Macklem }
7949ec7b004SRick Macklem 
7959ec7b004SRick Macklem /*
7969ec7b004SRick Macklem  * nfs write service
7979ec7b004SRick Macklem  */
7989ec7b004SRick Macklem APPLESTATIC int
7999ec7b004SRick Macklem nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
8009ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
8019ec7b004SRick Macklem {
8029ec7b004SRick Macklem 	int i, cnt;
8039ec7b004SRick Macklem 	u_int32_t *tl;
8049ec7b004SRick Macklem 	mbuf_t mp;
8059ec7b004SRick Macklem 	struct nfsvattr nva, forat;
8069ec7b004SRick Macklem 	int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
8079ec7b004SRick Macklem 	int stable = NFSWRITE_FILESYNC;
8089ec7b004SRick Macklem 	off_t off;
8099ec7b004SRick Macklem 	struct nfsstate st, *stp = &st;
8109ec7b004SRick Macklem 	struct nfslock lo, *lop = &lo;
8119ec7b004SRick Macklem 	nfsv4stateid_t stateid;
8129ec7b004SRick Macklem 	nfsquad_t clientid;
8139ec7b004SRick Macklem 
8149ec7b004SRick Macklem 	if (nd->nd_repstat) {
8159ec7b004SRick Macklem 		nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
816a9285ae5SZack Kirsch 		goto out;
8179ec7b004SRick Macklem 	}
8189ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV2) {
8199ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
8209ec7b004SRick Macklem 		off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
8219ec7b004SRick Macklem 		tl += 2;
8229ec7b004SRick Macklem 		retlen = len = fxdr_unsigned(int32_t, *tl);
8239ec7b004SRick Macklem 	} else if (nd->nd_flag & ND_NFSV3) {
8249ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
8259ec7b004SRick Macklem 		off = fxdr_hyper(tl);
8269ec7b004SRick Macklem 		tl += 3;
8279ec7b004SRick Macklem 		stable = fxdr_unsigned(int, *tl++);
8289ec7b004SRick Macklem 		retlen = len = fxdr_unsigned(int32_t, *tl);
8299ec7b004SRick Macklem 	} else {
8309ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
8319ec7b004SRick Macklem 		stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
8329ec7b004SRick Macklem 		lop->lo_flags = NFSLCK_WRITE;
8339ec7b004SRick Macklem 		stp->ls_ownerlen = 0;
8349ec7b004SRick Macklem 		stp->ls_op = NULL;
8359ec7b004SRick Macklem 		stp->ls_uid = nd->nd_cred->cr_uid;
8369ec7b004SRick Macklem 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
8379ec7b004SRick Macklem 		clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
8389ec7b004SRick Macklem 		clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
839c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
840c59e4cc3SRick Macklem 			if ((nd->nd_flag & ND_NFSV41) != 0)
841c59e4cc3SRick Macklem 				clientid.qval = nd->nd_clientid.qval;
842c59e4cc3SRick Macklem 			else if (nd->nd_clientid.qval != clientid.qval)
843c59e4cc3SRick Macklem 				printf("EEK2 multiple clids\n");
8449ec7b004SRick Macklem 		} else {
845c59e4cc3SRick Macklem 			if ((nd->nd_flag & ND_NFSV41) != 0)
846c59e4cc3SRick Macklem 				printf("EEK! no clientid from session\n");
8479ec7b004SRick Macklem 			nd->nd_flag |= ND_IMPLIEDCLID;
8489ec7b004SRick Macklem 			nd->nd_clientid.qval = clientid.qval;
8499ec7b004SRick Macklem 		}
8509ec7b004SRick Macklem 		stp->ls_stateid.other[2] = *tl++;
8519ec7b004SRick Macklem 		off = fxdr_hyper(tl);
8529ec7b004SRick Macklem 		lop->lo_first = off;
8539ec7b004SRick Macklem 		tl += 2;
8549ec7b004SRick Macklem 		stable = fxdr_unsigned(int, *tl++);
8559ec7b004SRick Macklem 		retlen = len = fxdr_unsigned(int32_t, *tl);
8569ec7b004SRick Macklem 		lop->lo_end = off + len;
8579ec7b004SRick Macklem 		/*
8589ec7b004SRick Macklem 		 * Paranoia, just in case it wraps around, which shouldn't
8599ec7b004SRick Macklem 		 * ever happen anyhow.
8609ec7b004SRick Macklem 		 */
8619ec7b004SRick Macklem 		if (lop->lo_end < lop->lo_first)
8629ec7b004SRick Macklem 			lop->lo_end = NFS64BITSSET;
8639ec7b004SRick Macklem 	}
8649ec7b004SRick Macklem 
8659ec7b004SRick Macklem 	/*
8669ec7b004SRick Macklem 	 * Loop through the mbuf chain, counting how many mbufs are a
8679ec7b004SRick Macklem 	 * part of this write operation, so the iovec size is known.
8689ec7b004SRick Macklem 	 */
8699ec7b004SRick Macklem 	cnt = 0;
8709ec7b004SRick Macklem 	mp = nd->nd_md;
8719ec7b004SRick Macklem 	i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
8729ec7b004SRick Macklem 	while (len > 0) {
8739ec7b004SRick Macklem 		if (i > 0) {
8749ec7b004SRick Macklem 			len -= i;
8759ec7b004SRick Macklem 			cnt++;
8769ec7b004SRick Macklem 		}
8779ec7b004SRick Macklem 		mp = mbuf_next(mp);
8789ec7b004SRick Macklem 		if (!mp) {
8799ec7b004SRick Macklem 			if (len > 0) {
8809ec7b004SRick Macklem 				error = EBADRPC;
8819ec7b004SRick Macklem 				goto nfsmout;
8829ec7b004SRick Macklem 			}
8839ec7b004SRick Macklem 		} else
8849ec7b004SRick Macklem 			i = mbuf_len(mp);
8859ec7b004SRick Macklem 	}
8869ec7b004SRick Macklem 
88766e80f77SRick Macklem 	if (retlen > NFS_SRVMAXIO || retlen < 0)
8889ec7b004SRick Macklem 		nd->nd_repstat = EIO;
8899ec7b004SRick Macklem 	if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
8909ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
8919ec7b004SRick Macklem 			nd->nd_repstat = EINVAL;
8929ec7b004SRick Macklem 		else
8939ec7b004SRick Macklem 			nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
8949ec7b004SRick Macklem 			    EINVAL;
8959ec7b004SRick Macklem 	}
8960cf42b62SRick Macklem 	forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1);
8979ec7b004SRick Macklem 	if (!nd->nd_repstat)
8989ec7b004SRick Macklem 		nd->nd_repstat = forat_ret;
8999ec7b004SRick Macklem 	if (!nd->nd_repstat &&
9009ec7b004SRick Macklem 	    (forat.na_uid != nd->nd_cred->cr_uid ||
9019ec7b004SRick Macklem 	     NFSVNO_EXSTRICTACCESS(exp)))
9028da45f2cSRick Macklem 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
9039ec7b004SRick Macklem 		    nd->nd_cred, exp, p,
9048da45f2cSRick Macklem 		    NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
9059ec7b004SRick Macklem 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
9069ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
9079ec7b004SRick Macklem 		    &stateid, exp, nd, p);
9089ec7b004SRick Macklem 	}
9099ec7b004SRick Macklem 	if (nd->nd_repstat) {
9109ec7b004SRick Macklem 		vput(vp);
9119ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
9129ec7b004SRick Macklem 			nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
913a9285ae5SZack Kirsch 		goto out;
9149ec7b004SRick Macklem 	}
9159ec7b004SRick Macklem 
9169ec7b004SRick Macklem 	/*
9179ec7b004SRick Macklem 	 * For NFS Version 2, it is not obvious what a write of zero length
9189ec7b004SRick Macklem 	 * should do, but I might as well be consistent with Version 3,
9199ec7b004SRick Macklem 	 * which is to return ok so long as there are no permission problems.
9209ec7b004SRick Macklem 	 */
9219ec7b004SRick Macklem 	if (retlen > 0) {
9229ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable,
9239ec7b004SRick Macklem 		    nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
9249ec7b004SRick Macklem 		error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
9259ec7b004SRick Macklem 		if (error)
926ce8d06feSRick Macklem 			goto nfsmout;
9279ec7b004SRick Macklem 	}
9289ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4)
9299ec7b004SRick Macklem 		aftat_ret = 0;
9309ec7b004SRick Macklem 	else
9310cf42b62SRick Macklem 		aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
9329ec7b004SRick Macklem 	vput(vp);
9339ec7b004SRick Macklem 	if (!nd->nd_repstat)
9349ec7b004SRick Macklem 		nd->nd_repstat = aftat_ret;
9359ec7b004SRick Macklem 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
9369ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
9379ec7b004SRick Macklem 			nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
9389ec7b004SRick Macklem 		if (nd->nd_repstat)
939a9285ae5SZack Kirsch 			goto out;
9409ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
9419ec7b004SRick Macklem 		*tl++ = txdr_unsigned(retlen);
942e4558aacSXin LI 		/*
943e4558aacSXin LI 		 * If nfs_async is set, then pretend the write was FILESYNC.
944e4558aacSXin LI 		 * Warning: Doing this violates RFC1813 and runs a risk
945e4558aacSXin LI 		 * of data written by a client being lost when the server
946e4558aacSXin LI 		 * crashes/reboots.
947e4558aacSXin LI 		 */
948e4558aacSXin LI 		if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
9499ec7b004SRick Macklem 			*tl++ = txdr_unsigned(stable);
9509ec7b004SRick Macklem 		else
9519ec7b004SRick Macklem 			*tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
9529ec7b004SRick Macklem 		/*
9539ec7b004SRick Macklem 		 * Actually, there is no need to txdr these fields,
9549ec7b004SRick Macklem 		 * but it may make the values more human readable,
9559ec7b004SRick Macklem 		 * for debugging purposes.
9569ec7b004SRick Macklem 		 */
9579ec7b004SRick Macklem 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
9589ec7b004SRick Macklem 		*tl = txdr_unsigned(nfsboottime.tv_usec);
9599ec7b004SRick Macklem 	} else if (!nd->nd_repstat)
9609ec7b004SRick Macklem 		nfsrv_fillattr(nd, &nva);
961a9285ae5SZack Kirsch 
962a9285ae5SZack Kirsch out:
963a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
9649ec7b004SRick Macklem 	return (0);
9659ec7b004SRick Macklem nfsmout:
9669ec7b004SRick Macklem 	vput(vp);
967a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
9689ec7b004SRick Macklem 	return (error);
9699ec7b004SRick Macklem }
9709ec7b004SRick Macklem 
9719ec7b004SRick Macklem /*
9729ec7b004SRick Macklem  * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
9739ec7b004SRick Macklem  * now does a truncate to 0 length via. setattr if it already exists
9749ec7b004SRick Macklem  * The core creation routine has been extracted out into nfsrv_creatsub(),
9759ec7b004SRick Macklem  * so it can also be used by nfsrv_open() for V4.
9769ec7b004SRick Macklem  */
9779ec7b004SRick Macklem APPLESTATIC int
9789ec7b004SRick Macklem nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
9799ec7b004SRick Macklem     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
9809ec7b004SRick Macklem {
9819ec7b004SRick Macklem 	struct nfsvattr nva, dirfor, diraft;
9829ec7b004SRick Macklem 	struct nfsv2_sattr *sp;
9839ec7b004SRick Macklem 	struct nameidata named;
9849ec7b004SRick Macklem 	u_int32_t *tl;
9859ec7b004SRick Macklem 	int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
9869ec7b004SRick Macklem 	int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
9879ec7b004SRick Macklem 	NFSDEV_T rdev = 0;
9889ec7b004SRick Macklem 	vnode_t vp = NULL, dirp = NULL;
9899ec7b004SRick Macklem 	fhandle_t fh;
9909ec7b004SRick Macklem 	char *bufp;
9919ec7b004SRick Macklem 	u_long *hashp;
9929ec7b004SRick Macklem 	enum vtype vtyp;
993086f6e0cSRick Macklem 	int32_t cverf[2], tverf[2] = { 0, 0 };
9949ec7b004SRick Macklem 
9959ec7b004SRick Macklem 	if (nd->nd_repstat) {
9969ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
997a9285ae5SZack Kirsch 		goto out;
9989ec7b004SRick Macklem 	}
9999ec7b004SRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
10006c21f6edSKonstantin Belousov 	    LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
10019ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
10029ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1003a9285ae5SZack Kirsch 	if (error)
1004a9285ae5SZack Kirsch 		goto nfsmout;
10059ec7b004SRick Macklem 	if (!nd->nd_repstat) {
10069ec7b004SRick Macklem 		NFSVNO_ATTRINIT(&nva);
10079ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV2) {
10089ec7b004SRick Macklem 			NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
10099ec7b004SRick Macklem 			vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
10109ec7b004SRick Macklem 			if (vtyp == VNON)
10119ec7b004SRick Macklem 				vtyp = VREG;
10129ec7b004SRick Macklem 			NFSVNO_SETATTRVAL(&nva, type, vtyp);
10139ec7b004SRick Macklem 			NFSVNO_SETATTRVAL(&nva, mode,
10149ec7b004SRick Macklem 			    nfstov_mode(sp->sa_mode));
10159ec7b004SRick Macklem 			switch (nva.na_type) {
10169ec7b004SRick Macklem 			case VREG:
10179ec7b004SRick Macklem 				tsize = fxdr_unsigned(int32_t, sp->sa_size);
10189ec7b004SRick Macklem 				if (tsize != -1)
10199ec7b004SRick Macklem 					NFSVNO_SETATTRVAL(&nva, size,
10209ec7b004SRick Macklem 					    (u_quad_t)tsize);
10219ec7b004SRick Macklem 				break;
10229ec7b004SRick Macklem 			case VCHR:
10239ec7b004SRick Macklem 			case VBLK:
10249ec7b004SRick Macklem 			case VFIFO:
10259ec7b004SRick Macklem 				rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
10269ec7b004SRick Macklem 				break;
10279ec7b004SRick Macklem 			default:
10289ec7b004SRick Macklem 				break;
102974b8d63dSPedro F. Giffuni 			}
10309ec7b004SRick Macklem 		} else {
10319ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
10329ec7b004SRick Macklem 			how = fxdr_unsigned(int, *tl);
10339ec7b004SRick Macklem 			switch (how) {
10349ec7b004SRick Macklem 			case NFSCREATE_GUARDED:
10359ec7b004SRick Macklem 			case NFSCREATE_UNCHECKED:
1036d8a5961fSMarcelo Araujo 				error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
10379ec7b004SRick Macklem 				if (error)
10389ec7b004SRick Macklem 					goto nfsmout;
10399ec7b004SRick Macklem 				break;
10409ec7b004SRick Macklem 			case NFSCREATE_EXCLUSIVE:
1041086f6e0cSRick Macklem 				NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1042086f6e0cSRick Macklem 				cverf[0] = *tl++;
1043086f6e0cSRick Macklem 				cverf[1] = *tl;
10449ec7b004SRick Macklem 				exclusive_flag = 1;
10459ec7b004SRick Macklem 				break;
104674b8d63dSPedro F. Giffuni 			}
10479ec7b004SRick Macklem 			NFSVNO_SETATTRVAL(&nva, type, VREG);
10489ec7b004SRick Macklem 		}
10499ec7b004SRick Macklem 	}
10509ec7b004SRick Macklem 	if (nd->nd_repstat) {
10519ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
10529ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
10539ec7b004SRick Macklem 			dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred,
10540cf42b62SRick Macklem 			    p, 1);
10559ec7b004SRick Macklem 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
10569ec7b004SRick Macklem 			    &diraft);
10579ec7b004SRick Macklem 		}
10589ec7b004SRick Macklem 		vput(dp);
1059a9285ae5SZack Kirsch 		goto out;
10609ec7b004SRick Macklem 	}
10619ec7b004SRick Macklem 
10629ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
10639ec7b004SRick Macklem 	if (dirp) {
10649ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV2) {
10659ec7b004SRick Macklem 			vrele(dirp);
10669ec7b004SRick Macklem 			dirp = NULL;
10679ec7b004SRick Macklem 		} else {
10689ec7b004SRick Macklem 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
10690cf42b62SRick Macklem 			    p, 0);
10709ec7b004SRick Macklem 		}
10719ec7b004SRick Macklem 	}
10729ec7b004SRick Macklem 	if (nd->nd_repstat) {
10739ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
10749ec7b004SRick Macklem 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
10759ec7b004SRick Macklem 			    &diraft);
10769ec7b004SRick Macklem 		if (dirp)
10779ec7b004SRick Macklem 			vrele(dirp);
1078a9285ae5SZack Kirsch 		goto out;
10799ec7b004SRick Macklem 	}
10809ec7b004SRick Macklem 
10819ec7b004SRick Macklem 	if (!(nd->nd_flag & ND_NFSV2)) {
10829ec7b004SRick Macklem 		switch (how) {
10839ec7b004SRick Macklem 		case NFSCREATE_GUARDED:
10849ec7b004SRick Macklem 			if (named.ni_vp)
10859ec7b004SRick Macklem 				nd->nd_repstat = EEXIST;
10869ec7b004SRick Macklem 			break;
10879ec7b004SRick Macklem 		case NFSCREATE_UNCHECKED:
10889ec7b004SRick Macklem 			break;
10899ec7b004SRick Macklem 		case NFSCREATE_EXCLUSIVE:
10909ec7b004SRick Macklem 			if (named.ni_vp == NULL)
10919ec7b004SRick Macklem 				NFSVNO_SETATTRVAL(&nva, mode, 0);
10929ec7b004SRick Macklem 			break;
109374b8d63dSPedro F. Giffuni 		}
10949ec7b004SRick Macklem 	}
10959ec7b004SRick Macklem 
10969ec7b004SRick Macklem 	/*
10979ec7b004SRick Macklem 	 * Iff doesn't exist, create it
10989ec7b004SRick Macklem 	 * otherwise just truncate to 0 length
10999ec7b004SRick Macklem 	 *   should I set the mode too ?
11009ec7b004SRick Macklem 	 */
11019ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
11029ec7b004SRick Macklem 	    &exclusive_flag, cverf, rdev, p, exp);
11039ec7b004SRick Macklem 
11049ec7b004SRick Macklem 	if (!nd->nd_repstat) {
11059ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
11069ec7b004SRick Macklem 		if (!nd->nd_repstat)
11079ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
11080cf42b62SRick Macklem 			    p, 1);
11099ec7b004SRick Macklem 		vput(vp);
1110086f6e0cSRick Macklem 		if (!nd->nd_repstat) {
1111086f6e0cSRick Macklem 			tverf[0] = nva.na_atime.tv_sec;
1112086f6e0cSRick Macklem 			tverf[1] = nva.na_atime.tv_nsec;
1113086f6e0cSRick Macklem 		}
11149ec7b004SRick Macklem 	}
11159ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV2) {
11169ec7b004SRick Macklem 		if (!nd->nd_repstat) {
11179ec7b004SRick Macklem 			(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
11189ec7b004SRick Macklem 			nfsrv_fillattr(nd, &nva);
11199ec7b004SRick Macklem 		}
11209ec7b004SRick Macklem 	} else {
1121086f6e0cSRick Macklem 		if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1122086f6e0cSRick Macklem 		    || cverf[1] != tverf[1]))
11239ec7b004SRick Macklem 			nd->nd_repstat = EEXIST;
11240cf42b62SRick Macklem 		diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
11259ec7b004SRick Macklem 		vrele(dirp);
11269ec7b004SRick Macklem 		if (!nd->nd_repstat) {
11279ec7b004SRick Macklem 			(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
11289ec7b004SRick Macklem 			nfsrv_postopattr(nd, 0, &nva);
11299ec7b004SRick Macklem 		}
11309ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
11319ec7b004SRick Macklem 	}
1132a9285ae5SZack Kirsch 
1133a9285ae5SZack Kirsch out:
1134a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
11359ec7b004SRick Macklem 	return (0);
11369ec7b004SRick Macklem nfsmout:
11379ec7b004SRick Macklem 	vput(dp);
11389ec7b004SRick Macklem 	nfsvno_relpathbuf(&named);
1139a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
11409ec7b004SRick Macklem 	return (error);
11419ec7b004SRick Macklem }
11429ec7b004SRick Macklem 
11439ec7b004SRick Macklem /*
11449ec7b004SRick Macklem  * nfs v3 mknod service (and v4 create)
11459ec7b004SRick Macklem  */
11469ec7b004SRick Macklem APPLESTATIC int
11479ec7b004SRick Macklem nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
11489ec7b004SRick Macklem     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
11499ec7b004SRick Macklem     struct nfsexstuff *exp)
11509ec7b004SRick Macklem {
11519ec7b004SRick Macklem 	struct nfsvattr nva, dirfor, diraft;
11529ec7b004SRick Macklem 	u_int32_t *tl;
11539ec7b004SRick Macklem 	struct nameidata named;
11549ec7b004SRick Macklem 	int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
11559ec7b004SRick Macklem 	u_int32_t major, minor;
11569ec7b004SRick Macklem 	enum vtype vtyp = VNON;
11579ec7b004SRick Macklem 	nfstype nfs4type = NFNON;
11589ec7b004SRick Macklem 	vnode_t vp, dirp = NULL;
11599ec7b004SRick Macklem 	nfsattrbit_t attrbits;
11609ec7b004SRick Macklem 	char *bufp = NULL, *pathcp = NULL;
11619ec7b004SRick Macklem 	u_long *hashp, cnflags;
11629ec7b004SRick Macklem 	NFSACL_T *aclp = NULL;
11639ec7b004SRick Macklem 
11649ec7b004SRick Macklem 	NFSVNO_ATTRINIT(&nva);
11659ec7b004SRick Macklem 	cnflags = (LOCKPARENT | SAVESTART);
11669ec7b004SRick Macklem 	if (nd->nd_repstat) {
11679ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1168a9285ae5SZack Kirsch 		goto out;
11699ec7b004SRick Macklem 	}
11709ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
1171c3e22f83SRick Macklem 	aclp = acl_alloc(M_WAITOK);
11729ec7b004SRick Macklem 	aclp->acl_cnt = 0;
11739ec7b004SRick Macklem #endif
11749ec7b004SRick Macklem 
11759ec7b004SRick Macklem 	/*
11769ec7b004SRick Macklem 	 * For V4, the creation stuff is here, Yuck!
11779ec7b004SRick Macklem 	 */
11789ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
11799ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
11809ec7b004SRick Macklem 		vtyp = nfsv34tov_type(*tl);
11819ec7b004SRick Macklem 		nfs4type = fxdr_unsigned(nfstype, *tl);
11829ec7b004SRick Macklem 		switch (nfs4type) {
11839ec7b004SRick Macklem 		case NFLNK:
11849ec7b004SRick Macklem 			error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
11859ec7b004SRick Macklem 			    &pathlen);
1186a9285ae5SZack Kirsch 			if (error)
1187a9285ae5SZack Kirsch 				goto nfsmout;
11889ec7b004SRick Macklem 			break;
11899ec7b004SRick Macklem 		case NFCHR:
11909ec7b004SRick Macklem 		case NFBLK:
11919ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
11929ec7b004SRick Macklem 			major = fxdr_unsigned(u_int32_t, *tl++);
11939ec7b004SRick Macklem 			minor = fxdr_unsigned(u_int32_t, *tl);
11949ec7b004SRick Macklem 			nva.na_rdev = NFSMAKEDEV(major, minor);
11959ec7b004SRick Macklem 			break;
11969ec7b004SRick Macklem 		case NFSOCK:
11979ec7b004SRick Macklem 		case NFFIFO:
11989ec7b004SRick Macklem 			break;
11999ec7b004SRick Macklem 		case NFDIR:
1200f61786cbSRick Macklem 			cnflags = (LOCKPARENT | SAVENAME);
12019ec7b004SRick Macklem 			break;
12029ec7b004SRick Macklem 		default:
12039ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_BADTYPE;
12049ec7b004SRick Macklem 			vrele(dp);
12059ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
12069ec7b004SRick Macklem 			acl_free(aclp);
12079ec7b004SRick Macklem #endif
1208a9285ae5SZack Kirsch 			goto out;
1209a9285ae5SZack Kirsch 		}
12109ec7b004SRick Macklem 	}
12116c21f6edSKonstantin Belousov 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE);
12129ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
12139ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1214a9285ae5SZack Kirsch 	if (error)
1215a9285ae5SZack Kirsch 		goto nfsmout;
12169ec7b004SRick Macklem 	if (!nd->nd_repstat) {
12179ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
12189ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
12199ec7b004SRick Macklem 			vtyp = nfsv34tov_type(*tl);
12209ec7b004SRick Macklem 		}
1221d8a5961fSMarcelo Araujo 		error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p);
1222a9285ae5SZack Kirsch 		if (error)
1223a9285ae5SZack Kirsch 			goto nfsmout;
12249ec7b004SRick Macklem 		nva.na_type = vtyp;
12259ec7b004SRick Macklem 		if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
12269ec7b004SRick Macklem 		    (vtyp == VCHR || vtyp == VBLK)) {
12279ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
12289ec7b004SRick Macklem 			major = fxdr_unsigned(u_int32_t, *tl++);
12299ec7b004SRick Macklem 			minor = fxdr_unsigned(u_int32_t, *tl);
12309ec7b004SRick Macklem 			nva.na_rdev = NFSMAKEDEV(major, minor);
12319ec7b004SRick Macklem 		}
12329ec7b004SRick Macklem 	}
12339ec7b004SRick Macklem 
12340cf42b62SRick Macklem 	dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
12359ec7b004SRick Macklem 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
12369ec7b004SRick Macklem 		if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
12379ec7b004SRick Macklem 		    dirfor.na_gid == nva.na_gid)
12389ec7b004SRick Macklem 			NFSVNO_UNSET(&nva, gid);
12399ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
12409ec7b004SRick Macklem 	}
12419ec7b004SRick Macklem 	if (nd->nd_repstat) {
12429ec7b004SRick Macklem 		vrele(dp);
12439ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
12449ec7b004SRick Macklem 		acl_free(aclp);
12459ec7b004SRick Macklem #endif
12469ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
12479ec7b004SRick Macklem 		if (pathcp)
1248222daa42SConrad Meyer 			free(pathcp, M_TEMP);
12499ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
12509ec7b004SRick Macklem 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
12519ec7b004SRick Macklem 			    &diraft);
1252a9285ae5SZack Kirsch 		goto out;
12539ec7b004SRick Macklem 	}
12549ec7b004SRick Macklem 
12559ec7b004SRick Macklem 	/*
12569ec7b004SRick Macklem 	 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
12579ec7b004SRick Macklem 	 * in va_mode, so we'll have to set a default here.
12589ec7b004SRick Macklem 	 */
12599ec7b004SRick Macklem 	if (NFSVNO_NOTSETMODE(&nva)) {
12609ec7b004SRick Macklem 		if (vtyp == VLNK)
12619ec7b004SRick Macklem 			nva.na_mode = 0755;
12629ec7b004SRick Macklem 		else
12639ec7b004SRick Macklem 			nva.na_mode = 0400;
12649ec7b004SRick Macklem 	}
12659ec7b004SRick Macklem 
12669ec7b004SRick Macklem 	if (vtyp == VDIR)
12679ec7b004SRick Macklem 		named.ni_cnd.cn_flags |= WILLBEDIR;
12689ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
12699ec7b004SRick Macklem 	if (nd->nd_repstat) {
12709ec7b004SRick Macklem 		if (dirp) {
12719ec7b004SRick Macklem 			if (nd->nd_flag & ND_NFSV3)
12729ec7b004SRick Macklem 				dirfor_ret = nfsvno_getattr(dirp, &dirfor,
12730cf42b62SRick Macklem 				    nd->nd_cred, p, 0);
12749ec7b004SRick Macklem 			vrele(dirp);
12759ec7b004SRick Macklem 		}
12769ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
12779ec7b004SRick Macklem 		acl_free(aclp);
12789ec7b004SRick Macklem #endif
12799ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
12809ec7b004SRick Macklem 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
12819ec7b004SRick Macklem 			    &diraft);
1282a9285ae5SZack Kirsch 		goto out;
12839ec7b004SRick Macklem 	}
12849ec7b004SRick Macklem 	if (dirp)
12850cf42b62SRick Macklem 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
12869ec7b004SRick Macklem 
12879ec7b004SRick Macklem 	if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
12889ec7b004SRick Macklem 		if (vtyp == VDIR) {
12899ec7b004SRick Macklem 			nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
12909ec7b004SRick Macklem 			    &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
12919ec7b004SRick Macklem 			    exp);
12929ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
12939ec7b004SRick Macklem 			acl_free(aclp);
12949ec7b004SRick Macklem #endif
1295a9285ae5SZack Kirsch 			goto out;
12969ec7b004SRick Macklem 		} else if (vtyp == VLNK) {
12979ec7b004SRick Macklem 			nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
12989ec7b004SRick Macklem 			    &dirfor, &diraft, &diraft_ret, &attrbits,
12999ec7b004SRick Macklem 			    aclp, p, exp, pathcp, pathlen);
13009ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
13019ec7b004SRick Macklem 			acl_free(aclp);
13029ec7b004SRick Macklem #endif
1303222daa42SConrad Meyer 			free(pathcp, M_TEMP);
1304a9285ae5SZack Kirsch 			goto out;
13059ec7b004SRick Macklem 		}
13069ec7b004SRick Macklem 	}
13079ec7b004SRick Macklem 
13089ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
13099ec7b004SRick Macklem 	if (!nd->nd_repstat) {
13109ec7b004SRick Macklem 		vp = named.ni_vp;
13119ec7b004SRick Macklem 		nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
13129ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
13139ec7b004SRick Macklem 		if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
13149ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
13150cf42b62SRick Macklem 			    p, 1);
131681f78d99SRick Macklem 		if (vpp != NULL && nd->nd_repstat == 0) {
1317a9989634SZack Kirsch 			NFSVOPUNLOCK(vp, 0);
13189ec7b004SRick Macklem 			*vpp = vp;
131981f78d99SRick Macklem 		} else
13209ec7b004SRick Macklem 			vput(vp);
13219ec7b004SRick Macklem 	}
13229ec7b004SRick Macklem 
13230cf42b62SRick Macklem 	diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
13249ec7b004SRick Macklem 	vrele(dirp);
13259ec7b004SRick Macklem 	if (!nd->nd_repstat) {
13269ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
13279ec7b004SRick Macklem 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
13289ec7b004SRick Macklem 			nfsrv_postopattr(nd, 0, &nva);
13299ec7b004SRick Macklem 		} else {
13309ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
13319ec7b004SRick Macklem 			*tl++ = newnfs_false;
13329ec7b004SRick Macklem 			txdr_hyper(dirfor.na_filerev, tl);
13339ec7b004SRick Macklem 			tl += 2;
13349ec7b004SRick Macklem 			txdr_hyper(diraft.na_filerev, tl);
13359ec7b004SRick Macklem 			(void) nfsrv_putattrbit(nd, &attrbits);
13369ec7b004SRick Macklem 		}
13379ec7b004SRick Macklem 	}
13389ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
13399ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
13409ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
13419ec7b004SRick Macklem 	acl_free(aclp);
13429ec7b004SRick Macklem #endif
1343a9285ae5SZack Kirsch 
1344a9285ae5SZack Kirsch out:
1345a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
13469ec7b004SRick Macklem 	return (0);
13479ec7b004SRick Macklem nfsmout:
13489ec7b004SRick Macklem 	vrele(dp);
13499ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
13509ec7b004SRick Macklem 	acl_free(aclp);
13519ec7b004SRick Macklem #endif
13529ec7b004SRick Macklem 	if (bufp)
13539ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
13549ec7b004SRick Macklem 	if (pathcp)
1355222daa42SConrad Meyer 		free(pathcp, M_TEMP);
1356a9285ae5SZack Kirsch 
1357a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
13589ec7b004SRick Macklem 	return (error);
13599ec7b004SRick Macklem }
13609ec7b004SRick Macklem 
13619ec7b004SRick Macklem /*
13629ec7b004SRick Macklem  * nfs remove service
13639ec7b004SRick Macklem  */
13649ec7b004SRick Macklem APPLESTATIC int
13659ec7b004SRick Macklem nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
13669ec7b004SRick Macklem     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
13679ec7b004SRick Macklem {
13689ec7b004SRick Macklem 	struct nameidata named;
13699ec7b004SRick Macklem 	u_int32_t *tl;
1370a9285ae5SZack Kirsch 	int error = 0, dirfor_ret = 1, diraft_ret = 1;
13719ec7b004SRick Macklem 	vnode_t dirp = NULL;
13729ec7b004SRick Macklem 	struct nfsvattr dirfor, diraft;
13739ec7b004SRick Macklem 	char *bufp;
13749ec7b004SRick Macklem 	u_long *hashp;
13759ec7b004SRick Macklem 
13769ec7b004SRick Macklem 	if (nd->nd_repstat) {
13779ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1378a9285ae5SZack Kirsch 		goto out;
13799ec7b004SRick Macklem 	}
13809ec7b004SRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
13819ec7b004SRick Macklem 	    LOCKPARENT | LOCKLEAF);
13829ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
13839ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
13849ec7b004SRick Macklem 	if (error) {
13859ec7b004SRick Macklem 		vput(dp);
13869ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
1387a9285ae5SZack Kirsch 		goto out;
13889ec7b004SRick Macklem 	}
13899ec7b004SRick Macklem 	if (!nd->nd_repstat) {
13909ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
13919ec7b004SRick Macklem 	} else {
13929ec7b004SRick Macklem 		vput(dp);
13939ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
13949ec7b004SRick Macklem 	}
13959ec7b004SRick Macklem 	if (dirp) {
13969ec7b004SRick Macklem 		if (!(nd->nd_flag & ND_NFSV2)) {
13979ec7b004SRick Macklem 			dirfor_ret = nfsvno_getattr(dirp, &dirfor,
13980cf42b62SRick Macklem 			    nd->nd_cred, p, 0);
13999ec7b004SRick Macklem 		} else {
14009ec7b004SRick Macklem 			vrele(dirp);
14019ec7b004SRick Macklem 			dirp = NULL;
14029ec7b004SRick Macklem 		}
14039ec7b004SRick Macklem 	}
14049ec7b004SRick Macklem 	if (!nd->nd_repstat) {
14059ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV4) {
14069ec7b004SRick Macklem 			if (vnode_vtype(named.ni_vp) == VDIR)
14079ec7b004SRick Macklem 				nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
14089ec7b004SRick Macklem 				    nd->nd_cred, p, exp);
14099ec7b004SRick Macklem 			else
14109ec7b004SRick Macklem 				nd->nd_repstat = nfsvno_removesub(&named, 1,
14119ec7b004SRick Macklem 				    nd->nd_cred, p, exp);
14129ec7b004SRick Macklem 		} else if (nd->nd_procnum == NFSPROC_RMDIR) {
14139ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
14149ec7b004SRick Macklem 			    nd->nd_cred, p, exp);
14159ec7b004SRick Macklem 		} else {
14169ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_removesub(&named, 0,
14179ec7b004SRick Macklem 			    nd->nd_cred, p, exp);
14189ec7b004SRick Macklem 		}
14199ec7b004SRick Macklem 	}
14209ec7b004SRick Macklem 	if (!(nd->nd_flag & ND_NFSV2)) {
14219ec7b004SRick Macklem 		if (dirp) {
14229ec7b004SRick Macklem 			diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred,
14230cf42b62SRick Macklem 			    p, 0);
14249ec7b004SRick Macklem 			vrele(dirp);
14259ec7b004SRick Macklem 		}
14269ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
14279ec7b004SRick Macklem 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
14289ec7b004SRick Macklem 			    &diraft);
14299ec7b004SRick Macklem 		} else if (!nd->nd_repstat) {
14309ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
14319ec7b004SRick Macklem 			*tl++ = newnfs_false;
14329ec7b004SRick Macklem 			txdr_hyper(dirfor.na_filerev, tl);
14339ec7b004SRick Macklem 			tl += 2;
14349ec7b004SRick Macklem 			txdr_hyper(diraft.na_filerev, tl);
14359ec7b004SRick Macklem 		}
14369ec7b004SRick Macklem 	}
1437a9285ae5SZack Kirsch 
1438a9285ae5SZack Kirsch out:
1439a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
1440a9285ae5SZack Kirsch 	return (error);
14419ec7b004SRick Macklem }
14429ec7b004SRick Macklem 
14439ec7b004SRick Macklem /*
14449ec7b004SRick Macklem  * nfs rename service
14459ec7b004SRick Macklem  */
14469ec7b004SRick Macklem APPLESTATIC int
14479ec7b004SRick Macklem nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
14489ec7b004SRick Macklem     vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp,
14499ec7b004SRick Macklem     struct nfsexstuff *toexp)
14509ec7b004SRick Macklem {
14519ec7b004SRick Macklem 	u_int32_t *tl;
1452a9285ae5SZack Kirsch 	int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
14539ec7b004SRick Macklem 	int tdirfor_ret = 1, tdiraft_ret = 1;
14549ec7b004SRick Macklem 	struct nameidata fromnd, tond;
14559ec7b004SRick Macklem 	vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
14569ec7b004SRick Macklem 	struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
14579ec7b004SRick Macklem 	struct nfsexstuff tnes;
14589ec7b004SRick Macklem 	struct nfsrvfh tfh;
14599ec7b004SRick Macklem 	char *bufp, *tbufp = NULL;
14609ec7b004SRick Macklem 	u_long *hashp;
14616b3dfc6aSRick Macklem 	fhandle_t fh;
14629ec7b004SRick Macklem 
14639ec7b004SRick Macklem 	if (nd->nd_repstat) {
14649ec7b004SRick Macklem 		nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
14659ec7b004SRick Macklem 		nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1466a9285ae5SZack Kirsch 		goto out;
14679ec7b004SRick Macklem 	}
14689ec7b004SRick Macklem 	if (!(nd->nd_flag & ND_NFSV2))
14690cf42b62SRick Macklem 		fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1);
14709ec7b004SRick Macklem 	tond.ni_cnd.cn_nameiop = 0;
14719ec7b004SRick Macklem 	tond.ni_startdir = NULL;
14729ec7b004SRick Macklem 	NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
14739ec7b004SRick Macklem 	nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
14749ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
14759ec7b004SRick Macklem 	if (error) {
14769ec7b004SRick Macklem 		vput(dp);
14779ec7b004SRick Macklem 		if (todp)
14789ec7b004SRick Macklem 			vrele(todp);
14799ec7b004SRick Macklem 		nfsvno_relpathbuf(&fromnd);
1480a9285ae5SZack Kirsch 		goto out;
14819ec7b004SRick Macklem 	}
148225bfde79SXin LI 	/*
148325bfde79SXin LI 	 * Unlock dp in this code section, so it is unlocked before
148425bfde79SXin LI 	 * tdp gets locked. This avoids a potential LOR if tdp is the
148525bfde79SXin LI 	 * parent directory of dp.
148625bfde79SXin LI 	 */
14879ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
14889ec7b004SRick Macklem 		tdp = todp;
14899ec7b004SRick Macklem 		tnes = *toexp;
149025bfde79SXin LI 		if (dp != tdp) {
149125bfde79SXin LI 			NFSVOPUNLOCK(dp, 0);
149225bfde79SXin LI 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
149325bfde79SXin LI 			    p, 0);	/* Might lock tdp. */
149425bfde79SXin LI 		} else {
149525bfde79SXin LI 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
149625bfde79SXin LI 			    p, 1);
149725bfde79SXin LI 			NFSVOPUNLOCK(dp, 0);
149825bfde79SXin LI 		}
14999ec7b004SRick Macklem 	} else {
15006b3dfc6aSRick Macklem 		tfh.nfsrvfh_len = 0;
15019ec7b004SRick Macklem 		error = nfsrv_mtofh(nd, &tfh);
15026b3dfc6aSRick Macklem 		if (error == 0)
15036b3dfc6aSRick Macklem 			error = nfsvno_getfh(dp, &fh, p);
15049ec7b004SRick Macklem 		if (error) {
15059ec7b004SRick Macklem 			vput(dp);
15069ec7b004SRick Macklem 			/* todp is always NULL except NFSv4 */
15079ec7b004SRick Macklem 			nfsvno_relpathbuf(&fromnd);
1508a9285ae5SZack Kirsch 			goto out;
15099ec7b004SRick Macklem 		}
15106b3dfc6aSRick Macklem 
15116b3dfc6aSRick Macklem 		/* If this is the same file handle, just VREF() the vnode. */
15126b3dfc6aSRick Macklem 		if (tfh.nfsrvfh_len == NFSX_MYFH &&
15136b3dfc6aSRick Macklem 		    !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
15146b3dfc6aSRick Macklem 			VREF(dp);
15156b3dfc6aSRick Macklem 			tdp = dp;
15166b3dfc6aSRick Macklem 			tnes = *exp;
15179ec7b004SRick Macklem 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
15180cf42b62SRick Macklem 			    p, 1);
151925bfde79SXin LI 			NFSVOPUNLOCK(dp, 0);
15206b3dfc6aSRick Macklem 		} else {
152125bfde79SXin LI 			NFSVOPUNLOCK(dp, 0);
15226b3dfc6aSRick Macklem 			nd->nd_cred->cr_uid = nd->nd_saveduid;
15236b3dfc6aSRick Macklem 			nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
152425bfde79SXin LI 			    0, p);	/* Locks tdp. */
15256b3dfc6aSRick Macklem 			if (tdp) {
15266b3dfc6aSRick Macklem 				tdirfor_ret = nfsvno_getattr(tdp, &tdirfor,
15276b3dfc6aSRick Macklem 				    nd->nd_cred, p, 1);
1528c383087cSZack Kirsch 				NFSVOPUNLOCK(tdp, 0);
15299ec7b004SRick Macklem 			}
15309ec7b004SRick Macklem 		}
15316b3dfc6aSRick Macklem 	}
15329ec7b004SRick Macklem 	NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
15339ec7b004SRick Macklem 	nfsvno_setpathbuf(&tond, &tbufp, &hashp);
15349ec7b004SRick Macklem 	if (!nd->nd_repstat) {
15359ec7b004SRick Macklem 		error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
15369ec7b004SRick Macklem 		if (error) {
15378974bc2fSRick Macklem 			if (tdp)
15389ec7b004SRick Macklem 				vrele(tdp);
153925bfde79SXin LI 			vrele(dp);
15409ec7b004SRick Macklem 			nfsvno_relpathbuf(&fromnd);
15419ec7b004SRick Macklem 			nfsvno_relpathbuf(&tond);
1542a9285ae5SZack Kirsch 			goto out;
15439ec7b004SRick Macklem 		}
15449ec7b004SRick Macklem 	}
15459ec7b004SRick Macklem 	if (nd->nd_repstat) {
15469ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
15479ec7b004SRick Macklem 			nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
15489ec7b004SRick Macklem 			    &fdiraft);
15499ec7b004SRick Macklem 			nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
15509ec7b004SRick Macklem 			    &tdiraft);
15519ec7b004SRick Macklem 		}
15528974bc2fSRick Macklem 		if (tdp)
15539ec7b004SRick Macklem 			vrele(tdp);
155425bfde79SXin LI 		vrele(dp);
15559ec7b004SRick Macklem 		nfsvno_relpathbuf(&fromnd);
15569ec7b004SRick Macklem 		nfsvno_relpathbuf(&tond);
1557a9285ae5SZack Kirsch 		goto out;
15589ec7b004SRick Macklem 	}
15599ec7b004SRick Macklem 
15609ec7b004SRick Macklem 	/*
15619ec7b004SRick Macklem 	 * Done parsing, now down to business.
15629ec7b004SRick Macklem 	 */
156325bfde79SXin LI 	nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
15649ec7b004SRick Macklem 	if (nd->nd_repstat) {
15659ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
15669ec7b004SRick Macklem 			nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
15679ec7b004SRick Macklem 			    &fdiraft);
15689ec7b004SRick Macklem 			nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
15699ec7b004SRick Macklem 			    &tdiraft);
15709ec7b004SRick Macklem 		}
15719ec7b004SRick Macklem 		if (fdirp)
15729ec7b004SRick Macklem 			vrele(fdirp);
15738974bc2fSRick Macklem 		if (tdp)
15749ec7b004SRick Macklem 			vrele(tdp);
15759ec7b004SRick Macklem 		nfsvno_relpathbuf(&tond);
1576a9285ae5SZack Kirsch 		goto out;
15779ec7b004SRick Macklem 	}
15789ec7b004SRick Macklem 	if (vnode_vtype(fromnd.ni_vp) == VDIR)
15799ec7b004SRick Macklem 		tond.ni_cnd.cn_flags |= WILLBEDIR;
15809ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
15819ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
15829ec7b004SRick Macklem 	    nd->nd_flag, nd->nd_cred, p);
15839ec7b004SRick Macklem 	if (fdirp)
15840cf42b62SRick Macklem 		fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
15850cf42b62SRick Macklem 		    0);
15869ec7b004SRick Macklem 	if (tdirp)
15870cf42b62SRick Macklem 		tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
15880cf42b62SRick Macklem 		    0);
15899ec7b004SRick Macklem 	if (fdirp)
15909ec7b004SRick Macklem 		vrele(fdirp);
15919ec7b004SRick Macklem 	if (tdirp)
15929ec7b004SRick Macklem 		vrele(tdirp);
15939ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
15949ec7b004SRick Macklem 		nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
15959ec7b004SRick Macklem 		nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
15969ec7b004SRick Macklem 	} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
15979ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
15989ec7b004SRick Macklem 		*tl++ = newnfs_false;
15999ec7b004SRick Macklem 		txdr_hyper(fdirfor.na_filerev, tl);
16009ec7b004SRick Macklem 		tl += 2;
16019ec7b004SRick Macklem 		txdr_hyper(fdiraft.na_filerev, tl);
16029ec7b004SRick Macklem 		tl += 2;
16039ec7b004SRick Macklem 		*tl++ = newnfs_false;
16049ec7b004SRick Macklem 		txdr_hyper(tdirfor.na_filerev, tl);
16059ec7b004SRick Macklem 		tl += 2;
16069ec7b004SRick Macklem 		txdr_hyper(tdiraft.na_filerev, tl);
16079ec7b004SRick Macklem 	}
1608a9285ae5SZack Kirsch 
1609a9285ae5SZack Kirsch out:
1610a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
1611a9285ae5SZack Kirsch 	return (error);
16129ec7b004SRick Macklem }
16139ec7b004SRick Macklem 
16149ec7b004SRick Macklem /*
16159ec7b004SRick Macklem  * nfs link service
16169ec7b004SRick Macklem  */
16179ec7b004SRick Macklem APPLESTATIC int
16189ec7b004SRick Macklem nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
16199ec7b004SRick Macklem     vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
16209ec7b004SRick Macklem     struct nfsexstuff *toexp)
16219ec7b004SRick Macklem {
16229ec7b004SRick Macklem 	struct nameidata named;
16239ec7b004SRick Macklem 	u_int32_t *tl;
16249ec7b004SRick Macklem 	int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
16259ec7b004SRick Macklem 	vnode_t dirp = NULL, dp = NULL;
16269ec7b004SRick Macklem 	struct nfsvattr dirfor, diraft, at;
16279ec7b004SRick Macklem 	struct nfsexstuff tnes;
16289ec7b004SRick Macklem 	struct nfsrvfh dfh;
16299ec7b004SRick Macklem 	char *bufp;
16309ec7b004SRick Macklem 	u_long *hashp;
16319ec7b004SRick Macklem 
16329ec7b004SRick Macklem 	if (nd->nd_repstat) {
16339ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &at);
16349ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1635a9285ae5SZack Kirsch 		goto out;
16369ec7b004SRick Macklem 	}
1637c383087cSZack Kirsch 	NFSVOPUNLOCK(vp, 0);
16389ec7b004SRick Macklem 	if (vnode_vtype(vp) == VDIR) {
16399ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV4)
16409ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_ISDIR;
16419ec7b004SRick Macklem 		else
16429ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_INVAL;
16439ec7b004SRick Macklem 		if (tovp)
16449ec7b004SRick Macklem 			vrele(tovp);
16459ec7b004SRick Macklem 	}
16469ec7b004SRick Macklem 	if (!nd->nd_repstat) {
16479ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV4) {
16489ec7b004SRick Macklem 			dp = tovp;
16499ec7b004SRick Macklem 			tnes = *toexp;
16509ec7b004SRick Macklem 		} else {
16519ec7b004SRick Macklem 			error = nfsrv_mtofh(nd, &dfh);
16529ec7b004SRick Macklem 			if (error) {
16539ec7b004SRick Macklem 				vrele(vp);
16549ec7b004SRick Macklem 				/* tovp is always NULL unless NFSv4 */
1655a9285ae5SZack Kirsch 				goto out;
16569ec7b004SRick Macklem 			}
16578974bc2fSRick Macklem 			nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0,
165817891d00SRick Macklem 			    p);
16599ec7b004SRick Macklem 			if (dp)
1660c383087cSZack Kirsch 				NFSVOPUNLOCK(dp, 0);
16619ec7b004SRick Macklem 		}
16629ec7b004SRick Macklem 	}
1663f61786cbSRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
16646c21f6edSKonstantin Belousov 	    LOCKPARENT | SAVENAME | NOCACHE);
16659ec7b004SRick Macklem 	if (!nd->nd_repstat) {
16669ec7b004SRick Macklem 		nfsvno_setpathbuf(&named, &bufp, &hashp);
16679ec7b004SRick Macklem 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
16689ec7b004SRick Macklem 		if (error) {
16699ec7b004SRick Macklem 			vrele(vp);
16708974bc2fSRick Macklem 			if (dp)
16719ec7b004SRick Macklem 				vrele(dp);
16729ec7b004SRick Macklem 			nfsvno_relpathbuf(&named);
1673a9285ae5SZack Kirsch 			goto out;
16749ec7b004SRick Macklem 		}
16759ec7b004SRick Macklem 		if (!nd->nd_repstat) {
16769ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
16779ec7b004SRick Macklem 			    p, &dirp);
16789ec7b004SRick Macklem 		} else {
16799ec7b004SRick Macklem 			if (dp)
16809ec7b004SRick Macklem 				vrele(dp);
16819ec7b004SRick Macklem 			nfsvno_relpathbuf(&named);
16829ec7b004SRick Macklem 		}
16839ec7b004SRick Macklem 	}
16849ec7b004SRick Macklem 	if (dirp) {
16859ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV2) {
16869ec7b004SRick Macklem 			vrele(dirp);
16879ec7b004SRick Macklem 			dirp = NULL;
16889ec7b004SRick Macklem 		} else {
16899ec7b004SRick Macklem 			dirfor_ret = nfsvno_getattr(dirp, &dirfor,
16900cf42b62SRick Macklem 			    nd->nd_cred, p, 0);
16919ec7b004SRick Macklem 		}
16929ec7b004SRick Macklem 	}
16939ec7b004SRick Macklem 	if (!nd->nd_repstat)
16949ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
16959ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
16960cf42b62SRick Macklem 		getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
16979ec7b004SRick Macklem 	if (dirp) {
16980cf42b62SRick Macklem 		diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
16999ec7b004SRick Macklem 		vrele(dirp);
17009ec7b004SRick Macklem 	}
17019ec7b004SRick Macklem 	vrele(vp);
17029ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
17039ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &at);
17049ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
17059ec7b004SRick Macklem 	} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
17069ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
17079ec7b004SRick Macklem 		*tl++ = newnfs_false;
17089ec7b004SRick Macklem 		txdr_hyper(dirfor.na_filerev, tl);
17099ec7b004SRick Macklem 		tl += 2;
17109ec7b004SRick Macklem 		txdr_hyper(diraft.na_filerev, tl);
17119ec7b004SRick Macklem 	}
1712a9285ae5SZack Kirsch 
1713a9285ae5SZack Kirsch out:
1714a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
1715a9285ae5SZack Kirsch 	return (error);
17169ec7b004SRick Macklem }
17179ec7b004SRick Macklem 
17189ec7b004SRick Macklem /*
17199ec7b004SRick Macklem  * nfs symbolic link service
17209ec7b004SRick Macklem  */
17219ec7b004SRick Macklem APPLESTATIC int
17229ec7b004SRick Macklem nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
17239ec7b004SRick Macklem     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
17249ec7b004SRick Macklem     struct nfsexstuff *exp)
17259ec7b004SRick Macklem {
17269ec7b004SRick Macklem 	struct nfsvattr nva, dirfor, diraft;
17279ec7b004SRick Macklem 	struct nameidata named;
1728a9285ae5SZack Kirsch 	int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
17299ec7b004SRick Macklem 	vnode_t dirp = NULL;
17309ec7b004SRick Macklem 	char *bufp, *pathcp = NULL;
17319ec7b004SRick Macklem 	u_long *hashp;
17329ec7b004SRick Macklem 
17339ec7b004SRick Macklem 	if (nd->nd_repstat) {
17349ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1735a9285ae5SZack Kirsch 		goto out;
17369ec7b004SRick Macklem 	}
17379ec7b004SRick Macklem 	if (vpp)
17389ec7b004SRick Macklem 		*vpp = NULL;
17399ec7b004SRick Macklem 	NFSVNO_ATTRINIT(&nva);
17409ec7b004SRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
17416c21f6edSKonstantin Belousov 	    LOCKPARENT | SAVESTART | NOCACHE);
17429ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
17439ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
17449ec7b004SRick Macklem 	if (!error && !nd->nd_repstat)
17459ec7b004SRick Macklem 		error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
17469ec7b004SRick Macklem 	if (error) {
17479ec7b004SRick Macklem 		vrele(dp);
17489ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
1749a9285ae5SZack Kirsch 		goto out;
17509ec7b004SRick Macklem 	}
17519ec7b004SRick Macklem 	if (!nd->nd_repstat) {
17529ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
17539ec7b004SRick Macklem 	} else {
17549ec7b004SRick Macklem 		vrele(dp);
17559ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
17569ec7b004SRick Macklem 	}
17579ec7b004SRick Macklem 	if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
17589ec7b004SRick Macklem 		vrele(dirp);
17599ec7b004SRick Macklem 		dirp = NULL;
17609ec7b004SRick Macklem 	}
17619ec7b004SRick Macklem 
17629ec7b004SRick Macklem 	/*
17639ec7b004SRick Macklem 	 * And call nfsrvd_symlinksub() to do the common code. It will
17649ec7b004SRick Macklem 	 * return EBADRPC upon a parsing error, 0 otherwise.
17659ec7b004SRick Macklem 	 */
17669ec7b004SRick Macklem 	if (!nd->nd_repstat) {
17679ec7b004SRick Macklem 		if (dirp != NULL)
17689ec7b004SRick Macklem 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
17690cf42b62SRick Macklem 			    p, 0);
17709ec7b004SRick Macklem 		nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
17719ec7b004SRick Macklem 		    &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
17729ec7b004SRick Macklem 		    pathcp, pathlen);
17739ec7b004SRick Macklem 	} else if (dirp != NULL) {
17740cf42b62SRick Macklem 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
17759ec7b004SRick Macklem 		vrele(dirp);
17769ec7b004SRick Macklem 	}
17779ec7b004SRick Macklem 	if (pathcp)
1778222daa42SConrad Meyer 		free(pathcp, M_TEMP);
17799ec7b004SRick Macklem 
17809ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
17819ec7b004SRick Macklem 		if (!nd->nd_repstat) {
17829ec7b004SRick Macklem 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
17839ec7b004SRick Macklem 			nfsrv_postopattr(nd, 0, &nva);
17849ec7b004SRick Macklem 		}
17859ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
17869ec7b004SRick Macklem 	}
1787a9285ae5SZack Kirsch 
1788a9285ae5SZack Kirsch out:
1789a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
1790a9285ae5SZack Kirsch 	return (error);
17919ec7b004SRick Macklem }
17929ec7b004SRick Macklem 
17939ec7b004SRick Macklem /*
17949ec7b004SRick Macklem  * Common code for creating a symbolic link.
17959ec7b004SRick Macklem  */
17969ec7b004SRick Macklem static void
17979ec7b004SRick Macklem nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
17989ec7b004SRick Macklem     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
17999ec7b004SRick Macklem     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
18009ec7b004SRick Macklem     int *diraft_retp, nfsattrbit_t *attrbitp,
18019ec7b004SRick Macklem     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
18029ec7b004SRick Macklem     int pathlen)
18039ec7b004SRick Macklem {
18049ec7b004SRick Macklem 	u_int32_t *tl;
18059ec7b004SRick Macklem 
18069ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
18079ec7b004SRick Macklem 	    !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
18089ec7b004SRick Macklem 	if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
18099ec7b004SRick Macklem 		nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
18109ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
18119ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
18129ec7b004SRick Macklem 			if (!nd->nd_repstat)
18139ec7b004SRick Macklem 				nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
18140cf42b62SRick Macklem 				    nvap, nd->nd_cred, p, 1);
18159ec7b004SRick Macklem 		}
181681f78d99SRick Macklem 		if (vpp != NULL && nd->nd_repstat == 0) {
1817a9989634SZack Kirsch 			NFSVOPUNLOCK(ndp->ni_vp, 0);
18189ec7b004SRick Macklem 			*vpp = ndp->ni_vp;
181981f78d99SRick Macklem 		} else
18209ec7b004SRick Macklem 			vput(ndp->ni_vp);
18219ec7b004SRick Macklem 	}
18229ec7b004SRick Macklem 	if (dirp) {
18230cf42b62SRick Macklem 		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
18249ec7b004SRick Macklem 		vrele(dirp);
18259ec7b004SRick Macklem 	}
18269ec7b004SRick Macklem 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
18279ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
18289ec7b004SRick Macklem 		*tl++ = newnfs_false;
18299ec7b004SRick Macklem 		txdr_hyper(dirforp->na_filerev, tl);
18309ec7b004SRick Macklem 		tl += 2;
18319ec7b004SRick Macklem 		txdr_hyper(diraftp->na_filerev, tl);
18329ec7b004SRick Macklem 		(void) nfsrv_putattrbit(nd, attrbitp);
18339ec7b004SRick Macklem 	}
1834a9285ae5SZack Kirsch 
1835a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
18369ec7b004SRick Macklem }
18379ec7b004SRick Macklem 
18389ec7b004SRick Macklem /*
18399ec7b004SRick Macklem  * nfs mkdir service
18409ec7b004SRick Macklem  */
18419ec7b004SRick Macklem APPLESTATIC int
18429ec7b004SRick Macklem nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
18439ec7b004SRick Macklem     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
18449ec7b004SRick Macklem     struct nfsexstuff *exp)
18459ec7b004SRick Macklem {
18469ec7b004SRick Macklem 	struct nfsvattr nva, dirfor, diraft;
18479ec7b004SRick Macklem 	struct nameidata named;
18489ec7b004SRick Macklem 	u_int32_t *tl;
1849a9285ae5SZack Kirsch 	int error = 0, dirfor_ret = 1, diraft_ret = 1;
18509ec7b004SRick Macklem 	vnode_t dirp = NULL;
18519ec7b004SRick Macklem 	char *bufp;
18529ec7b004SRick Macklem 	u_long *hashp;
18539ec7b004SRick Macklem 
18549ec7b004SRick Macklem 	if (nd->nd_repstat) {
18559ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1856a9285ae5SZack Kirsch 		goto out;
18579ec7b004SRick Macklem 	}
1858f61786cbSRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
18596c21f6edSKonstantin Belousov 	    LOCKPARENT | SAVENAME | NOCACHE);
18609ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
18619ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1862a9285ae5SZack Kirsch 	if (error)
1863a9285ae5SZack Kirsch 		goto nfsmout;
18649ec7b004SRick Macklem 	if (!nd->nd_repstat) {
18659ec7b004SRick Macklem 		NFSVNO_ATTRINIT(&nva);
18669ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
1867d8a5961fSMarcelo Araujo 			error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1868a9285ae5SZack Kirsch 			if (error)
1869a9285ae5SZack Kirsch 				goto nfsmout;
18709ec7b004SRick Macklem 		} else {
18719ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
18729ec7b004SRick Macklem 			nva.na_mode = nfstov_mode(*tl++);
18739ec7b004SRick Macklem 		}
18749ec7b004SRick Macklem 	}
18759ec7b004SRick Macklem 	if (!nd->nd_repstat) {
18769ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
18779ec7b004SRick Macklem 	} else {
18789ec7b004SRick Macklem 		vrele(dp);
18799ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
18809ec7b004SRick Macklem 	}
18819ec7b004SRick Macklem 	if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
18829ec7b004SRick Macklem 		vrele(dirp);
18839ec7b004SRick Macklem 		dirp = NULL;
18849ec7b004SRick Macklem 	}
18859ec7b004SRick Macklem 	if (nd->nd_repstat) {
18869ec7b004SRick Macklem 		if (dirp != NULL) {
18879ec7b004SRick Macklem 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
18880cf42b62SRick Macklem 			    p, 0);
18899ec7b004SRick Macklem 			vrele(dirp);
18909ec7b004SRick Macklem 		}
18919ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
18929ec7b004SRick Macklem 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
18939ec7b004SRick Macklem 			    &diraft);
1894a9285ae5SZack Kirsch 		goto out;
18959ec7b004SRick Macklem 	}
18969ec7b004SRick Macklem 	if (dirp != NULL)
18970cf42b62SRick Macklem 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
18989ec7b004SRick Macklem 
18999ec7b004SRick Macklem 	/*
19009ec7b004SRick Macklem 	 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
19019ec7b004SRick Macklem 	 */
19029ec7b004SRick Macklem 	nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
19039ec7b004SRick Macklem 	    &diraft_ret, NULL, NULL, p, exp);
19049ec7b004SRick Macklem 
19059ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
19069ec7b004SRick Macklem 		if (!nd->nd_repstat) {
19079ec7b004SRick Macklem 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
19089ec7b004SRick Macklem 			nfsrv_postopattr(nd, 0, &nva);
19099ec7b004SRick Macklem 		}
19109ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
19119ec7b004SRick Macklem 	} else if (!nd->nd_repstat) {
19129ec7b004SRick Macklem 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
19139ec7b004SRick Macklem 		nfsrv_fillattr(nd, &nva);
19149ec7b004SRick Macklem 	}
1915a9285ae5SZack Kirsch 
1916a9285ae5SZack Kirsch out:
1917a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
19189ec7b004SRick Macklem 	return (0);
19199ec7b004SRick Macklem nfsmout:
19209ec7b004SRick Macklem 	vrele(dp);
19219ec7b004SRick Macklem 	nfsvno_relpathbuf(&named);
1922a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
19239ec7b004SRick Macklem 	return (error);
19249ec7b004SRick Macklem }
19259ec7b004SRick Macklem 
19269ec7b004SRick Macklem /*
19279ec7b004SRick Macklem  * Code common to mkdir for V2,3 and 4.
19289ec7b004SRick Macklem  */
19299ec7b004SRick Macklem static void
19309ec7b004SRick Macklem nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
19319ec7b004SRick Macklem     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
19329ec7b004SRick Macklem     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
19339ec7b004SRick Macklem     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
19349ec7b004SRick Macklem     NFSPROC_T *p, struct nfsexstuff *exp)
19359ec7b004SRick Macklem {
19369ec7b004SRick Macklem 	vnode_t vp;
19379ec7b004SRick Macklem 	u_int32_t *tl;
19389ec7b004SRick Macklem 
19399ec7b004SRick Macklem 	NFSVNO_SETATTRVAL(nvap, type, VDIR);
19409ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
19419ec7b004SRick Macklem 	    nd->nd_cred, p, exp);
19429ec7b004SRick Macklem 	if (!nd->nd_repstat) {
19439ec7b004SRick Macklem 		vp = ndp->ni_vp;
19449ec7b004SRick Macklem 		nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
19459ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
19469ec7b004SRick Macklem 		if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
19479ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
19480cf42b62SRick Macklem 			    p, 1);
19499ec7b004SRick Macklem 		if (vpp && !nd->nd_repstat) {
1950c383087cSZack Kirsch 			NFSVOPUNLOCK(vp, 0);
19519ec7b004SRick Macklem 			*vpp = vp;
19529ec7b004SRick Macklem 		} else {
19539ec7b004SRick Macklem 			vput(vp);
19549ec7b004SRick Macklem 		}
19559ec7b004SRick Macklem 	}
19569ec7b004SRick Macklem 	if (dirp) {
19570cf42b62SRick Macklem 		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
19589ec7b004SRick Macklem 		vrele(dirp);
19599ec7b004SRick Macklem 	}
19609ec7b004SRick Macklem 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
19619ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
19629ec7b004SRick Macklem 		*tl++ = newnfs_false;
19639ec7b004SRick Macklem 		txdr_hyper(dirforp->na_filerev, tl);
19649ec7b004SRick Macklem 		tl += 2;
19659ec7b004SRick Macklem 		txdr_hyper(diraftp->na_filerev, tl);
19669ec7b004SRick Macklem 		(void) nfsrv_putattrbit(nd, attrbitp);
19679ec7b004SRick Macklem 	}
1968a9285ae5SZack Kirsch 
1969a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
19709ec7b004SRick Macklem }
19719ec7b004SRick Macklem 
19729ec7b004SRick Macklem /*
19739ec7b004SRick Macklem  * nfs commit service
19749ec7b004SRick Macklem  */
19759ec7b004SRick Macklem APPLESTATIC int
19769ec7b004SRick Macklem nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
19779ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
19789ec7b004SRick Macklem {
19799ec7b004SRick Macklem 	struct nfsvattr bfor, aft;
19809ec7b004SRick Macklem 	u_int32_t *tl;
19819ec7b004SRick Macklem 	int error = 0, for_ret = 1, aft_ret = 1, cnt;
19829ec7b004SRick Macklem 	u_int64_t off;
19839ec7b004SRick Macklem 
19849ec7b004SRick Macklem        if (nd->nd_repstat) {
19859ec7b004SRick Macklem 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1986a9285ae5SZack Kirsch 		goto out;
19879ec7b004SRick Macklem 	}
1988d8a5961fSMarcelo Araujo 
1989d8a5961fSMarcelo Araujo 	/* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */
1990d8a5961fSMarcelo Araujo 	if (vp->v_type != VREG) {
1991d8a5961fSMarcelo Araujo 		if (nd->nd_flag & ND_NFSV3)
1992d8a5961fSMarcelo Araujo 			error = NFSERR_NOTSUPP;
1993d8a5961fSMarcelo Araujo 		else
1994d8a5961fSMarcelo Araujo 			error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL;
1995d8a5961fSMarcelo Araujo 		goto nfsmout;
1996d8a5961fSMarcelo Araujo 	}
19979ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1998d8a5961fSMarcelo Araujo 
19999ec7b004SRick Macklem 	/*
20009ec7b004SRick Macklem 	 * XXX At this time VOP_FSYNC() does not accept offset and byte
20019ec7b004SRick Macklem 	 * count parameters, so these arguments are useless (someday maybe).
20029ec7b004SRick Macklem 	 */
20039ec7b004SRick Macklem 	off = fxdr_hyper(tl);
20049ec7b004SRick Macklem 	tl += 2;
20059ec7b004SRick Macklem 	cnt = fxdr_unsigned(int, *tl);
20069ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
20070cf42b62SRick Macklem 		for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
20089ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
20099ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
20100cf42b62SRick Macklem 		aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
20119ec7b004SRick Macklem 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
20129ec7b004SRick Macklem 	}
20139ec7b004SRick Macklem 	vput(vp);
20149ec7b004SRick Macklem 	if (!nd->nd_repstat) {
20159ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
20169ec7b004SRick Macklem 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
20179ec7b004SRick Macklem 		*tl = txdr_unsigned(nfsboottime.tv_usec);
20189ec7b004SRick Macklem 	}
2019a9285ae5SZack Kirsch 
2020a9285ae5SZack Kirsch out:
2021a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
20229ec7b004SRick Macklem 	return (0);
20239ec7b004SRick Macklem nfsmout:
20249ec7b004SRick Macklem 	vput(vp);
2025a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
20269ec7b004SRick Macklem 	return (error);
20279ec7b004SRick Macklem }
20289ec7b004SRick Macklem 
20299ec7b004SRick Macklem /*
20309ec7b004SRick Macklem  * nfs statfs service
20319ec7b004SRick Macklem  */
20329ec7b004SRick Macklem APPLESTATIC int
20339ec7b004SRick Macklem nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
20349ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
20359ec7b004SRick Macklem {
20369ec7b004SRick Macklem 	struct statfs *sf;
20379ec7b004SRick Macklem 	u_int32_t *tl;
20389ec7b004SRick Macklem 	int getret = 1;
20399ec7b004SRick Macklem 	struct nfsvattr at;
20409ec7b004SRick Macklem 	u_quad_t tval;
20419ec7b004SRick Macklem 
20422f304845SKonstantin Belousov 	sf = NULL;
20439ec7b004SRick Macklem 	if (nd->nd_repstat) {
20449ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &at);
2045a9285ae5SZack Kirsch 		goto out;
20469ec7b004SRick Macklem 	}
20472f304845SKonstantin Belousov 	sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2048dfd233edSAttilio Rao 	nd->nd_repstat = nfsvno_statfs(vp, sf);
20490cf42b62SRick Macklem 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
20509ec7b004SRick Macklem 	vput(vp);
20519ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
20529ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &at);
20539ec7b004SRick Macklem 	if (nd->nd_repstat)
2054a9285ae5SZack Kirsch 		goto out;
20559ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV2) {
20569ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
20579ec7b004SRick Macklem 		*tl++ = txdr_unsigned(NFS_V2MAXDATA);
20589ec7b004SRick Macklem 		*tl++ = txdr_unsigned(sf->f_bsize);
20599ec7b004SRick Macklem 		*tl++ = txdr_unsigned(sf->f_blocks);
20609ec7b004SRick Macklem 		*tl++ = txdr_unsigned(sf->f_bfree);
20619ec7b004SRick Macklem 		*tl = txdr_unsigned(sf->f_bavail);
20629ec7b004SRick Macklem 	} else {
20639ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
20649ec7b004SRick Macklem 		tval = (u_quad_t)sf->f_blocks;
20659ec7b004SRick Macklem 		tval *= (u_quad_t)sf->f_bsize;
20669ec7b004SRick Macklem 		txdr_hyper(tval, tl); tl += 2;
20679ec7b004SRick Macklem 		tval = (u_quad_t)sf->f_bfree;
20689ec7b004SRick Macklem 		tval *= (u_quad_t)sf->f_bsize;
20699ec7b004SRick Macklem 		txdr_hyper(tval, tl); tl += 2;
20709ec7b004SRick Macklem 		tval = (u_quad_t)sf->f_bavail;
20719ec7b004SRick Macklem 		tval *= (u_quad_t)sf->f_bsize;
20729ec7b004SRick Macklem 		txdr_hyper(tval, tl); tl += 2;
20739ec7b004SRick Macklem 		tval = (u_quad_t)sf->f_files;
20749ec7b004SRick Macklem 		txdr_hyper(tval, tl); tl += 2;
20759ec7b004SRick Macklem 		tval = (u_quad_t)sf->f_ffree;
20769ec7b004SRick Macklem 		txdr_hyper(tval, tl); tl += 2;
20779ec7b004SRick Macklem 		tval = (u_quad_t)sf->f_ffree;
20789ec7b004SRick Macklem 		txdr_hyper(tval, tl); tl += 2;
20799ec7b004SRick Macklem 		*tl = 0;
20809ec7b004SRick Macklem 	}
2081a9285ae5SZack Kirsch 
2082a9285ae5SZack Kirsch out:
20832f304845SKonstantin Belousov 	free(sf, M_STATFS);
2084a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
20859ec7b004SRick Macklem 	return (0);
20869ec7b004SRick Macklem }
20879ec7b004SRick Macklem 
20889ec7b004SRick Macklem /*
20899ec7b004SRick Macklem  * nfs fsinfo service
20909ec7b004SRick Macklem  */
20919ec7b004SRick Macklem APPLESTATIC int
20929ec7b004SRick Macklem nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
20939ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
20949ec7b004SRick Macklem {
20959ec7b004SRick Macklem 	u_int32_t *tl;
20969ec7b004SRick Macklem 	struct nfsfsinfo fs;
20979ec7b004SRick Macklem 	int getret = 1;
20989ec7b004SRick Macklem 	struct nfsvattr at;
20999ec7b004SRick Macklem 
21009ec7b004SRick Macklem 	if (nd->nd_repstat) {
21019ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &at);
2102a9285ae5SZack Kirsch 		goto out;
21039ec7b004SRick Macklem 	}
21040cf42b62SRick Macklem 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
21059ec7b004SRick Macklem 	nfsvno_getfs(&fs, isdgram);
21069ec7b004SRick Macklem 	vput(vp);
21079ec7b004SRick Macklem 	nfsrv_postopattr(nd, getret, &at);
21089ec7b004SRick Macklem 	NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
21099ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_rtmax);
21109ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_rtpref);
21119ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_rtmult);
21129ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_wtmax);
21139ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_wtpref);
21149ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_wtmult);
21159ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_dtpref);
21169ec7b004SRick Macklem 	txdr_hyper(fs.fs_maxfilesize, tl);
21179ec7b004SRick Macklem 	tl += 2;
21189ec7b004SRick Macklem 	txdr_nfsv3time(&fs.fs_timedelta, tl);
21199ec7b004SRick Macklem 	tl += 2;
21209ec7b004SRick Macklem 	*tl = txdr_unsigned(fs.fs_properties);
2121a9285ae5SZack Kirsch 
2122a9285ae5SZack Kirsch out:
2123a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
21249ec7b004SRick Macklem 	return (0);
21259ec7b004SRick Macklem }
21269ec7b004SRick Macklem 
21279ec7b004SRick Macklem /*
21289ec7b004SRick Macklem  * nfs pathconf service
21299ec7b004SRick Macklem  */
21309ec7b004SRick Macklem APPLESTATIC int
21319ec7b004SRick Macklem nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
21329ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
21339ec7b004SRick Macklem {
21349ec7b004SRick Macklem 	struct nfsv3_pathconf *pc;
21359ec7b004SRick Macklem 	int getret = 1;
2136b1288166SJohn Baldwin 	long linkmax, namemax, chownres, notrunc;
21379ec7b004SRick Macklem 	struct nfsvattr at;
21389ec7b004SRick Macklem 
21399ec7b004SRick Macklem 	if (nd->nd_repstat) {
21409ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &at);
2141a9285ae5SZack Kirsch 		goto out;
21429ec7b004SRick Macklem 	}
21439ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
21449ec7b004SRick Macklem 	    nd->nd_cred, p);
21459ec7b004SRick Macklem 	if (!nd->nd_repstat)
21469ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
21479ec7b004SRick Macklem 		    nd->nd_cred, p);
21489ec7b004SRick Macklem 	if (!nd->nd_repstat)
21499ec7b004SRick Macklem 		nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
21509ec7b004SRick Macklem 		    &chownres, nd->nd_cred, p);
21519ec7b004SRick Macklem 	if (!nd->nd_repstat)
21529ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, &notrunc,
21539ec7b004SRick Macklem 		    nd->nd_cred, p);
21540cf42b62SRick Macklem 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
21559ec7b004SRick Macklem 	vput(vp);
21569ec7b004SRick Macklem 	nfsrv_postopattr(nd, getret, &at);
21579ec7b004SRick Macklem 	if (!nd->nd_repstat) {
21589ec7b004SRick Macklem 		NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
21599ec7b004SRick Macklem 		pc->pc_linkmax = txdr_unsigned(linkmax);
21609ec7b004SRick Macklem 		pc->pc_namemax = txdr_unsigned(namemax);
21619ec7b004SRick Macklem 		pc->pc_notrunc = txdr_unsigned(notrunc);
21629ec7b004SRick Macklem 		pc->pc_chownrestricted = txdr_unsigned(chownres);
21639ec7b004SRick Macklem 
21649ec7b004SRick Macklem 		/*
21659ec7b004SRick Macklem 		 * These should probably be supported by VOP_PATHCONF(), but
21669ec7b004SRick Macklem 		 * until msdosfs is exportable (why would you want to?), the
21679ec7b004SRick Macklem 		 * Unix defaults should be ok.
21689ec7b004SRick Macklem 		 */
21699ec7b004SRick Macklem 		pc->pc_caseinsensitive = newnfs_false;
21709ec7b004SRick Macklem 		pc->pc_casepreserving = newnfs_true;
21719ec7b004SRick Macklem 	}
2172a9285ae5SZack Kirsch 
2173a9285ae5SZack Kirsch out:
2174a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
21759ec7b004SRick Macklem 	return (0);
21769ec7b004SRick Macklem }
21779ec7b004SRick Macklem 
21789ec7b004SRick Macklem /*
21799ec7b004SRick Macklem  * nfsv4 lock service
21809ec7b004SRick Macklem  */
21819ec7b004SRick Macklem APPLESTATIC int
21829ec7b004SRick Macklem nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
21839ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
21849ec7b004SRick Macklem {
21859ec7b004SRick Macklem 	u_int32_t *tl;
21869ec7b004SRick Macklem 	int i;
21879ec7b004SRick Macklem 	struct nfsstate *stp = NULL;
21889ec7b004SRick Macklem 	struct nfslock *lop;
21899ec7b004SRick Macklem 	struct nfslockconflict cf;
21909ec7b004SRick Macklem 	int error = 0;
21919ec7b004SRick Macklem 	u_short flags = NFSLCK_LOCK, lflags;
21929ec7b004SRick Macklem 	u_int64_t offset, len;
21939ec7b004SRick Macklem 	nfsv4stateid_t stateid;
21949ec7b004SRick Macklem 	nfsquad_t clientid;
21959ec7b004SRick Macklem 
21969ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
21979ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl++);
21989ec7b004SRick Macklem 	switch (i) {
21999ec7b004SRick Macklem 	case NFSV4LOCKT_READW:
22009ec7b004SRick Macklem 		flags |= NFSLCK_BLOCKING;
22019ec7b004SRick Macklem 	case NFSV4LOCKT_READ:
22029ec7b004SRick Macklem 		lflags = NFSLCK_READ;
22039ec7b004SRick Macklem 		break;
22049ec7b004SRick Macklem 	case NFSV4LOCKT_WRITEW:
22059ec7b004SRick Macklem 		flags |= NFSLCK_BLOCKING;
22069ec7b004SRick Macklem 	case NFSV4LOCKT_WRITE:
22079ec7b004SRick Macklem 		lflags = NFSLCK_WRITE;
22089ec7b004SRick Macklem 		break;
22099ec7b004SRick Macklem 	default:
22109ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
22119ec7b004SRick Macklem 		goto nfsmout;
221274b8d63dSPedro F. Giffuni 	}
22139ec7b004SRick Macklem 	if (*tl++ == newnfs_true)
22149ec7b004SRick Macklem 		flags |= NFSLCK_RECLAIM;
22159ec7b004SRick Macklem 	offset = fxdr_hyper(tl);
22169ec7b004SRick Macklem 	tl += 2;
22179ec7b004SRick Macklem 	len = fxdr_hyper(tl);
22189ec7b004SRick Macklem 	tl += 2;
22199ec7b004SRick Macklem 	if (*tl == newnfs_true)
22209ec7b004SRick Macklem 		flags |= NFSLCK_OPENTOLOCK;
22219ec7b004SRick Macklem 	if (flags & NFSLCK_OPENTOLOCK) {
22229ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
22239ec7b004SRick Macklem 		i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
22242a45247cSRick Macklem 		if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
22252a45247cSRick Macklem 			nd->nd_repstat = NFSERR_BADXDR;
22262a45247cSRick Macklem 			goto nfsmout;
22272a45247cSRick Macklem 		}
2228222daa42SConrad Meyer 		stp = malloc(sizeof (struct nfsstate) + i,
22299ec7b004SRick Macklem 			M_NFSDSTATE, M_WAITOK);
22309ec7b004SRick Macklem 		stp->ls_ownerlen = i;
22319ec7b004SRick Macklem 		stp->ls_op = nd->nd_rp;
22329ec7b004SRick Macklem 		stp->ls_seq = fxdr_unsigned(int, *tl++);
22339ec7b004SRick Macklem 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
22349ec7b004SRick Macklem 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
22359ec7b004SRick Macklem 			NFSX_STATEIDOTHER);
22369ec7b004SRick Macklem 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
22379ec7b004SRick Macklem 		stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
22389ec7b004SRick Macklem 		clientid.lval[0] = *tl++;
22399ec7b004SRick Macklem 		clientid.lval[1] = *tl++;
2240c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2241c59e4cc3SRick Macklem 			if ((nd->nd_flag & ND_NFSV41) != 0)
2242c59e4cc3SRick Macklem 				clientid.qval = nd->nd_clientid.qval;
2243c59e4cc3SRick Macklem 			else if (nd->nd_clientid.qval != clientid.qval)
2244c59e4cc3SRick Macklem 				printf("EEK3 multiple clids\n");
22459ec7b004SRick Macklem 		} else {
2246c59e4cc3SRick Macklem 			if ((nd->nd_flag & ND_NFSV41) != 0)
2247c59e4cc3SRick Macklem 				printf("EEK! no clientid from session\n");
22489ec7b004SRick Macklem 			nd->nd_flag |= ND_IMPLIEDCLID;
22499ec7b004SRick Macklem 			nd->nd_clientid.qval = clientid.qval;
22509ec7b004SRick Macklem 		}
22519ec7b004SRick Macklem 		error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
22529ec7b004SRick Macklem 		if (error)
22539ec7b004SRick Macklem 			goto nfsmout;
22549ec7b004SRick Macklem 	} else {
22559ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2256222daa42SConrad Meyer 		stp = malloc(sizeof (struct nfsstate),
22579ec7b004SRick Macklem 			M_NFSDSTATE, M_WAITOK);
22589ec7b004SRick Macklem 		stp->ls_ownerlen = 0;
22599ec7b004SRick Macklem 		stp->ls_op = nd->nd_rp;
22609ec7b004SRick Macklem 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
22619ec7b004SRick Macklem 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
22629ec7b004SRick Macklem 			NFSX_STATEIDOTHER);
22639ec7b004SRick Macklem 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
22649ec7b004SRick Macklem 		stp->ls_seq = fxdr_unsigned(int, *tl);
22659ec7b004SRick Macklem 		clientid.lval[0] = stp->ls_stateid.other[0];
22669ec7b004SRick Macklem 		clientid.lval[1] = stp->ls_stateid.other[1];
2267c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2268c59e4cc3SRick Macklem 			if ((nd->nd_flag & ND_NFSV41) != 0)
2269c59e4cc3SRick Macklem 				clientid.qval = nd->nd_clientid.qval;
2270c59e4cc3SRick Macklem 			else if (nd->nd_clientid.qval != clientid.qval)
2271c59e4cc3SRick Macklem 				printf("EEK4 multiple clids\n");
22729ec7b004SRick Macklem 		} else {
2273c59e4cc3SRick Macklem 			if ((nd->nd_flag & ND_NFSV41) != 0)
2274c59e4cc3SRick Macklem 				printf("EEK! no clientid from session\n");
22759ec7b004SRick Macklem 			nd->nd_flag |= ND_IMPLIEDCLID;
22769ec7b004SRick Macklem 			nd->nd_clientid.qval = clientid.qval;
22779ec7b004SRick Macklem 		}
22789ec7b004SRick Macklem 	}
2279222daa42SConrad Meyer 	lop = malloc(sizeof (struct nfslock),
22809ec7b004SRick Macklem 		M_NFSDLOCK, M_WAITOK);
22819ec7b004SRick Macklem 	lop->lo_first = offset;
22829ec7b004SRick Macklem 	if (len == NFS64BITSSET) {
22839ec7b004SRick Macklem 		lop->lo_end = NFS64BITSSET;
22849ec7b004SRick Macklem 	} else {
22859ec7b004SRick Macklem 		lop->lo_end = offset + len;
22869ec7b004SRick Macklem 		if (lop->lo_end <= lop->lo_first)
22879ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_INVAL;
22889ec7b004SRick Macklem 	}
22899ec7b004SRick Macklem 	lop->lo_flags = lflags;
22909ec7b004SRick Macklem 	stp->ls_flags = flags;
22919ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
22929ec7b004SRick Macklem 
22939ec7b004SRick Macklem 	/*
22949ec7b004SRick Macklem 	 * Do basic access checking.
22959ec7b004SRick Macklem 	 */
22969ec7b004SRick Macklem 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
22979ec7b004SRick Macklem 	    if (vnode_vtype(vp) == VDIR)
22989ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_ISDIR;
22999ec7b004SRick Macklem 	    else
23009ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
23019ec7b004SRick Macklem 	}
23029ec7b004SRick Macklem 	if (!nd->nd_repstat) {
23039ec7b004SRick Macklem 	    if (lflags & NFSLCK_WRITE) {
23048da45f2cSRick Macklem 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
23059ec7b004SRick Macklem 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
23068da45f2cSRick Macklem 		    NFSACCCHK_VPISLOCKED, NULL);
23079ec7b004SRick Macklem 	    } else {
23088da45f2cSRick Macklem 		nd->nd_repstat = nfsvno_accchk(vp, VREAD,
23099ec7b004SRick Macklem 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
23108da45f2cSRick Macklem 		    NFSACCCHK_VPISLOCKED, NULL);
23119ec7b004SRick Macklem 		if (nd->nd_repstat)
23128da45f2cSRick Macklem 		    nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
23139ec7b004SRick Macklem 			nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
23148da45f2cSRick Macklem 			NFSACCCHK_VPISLOCKED, NULL);
23159ec7b004SRick Macklem 	    }
23169ec7b004SRick Macklem 	}
23179ec7b004SRick Macklem 
23189ec7b004SRick Macklem 	/*
23199ec7b004SRick Macklem 	 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
23209ec7b004SRick Macklem 	 * seqid# gets updated. nfsrv_lockctrl() will return the value
23219ec7b004SRick Macklem 	 * of nd_repstat, if it gets that far.
23229ec7b004SRick Macklem 	 */
23239ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
23249ec7b004SRick Macklem 		&stateid, exp, nd, p);
23259ec7b004SRick Macklem 	if (lop)
2326222daa42SConrad Meyer 		free(lop, M_NFSDLOCK);
23279ec7b004SRick Macklem 	if (stp)
2328222daa42SConrad Meyer 		free(stp, M_NFSDSTATE);
23299ec7b004SRick Macklem 	if (!nd->nd_repstat) {
23309ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
23319ec7b004SRick Macklem 		*tl++ = txdr_unsigned(stateid.seqid);
23329ec7b004SRick Macklem 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
23339ec7b004SRick Macklem 	} else if (nd->nd_repstat == NFSERR_DENIED) {
23349ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
23359ec7b004SRick Macklem 		txdr_hyper(cf.cl_first, tl);
23369ec7b004SRick Macklem 		tl += 2;
23379ec7b004SRick Macklem 		if (cf.cl_end == NFS64BITSSET)
23389ec7b004SRick Macklem 			len = NFS64BITSSET;
23399ec7b004SRick Macklem 		else
23409ec7b004SRick Macklem 			len = cf.cl_end - cf.cl_first;
23419ec7b004SRick Macklem 		txdr_hyper(len, tl);
23429ec7b004SRick Macklem 		tl += 2;
23439ec7b004SRick Macklem 		if (cf.cl_flags == NFSLCK_WRITE)
23449ec7b004SRick Macklem 			*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
23459ec7b004SRick Macklem 		else
23469ec7b004SRick Macklem 			*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
23479ec7b004SRick Macklem 		*tl++ = stateid.other[0];
23489ec7b004SRick Macklem 		*tl = stateid.other[1];
23499ec7b004SRick Macklem 		(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
23509ec7b004SRick Macklem 	}
23519ec7b004SRick Macklem 	vput(vp);
2352a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
23539ec7b004SRick Macklem 	return (0);
23549ec7b004SRick Macklem nfsmout:
23559ec7b004SRick Macklem 	vput(vp);
23569ec7b004SRick Macklem 	if (stp)
2357222daa42SConrad Meyer 		free(stp, M_NFSDSTATE);
2358a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
23599ec7b004SRick Macklem 	return (error);
23609ec7b004SRick Macklem }
23619ec7b004SRick Macklem 
23629ec7b004SRick Macklem /*
23639ec7b004SRick Macklem  * nfsv4 lock test service
23649ec7b004SRick Macklem  */
23659ec7b004SRick Macklem APPLESTATIC int
23669ec7b004SRick Macklem nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
23679ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
23689ec7b004SRick Macklem {
23699ec7b004SRick Macklem 	u_int32_t *tl;
23709ec7b004SRick Macklem 	int i;
23719ec7b004SRick Macklem 	struct nfsstate *stp = NULL;
23729ec7b004SRick Macklem 	struct nfslock lo, *lop = &lo;
23739ec7b004SRick Macklem 	struct nfslockconflict cf;
23749ec7b004SRick Macklem 	int error = 0;
23759ec7b004SRick Macklem 	nfsv4stateid_t stateid;
23769ec7b004SRick Macklem 	nfsquad_t clientid;
23779ec7b004SRick Macklem 	u_int64_t len;
23789ec7b004SRick Macklem 
23799ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
23809ec7b004SRick Macklem 	i = fxdr_unsigned(int, *(tl + 7));
23812a45247cSRick Macklem 	if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
23822a45247cSRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
23832a45247cSRick Macklem 		goto nfsmout;
23842a45247cSRick Macklem 	}
2385222daa42SConrad Meyer 	stp = malloc(sizeof (struct nfsstate) + i,
23869ec7b004SRick Macklem 	    M_NFSDSTATE, M_WAITOK);
23879ec7b004SRick Macklem 	stp->ls_ownerlen = i;
23889ec7b004SRick Macklem 	stp->ls_op = NULL;
23899ec7b004SRick Macklem 	stp->ls_flags = NFSLCK_TEST;
23909ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
23919ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl++);
23929ec7b004SRick Macklem 	switch (i) {
23939ec7b004SRick Macklem 	case NFSV4LOCKT_READW:
23949ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_BLOCKING;
23959ec7b004SRick Macklem 	case NFSV4LOCKT_READ:
23969ec7b004SRick Macklem 		lo.lo_flags = NFSLCK_READ;
23979ec7b004SRick Macklem 		break;
23989ec7b004SRick Macklem 	case NFSV4LOCKT_WRITEW:
23999ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_BLOCKING;
24009ec7b004SRick Macklem 	case NFSV4LOCKT_WRITE:
24019ec7b004SRick Macklem 		lo.lo_flags = NFSLCK_WRITE;
24029ec7b004SRick Macklem 		break;
24039ec7b004SRick Macklem 	default:
24049ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
24059ec7b004SRick Macklem 		goto nfsmout;
240674b8d63dSPedro F. Giffuni 	}
24079ec7b004SRick Macklem 	lo.lo_first = fxdr_hyper(tl);
24089ec7b004SRick Macklem 	tl += 2;
24099ec7b004SRick Macklem 	len = fxdr_hyper(tl);
24109ec7b004SRick Macklem 	if (len == NFS64BITSSET) {
24119ec7b004SRick Macklem 		lo.lo_end = NFS64BITSSET;
24129ec7b004SRick Macklem 	} else {
24139ec7b004SRick Macklem 		lo.lo_end = lo.lo_first + len;
24149ec7b004SRick Macklem 		if (lo.lo_end <= lo.lo_first)
24159ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_INVAL;
24169ec7b004SRick Macklem 	}
24179ec7b004SRick Macklem 	tl += 2;
24189ec7b004SRick Macklem 	clientid.lval[0] = *tl++;
24199ec7b004SRick Macklem 	clientid.lval[1] = *tl;
2420c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2421c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
2422c59e4cc3SRick Macklem 			clientid.qval = nd->nd_clientid.qval;
2423c59e4cc3SRick Macklem 		else if (nd->nd_clientid.qval != clientid.qval)
2424c59e4cc3SRick Macklem 			printf("EEK5 multiple clids\n");
24259ec7b004SRick Macklem 	} else {
2426c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
2427c59e4cc3SRick Macklem 			printf("EEK! no clientid from session\n");
24289ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
24299ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
24309ec7b004SRick Macklem 	}
24319ec7b004SRick Macklem 	error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
24329ec7b004SRick Macklem 	if (error)
24339ec7b004SRick Macklem 		goto nfsmout;
24349ec7b004SRick Macklem 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
24359ec7b004SRick Macklem 	    if (vnode_vtype(vp) == VDIR)
24369ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_ISDIR;
24379ec7b004SRick Macklem 	    else
24389ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
24399ec7b004SRick Macklem 	}
24409ec7b004SRick Macklem 	if (!nd->nd_repstat)
24419ec7b004SRick Macklem 	  nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
24429ec7b004SRick Macklem 	    &stateid, exp, nd, p);
24439ec7b004SRick Macklem 	if (nd->nd_repstat) {
24449ec7b004SRick Macklem 	    if (nd->nd_repstat == NFSERR_DENIED) {
24459ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
24469ec7b004SRick Macklem 		txdr_hyper(cf.cl_first, tl);
24479ec7b004SRick Macklem 		tl += 2;
24489ec7b004SRick Macklem 		if (cf.cl_end == NFS64BITSSET)
24499ec7b004SRick Macklem 			len = NFS64BITSSET;
24509ec7b004SRick Macklem 		else
24519ec7b004SRick Macklem 			len = cf.cl_end - cf.cl_first;
24529ec7b004SRick Macklem 		txdr_hyper(len, tl);
24539ec7b004SRick Macklem 		tl += 2;
24549ec7b004SRick Macklem 		if (cf.cl_flags == NFSLCK_WRITE)
24559ec7b004SRick Macklem 			*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
24569ec7b004SRick Macklem 		else
24579ec7b004SRick Macklem 			*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
24589ec7b004SRick Macklem 		*tl++ = stp->ls_stateid.other[0];
24599ec7b004SRick Macklem 		*tl = stp->ls_stateid.other[1];
24609ec7b004SRick Macklem 		(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
24619ec7b004SRick Macklem 	    }
24629ec7b004SRick Macklem 	}
24639ec7b004SRick Macklem 	vput(vp);
24645ecc225fSConrad Meyer 	if (stp)
2465222daa42SConrad Meyer 		free(stp, M_NFSDSTATE);
2466a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
24679ec7b004SRick Macklem 	return (0);
24689ec7b004SRick Macklem nfsmout:
24699ec7b004SRick Macklem 	vput(vp);
24709ec7b004SRick Macklem 	if (stp)
2471222daa42SConrad Meyer 		free(stp, M_NFSDSTATE);
2472a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
24739ec7b004SRick Macklem 	return (error);
24749ec7b004SRick Macklem }
24759ec7b004SRick Macklem 
24769ec7b004SRick Macklem /*
24779ec7b004SRick Macklem  * nfsv4 unlock service
24789ec7b004SRick Macklem  */
24799ec7b004SRick Macklem APPLESTATIC int
24809ec7b004SRick Macklem nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
24819ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
24829ec7b004SRick Macklem {
24839ec7b004SRick Macklem 	u_int32_t *tl;
24849ec7b004SRick Macklem 	int i;
24859ec7b004SRick Macklem 	struct nfsstate *stp;
24869ec7b004SRick Macklem 	struct nfslock *lop;
24879ec7b004SRick Macklem 	int error = 0;
24889ec7b004SRick Macklem 	nfsv4stateid_t stateid;
24899ec7b004SRick Macklem 	nfsquad_t clientid;
24909ec7b004SRick Macklem 	u_int64_t len;
24919ec7b004SRick Macklem 
24929ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2493222daa42SConrad Meyer 	stp = malloc(sizeof (struct nfsstate),
24949ec7b004SRick Macklem 	    M_NFSDSTATE, M_WAITOK);
2495222daa42SConrad Meyer 	lop = malloc(sizeof (struct nfslock),
24969ec7b004SRick Macklem 	    M_NFSDLOCK, M_WAITOK);
24979ec7b004SRick Macklem 	stp->ls_flags = NFSLCK_UNLOCK;
24989ec7b004SRick Macklem 	lop->lo_flags = NFSLCK_UNLOCK;
24999ec7b004SRick Macklem 	stp->ls_op = nd->nd_rp;
25009ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl++);
25019ec7b004SRick Macklem 	switch (i) {
25029ec7b004SRick Macklem 	case NFSV4LOCKT_READW:
25039ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_BLOCKING;
25049ec7b004SRick Macklem 	case NFSV4LOCKT_READ:
25059ec7b004SRick Macklem 		break;
25069ec7b004SRick Macklem 	case NFSV4LOCKT_WRITEW:
25079ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_BLOCKING;
25089ec7b004SRick Macklem 	case NFSV4LOCKT_WRITE:
25099ec7b004SRick Macklem 		break;
25109ec7b004SRick Macklem 	default:
25119ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
25122a45247cSRick Macklem 		free(stp, M_NFSDSTATE);
25132a45247cSRick Macklem 		free(lop, M_NFSDLOCK);
25149ec7b004SRick Macklem 		goto nfsmout;
251574b8d63dSPedro F. Giffuni 	}
25169ec7b004SRick Macklem 	stp->ls_ownerlen = 0;
25179ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
25189ec7b004SRick Macklem 	stp->ls_seq = fxdr_unsigned(int, *tl++);
25199ec7b004SRick Macklem 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
25209ec7b004SRick Macklem 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
25219ec7b004SRick Macklem 	    NFSX_STATEIDOTHER);
25229ec7b004SRick Macklem 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
25239ec7b004SRick Macklem 	lop->lo_first = fxdr_hyper(tl);
25249ec7b004SRick Macklem 	tl += 2;
25259ec7b004SRick Macklem 	len = fxdr_hyper(tl);
25269ec7b004SRick Macklem 	if (len == NFS64BITSSET) {
25279ec7b004SRick Macklem 		lop->lo_end = NFS64BITSSET;
25289ec7b004SRick Macklem 	} else {
25299ec7b004SRick Macklem 		lop->lo_end = lop->lo_first + len;
25309ec7b004SRick Macklem 		if (lop->lo_end <= lop->lo_first)
25319ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_INVAL;
25329ec7b004SRick Macklem 	}
25339ec7b004SRick Macklem 	clientid.lval[0] = stp->ls_stateid.other[0];
25349ec7b004SRick Macklem 	clientid.lval[1] = stp->ls_stateid.other[1];
2535c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2536c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
2537c59e4cc3SRick Macklem 			clientid.qval = nd->nd_clientid.qval;
2538c59e4cc3SRick Macklem 		else if (nd->nd_clientid.qval != clientid.qval)
2539c59e4cc3SRick Macklem 			printf("EEK6 multiple clids\n");
25409ec7b004SRick Macklem 	} else {
2541c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
2542c59e4cc3SRick Macklem 			printf("EEK! no clientid from session\n");
25439ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
25449ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
25459ec7b004SRick Macklem 	}
25469ec7b004SRick Macklem 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
25479ec7b004SRick Macklem 	    if (vnode_vtype(vp) == VDIR)
25489ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_ISDIR;
25499ec7b004SRick Macklem 	    else
25509ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
25519ec7b004SRick Macklem 	}
25529ec7b004SRick Macklem 	/*
25539ec7b004SRick Macklem 	 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
25549ec7b004SRick Macklem 	 * seqid# gets incremented. nfsrv_lockctrl() will return the
25559ec7b004SRick Macklem 	 * value of nd_repstat, if it gets that far.
25569ec7b004SRick Macklem 	 */
25579ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
25589ec7b004SRick Macklem 	    &stateid, exp, nd, p);
25599ec7b004SRick Macklem 	if (stp)
2560222daa42SConrad Meyer 		free(stp, M_NFSDSTATE);
25619ec7b004SRick Macklem 	if (lop)
2562222daa42SConrad Meyer 		free(lop, M_NFSDLOCK);
25639ec7b004SRick Macklem 	if (!nd->nd_repstat) {
25649ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
25659ec7b004SRick Macklem 		*tl++ = txdr_unsigned(stateid.seqid);
25669ec7b004SRick Macklem 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
25679ec7b004SRick Macklem 	}
25689ec7b004SRick Macklem nfsmout:
25699ec7b004SRick Macklem 	vput(vp);
2570a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
25719ec7b004SRick Macklem 	return (error);
25729ec7b004SRick Macklem }
25739ec7b004SRick Macklem 
25749ec7b004SRick Macklem /*
25759ec7b004SRick Macklem  * nfsv4 open service
25769ec7b004SRick Macklem  */
25779ec7b004SRick Macklem APPLESTATIC int
25789ec7b004SRick Macklem nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
25799ec7b004SRick Macklem     vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
25809ec7b004SRick Macklem     struct nfsexstuff *exp)
25819ec7b004SRick Macklem {
25829ec7b004SRick Macklem 	u_int32_t *tl;
2583c59e4cc3SRick Macklem 	int i, retext;
25849ec7b004SRick Macklem 	struct nfsstate *stp = NULL;
25859ec7b004SRick Macklem 	int error = 0, create, claim, exclusive_flag = 0;
25869ec7b004SRick Macklem 	u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
25879ec7b004SRick Macklem 	int how = NFSCREATE_UNCHECKED;
2588086f6e0cSRick Macklem 	int32_t cverf[2], tverf[2] = { 0, 0 };
25899ec7b004SRick Macklem 	vnode_t vp = NULL, dirp = NULL;
25909ec7b004SRick Macklem 	struct nfsvattr nva, dirfor, diraft;
25919ec7b004SRick Macklem 	struct nameidata named;
25929ec7b004SRick Macklem 	nfsv4stateid_t stateid, delegstateid;
25939ec7b004SRick Macklem 	nfsattrbit_t attrbits;
25949ec7b004SRick Macklem 	nfsquad_t clientid;
25959ec7b004SRick Macklem 	char *bufp = NULL;
25969ec7b004SRick Macklem 	u_long *hashp;
25979ec7b004SRick Macklem 	NFSACL_T *aclp = NULL;
25989ec7b004SRick Macklem 
25999ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
2600c3e22f83SRick Macklem 	aclp = acl_alloc(M_WAITOK);
26019ec7b004SRick Macklem 	aclp->acl_cnt = 0;
26029ec7b004SRick Macklem #endif
26039ec7b004SRick Macklem 	NFSZERO_ATTRBIT(&attrbits);
26049ec7b004SRick Macklem 	named.ni_startdir = NULL;
26059ec7b004SRick Macklem 	named.ni_cnd.cn_nameiop = 0;
26069ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
26079ec7b004SRick Macklem 	i = fxdr_unsigned(int, *(tl + 5));
26082a45247cSRick Macklem 	if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
26092a45247cSRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
2610a9285ae5SZack Kirsch 		goto nfsmout;
26112a45247cSRick Macklem 	}
2612222daa42SConrad Meyer 	stp = malloc(sizeof (struct nfsstate) + i,
26139ec7b004SRick Macklem 	    M_NFSDSTATE, M_WAITOK);
26149ec7b004SRick Macklem 	stp->ls_ownerlen = i;
26159ec7b004SRick Macklem 	stp->ls_op = nd->nd_rp;
26169ec7b004SRick Macklem 	stp->ls_flags = NFSLCK_OPEN;
26179ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
26189ec7b004SRick Macklem 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
26199ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl++);
2620c59e4cc3SRick Macklem 	retext = 0;
2621c59e4cc3SRick Macklem 	if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
2622c59e4cc3SRick Macklem 	    NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
2623c59e4cc3SRick Macklem 		retext = 1;
2624c59e4cc3SRick Macklem 		/* For now, ignore these. */
2625c59e4cc3SRick Macklem 		i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
2626c59e4cc3SRick Macklem 		switch (i & NFSV4OPEN_WANTDELEGMASK) {
2627c59e4cc3SRick Macklem 		case NFSV4OPEN_WANTANYDELEG:
2628c59e4cc3SRick Macklem 			stp->ls_flags |= (NFSLCK_WANTRDELEG |
2629c59e4cc3SRick Macklem 			    NFSLCK_WANTWDELEG);
2630c59e4cc3SRick Macklem 			i &= ~NFSV4OPEN_WANTDELEGMASK;
2631c59e4cc3SRick Macklem 			break;
2632c59e4cc3SRick Macklem 		case NFSV4OPEN_WANTREADDELEG:
2633c59e4cc3SRick Macklem 			stp->ls_flags |= NFSLCK_WANTRDELEG;
2634c59e4cc3SRick Macklem 			i &= ~NFSV4OPEN_WANTDELEGMASK;
2635c59e4cc3SRick Macklem 			break;
2636c59e4cc3SRick Macklem 		case NFSV4OPEN_WANTWRITEDELEG:
2637c59e4cc3SRick Macklem 			stp->ls_flags |= NFSLCK_WANTWDELEG;
2638c59e4cc3SRick Macklem 			i &= ~NFSV4OPEN_WANTDELEGMASK;
2639c59e4cc3SRick Macklem 			break;
2640c59e4cc3SRick Macklem 		case NFSV4OPEN_WANTNODELEG:
2641c59e4cc3SRick Macklem 			stp->ls_flags |= NFSLCK_WANTNODELEG;
2642c59e4cc3SRick Macklem 			i &= ~NFSV4OPEN_WANTDELEGMASK;
2643c59e4cc3SRick Macklem 			break;
2644c59e4cc3SRick Macklem 		case NFSV4OPEN_WANTCANCEL:
2645c59e4cc3SRick Macklem 			printf("NFSv4: ignore Open WantCancel\n");
2646c59e4cc3SRick Macklem 			i &= ~NFSV4OPEN_WANTDELEGMASK;
2647c59e4cc3SRick Macklem 			break;
2648c59e4cc3SRick Macklem 		default:
2649c59e4cc3SRick Macklem 			/* nd_repstat will be set to NFSERR_INVAL below. */
2650c59e4cc3SRick Macklem 			break;
265174b8d63dSPedro F. Giffuni 		}
2652c59e4cc3SRick Macklem 	}
26539ec7b004SRick Macklem 	switch (i) {
26549ec7b004SRick Macklem 	case NFSV4OPEN_ACCESSREAD:
26559ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_READACCESS;
26569ec7b004SRick Macklem 		break;
26579ec7b004SRick Macklem 	case NFSV4OPEN_ACCESSWRITE:
26589ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_WRITEACCESS;
26599ec7b004SRick Macklem 		break;
26609ec7b004SRick Macklem 	case NFSV4OPEN_ACCESSBOTH:
26619ec7b004SRick Macklem 		stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
26629ec7b004SRick Macklem 		break;
26639ec7b004SRick Macklem 	default:
26649ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
266574b8d63dSPedro F. Giffuni 	}
26669ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl++);
26679ec7b004SRick Macklem 	switch (i) {
26689ec7b004SRick Macklem 	case NFSV4OPEN_DENYNONE:
26699ec7b004SRick Macklem 		break;
26709ec7b004SRick Macklem 	case NFSV4OPEN_DENYREAD:
26719ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_READDENY;
26729ec7b004SRick Macklem 		break;
26739ec7b004SRick Macklem 	case NFSV4OPEN_DENYWRITE:
26749ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_WRITEDENY;
26759ec7b004SRick Macklem 		break;
26769ec7b004SRick Macklem 	case NFSV4OPEN_DENYBOTH:
26779ec7b004SRick Macklem 		stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
26789ec7b004SRick Macklem 		break;
26799ec7b004SRick Macklem 	default:
26809ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
268174b8d63dSPedro F. Giffuni 	}
26829ec7b004SRick Macklem 	clientid.lval[0] = *tl++;
26839ec7b004SRick Macklem 	clientid.lval[1] = *tl;
2684c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2685c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
2686c59e4cc3SRick Macklem 			clientid.qval = nd->nd_clientid.qval;
2687c59e4cc3SRick Macklem 		else if (nd->nd_clientid.qval != clientid.qval)
2688c59e4cc3SRick Macklem 			printf("EEK7 multiple clids\n");
26899ec7b004SRick Macklem 	} else {
2690c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
2691c59e4cc3SRick Macklem 			printf("EEK! no clientid from session\n");
26929ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
26939ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
26949ec7b004SRick Macklem 	}
26959ec7b004SRick Macklem 	error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2696a9285ae5SZack Kirsch 	if (error)
2697a9285ae5SZack Kirsch 		goto nfsmout;
26989ec7b004SRick Macklem 	NFSVNO_ATTRINIT(&nva);
26999ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
27009ec7b004SRick Macklem 	create = fxdr_unsigned(int, *tl);
27019ec7b004SRick Macklem 	if (!nd->nd_repstat)
27020cf42b62SRick Macklem 		nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
27039ec7b004SRick Macklem 	if (create == NFSV4OPEN_CREATE) {
27049ec7b004SRick Macklem 		nva.na_type = VREG;
27059ec7b004SRick Macklem 		nva.na_mode = 0;
27069ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
27079ec7b004SRick Macklem 		how = fxdr_unsigned(int, *tl);
27089ec7b004SRick Macklem 		switch (how) {
27099ec7b004SRick Macklem 		case NFSCREATE_UNCHECKED:
27109ec7b004SRick Macklem 		case NFSCREATE_GUARDED:
2711d8a5961fSMarcelo Araujo 			error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
2712a9285ae5SZack Kirsch 			if (error)
2713a9285ae5SZack Kirsch 				goto nfsmout;
27149ec7b004SRick Macklem 			/*
27159ec7b004SRick Macklem 			 * If the na_gid being set is the same as that of
27169ec7b004SRick Macklem 			 * the directory it is going in, clear it, since
27179ec7b004SRick Macklem 			 * that is what will be set by default. This allows
27189ec7b004SRick Macklem 			 * a user that isn't in that group to do the create.
27199ec7b004SRick Macklem 			 */
27209ec7b004SRick Macklem 			if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
27219ec7b004SRick Macklem 			    nva.na_gid == dirfor.na_gid)
27229ec7b004SRick Macklem 				NFSVNO_UNSET(&nva, gid);
27239ec7b004SRick Macklem 			if (!nd->nd_repstat)
27249ec7b004SRick Macklem 				nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
27259ec7b004SRick Macklem 			break;
27269ec7b004SRick Macklem 		case NFSCREATE_EXCLUSIVE:
27279ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2728086f6e0cSRick Macklem 			cverf[0] = *tl++;
2729086f6e0cSRick Macklem 			cverf[1] = *tl;
27309ec7b004SRick Macklem 			break;
2731c59e4cc3SRick Macklem 		case NFSCREATE_EXCLUSIVE41:
2732c59e4cc3SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2733c59e4cc3SRick Macklem 			cverf[0] = *tl++;
2734c59e4cc3SRick Macklem 			cverf[1] = *tl;
2735d8a5961fSMarcelo Araujo 			error = nfsv4_sattr(nd, vp, &nva, &attrbits, aclp, p);
2736c59e4cc3SRick Macklem 			if (error != 0)
2737c59e4cc3SRick Macklem 				goto nfsmout;
2738c59e4cc3SRick Macklem 			if (NFSISSET_ATTRBIT(&attrbits,
2739c59e4cc3SRick Macklem 			    NFSATTRBIT_TIMEACCESSSET))
2740c59e4cc3SRick Macklem 				nd->nd_repstat = NFSERR_INVAL;
2741c59e4cc3SRick Macklem 			/*
2742c59e4cc3SRick Macklem 			 * If the na_gid being set is the same as that of
2743c59e4cc3SRick Macklem 			 * the directory it is going in, clear it, since
2744c59e4cc3SRick Macklem 			 * that is what will be set by default. This allows
2745c59e4cc3SRick Macklem 			 * a user that isn't in that group to do the create.
2746c59e4cc3SRick Macklem 			 */
2747c59e4cc3SRick Macklem 			if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
2748c59e4cc3SRick Macklem 			    nva.na_gid == dirfor.na_gid)
2749c59e4cc3SRick Macklem 				NFSVNO_UNSET(&nva, gid);
2750c59e4cc3SRick Macklem 			if (nd->nd_repstat == 0)
2751c59e4cc3SRick Macklem 				nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2752c59e4cc3SRick Macklem 			break;
27539ec7b004SRick Macklem 		default:
27549ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_BADXDR;
2755a9285ae5SZack Kirsch 			goto nfsmout;
275674b8d63dSPedro F. Giffuni 		}
27579ec7b004SRick Macklem 	} else if (create != NFSV4OPEN_NOCREATE) {
27589ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
2759a9285ae5SZack Kirsch 		goto nfsmout;
27609ec7b004SRick Macklem 	}
27619ec7b004SRick Macklem 
27629ec7b004SRick Macklem 	/*
27639ec7b004SRick Macklem 	 * Now, handle the claim, which usually includes looking up a
27649ec7b004SRick Macklem 	 * name in the directory referenced by dp. The exception is
27659ec7b004SRick Macklem 	 * NFSV4OPEN_CLAIMPREVIOUS.
27669ec7b004SRick Macklem 	 */
27679ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
27689ec7b004SRick Macklem 	claim = fxdr_unsigned(int, *tl);
27699ec7b004SRick Macklem 	if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
27709ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
27719ec7b004SRick Macklem 		stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
27729ec7b004SRick Macklem 		NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
27739ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_DELEGCUR;
27749ec7b004SRick Macklem 	} else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
27759ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_DELEGPREV;
27769ec7b004SRick Macklem 	}
27779ec7b004SRick Macklem 	if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
27789ec7b004SRick Macklem 	    || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
27799ec7b004SRick Macklem 		if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
27809ec7b004SRick Macklem 		    claim != NFSV4OPEN_CLAIMNULL)
27819ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_INVAL;
27829ec7b004SRick Macklem 		if (nd->nd_repstat) {
27839ec7b004SRick Macklem 			nd->nd_repstat = nfsrv_opencheck(clientid,
27849ec7b004SRick Macklem 			    &stateid, stp, NULL, nd, p, nd->nd_repstat);
2785a9285ae5SZack Kirsch 			goto nfsmout;
27869ec7b004SRick Macklem 		}
27879ec7b004SRick Macklem 		if (create == NFSV4OPEN_CREATE)
27889ec7b004SRick Macklem 		    NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
27896c21f6edSKonstantin Belousov 			LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
27909ec7b004SRick Macklem 		else
27919ec7b004SRick Macklem 		    NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
27929ec7b004SRick Macklem 			LOCKLEAF | SAVESTART);
27939ec7b004SRick Macklem 		nfsvno_setpathbuf(&named, &bufp, &hashp);
27949ec7b004SRick Macklem 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
27959ec7b004SRick Macklem 		if (error) {
27969ec7b004SRick Macklem 			vrele(dp);
27979ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
27989ec7b004SRick Macklem 			acl_free(aclp);
27999ec7b004SRick Macklem #endif
2800222daa42SConrad Meyer 			free(stp, M_NFSDSTATE);
28019ec7b004SRick Macklem 			nfsvno_relpathbuf(&named);
2802a9285ae5SZack Kirsch 			NFSEXITCODE2(error, nd);
28039ec7b004SRick Macklem 			return (error);
28049ec7b004SRick Macklem 		}
28059ec7b004SRick Macklem 		if (!nd->nd_repstat) {
28069ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
28079ec7b004SRick Macklem 			    p, &dirp);
28089ec7b004SRick Macklem 		} else {
28099ec7b004SRick Macklem 			vrele(dp);
28109ec7b004SRick Macklem 			nfsvno_relpathbuf(&named);
28119ec7b004SRick Macklem 		}
28129ec7b004SRick Macklem 		if (create == NFSV4OPEN_CREATE) {
28139ec7b004SRick Macklem 		    switch (how) {
28149ec7b004SRick Macklem 		    case NFSCREATE_UNCHECKED:
28159ec7b004SRick Macklem 			if (named.ni_vp) {
28169ec7b004SRick Macklem 				/*
28179ec7b004SRick Macklem 				 * Clear the setable attribute bits, except
28189ec7b004SRick Macklem 				 * for Size, if it is being truncated.
28199ec7b004SRick Macklem 				 */
28209ec7b004SRick Macklem 				NFSZERO_ATTRBIT(&attrbits);
28219ec7b004SRick Macklem 				if (NFSVNO_ISSETSIZE(&nva))
28229ec7b004SRick Macklem 					NFSSETBIT_ATTRBIT(&attrbits,
28239ec7b004SRick Macklem 					    NFSATTRBIT_SIZE);
28249ec7b004SRick Macklem 			}
28259ec7b004SRick Macklem 			break;
28269ec7b004SRick Macklem 		    case NFSCREATE_GUARDED:
28279ec7b004SRick Macklem 			if (named.ni_vp && !nd->nd_repstat)
28289ec7b004SRick Macklem 				nd->nd_repstat = EEXIST;
28299ec7b004SRick Macklem 			break;
28309ec7b004SRick Macklem 		    case NFSCREATE_EXCLUSIVE:
28319ec7b004SRick Macklem 			exclusive_flag = 1;
28329ec7b004SRick Macklem 			if (!named.ni_vp)
28339ec7b004SRick Macklem 				nva.na_mode = 0;
2834c59e4cc3SRick Macklem 			break;
2835c59e4cc3SRick Macklem 		    case NFSCREATE_EXCLUSIVE41:
2836c59e4cc3SRick Macklem 			exclusive_flag = 1;
2837c59e4cc3SRick Macklem 			break;
283874b8d63dSPedro F. Giffuni 		    }
28399ec7b004SRick Macklem 		}
28409ec7b004SRick Macklem 		nfsvno_open(nd, &named, clientid, &stateid, stp,
28419ec7b004SRick Macklem 		    &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
28429ec7b004SRick Macklem 		    nd->nd_cred, p, exp, &vp);
2843c59e4cc3SRick Macklem 	} else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
2844c59e4cc3SRick Macklem 	    NFSV4OPEN_CLAIMFH) {
2845c59e4cc3SRick Macklem 		if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
28469ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
28479ec7b004SRick Macklem 			i = fxdr_unsigned(int, *tl);
28489ec7b004SRick Macklem 			switch (i) {
28499ec7b004SRick Macklem 			case NFSV4OPEN_DELEGATEREAD:
28509ec7b004SRick Macklem 				stp->ls_flags |= NFSLCK_DELEGREAD;
28519ec7b004SRick Macklem 				break;
28529ec7b004SRick Macklem 			case NFSV4OPEN_DELEGATEWRITE:
28539ec7b004SRick Macklem 				stp->ls_flags |= NFSLCK_DELEGWRITE;
28549ec7b004SRick Macklem 			case NFSV4OPEN_DELEGATENONE:
28559ec7b004SRick Macklem 				break;
28569ec7b004SRick Macklem 			default:
28579ec7b004SRick Macklem 				nd->nd_repstat = NFSERR_BADXDR;
2858a9285ae5SZack Kirsch 				goto nfsmout;
285974b8d63dSPedro F. Giffuni 			}
28609ec7b004SRick Macklem 			stp->ls_flags |= NFSLCK_RECLAIM;
2861c59e4cc3SRick Macklem 		} else {
2862c59e4cc3SRick Macklem 			/* CLAIM_NULL_FH */
2863c59e4cc3SRick Macklem 			if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
2864c59e4cc3SRick Macklem 				nd->nd_repstat = NFSERR_INVAL;
2865c59e4cc3SRick Macklem 		}
28669ec7b004SRick Macklem 		vp = dp;
286798f234f3SZack Kirsch 		NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
2868629fa50eSRick Macklem 		if ((vp->v_iflag & VI_DOOMED) == 0)
2869629fa50eSRick Macklem 			nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
2870629fa50eSRick Macklem 			    stp, vp, nd, p, nd->nd_repstat);
2871629fa50eSRick Macklem 		else
2872629fa50eSRick Macklem 			nd->nd_repstat = NFSERR_PERM;
28739ec7b004SRick Macklem 	} else {
28749ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
2875a9285ae5SZack Kirsch 		goto nfsmout;
28769ec7b004SRick Macklem 	}
28779ec7b004SRick Macklem 
28789ec7b004SRick Macklem 	/*
28799ec7b004SRick Macklem 	 * Do basic access checking.
28809ec7b004SRick Macklem 	 */
28819ec7b004SRick Macklem 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2882de67b496SRick Macklem 		/*
2883de67b496SRick Macklem 		 * The IETF working group decided that this is the correct
2884de67b496SRick Macklem 		 * error return for all non-regular files.
2885de67b496SRick Macklem 		 */
2886d8a5961fSMarcelo Araujo 		nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
28879ec7b004SRick Macklem 	}
28889ec7b004SRick Macklem 	if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
28898da45f2cSRick Macklem 	    nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
28908da45f2cSRick Macklem 	        exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
28919ec7b004SRick Macklem 	if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
28928da45f2cSRick Macklem 	    nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
28938da45f2cSRick Macklem 	        exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
28949ec7b004SRick Macklem 	    if (nd->nd_repstat)
28958da45f2cSRick Macklem 		nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
28969ec7b004SRick Macklem 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
28978da45f2cSRick Macklem 		    NFSACCCHK_VPISLOCKED, NULL);
28989ec7b004SRick Macklem 	}
28999ec7b004SRick Macklem 
2900086f6e0cSRick Macklem 	if (!nd->nd_repstat) {
29010cf42b62SRick Macklem 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2902086f6e0cSRick Macklem 		if (!nd->nd_repstat) {
2903086f6e0cSRick Macklem 			tverf[0] = nva.na_atime.tv_sec;
2904086f6e0cSRick Macklem 			tverf[1] = nva.na_atime.tv_nsec;
2905086f6e0cSRick Macklem 		}
2906086f6e0cSRick Macklem 	}
2907086f6e0cSRick Macklem 	if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
2908086f6e0cSRick Macklem 	    cverf[1] != tverf[1]))
29099ec7b004SRick Macklem 		nd->nd_repstat = EEXIST;
29109ec7b004SRick Macklem 	/*
29119ec7b004SRick Macklem 	 * Do the open locking/delegation stuff.
29129ec7b004SRick Macklem 	 */
29139ec7b004SRick Macklem 	if (!nd->nd_repstat)
29149ec7b004SRick Macklem 	    nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
29159ec7b004SRick Macklem 		&delegstateid, &rflags, exp, p, nva.na_filerev);
29169ec7b004SRick Macklem 
29179ec7b004SRick Macklem 	/*
29189ec7b004SRick Macklem 	 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
29199ec7b004SRick Macklem 	 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
29209ec7b004SRick Macklem 	 * (ie: Leave the NFSVOPUNLOCK() about here.)
29219ec7b004SRick Macklem 	 */
29229ec7b004SRick Macklem 	if (vp)
2923c383087cSZack Kirsch 		NFSVOPUNLOCK(vp, 0);
29249ec7b004SRick Macklem 	if (stp)
2925222daa42SConrad Meyer 		free(stp, M_NFSDSTATE);
29269ec7b004SRick Macklem 	if (!nd->nd_repstat && dirp)
29270cf42b62SRick Macklem 		nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
29280cf42b62SRick Macklem 		    0);
29299ec7b004SRick Macklem 	if (!nd->nd_repstat) {
29309ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
29319ec7b004SRick Macklem 		*tl++ = txdr_unsigned(stateid.seqid);
29329ec7b004SRick Macklem 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
29339ec7b004SRick Macklem 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
29349ec7b004SRick Macklem 		if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
29359ec7b004SRick Macklem 			*tl++ = newnfs_true;
29369ec7b004SRick Macklem 			*tl++ = 0;
29379ec7b004SRick Macklem 			*tl++ = 0;
29389ec7b004SRick Macklem 			*tl++ = 0;
29399ec7b004SRick Macklem 			*tl++ = 0;
29409ec7b004SRick Macklem 		} else {
29419ec7b004SRick Macklem 			*tl++ = newnfs_false;	/* Since dirp is not locked */
29429ec7b004SRick Macklem 			txdr_hyper(dirfor.na_filerev, tl);
29439ec7b004SRick Macklem 			tl += 2;
29449ec7b004SRick Macklem 			txdr_hyper(diraft.na_filerev, tl);
29459ec7b004SRick Macklem 			tl += 2;
29469ec7b004SRick Macklem 		}
29479ec7b004SRick Macklem 		*tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
29489ec7b004SRick Macklem 		(void) nfsrv_putattrbit(nd, &attrbits);
29499ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
29509ec7b004SRick Macklem 		if (rflags & NFSV4OPEN_READDELEGATE)
29519ec7b004SRick Macklem 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
29529ec7b004SRick Macklem 		else if (rflags & NFSV4OPEN_WRITEDELEGATE)
29539ec7b004SRick Macklem 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
2954c59e4cc3SRick Macklem 		else if (retext != 0) {
2955c59e4cc3SRick Macklem 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
2956c59e4cc3SRick Macklem 			if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
2957c59e4cc3SRick Macklem 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2958c59e4cc3SRick Macklem 				*tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
2959c59e4cc3SRick Macklem 				*tl = newnfs_false;
2960c59e4cc3SRick Macklem 			} else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
2961c59e4cc3SRick Macklem 				NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2962c59e4cc3SRick Macklem 				*tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
2963c59e4cc3SRick Macklem 				*tl = newnfs_false;
2964c59e4cc3SRick Macklem 			} else {
2965c59e4cc3SRick Macklem 				NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2966c59e4cc3SRick Macklem 				*tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
2967c59e4cc3SRick Macklem 			}
2968c59e4cc3SRick Macklem 		} else
29699ec7b004SRick Macklem 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
29709ec7b004SRick Macklem 		if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
29719ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
29729ec7b004SRick Macklem 			*tl++ = txdr_unsigned(delegstateid.seqid);
29739ec7b004SRick Macklem 			NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
29749ec7b004SRick Macklem 			    NFSX_STATEIDOTHER);
29759ec7b004SRick Macklem 			tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
29769ec7b004SRick Macklem 			if (rflags & NFSV4OPEN_RECALL)
29779ec7b004SRick Macklem 				*tl = newnfs_true;
29789ec7b004SRick Macklem 			else
29799ec7b004SRick Macklem 				*tl = newnfs_false;
29809ec7b004SRick Macklem 			if (rflags & NFSV4OPEN_WRITEDELEGATE) {
29819ec7b004SRick Macklem 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
29829ec7b004SRick Macklem 				*tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
29839ec7b004SRick Macklem 				txdr_hyper(nva.na_size, tl);
29849ec7b004SRick Macklem 			}
29859ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
29869ec7b004SRick Macklem 			*tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
29879ec7b004SRick Macklem 			*tl++ = txdr_unsigned(0x0);
29889ec7b004SRick Macklem 			acemask = NFSV4ACE_ALLFILESMASK;
29899ec7b004SRick Macklem 			if (nva.na_mode & S_IRUSR)
29909ec7b004SRick Macklem 			    acemask |= NFSV4ACE_READMASK;
29919ec7b004SRick Macklem 			if (nva.na_mode & S_IWUSR)
29929ec7b004SRick Macklem 			    acemask |= NFSV4ACE_WRITEMASK;
29939ec7b004SRick Macklem 			if (nva.na_mode & S_IXUSR)
29949ec7b004SRick Macklem 			    acemask |= NFSV4ACE_EXECUTEMASK;
29959ec7b004SRick Macklem 			*tl = txdr_unsigned(acemask);
29969ec7b004SRick Macklem 			(void) nfsm_strtom(nd, "OWNER@", 6);
29979ec7b004SRick Macklem 		}
29989ec7b004SRick Macklem 		*vpp = vp;
29999ec7b004SRick Macklem 	} else if (vp) {
30009ec7b004SRick Macklem 		vrele(vp);
30019ec7b004SRick Macklem 	}
30029ec7b004SRick Macklem 	if (dirp)
30039ec7b004SRick Macklem 		vrele(dirp);
30049ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
30059ec7b004SRick Macklem 	acl_free(aclp);
30069ec7b004SRick Macklem #endif
3007a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
30089ec7b004SRick Macklem 	return (0);
30099ec7b004SRick Macklem nfsmout:
30109ec7b004SRick Macklem 	vrele(dp);
30119ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
30129ec7b004SRick Macklem 	acl_free(aclp);
30139ec7b004SRick Macklem #endif
30149ec7b004SRick Macklem 	if (stp)
3015222daa42SConrad Meyer 		free(stp, M_NFSDSTATE);
3016a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
30179ec7b004SRick Macklem 	return (error);
30189ec7b004SRick Macklem }
30199ec7b004SRick Macklem 
30209ec7b004SRick Macklem /*
30219ec7b004SRick Macklem  * nfsv4 close service
30229ec7b004SRick Macklem  */
30239ec7b004SRick Macklem APPLESTATIC int
30249ec7b004SRick Macklem nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
30259ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
30269ec7b004SRick Macklem {
30279ec7b004SRick Macklem 	u_int32_t *tl;
30289ec7b004SRick Macklem 	struct nfsstate st, *stp = &st;
30299ec7b004SRick Macklem 	int error = 0;
30309ec7b004SRick Macklem 	nfsv4stateid_t stateid;
30319ec7b004SRick Macklem 	nfsquad_t clientid;
30329ec7b004SRick Macklem 
30339ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
30349ec7b004SRick Macklem 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
30359ec7b004SRick Macklem 	stp->ls_ownerlen = 0;
30369ec7b004SRick Macklem 	stp->ls_op = nd->nd_rp;
30379ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
30389ec7b004SRick Macklem 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
30399ec7b004SRick Macklem 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
30409ec7b004SRick Macklem 	    NFSX_STATEIDOTHER);
30419ec7b004SRick Macklem 	stp->ls_flags = NFSLCK_CLOSE;
30429ec7b004SRick Macklem 	clientid.lval[0] = stp->ls_stateid.other[0];
30439ec7b004SRick Macklem 	clientid.lval[1] = stp->ls_stateid.other[1];
3044c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3045c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3046c59e4cc3SRick Macklem 			clientid.qval = nd->nd_clientid.qval;
3047c59e4cc3SRick Macklem 		else if (nd->nd_clientid.qval != clientid.qval)
3048c59e4cc3SRick Macklem 			printf("EEK8 multiple clids\n");
30499ec7b004SRick Macklem 	} else {
3050c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3051c59e4cc3SRick Macklem 			printf("EEK! no clientid from session\n");
30529ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
30539ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
30549ec7b004SRick Macklem 	}
30559ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
30569ec7b004SRick Macklem 	vput(vp);
30579ec7b004SRick Macklem 	if (!nd->nd_repstat) {
30589ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
30599ec7b004SRick Macklem 		*tl++ = txdr_unsigned(stateid.seqid);
30609ec7b004SRick Macklem 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
30619ec7b004SRick Macklem 	}
3062a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
30639ec7b004SRick Macklem 	return (0);
30649ec7b004SRick Macklem nfsmout:
30659ec7b004SRick Macklem 	vput(vp);
3066a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
30679ec7b004SRick Macklem 	return (error);
30689ec7b004SRick Macklem }
30699ec7b004SRick Macklem 
30709ec7b004SRick Macklem /*
30719ec7b004SRick Macklem  * nfsv4 delegpurge service
30729ec7b004SRick Macklem  */
30739ec7b004SRick Macklem APPLESTATIC int
30749ec7b004SRick Macklem nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
30759ec7b004SRick Macklem     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
30769ec7b004SRick Macklem {
30779ec7b004SRick Macklem 	u_int32_t *tl;
30789ec7b004SRick Macklem 	int error = 0;
30799ec7b004SRick Macklem 	nfsquad_t clientid;
30809ec7b004SRick Macklem 
3081c9aad40fSRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3082b1cfc0d9SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
3083a9285ae5SZack Kirsch 		goto nfsmout;
3084b1cfc0d9SRick Macklem 	}
30859ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
30869ec7b004SRick Macklem 	clientid.lval[0] = *tl++;
30879ec7b004SRick Macklem 	clientid.lval[1] = *tl;
3088c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3089c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3090c59e4cc3SRick Macklem 			clientid.qval = nd->nd_clientid.qval;
3091c59e4cc3SRick Macklem 		else if (nd->nd_clientid.qval != clientid.qval)
3092c59e4cc3SRick Macklem 			printf("EEK9 multiple clids\n");
30939ec7b004SRick Macklem 	} else {
3094c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3095c59e4cc3SRick Macklem 			printf("EEK! no clientid from session\n");
30969ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
30979ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
30989ec7b004SRick Macklem 	}
3099c59e4cc3SRick Macklem 	nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
31009ec7b004SRick Macklem 	    NFSV4OP_DELEGPURGE, nd->nd_cred, p);
31019ec7b004SRick Macklem nfsmout:
3102a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
31039ec7b004SRick Macklem 	return (error);
31049ec7b004SRick Macklem }
31059ec7b004SRick Macklem 
31069ec7b004SRick Macklem /*
31079ec7b004SRick Macklem  * nfsv4 delegreturn service
31089ec7b004SRick Macklem  */
31099ec7b004SRick Macklem APPLESTATIC int
31109ec7b004SRick Macklem nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
31119ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
31129ec7b004SRick Macklem {
31139ec7b004SRick Macklem 	u_int32_t *tl;
31149ec7b004SRick Macklem 	int error = 0;
31159ec7b004SRick Macklem 	nfsv4stateid_t stateid;
31169ec7b004SRick Macklem 	nfsquad_t clientid;
31179ec7b004SRick Macklem 
31189ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
31199ec7b004SRick Macklem 	stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
31209ec7b004SRick Macklem 	NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
31219ec7b004SRick Macklem 	clientid.lval[0] = stateid.other[0];
31229ec7b004SRick Macklem 	clientid.lval[1] = stateid.other[1];
3123c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3124c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3125c59e4cc3SRick Macklem 			clientid.qval = nd->nd_clientid.qval;
3126c59e4cc3SRick Macklem 		else if (nd->nd_clientid.qval != clientid.qval)
3127c59e4cc3SRick Macklem 			printf("EEK10 multiple clids\n");
31289ec7b004SRick Macklem 	} else {
3129c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3130c59e4cc3SRick Macklem 			printf("EEK! no clientid from session\n");
31319ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
31329ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
31339ec7b004SRick Macklem 	}
3134c59e4cc3SRick Macklem 	nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
31359ec7b004SRick Macklem 	    NFSV4OP_DELEGRETURN, nd->nd_cred, p);
31369ec7b004SRick Macklem nfsmout:
31379ec7b004SRick Macklem 	vput(vp);
3138a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
31399ec7b004SRick Macklem 	return (error);
31409ec7b004SRick Macklem }
31419ec7b004SRick Macklem 
31429ec7b004SRick Macklem /*
31439ec7b004SRick Macklem  * nfsv4 get file handle service
31449ec7b004SRick Macklem  */
31459ec7b004SRick Macklem APPLESTATIC int
31469ec7b004SRick Macklem nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
31479ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
31489ec7b004SRick Macklem {
31499ec7b004SRick Macklem 	fhandle_t fh;
31509ec7b004SRick Macklem 
31519ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
31529ec7b004SRick Macklem 	vput(vp);
31539ec7b004SRick Macklem 	if (!nd->nd_repstat)
31549ec7b004SRick Macklem 		(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
3155a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
31569ec7b004SRick Macklem 	return (0);
31579ec7b004SRick Macklem }
31589ec7b004SRick Macklem 
31599ec7b004SRick Macklem /*
31609ec7b004SRick Macklem  * nfsv4 open confirm service
31619ec7b004SRick Macklem  */
31629ec7b004SRick Macklem APPLESTATIC int
31639ec7b004SRick Macklem nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
31649ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
31659ec7b004SRick Macklem {
31669ec7b004SRick Macklem 	u_int32_t *tl;
31679ec7b004SRick Macklem 	struct nfsstate st, *stp = &st;
31689ec7b004SRick Macklem 	int error = 0;
31699ec7b004SRick Macklem 	nfsv4stateid_t stateid;
31709ec7b004SRick Macklem 	nfsquad_t clientid;
31719ec7b004SRick Macklem 
3172c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_NFSV41) != 0) {
3173c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_NOTSUPP;
3174c59e4cc3SRick Macklem 		goto nfsmout;
3175c59e4cc3SRick Macklem 	}
31769ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
31779ec7b004SRick Macklem 	stp->ls_ownerlen = 0;
31789ec7b004SRick Macklem 	stp->ls_op = nd->nd_rp;
31799ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
31809ec7b004SRick Macklem 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
31819ec7b004SRick Macklem 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
31829ec7b004SRick Macklem 	    NFSX_STATEIDOTHER);
31839ec7b004SRick Macklem 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
31849ec7b004SRick Macklem 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
31859ec7b004SRick Macklem 	stp->ls_flags = NFSLCK_CONFIRM;
31869ec7b004SRick Macklem 	clientid.lval[0] = stp->ls_stateid.other[0];
31879ec7b004SRick Macklem 	clientid.lval[1] = stp->ls_stateid.other[1];
3188c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3189c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3190c59e4cc3SRick Macklem 			clientid.qval = nd->nd_clientid.qval;
3191c59e4cc3SRick Macklem 		else if (nd->nd_clientid.qval != clientid.qval)
3192c59e4cc3SRick Macklem 			printf("EEK11 multiple clids\n");
31939ec7b004SRick Macklem 	} else {
3194c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3195c59e4cc3SRick Macklem 			printf("EEK! no clientid from session\n");
31969ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
31979ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
31989ec7b004SRick Macklem 	}
31999ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
32009ec7b004SRick Macklem 	if (!nd->nd_repstat) {
32019ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
32029ec7b004SRick Macklem 		*tl++ = txdr_unsigned(stateid.seqid);
32039ec7b004SRick Macklem 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
32049ec7b004SRick Macklem 	}
32059ec7b004SRick Macklem nfsmout:
32069ec7b004SRick Macklem 	vput(vp);
3207a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
32089ec7b004SRick Macklem 	return (error);
32099ec7b004SRick Macklem }
32109ec7b004SRick Macklem 
32119ec7b004SRick Macklem /*
32129ec7b004SRick Macklem  * nfsv4 open downgrade service
32139ec7b004SRick Macklem  */
32149ec7b004SRick Macklem APPLESTATIC int
32159ec7b004SRick Macklem nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
32169ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
32179ec7b004SRick Macklem {
32189ec7b004SRick Macklem 	u_int32_t *tl;
32199ec7b004SRick Macklem 	int i;
32209ec7b004SRick Macklem 	struct nfsstate st, *stp = &st;
32219ec7b004SRick Macklem 	int error = 0;
32229ec7b004SRick Macklem 	nfsv4stateid_t stateid;
32239ec7b004SRick Macklem 	nfsquad_t clientid;
32249ec7b004SRick Macklem 
3225d8a5961fSMarcelo Araujo 	/* opendowngrade can only work on a file object.*/
3226d8a5961fSMarcelo Araujo 	if (vp->v_type != VREG) {
3227d8a5961fSMarcelo Araujo 		error = NFSERR_INVAL;
3228d8a5961fSMarcelo Araujo 		goto nfsmout;
3229d8a5961fSMarcelo Araujo 	}
32309ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
32319ec7b004SRick Macklem 	stp->ls_ownerlen = 0;
32329ec7b004SRick Macklem 	stp->ls_op = nd->nd_rp;
32339ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
32349ec7b004SRick Macklem 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
32359ec7b004SRick Macklem 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
32369ec7b004SRick Macklem 	    NFSX_STATEIDOTHER);
32379ec7b004SRick Macklem 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
32389ec7b004SRick Macklem 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
32399ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl++);
32409ec7b004SRick Macklem 	switch (i) {
32419ec7b004SRick Macklem 	case NFSV4OPEN_ACCESSREAD:
32429ec7b004SRick Macklem 		stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
32439ec7b004SRick Macklem 		break;
32449ec7b004SRick Macklem 	case NFSV4OPEN_ACCESSWRITE:
32459ec7b004SRick Macklem 		stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
32469ec7b004SRick Macklem 		break;
32479ec7b004SRick Macklem 	case NFSV4OPEN_ACCESSBOTH:
32489ec7b004SRick Macklem 		stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
32499ec7b004SRick Macklem 		    NFSLCK_DOWNGRADE);
32509ec7b004SRick Macklem 		break;
32519ec7b004SRick Macklem 	default:
32529ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
325374b8d63dSPedro F. Giffuni 	}
32549ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl);
32559ec7b004SRick Macklem 	switch (i) {
32569ec7b004SRick Macklem 	case NFSV4OPEN_DENYNONE:
32579ec7b004SRick Macklem 		break;
32589ec7b004SRick Macklem 	case NFSV4OPEN_DENYREAD:
32599ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_READDENY;
32609ec7b004SRick Macklem 		break;
32619ec7b004SRick Macklem 	case NFSV4OPEN_DENYWRITE:
32629ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_WRITEDENY;
32639ec7b004SRick Macklem 		break;
32649ec7b004SRick Macklem 	case NFSV4OPEN_DENYBOTH:
32659ec7b004SRick Macklem 		stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
32669ec7b004SRick Macklem 		break;
32679ec7b004SRick Macklem 	default:
32689ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
326974b8d63dSPedro F. Giffuni 	}
32709ec7b004SRick Macklem 
32719ec7b004SRick Macklem 	clientid.lval[0] = stp->ls_stateid.other[0];
32729ec7b004SRick Macklem 	clientid.lval[1] = stp->ls_stateid.other[1];
3273c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3274c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3275c59e4cc3SRick Macklem 			clientid.qval = nd->nd_clientid.qval;
3276c59e4cc3SRick Macklem 		else if (nd->nd_clientid.qval != clientid.qval)
3277c59e4cc3SRick Macklem 			printf("EEK12 multiple clids\n");
32789ec7b004SRick Macklem 	} else {
3279c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3280c59e4cc3SRick Macklem 			printf("EEK! no clientid from session\n");
32819ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
32829ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
32839ec7b004SRick Macklem 	}
32849ec7b004SRick Macklem 	if (!nd->nd_repstat)
32859ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
32869ec7b004SRick Macklem 		    nd, p);
32879ec7b004SRick Macklem 	if (!nd->nd_repstat) {
32889ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
32899ec7b004SRick Macklem 		*tl++ = txdr_unsigned(stateid.seqid);
32909ec7b004SRick Macklem 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
32919ec7b004SRick Macklem 	}
32929ec7b004SRick Macklem nfsmout:
32939ec7b004SRick Macklem 	vput(vp);
3294a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
32959ec7b004SRick Macklem 	return (error);
32969ec7b004SRick Macklem }
32979ec7b004SRick Macklem 
32989ec7b004SRick Macklem /*
32999ec7b004SRick Macklem  * nfsv4 renew lease service
33009ec7b004SRick Macklem  */
33019ec7b004SRick Macklem APPLESTATIC int
33029ec7b004SRick Macklem nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
33039ec7b004SRick Macklem     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
33049ec7b004SRick Macklem {
33059ec7b004SRick Macklem 	u_int32_t *tl;
33069ec7b004SRick Macklem 	int error = 0;
33079ec7b004SRick Macklem 	nfsquad_t clientid;
33089ec7b004SRick Macklem 
3309c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_NFSV41) != 0) {
3310c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_NOTSUPP;
3311c59e4cc3SRick Macklem 		goto nfsmout;
3312c59e4cc3SRick Macklem 	}
3313c9aad40fSRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3314b1cfc0d9SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
3315a9285ae5SZack Kirsch 		goto nfsmout;
3316b1cfc0d9SRick Macklem 	}
33179ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
33189ec7b004SRick Macklem 	clientid.lval[0] = *tl++;
33199ec7b004SRick Macklem 	clientid.lval[1] = *tl;
3320c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3321c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3322c59e4cc3SRick Macklem 			clientid.qval = nd->nd_clientid.qval;
3323c59e4cc3SRick Macklem 		else if (nd->nd_clientid.qval != clientid.qval)
3324c59e4cc3SRick Macklem 			printf("EEK13 multiple clids\n");
33259ec7b004SRick Macklem 	} else {
3326c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3327c59e4cc3SRick Macklem 			printf("EEK! no clientid from session\n");
33289ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
33299ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
33309ec7b004SRick Macklem 	}
33319ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3332c59e4cc3SRick Macklem 	    NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
33339ec7b004SRick Macklem nfsmout:
3334a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
33359ec7b004SRick Macklem 	return (error);
33369ec7b004SRick Macklem }
33379ec7b004SRick Macklem 
33389ec7b004SRick Macklem /*
33399ec7b004SRick Macklem  * nfsv4 security info service
33409ec7b004SRick Macklem  */
33419ec7b004SRick Macklem APPLESTATIC int
33429ec7b004SRick Macklem nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
33439ec7b004SRick Macklem     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
33449ec7b004SRick Macklem {
33459ec7b004SRick Macklem 	u_int32_t *tl;
33469ec7b004SRick Macklem 	int len;
33479ec7b004SRick Macklem 	struct nameidata named;
33489ec7b004SRick Macklem 	vnode_t dirp = NULL, vp;
33499ec7b004SRick Macklem 	struct nfsrvfh fh;
33509ec7b004SRick Macklem 	struct nfsexstuff retnes;
33519ec7b004SRick Macklem 	u_int32_t *sizp;
3352a9285ae5SZack Kirsch 	int error = 0, savflag, i;
33539ec7b004SRick Macklem 	char *bufp;
33549ec7b004SRick Macklem 	u_long *hashp;
33559ec7b004SRick Macklem 
33569ec7b004SRick Macklem 	/*
33579ec7b004SRick Macklem 	 * All this just to get the export flags for the name.
33589ec7b004SRick Macklem 	 */
33599ec7b004SRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
33609ec7b004SRick Macklem 	    LOCKLEAF | SAVESTART);
33619ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
33629ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
33639ec7b004SRick Macklem 	if (error) {
33649ec7b004SRick Macklem 		vput(dp);
33659ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
3366a9285ae5SZack Kirsch 		goto out;
33679ec7b004SRick Macklem 	}
33689ec7b004SRick Macklem 	if (!nd->nd_repstat) {
33699ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
33709ec7b004SRick Macklem 	} else {
33719ec7b004SRick Macklem 		vput(dp);
33729ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
33739ec7b004SRick Macklem 	}
33749ec7b004SRick Macklem 	if (dirp)
33759ec7b004SRick Macklem 		vrele(dirp);
33769ec7b004SRick Macklem 	if (nd->nd_repstat)
3377a9285ae5SZack Kirsch 		goto out;
33789ec7b004SRick Macklem 	vrele(named.ni_startdir);
33799ec7b004SRick Macklem 	nfsvno_relpathbuf(&named);
33809ec7b004SRick Macklem 	fh.nfsrvfh_len = NFSX_MYFH;
33819ec7b004SRick Macklem 	vp = named.ni_vp;
33829ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
33839ec7b004SRick Macklem 	vput(vp);
33849ec7b004SRick Macklem 	savflag = nd->nd_flag;
33859ec7b004SRick Macklem 	if (!nd->nd_repstat) {
33868974bc2fSRick Macklem 		nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
33879ec7b004SRick Macklem 		if (vp)
33889ec7b004SRick Macklem 			vput(vp);
33899ec7b004SRick Macklem 	}
33909ec7b004SRick Macklem 	nd->nd_flag = savflag;
33919ec7b004SRick Macklem 	if (nd->nd_repstat)
3392a9285ae5SZack Kirsch 		goto out;
33939ec7b004SRick Macklem 
33949ec7b004SRick Macklem 	/*
33959ec7b004SRick Macklem 	 * Finally have the export flags for name, so we can create
33969ec7b004SRick Macklem 	 * the security info.
33979ec7b004SRick Macklem 	 */
33989ec7b004SRick Macklem 	len = 0;
33999ec7b004SRick Macklem 	NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
340098ad4453SRick Macklem 	for (i = 0; i < retnes.nes_numsecflavor; i++) {
340198ad4453SRick Macklem 		if (retnes.nes_secflavors[i] == AUTH_SYS) {
34029ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
34039ec7b004SRick Macklem 			*tl = txdr_unsigned(RPCAUTH_UNIX);
34049ec7b004SRick Macklem 			len++;
340598ad4453SRick Macklem 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
34069ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
34079ec7b004SRick Macklem 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
34089ec7b004SRick Macklem 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
34099ec7b004SRick Macklem 			    nfsgss_mechlist[KERBV_MECH].len);
34109ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
34119ec7b004SRick Macklem 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
341298ad4453SRick Macklem 			*tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
34139ec7b004SRick Macklem 			len++;
341498ad4453SRick Macklem 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
341598ad4453SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
341698ad4453SRick Macklem 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
341798ad4453SRick Macklem 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
341898ad4453SRick Macklem 			    nfsgss_mechlist[KERBV_MECH].len);
341998ad4453SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
342098ad4453SRick Macklem 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
342198ad4453SRick Macklem 			*tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
342298ad4453SRick Macklem 			len++;
342398ad4453SRick Macklem 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
342498ad4453SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
342598ad4453SRick Macklem 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
342698ad4453SRick Macklem 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
342798ad4453SRick Macklem 			    nfsgss_mechlist[KERBV_MECH].len);
342898ad4453SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
342998ad4453SRick Macklem 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
343098ad4453SRick Macklem 			*tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
343198ad4453SRick Macklem 			len++;
343298ad4453SRick Macklem 		}
34339ec7b004SRick Macklem 	}
34349ec7b004SRick Macklem 	*sizp = txdr_unsigned(len);
3435a9285ae5SZack Kirsch 
3436a9285ae5SZack Kirsch out:
3437a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
3438a9285ae5SZack Kirsch 	return (error);
34399ec7b004SRick Macklem }
34409ec7b004SRick Macklem 
34419ec7b004SRick Macklem /*
34429ec7b004SRick Macklem  * nfsv4 set client id service
34439ec7b004SRick Macklem  */
34449ec7b004SRick Macklem APPLESTATIC int
34459ec7b004SRick Macklem nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
34469ec7b004SRick Macklem     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
34479ec7b004SRick Macklem {
34489ec7b004SRick Macklem 	u_int32_t *tl;
34499ec7b004SRick Macklem 	int i;
34509ec7b004SRick Macklem 	int error = 0, idlen;
34519ec7b004SRick Macklem 	struct nfsclient *clp = NULL;
34529ec7b004SRick Macklem 	struct sockaddr_in *rad;
34539ec7b004SRick Macklem 	u_char *verf, *ucp, *ucp2, addrbuf[24];
34549ec7b004SRick Macklem 	nfsquad_t clientid, confirm;
34559ec7b004SRick Macklem 
3456c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_NFSV41) != 0) {
3457c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_NOTSUPP;
3458c59e4cc3SRick Macklem 		goto nfsmout;
3459c59e4cc3SRick Macklem 	}
3460c9aad40fSRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
34619ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
3462a9285ae5SZack Kirsch 		goto out;
34639ec7b004SRick Macklem 	}
34649ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
34659ec7b004SRick Macklem 	verf = (u_char *)tl;
34669ec7b004SRick Macklem 	tl += (NFSX_VERF / NFSX_UNSIGNED);
34679ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl);
34689ec7b004SRick Macklem 	if (i > NFSV4_OPAQUELIMIT || i <= 0) {
34699ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
3470a9285ae5SZack Kirsch 		goto nfsmout;
34719ec7b004SRick Macklem 	}
34729ec7b004SRick Macklem 	idlen = i;
34739ec7b004SRick Macklem 	if (nd->nd_flag & ND_GSS)
34749ec7b004SRick Macklem 		i += nd->nd_princlen;
34751f54e596SRick Macklem 	clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
34761f54e596SRick Macklem 	    M_ZERO);
34771f54e596SRick Macklem 	clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
34781f54e596SRick Macklem 	    nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
34799ec7b004SRick Macklem 	NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3480*b97b91b5SConrad Meyer 	clp->lc_req.nr_nam = malloc(sizeof(*clp->lc_req.nr_nam), M_SONAME,
3481*b97b91b5SConrad Meyer 	    M_WAITOK | M_ZERO);
34829ec7b004SRick Macklem 	NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
34839ec7b004SRick Macklem 	clp->lc_req.nr_cred = NULL;
34849ec7b004SRick Macklem 	NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
34859ec7b004SRick Macklem 	clp->lc_idlen = idlen;
34869ec7b004SRick Macklem 	error = nfsrv_mtostr(nd, clp->lc_id, idlen);
34879ec7b004SRick Macklem 	if (error)
34889ec7b004SRick Macklem 		goto nfsmout;
34899ec7b004SRick Macklem 	if (nd->nd_flag & ND_GSS) {
34909ec7b004SRick Macklem 		clp->lc_flags = LCL_GSS;
34919ec7b004SRick Macklem 		if (nd->nd_flag & ND_GSSINTEGRITY)
34929ec7b004SRick Macklem 			clp->lc_flags |= LCL_GSSINTEGRITY;
34939ec7b004SRick Macklem 		else if (nd->nd_flag & ND_GSSPRIVACY)
34949ec7b004SRick Macklem 			clp->lc_flags |= LCL_GSSPRIVACY;
34959ec7b004SRick Macklem 	} else {
34969ec7b004SRick Macklem 		clp->lc_flags = 0;
34979ec7b004SRick Macklem 	}
34989ec7b004SRick Macklem 	if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
34999ec7b004SRick Macklem 		clp->lc_flags |= LCL_NAME;
35009ec7b004SRick Macklem 		clp->lc_namelen = nd->nd_princlen;
35019ec7b004SRick Macklem 		clp->lc_name = &clp->lc_id[idlen];
35029ec7b004SRick Macklem 		NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
35039ec7b004SRick Macklem 	} else {
35049ec7b004SRick Macklem 		clp->lc_uid = nd->nd_cred->cr_uid;
35059ec7b004SRick Macklem 		clp->lc_gid = nd->nd_cred->cr_gid;
35069ec7b004SRick Macklem 	}
35079ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
35089ec7b004SRick Macklem 	clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
35099ec7b004SRick Macklem 	error = nfsrv_getclientipaddr(nd, clp);
35109ec7b004SRick Macklem 	if (error)
35119ec7b004SRick Macklem 		goto nfsmout;
35129ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
35139ec7b004SRick Macklem 	clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
35149ec7b004SRick Macklem 
35159ec7b004SRick Macklem 	/*
35169ec7b004SRick Macklem 	 * nfsrv_setclient() does the actual work of adding it to the
35179ec7b004SRick Macklem 	 * client list. If there is no error, the structure has been
35189ec7b004SRick Macklem 	 * linked into the client list and clp should no longer be used
35199ec7b004SRick Macklem 	 * here. When an error is returned, it has not been linked in,
35209ec7b004SRick Macklem 	 * so it should be free'd.
35219ec7b004SRick Macklem 	 */
35229ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
35239ec7b004SRick Macklem 	if (nd->nd_repstat == NFSERR_CLIDINUSE) {
35249ec7b004SRick Macklem 		if (clp->lc_flags & LCL_TCPCALLBACK)
35259ec7b004SRick Macklem 			(void) nfsm_strtom(nd, "tcp", 3);
35269ec7b004SRick Macklem 		else
35279ec7b004SRick Macklem 			(void) nfsm_strtom(nd, "udp", 3);
35289ec7b004SRick Macklem 		rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
35299ec7b004SRick Macklem 		ucp = (u_char *)&rad->sin_addr.s_addr;
35309ec7b004SRick Macklem 		ucp2 = (u_char *)&rad->sin_port;
35319ec7b004SRick Macklem 		sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
35329ec7b004SRick Macklem 		    ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
35339ec7b004SRick Macklem 		    ucp2[0] & 0xff, ucp2[1] & 0xff);
35349ec7b004SRick Macklem 		(void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
35359ec7b004SRick Macklem 	}
35369ec7b004SRick Macklem 	if (clp) {
3537*b97b91b5SConrad Meyer 		free(clp->lc_req.nr_nam, M_SONAME);
35389ec7b004SRick Macklem 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
35391f54e596SRick Macklem 		free(clp->lc_stateid, M_NFSDCLIENT);
35401f54e596SRick Macklem 		free(clp, M_NFSDCLIENT);
35419ec7b004SRick Macklem 	}
35429ec7b004SRick Macklem 	if (!nd->nd_repstat) {
35439ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
35449ec7b004SRick Macklem 		*tl++ = clientid.lval[0];
35459ec7b004SRick Macklem 		*tl++ = clientid.lval[1];
35469ec7b004SRick Macklem 		*tl++ = confirm.lval[0];
35479ec7b004SRick Macklem 		*tl = confirm.lval[1];
35489ec7b004SRick Macklem 	}
3549a9285ae5SZack Kirsch 
3550a9285ae5SZack Kirsch out:
3551a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
35529ec7b004SRick Macklem 	return (0);
35539ec7b004SRick Macklem nfsmout:
35549ec7b004SRick Macklem 	if (clp) {
3555*b97b91b5SConrad Meyer 		free(clp->lc_req.nr_nam, M_SONAME);
35569ec7b004SRick Macklem 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
35571f54e596SRick Macklem 		free(clp->lc_stateid, M_NFSDCLIENT);
35581f54e596SRick Macklem 		free(clp, M_NFSDCLIENT);
35599ec7b004SRick Macklem 	}
3560a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
35619ec7b004SRick Macklem 	return (error);
35629ec7b004SRick Macklem }
35639ec7b004SRick Macklem 
35649ec7b004SRick Macklem /*
35659ec7b004SRick Macklem  * nfsv4 set client id confirm service
35669ec7b004SRick Macklem  */
35679ec7b004SRick Macklem APPLESTATIC int
35689ec7b004SRick Macklem nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
35699ec7b004SRick Macklem     __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
35709ec7b004SRick Macklem     __unused struct nfsexstuff *exp)
35719ec7b004SRick Macklem {
35729ec7b004SRick Macklem 	u_int32_t *tl;
35739ec7b004SRick Macklem 	int error = 0;
35749ec7b004SRick Macklem 	nfsquad_t clientid, confirm;
35759ec7b004SRick Macklem 
3576c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_NFSV41) != 0) {
3577c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_NOTSUPP;
3578c59e4cc3SRick Macklem 		goto nfsmout;
3579c59e4cc3SRick Macklem 	}
3580c9aad40fSRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
35819ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
3582a9285ae5SZack Kirsch 		goto nfsmout;
35839ec7b004SRick Macklem 	}
35849ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
35859ec7b004SRick Macklem 	clientid.lval[0] = *tl++;
35869ec7b004SRick Macklem 	clientid.lval[1] = *tl++;
35879ec7b004SRick Macklem 	confirm.lval[0] = *tl++;
35889ec7b004SRick Macklem 	confirm.lval[1] = *tl;
35899ec7b004SRick Macklem 
35909ec7b004SRick Macklem 	/*
35919ec7b004SRick Macklem 	 * nfsrv_getclient() searches the client list for a match and
35929ec7b004SRick Macklem 	 * returns the appropriate NFSERR status.
35939ec7b004SRick Macklem 	 */
35949ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3595c59e4cc3SRick Macklem 	    NULL, NULL, confirm, 0, nd, p);
35969ec7b004SRick Macklem nfsmout:
3597a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
35989ec7b004SRick Macklem 	return (error);
35999ec7b004SRick Macklem }
36009ec7b004SRick Macklem 
36019ec7b004SRick Macklem /*
36029ec7b004SRick Macklem  * nfsv4 verify service
36039ec7b004SRick Macklem  */
36049ec7b004SRick Macklem APPLESTATIC int
36059ec7b004SRick Macklem nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
36069ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
36079ec7b004SRick Macklem {
36089ec7b004SRick Macklem 	int error = 0, ret, fhsize = NFSX_MYFH;
36099ec7b004SRick Macklem 	struct nfsvattr nva;
36102f304845SKonstantin Belousov 	struct statfs *sf;
36119ec7b004SRick Macklem 	struct nfsfsinfo fs;
36129ec7b004SRick Macklem 	fhandle_t fh;
36139ec7b004SRick Macklem 
36142f304845SKonstantin Belousov 	sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
36150cf42b62SRick Macklem 	nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
36169ec7b004SRick Macklem 	if (!nd->nd_repstat)
36172f304845SKonstantin Belousov 		nd->nd_repstat = nfsvno_statfs(vp, sf);
36189ec7b004SRick Macklem 	if (!nd->nd_repstat)
36199ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
36209ec7b004SRick Macklem 	if (!nd->nd_repstat) {
36219ec7b004SRick Macklem 		nfsvno_getfs(&fs, isdgram);
36229ec7b004SRick Macklem 		error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
36232f304845SKonstantin Belousov 		    sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
36249ec7b004SRick Macklem 		if (!error) {
36259ec7b004SRick Macklem 			if (nd->nd_procnum == NFSV4OP_NVERIFY) {
36269ec7b004SRick Macklem 				if (ret == 0)
36279ec7b004SRick Macklem 					nd->nd_repstat = NFSERR_SAME;
36289ec7b004SRick Macklem 				else if (ret != NFSERR_NOTSAME)
36299ec7b004SRick Macklem 					nd->nd_repstat = ret;
36309ec7b004SRick Macklem 			} else if (ret)
36319ec7b004SRick Macklem 				nd->nd_repstat = ret;
36329ec7b004SRick Macklem 		}
36339ec7b004SRick Macklem 	}
36349ec7b004SRick Macklem 	vput(vp);
36352f304845SKonstantin Belousov 	free(sf, M_STATFS);
3636a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
36379ec7b004SRick Macklem 	return (error);
36389ec7b004SRick Macklem }
36399ec7b004SRick Macklem 
36409ec7b004SRick Macklem /*
36419ec7b004SRick Macklem  * nfs openattr rpc
36429ec7b004SRick Macklem  */
36439ec7b004SRick Macklem APPLESTATIC int
36449ec7b004SRick Macklem nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
36459ec7b004SRick Macklem     vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
36469ec7b004SRick Macklem     __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
36479ec7b004SRick Macklem {
36489ec7b004SRick Macklem 	u_int32_t *tl;
36499ec7b004SRick Macklem 	int error = 0, createdir;
36509ec7b004SRick Macklem 
36519ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
36529ec7b004SRick Macklem 	createdir = fxdr_unsigned(int, *tl);
36539ec7b004SRick Macklem 	nd->nd_repstat = NFSERR_NOTSUPP;
36549ec7b004SRick Macklem nfsmout:
36559ec7b004SRick Macklem 	vrele(dp);
3656a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
36579ec7b004SRick Macklem 	return (error);
36589ec7b004SRick Macklem }
36599ec7b004SRick Macklem 
36609ec7b004SRick Macklem /*
36619ec7b004SRick Macklem  * nfsv4 release lock owner service
36629ec7b004SRick Macklem  */
36639ec7b004SRick Macklem APPLESTATIC int
36649ec7b004SRick Macklem nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
36659ec7b004SRick Macklem     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
36669ec7b004SRick Macklem {
36679ec7b004SRick Macklem 	u_int32_t *tl;
36689ec7b004SRick Macklem 	struct nfsstate *stp = NULL;
36699ec7b004SRick Macklem 	int error = 0, len;
36709ec7b004SRick Macklem 	nfsquad_t clientid;
36719ec7b004SRick Macklem 
3672c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_NFSV41) != 0) {
3673c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_NOTSUPP;
3674c59e4cc3SRick Macklem 		goto nfsmout;
3675c59e4cc3SRick Macklem 	}
3676c9aad40fSRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3677b1cfc0d9SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
3678a9285ae5SZack Kirsch 		goto nfsmout;
3679b1cfc0d9SRick Macklem 	}
36809ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
36819ec7b004SRick Macklem 	len = fxdr_unsigned(int, *(tl + 2));
36822a45247cSRick Macklem 	if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
36832a45247cSRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
3684a9285ae5SZack Kirsch 		goto nfsmout;
36852a45247cSRick Macklem 	}
3686222daa42SConrad Meyer 	stp = malloc(sizeof (struct nfsstate) + len,
36879ec7b004SRick Macklem 	    M_NFSDSTATE, M_WAITOK);
36889ec7b004SRick Macklem 	stp->ls_ownerlen = len;
36899ec7b004SRick Macklem 	stp->ls_op = NULL;
36909ec7b004SRick Macklem 	stp->ls_flags = NFSLCK_RELEASE;
36919ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
36929ec7b004SRick Macklem 	clientid.lval[0] = *tl++;
36939ec7b004SRick Macklem 	clientid.lval[1] = *tl;
3694c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3695c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3696c59e4cc3SRick Macklem 			clientid.qval = nd->nd_clientid.qval;
3697c59e4cc3SRick Macklem 		else if (nd->nd_clientid.qval != clientid.qval)
3698c59e4cc3SRick Macklem 			printf("EEK14 multiple clids\n");
36999ec7b004SRick Macklem 	} else {
3700c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_NFSV41) != 0)
3701c59e4cc3SRick Macklem 			printf("EEK! no clientid from session\n");
37029ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
37039ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
37049ec7b004SRick Macklem 	}
37059ec7b004SRick Macklem 	error = nfsrv_mtostr(nd, stp->ls_owner, len);
37069ec7b004SRick Macklem 	if (error)
37079ec7b004SRick Macklem 		goto nfsmout;
37089ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3709222daa42SConrad Meyer 	free(stp, M_NFSDSTATE);
3710a9285ae5SZack Kirsch 
3711a9285ae5SZack Kirsch 	NFSEXITCODE2(0, nd);
37129ec7b004SRick Macklem 	return (0);
37139ec7b004SRick Macklem nfsmout:
37149ec7b004SRick Macklem 	if (stp)
3715222daa42SConrad Meyer 		free(stp, M_NFSDSTATE);
3716a9285ae5SZack Kirsch 	NFSEXITCODE2(error, nd);
37179ec7b004SRick Macklem 	return (error);
37189ec7b004SRick Macklem }
3719c59e4cc3SRick Macklem 
3720c59e4cc3SRick Macklem /*
3721c59e4cc3SRick Macklem  * nfsv4 exchange_id service
3722c59e4cc3SRick Macklem  */
3723c59e4cc3SRick Macklem APPLESTATIC int
3724c59e4cc3SRick Macklem nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
3725c59e4cc3SRick Macklem     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3726c59e4cc3SRick Macklem {
3727c59e4cc3SRick Macklem 	uint32_t *tl;
3728c59e4cc3SRick Macklem 	int error = 0, i, idlen;
3729c59e4cc3SRick Macklem 	struct nfsclient *clp = NULL;
3730c59e4cc3SRick Macklem 	nfsquad_t clientid, confirm;
3731c59e4cc3SRick Macklem 	uint8_t *verf;
3732c59e4cc3SRick Macklem 	uint32_t sp4type, v41flags;
3733c59e4cc3SRick Macklem 	uint64_t owner_minor;
3734c59e4cc3SRick Macklem 	struct timespec verstime;
373557ef3db3SRick Macklem 	struct sockaddr_in *sad, *rad;
3736c59e4cc3SRick Macklem 
3737c59e4cc3SRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3738c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
3739c59e4cc3SRick Macklem 		goto nfsmout;
3740c59e4cc3SRick Macklem 	}
3741c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3742c59e4cc3SRick Macklem 	verf = (uint8_t *)tl;
3743c59e4cc3SRick Macklem 	tl += (NFSX_VERF / NFSX_UNSIGNED);
3744c59e4cc3SRick Macklem 	i = fxdr_unsigned(int, *tl);
3745c59e4cc3SRick Macklem 	if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3746c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
3747c59e4cc3SRick Macklem 		goto nfsmout;
3748c59e4cc3SRick Macklem 	}
3749c59e4cc3SRick Macklem 	idlen = i;
3750c59e4cc3SRick Macklem 	if (nd->nd_flag & ND_GSS)
3751c59e4cc3SRick Macklem 		i += nd->nd_princlen;
37521f54e596SRick Macklem 	clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
37531f54e596SRick Macklem 	    M_ZERO);
37541f54e596SRick Macklem 	clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
37551f54e596SRick Macklem 	    nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
3756c59e4cc3SRick Macklem 	NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3757*b97b91b5SConrad Meyer 	clp->lc_req.nr_nam = malloc(sizeof(*clp->lc_req.nr_nam), M_SONAME,
3758*b97b91b5SConrad Meyer 	    M_WAITOK | M_ZERO);
3759c59e4cc3SRick Macklem 	NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
376057ef3db3SRick Macklem 	sad = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in *);
376157ef3db3SRick Macklem 	rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
376257ef3db3SRick Macklem 	rad->sin_family = AF_INET;
376357ef3db3SRick Macklem 	rad->sin_addr.s_addr = 0;
376457ef3db3SRick Macklem 	rad->sin_port = 0;
376557ef3db3SRick Macklem 	if (sad->sin_family == AF_INET)
376657ef3db3SRick Macklem 		rad->sin_addr.s_addr = sad->sin_addr.s_addr;
3767c59e4cc3SRick Macklem 	clp->lc_req.nr_cred = NULL;
3768c59e4cc3SRick Macklem 	NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3769c59e4cc3SRick Macklem 	clp->lc_idlen = idlen;
3770c59e4cc3SRick Macklem 	error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3771c59e4cc3SRick Macklem 	if (error != 0)
3772c59e4cc3SRick Macklem 		goto nfsmout;
3773c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_GSS) != 0) {
3774c59e4cc3SRick Macklem 		clp->lc_flags = LCL_GSS | LCL_NFSV41;
3775c59e4cc3SRick Macklem 		if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
3776c59e4cc3SRick Macklem 			clp->lc_flags |= LCL_GSSINTEGRITY;
3777c59e4cc3SRick Macklem 		else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
3778c59e4cc3SRick Macklem 			clp->lc_flags |= LCL_GSSPRIVACY;
3779c59e4cc3SRick Macklem 	} else
3780c59e4cc3SRick Macklem 		clp->lc_flags = LCL_NFSV41;
3781c59e4cc3SRick Macklem 	if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
3782c59e4cc3SRick Macklem 		clp->lc_flags |= LCL_NAME;
3783c59e4cc3SRick Macklem 		clp->lc_namelen = nd->nd_princlen;
3784c59e4cc3SRick Macklem 		clp->lc_name = &clp->lc_id[idlen];
3785c59e4cc3SRick Macklem 		NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3786c59e4cc3SRick Macklem 	} else {
3787c59e4cc3SRick Macklem 		clp->lc_uid = nd->nd_cred->cr_uid;
3788c59e4cc3SRick Macklem 		clp->lc_gid = nd->nd_cred->cr_gid;
3789c59e4cc3SRick Macklem 	}
3790c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3791c59e4cc3SRick Macklem 	v41flags = fxdr_unsigned(uint32_t, *tl++);
3792c59e4cc3SRick Macklem 	if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
3793c59e4cc3SRick Macklem 	    NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
3794c59e4cc3SRick Macklem 	    NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
3795c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
3796c59e4cc3SRick Macklem 		goto nfsmout;
3797c59e4cc3SRick Macklem 	}
3798c59e4cc3SRick Macklem 	if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
3799c59e4cc3SRick Macklem 		confirm.lval[1] = 1;
3800c59e4cc3SRick Macklem 	else
3801c59e4cc3SRick Macklem 		confirm.lval[1] = 0;
3802c59e4cc3SRick Macklem 	v41flags = NFSV4EXCH_USENONPNFS;
3803c59e4cc3SRick Macklem 	sp4type = fxdr_unsigned(uint32_t, *tl);
3804c59e4cc3SRick Macklem 	if (sp4type != NFSV4EXCH_SP4NONE) {
3805c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_NOTSUPP;
3806c59e4cc3SRick Macklem 		goto nfsmout;
3807c59e4cc3SRick Macklem 	}
3808c59e4cc3SRick Macklem 
3809c59e4cc3SRick Macklem 	/*
3810c59e4cc3SRick Macklem 	 * nfsrv_setclient() does the actual work of adding it to the
3811c59e4cc3SRick Macklem 	 * client list. If there is no error, the structure has been
3812c59e4cc3SRick Macklem 	 * linked into the client list and clp should no longer be used
3813c59e4cc3SRick Macklem 	 * here. When an error is returned, it has not been linked in,
3814c59e4cc3SRick Macklem 	 * so it should be free'd.
3815c59e4cc3SRick Macklem 	 */
3816c59e4cc3SRick Macklem 	nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3817c59e4cc3SRick Macklem 	if (clp != NULL) {
3818*b97b91b5SConrad Meyer 		free(clp->lc_req.nr_nam, M_SONAME);
3819c59e4cc3SRick Macklem 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
38201f54e596SRick Macklem 		free(clp->lc_stateid, M_NFSDCLIENT);
3821c59e4cc3SRick Macklem 		free(clp, M_NFSDCLIENT);
3822c59e4cc3SRick Macklem 	}
3823c59e4cc3SRick Macklem 	if (nd->nd_repstat == 0) {
3824c59e4cc3SRick Macklem 		if (confirm.lval[1] != 0)
3825c59e4cc3SRick Macklem 			v41flags |= NFSV4EXCH_CONFIRMEDR;
3826c59e4cc3SRick Macklem 		NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
3827c59e4cc3SRick Macklem 		*tl++ = clientid.lval[0];			/* ClientID */
3828c59e4cc3SRick Macklem 		*tl++ = clientid.lval[1];
3829c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(confirm.lval[0]);		/* SequenceID */
3830c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(v41flags);		/* Exch flags */
3831c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE);	/* No SSV */
3832c59e4cc3SRick Macklem 		owner_minor = 0;				/* Owner */
3833c59e4cc3SRick Macklem 		txdr_hyper(owner_minor, tl);			/* Minor */
3834c59e4cc3SRick Macklem 		(void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
3835c59e4cc3SRick Macklem 		    strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */
3836c59e4cc3SRick Macklem 		NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3837c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(NFSX_UNSIGNED);
3838c59e4cc3SRick Macklem 		*tl++ = time_uptime;		/* Make scope a unique value. */
3839c59e4cc3SRick Macklem 		*tl = txdr_unsigned(1);
3840c59e4cc3SRick Macklem 		(void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
3841c59e4cc3SRick Macklem 		(void)nfsm_strtom(nd, version, strlen(version));
3842c59e4cc3SRick Macklem 		NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
3843c59e4cc3SRick Macklem 		verstime.tv_sec = 1293840000;		/* Jan 1, 2011 */
3844c59e4cc3SRick Macklem 		verstime.tv_nsec = 0;
3845c59e4cc3SRick Macklem 		txdr_nfsv4time(&verstime, tl);
3846c59e4cc3SRick Macklem 	}
3847c59e4cc3SRick Macklem 	NFSEXITCODE2(0, nd);
3848c59e4cc3SRick Macklem 	return (0);
3849c59e4cc3SRick Macklem nfsmout:
3850c59e4cc3SRick Macklem 	if (clp != NULL) {
3851*b97b91b5SConrad Meyer 		free(clp->lc_req.nr_nam, M_SONAME);
3852c59e4cc3SRick Macklem 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
38531f54e596SRick Macklem 		free(clp->lc_stateid, M_NFSDCLIENT);
3854c59e4cc3SRick Macklem 		free(clp, M_NFSDCLIENT);
3855c59e4cc3SRick Macklem 	}
3856c59e4cc3SRick Macklem 	NFSEXITCODE2(error, nd);
3857c59e4cc3SRick Macklem 	return (error);
3858c59e4cc3SRick Macklem }
3859c59e4cc3SRick Macklem 
3860c59e4cc3SRick Macklem /*
3861c59e4cc3SRick Macklem  * nfsv4 create session service
3862c59e4cc3SRick Macklem  */
3863c59e4cc3SRick Macklem APPLESTATIC int
3864c59e4cc3SRick Macklem nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
3865c59e4cc3SRick Macklem     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3866c59e4cc3SRick Macklem {
3867c59e4cc3SRick Macklem 	uint32_t *tl;
3868c59e4cc3SRick Macklem 	int error = 0;
3869c59e4cc3SRick Macklem 	nfsquad_t clientid, confirm;
3870c59e4cc3SRick Macklem 	struct nfsdsession *sep = NULL;
3871c59e4cc3SRick Macklem 	uint32_t rdmacnt;
3872c59e4cc3SRick Macklem 
3873c59e4cc3SRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3874c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
3875c59e4cc3SRick Macklem 		goto nfsmout;
3876c59e4cc3SRick Macklem 	}
3877c59e4cc3SRick Macklem 	sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
3878c59e4cc3SRick Macklem 	    M_NFSDSESSION, M_WAITOK | M_ZERO);
3879c59e4cc3SRick Macklem 	sep->sess_refcnt = 1;
3880c59e4cc3SRick Macklem 	mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
3881c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
3882c59e4cc3SRick Macklem 	clientid.lval[0] = *tl++;
3883c59e4cc3SRick Macklem 	clientid.lval[1] = *tl++;
3884c59e4cc3SRick Macklem 	confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
3885c59e4cc3SRick Macklem 	sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
3886c59e4cc3SRick Macklem 	/* Persistent sessions and RDMA are not supported. */
3887c59e4cc3SRick Macklem 	sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
3888c59e4cc3SRick Macklem 
3889c59e4cc3SRick Macklem 	/* Fore channel attributes. */
3890c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
3891c59e4cc3SRick Macklem 	tl++;					/* Header pad always 0. */
3892c59e4cc3SRick Macklem 	sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
3893c59e4cc3SRick Macklem 	sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
3894c59e4cc3SRick Macklem 	sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
3895c59e4cc3SRick Macklem 	sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
3896c59e4cc3SRick Macklem 	sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
3897c59e4cc3SRick Macklem 	if (sep->sess_maxslots > NFSV4_SLOTS)
3898c59e4cc3SRick Macklem 		sep->sess_maxslots = NFSV4_SLOTS;
3899c59e4cc3SRick Macklem 	rdmacnt = fxdr_unsigned(uint32_t, *tl);
3900c59e4cc3SRick Macklem 	if (rdmacnt > 1) {
3901c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
3902c59e4cc3SRick Macklem 		goto nfsmout;
3903c59e4cc3SRick Macklem 	} else if (rdmacnt == 1)
3904c59e4cc3SRick Macklem 		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3905c59e4cc3SRick Macklem 
3906c59e4cc3SRick Macklem 	/* Back channel attributes. */
3907c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
3908c59e4cc3SRick Macklem 	tl++;					/* Header pad always 0. */
3909c59e4cc3SRick Macklem 	sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
3910c59e4cc3SRick Macklem 	sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
3911c59e4cc3SRick Macklem 	sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
3912c59e4cc3SRick Macklem 	sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
3913c59e4cc3SRick Macklem 	sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
3914c59e4cc3SRick Macklem 	rdmacnt = fxdr_unsigned(uint32_t, *tl);
3915c59e4cc3SRick Macklem 	if (rdmacnt > 1) {
3916c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
3917c59e4cc3SRick Macklem 		goto nfsmout;
3918c59e4cc3SRick Macklem 	} else if (rdmacnt == 1)
3919c59e4cc3SRick Macklem 		NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3920c59e4cc3SRick Macklem 
3921c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3922c59e4cc3SRick Macklem 	sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
3923c59e4cc3SRick Macklem 
3924c59e4cc3SRick Macklem 	/*
3925c59e4cc3SRick Macklem 	 * nfsrv_getclient() searches the client list for a match and
3926c59e4cc3SRick Macklem 	 * returns the appropriate NFSERR status.
3927c59e4cc3SRick Macklem 	 */
3928c59e4cc3SRick Macklem 	nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
3929c59e4cc3SRick Macklem 	    NULL, sep, confirm, sep->sess_cbprogram, nd, p);
3930c59e4cc3SRick Macklem 	if (nd->nd_repstat == 0) {
3931c59e4cc3SRick Macklem 		NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
3932c59e4cc3SRick Macklem 		NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
3933c59e4cc3SRick Macklem 		NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
3934c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(confirm.lval[0]);	/* sequenceid */
3935c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_crflags);
3936c59e4cc3SRick Macklem 
3937c59e4cc3SRick Macklem 		/* Fore channel attributes. */
3938c59e4cc3SRick Macklem 		*tl++ = 0;
3939c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_maxreq);
3940c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_maxresp);
3941c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_maxrespcached);
3942c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_maxops);
3943c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_maxslots);
3944c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(1);
3945c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(0);			/* No RDMA. */
3946c59e4cc3SRick Macklem 
3947c59e4cc3SRick Macklem 		/* Back channel attributes. */
3948c59e4cc3SRick Macklem 		*tl++ = 0;
3949c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_cbmaxreq);
3950c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_cbmaxresp);
3951c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
3952c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_cbmaxops);
3953c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
3954c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(1);
3955c59e4cc3SRick Macklem 		*tl = txdr_unsigned(0);			/* No RDMA. */
3956c59e4cc3SRick Macklem 	}
3957c59e4cc3SRick Macklem nfsmout:
3958c59e4cc3SRick Macklem 	if (nd->nd_repstat != 0 && sep != NULL)
3959c59e4cc3SRick Macklem 		free(sep, M_NFSDSESSION);
3960c59e4cc3SRick Macklem 	NFSEXITCODE2(error, nd);
3961c59e4cc3SRick Macklem 	return (error);
3962c59e4cc3SRick Macklem }
3963c59e4cc3SRick Macklem 
3964c59e4cc3SRick Macklem /*
3965c59e4cc3SRick Macklem  * nfsv4 sequence service
3966c59e4cc3SRick Macklem  */
3967c59e4cc3SRick Macklem APPLESTATIC int
3968c59e4cc3SRick Macklem nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
3969c59e4cc3SRick Macklem     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3970c59e4cc3SRick Macklem {
3971c59e4cc3SRick Macklem 	uint32_t *tl;
3972c59e4cc3SRick Macklem 	uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
3973c59e4cc3SRick Macklem 	int cache_this, error = 0;
3974c59e4cc3SRick Macklem 
3975c59e4cc3SRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3976c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
3977c59e4cc3SRick Macklem 		goto nfsmout;
3978c59e4cc3SRick Macklem 	}
3979c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
3980c59e4cc3SRick Macklem 	NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
3981c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
3982c59e4cc3SRick Macklem 	sequenceid = fxdr_unsigned(uint32_t, *tl++);
3983c59e4cc3SRick Macklem 	nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
3984c59e4cc3SRick Macklem 	highest_slotid = fxdr_unsigned(uint32_t, *tl++);
3985c59e4cc3SRick Macklem 	if (*tl == newnfs_true)
3986c59e4cc3SRick Macklem 		cache_this = 1;
3987c59e4cc3SRick Macklem 	else
3988c59e4cc3SRick Macklem 		cache_this = 0;
3989c59e4cc3SRick Macklem 	nd->nd_flag |= ND_HASSEQUENCE;
3990c59e4cc3SRick Macklem 	nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
3991c59e4cc3SRick Macklem 	    &target_highest_slotid, cache_this, &sflags, p);
3992c59e4cc3SRick Macklem 	if (nd->nd_repstat == 0) {
3993c59e4cc3SRick Macklem 		NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
3994c59e4cc3SRick Macklem 		NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
3995c59e4cc3SRick Macklem 		NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
3996c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(sequenceid);
3997c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(nd->nd_slotid);
3998c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(highest_slotid);
3999c59e4cc3SRick Macklem 		*tl++ = txdr_unsigned(target_highest_slotid);
4000c59e4cc3SRick Macklem 		*tl = txdr_unsigned(sflags);
4001c59e4cc3SRick Macklem 	}
4002c59e4cc3SRick Macklem nfsmout:
4003c59e4cc3SRick Macklem 	NFSEXITCODE2(error, nd);
4004c59e4cc3SRick Macklem 	return (error);
4005c59e4cc3SRick Macklem }
4006c59e4cc3SRick Macklem 
4007c59e4cc3SRick Macklem /*
4008c59e4cc3SRick Macklem  * nfsv4 reclaim complete service
4009c59e4cc3SRick Macklem  */
4010c59e4cc3SRick Macklem APPLESTATIC int
4011c59e4cc3SRick Macklem nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
4012c59e4cc3SRick Macklem     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
4013c59e4cc3SRick Macklem {
4014c59e4cc3SRick Macklem 	uint32_t *tl;
4015c59e4cc3SRick Macklem 	int error = 0;
4016c59e4cc3SRick Macklem 
4017c59e4cc3SRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4018c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
4019c59e4cc3SRick Macklem 		goto nfsmout;
4020c59e4cc3SRick Macklem 	}
4021c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4022c59e4cc3SRick Macklem 	if (*tl == newnfs_true)
4023c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_NOTSUPP;
4024c59e4cc3SRick Macklem 	else
4025c59e4cc3SRick Macklem 		nd->nd_repstat = nfsrv_checkreclaimcomplete(nd);
4026c59e4cc3SRick Macklem nfsmout:
4027c59e4cc3SRick Macklem 	NFSEXITCODE2(error, nd);
4028c59e4cc3SRick Macklem 	return (error);
4029c59e4cc3SRick Macklem }
4030c59e4cc3SRick Macklem 
4031c59e4cc3SRick Macklem /*
4032c59e4cc3SRick Macklem  * nfsv4 destroy clientid service
4033c59e4cc3SRick Macklem  */
4034c59e4cc3SRick Macklem APPLESTATIC int
4035c59e4cc3SRick Macklem nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
4036c59e4cc3SRick Macklem     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
4037c59e4cc3SRick Macklem {
4038c59e4cc3SRick Macklem 	uint32_t *tl;
4039c59e4cc3SRick Macklem 	nfsquad_t clientid;
4040c59e4cc3SRick Macklem 	int error = 0;
4041c59e4cc3SRick Macklem 
4042c59e4cc3SRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4043c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
4044c59e4cc3SRick Macklem 		goto nfsmout;
4045c59e4cc3SRick Macklem 	}
4046c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4047c59e4cc3SRick Macklem 	clientid.lval[0] = *tl++;
4048c59e4cc3SRick Macklem 	clientid.lval[1] = *tl;
4049c59e4cc3SRick Macklem 	nd->nd_repstat = nfsrv_destroyclient(clientid, p);
4050c59e4cc3SRick Macklem nfsmout:
4051c59e4cc3SRick Macklem 	NFSEXITCODE2(error, nd);
4052c59e4cc3SRick Macklem 	return (error);
4053c59e4cc3SRick Macklem }
4054c59e4cc3SRick Macklem 
4055c59e4cc3SRick Macklem /*
4056c59e4cc3SRick Macklem  * nfsv4 destroy session service
4057c59e4cc3SRick Macklem  */
4058c59e4cc3SRick Macklem APPLESTATIC int
4059c59e4cc3SRick Macklem nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4060c59e4cc3SRick Macklem     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
4061c59e4cc3SRick Macklem {
4062c59e4cc3SRick Macklem 	uint8_t *cp, sessid[NFSX_V4SESSIONID];
4063c59e4cc3SRick Macklem 	int error = 0;
4064c59e4cc3SRick Macklem 
4065c59e4cc3SRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4066c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
4067c59e4cc3SRick Macklem 		goto nfsmout;
4068c59e4cc3SRick Macklem 	}
4069c59e4cc3SRick Macklem 	NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4070c59e4cc3SRick Macklem 	NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4071c59e4cc3SRick Macklem 	nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4072c59e4cc3SRick Macklem nfsmout:
4073c59e4cc3SRick Macklem 	NFSEXITCODE2(error, nd);
4074c59e4cc3SRick Macklem 	return (error);
4075c59e4cc3SRick Macklem }
4076c59e4cc3SRick Macklem 
4077c59e4cc3SRick Macklem /*
4078c59e4cc3SRick Macklem  * nfsv4 free stateid service
4079c59e4cc3SRick Macklem  */
4080c59e4cc3SRick Macklem APPLESTATIC int
4081c59e4cc3SRick Macklem nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
4082c59e4cc3SRick Macklem     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
4083c59e4cc3SRick Macklem {
4084c59e4cc3SRick Macklem 	uint32_t *tl;
4085c59e4cc3SRick Macklem 	nfsv4stateid_t stateid;
4086c59e4cc3SRick Macklem 	int error = 0;
4087c59e4cc3SRick Macklem 
4088c59e4cc3SRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
4089c59e4cc3SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
4090c59e4cc3SRick Macklem 		goto nfsmout;
4091c59e4cc3SRick Macklem 	}
4092c59e4cc3SRick Macklem 	NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4093c59e4cc3SRick Macklem 	stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4094c59e4cc3SRick Macklem 	NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4095c59e4cc3SRick Macklem 	nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
4096c59e4cc3SRick Macklem nfsmout:
4097c59e4cc3SRick Macklem 	NFSEXITCODE2(error, nd);
4098c59e4cc3SRick Macklem 	return (error);
4099c59e4cc3SRick Macklem }
4100c59e4cc3SRick Macklem 
4101c59e4cc3SRick Macklem /*
4102c59e4cc3SRick Macklem  * nfsv4 service not supported
4103c59e4cc3SRick Macklem  */
4104c59e4cc3SRick Macklem APPLESTATIC int
4105c59e4cc3SRick Macklem nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
4106c59e4cc3SRick Macklem     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
4107c59e4cc3SRick Macklem {
4108c59e4cc3SRick Macklem 
4109c59e4cc3SRick Macklem 	nd->nd_repstat = NFSERR_NOTSUPP;
4110c59e4cc3SRick Macklem 	NFSEXITCODE2(0, nd);
4111c59e4cc3SRick Macklem 	return (0);
4112c59e4cc3SRick Macklem }
4113c59e4cc3SRick Macklem 
4114