xref: /freebsd/sys/fs/nfsserver/nfs_nfsdserv.c (revision 81f78d997d8796c5dad7982048843ed8bfa0cbbf)
19ec7b004SRick Macklem /*-
29ec7b004SRick Macklem  * Copyright (c) 1989, 1993
39ec7b004SRick Macklem  *	The Regents of the University of California.  All rights reserved.
49ec7b004SRick Macklem  *
59ec7b004SRick Macklem  * This code is derived from software contributed to Berkeley by
69ec7b004SRick Macklem  * Rick Macklem at The University of Guelph.
79ec7b004SRick Macklem  *
89ec7b004SRick Macklem  * Redistribution and use in source and binary forms, with or without
99ec7b004SRick Macklem  * modification, are permitted provided that the following conditions
109ec7b004SRick Macklem  * are met:
119ec7b004SRick Macklem  * 1. Redistributions of source code must retain the above copyright
129ec7b004SRick Macklem  *    notice, this list of conditions and the following disclaimer.
139ec7b004SRick Macklem  * 2. Redistributions in binary form must reproduce the above copyright
149ec7b004SRick Macklem  *    notice, this list of conditions and the following disclaimer in the
159ec7b004SRick Macklem  *    documentation and/or other materials provided with the distribution.
169ec7b004SRick Macklem  * 4. Neither the name of the University nor the names of its contributors
179ec7b004SRick Macklem  *    may be used to endorse or promote products derived from this software
189ec7b004SRick Macklem  *    without specific prior written permission.
199ec7b004SRick Macklem  *
209ec7b004SRick Macklem  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
219ec7b004SRick Macklem  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
229ec7b004SRick Macklem  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
239ec7b004SRick Macklem  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
249ec7b004SRick Macklem  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
259ec7b004SRick Macklem  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
269ec7b004SRick Macklem  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
279ec7b004SRick Macklem  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
289ec7b004SRick Macklem  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
299ec7b004SRick Macklem  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
309ec7b004SRick Macklem  * SUCH DAMAGE.
319ec7b004SRick Macklem  *
329ec7b004SRick Macklem  */
339ec7b004SRick Macklem 
349ec7b004SRick Macklem #include <sys/cdefs.h>
359ec7b004SRick Macklem __FBSDID("$FreeBSD$");
369ec7b004SRick Macklem 
379ec7b004SRick Macklem /*
389ec7b004SRick Macklem  * nfs version 2, 3 and 4 server calls to vnode ops
399ec7b004SRick Macklem  * - these routines generally have 3 phases
409ec7b004SRick Macklem  *   1 - break down and validate rpc request in mbuf list
419ec7b004SRick Macklem  *   2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
429ec7b004SRick Macklem  *       function in nfsd_port.c
439ec7b004SRick Macklem  *   3 - build the rpc reply in an mbuf list
449ec7b004SRick Macklem  * For nfsv4, these functions are called for each Op within the Compound RPC.
459ec7b004SRick Macklem  */
469ec7b004SRick Macklem 
479ec7b004SRick Macklem #ifndef APPLEKEXT
489ec7b004SRick Macklem #include <fs/nfs/nfsport.h>
499ec7b004SRick Macklem 
509ec7b004SRick Macklem /* Global vars */
519ec7b004SRick Macklem extern u_int32_t newnfs_false, newnfs_true;
529ec7b004SRick Macklem extern enum vtype nv34tov_type[8];
539ec7b004SRick Macklem extern struct timeval nfsboottime;
54c9aad40fSRick Macklem extern int nfs_rootfhset;
559ec7b004SRick Macklem #endif	/* !APPLEKEXT */
569ec7b004SRick Macklem 
579ec7b004SRick Macklem /*
589ec7b004SRick Macklem  * This list defines the GSS mechanisms supported.
599ec7b004SRick Macklem  * (Don't ask me how you get these strings from the RFC stuff like
609ec7b004SRick Macklem  *  iso(1), org(3)... but someone did it, so I don't need to know.)
619ec7b004SRick Macklem  */
629ec7b004SRick Macklem static struct nfsgss_mechlist nfsgss_mechlist[] = {
639ec7b004SRick Macklem 	{ 9, "\052\206\110\206\367\022\001\002\002", 11 },
649ec7b004SRick Macklem 	{ 0, "", 0 },
659ec7b004SRick Macklem };
669ec7b004SRick Macklem 
679ec7b004SRick Macklem /* local functions */
689ec7b004SRick Macklem static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
699ec7b004SRick Macklem     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
709ec7b004SRick Macklem     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
719ec7b004SRick Macklem     int *diraft_retp, nfsattrbit_t *attrbitp,
729ec7b004SRick Macklem     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
739ec7b004SRick Macklem     int pathlen);
749ec7b004SRick Macklem static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
759ec7b004SRick Macklem     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
769ec7b004SRick Macklem     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
779ec7b004SRick Macklem     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
789ec7b004SRick Macklem     NFSPROC_T *p, struct nfsexstuff *exp);
799ec7b004SRick Macklem 
809ec7b004SRick Macklem /*
819ec7b004SRick Macklem  * nfs access service (not a part of NFS V2)
829ec7b004SRick Macklem  */
839ec7b004SRick Macklem APPLESTATIC int
849ec7b004SRick Macklem nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
859ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
869ec7b004SRick Macklem {
879ec7b004SRick Macklem 	u_int32_t *tl;
889ec7b004SRick Macklem 	int getret, error = 0;
899ec7b004SRick Macklem 	struct nfsvattr nva;
909ec7b004SRick Macklem 	u_int32_t testmode, nfsmode, supported = 0;
918da45f2cSRick Macklem 	accmode_t deletebit;
929ec7b004SRick Macklem 
939ec7b004SRick Macklem 	if (nd->nd_repstat) {
949ec7b004SRick Macklem 		nfsrv_postopattr(nd, 1, &nva);
959ec7b004SRick Macklem 		return (0);
969ec7b004SRick Macklem 	}
979ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
989ec7b004SRick Macklem 	nfsmode = fxdr_unsigned(u_int32_t, *tl);
999ec7b004SRick Macklem 	if ((nd->nd_flag & ND_NFSV4) &&
1009ec7b004SRick Macklem 	    (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
1019ec7b004SRick Macklem 	     NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
1029ec7b004SRick Macklem 	     NFSACCESS_EXECUTE))) {
1039ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
1049ec7b004SRick Macklem 		vput(vp);
1059ec7b004SRick Macklem 		return (0);
1069ec7b004SRick Macklem 	}
1079ec7b004SRick Macklem 	if (nfsmode & NFSACCESS_READ) {
1089ec7b004SRick Macklem 		supported |= NFSACCESS_READ;
1098da45f2cSRick Macklem 		if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
1108da45f2cSRick Macklem 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
1119ec7b004SRick Macklem 			nfsmode &= ~NFSACCESS_READ;
1129ec7b004SRick Macklem 	}
1139ec7b004SRick Macklem 	if (nfsmode & NFSACCESS_MODIFY) {
1149ec7b004SRick Macklem 		supported |= NFSACCESS_MODIFY;
1158da45f2cSRick Macklem 		if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
1168da45f2cSRick Macklem 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
1179ec7b004SRick Macklem 			nfsmode &= ~NFSACCESS_MODIFY;
1189ec7b004SRick Macklem 	}
1199ec7b004SRick Macklem 	if (nfsmode & NFSACCESS_EXTEND) {
1209ec7b004SRick Macklem 		supported |= NFSACCESS_EXTEND;
1218da45f2cSRick Macklem 		if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
1228da45f2cSRick Macklem 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
1239ec7b004SRick Macklem 			nfsmode &= ~NFSACCESS_EXTEND;
1249ec7b004SRick Macklem 	}
1259ec7b004SRick Macklem 	if (nfsmode & NFSACCESS_DELETE) {
1269ec7b004SRick Macklem 		supported |= NFSACCESS_DELETE;
1278da45f2cSRick Macklem 		if (vp->v_type == VDIR)
1288da45f2cSRick Macklem 			deletebit = VDELETE_CHILD;
1298da45f2cSRick Macklem 		else
1308da45f2cSRick Macklem 			deletebit = VDELETE;
1318da45f2cSRick Macklem 		if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
1328da45f2cSRick Macklem 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
1339ec7b004SRick Macklem 			nfsmode &= ~NFSACCESS_DELETE;
1349ec7b004SRick Macklem 	}
1359ec7b004SRick Macklem 	if (vnode_vtype(vp) == VDIR)
1369ec7b004SRick Macklem 		testmode = NFSACCESS_LOOKUP;
1379ec7b004SRick Macklem 	else
1389ec7b004SRick Macklem 		testmode = NFSACCESS_EXECUTE;
1399ec7b004SRick Macklem 	if (nfsmode & testmode) {
1409ec7b004SRick Macklem 		supported |= (nfsmode & testmode);
1418da45f2cSRick Macklem 		if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
1428da45f2cSRick Macklem 		    NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
1439ec7b004SRick Macklem 			nfsmode &= ~testmode;
1449ec7b004SRick Macklem 	}
1459ec7b004SRick Macklem 	nfsmode &= supported;
1469ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
1470cf42b62SRick Macklem 		getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
1489ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &nva);
1499ec7b004SRick Macklem 	}
1509ec7b004SRick Macklem 	vput(vp);
1519ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
1529ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1539ec7b004SRick Macklem 		*tl++ = txdr_unsigned(supported);
1549ec7b004SRick Macklem 	} else
1559ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1569ec7b004SRick Macklem 	*tl = txdr_unsigned(nfsmode);
1579ec7b004SRick Macklem 	return (0);
1589ec7b004SRick Macklem nfsmout:
1599ec7b004SRick Macklem 	vput(vp);
1609ec7b004SRick Macklem 	return (error);
1619ec7b004SRick Macklem }
1629ec7b004SRick Macklem 
1639ec7b004SRick Macklem /*
1649ec7b004SRick Macklem  * nfs getattr service
1659ec7b004SRick Macklem  */
1669ec7b004SRick Macklem APPLESTATIC int
1679ec7b004SRick Macklem nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
1689ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1699ec7b004SRick Macklem {
1709ec7b004SRick Macklem 	struct nfsvattr nva;
1719ec7b004SRick Macklem 	fhandle_t fh;
1729ec7b004SRick Macklem 	int error = 0;
1739ec7b004SRick Macklem 	struct nfsreferral *refp;
1749ec7b004SRick Macklem 	nfsattrbit_t attrbits;
1759ec7b004SRick Macklem 
1769ec7b004SRick Macklem 	if (nd->nd_repstat)
1779ec7b004SRick Macklem 		return (0);
1789ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
1799ec7b004SRick Macklem 		error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1809ec7b004SRick Macklem 		if (error) {
1819ec7b004SRick Macklem 			vput(vp);
1829ec7b004SRick Macklem 			return (error);
1839ec7b004SRick Macklem 		}
1849ec7b004SRick Macklem 
1859ec7b004SRick Macklem 		/*
1869ec7b004SRick Macklem 		 * Check for a referral.
1879ec7b004SRick Macklem 		 */
1889ec7b004SRick Macklem 		refp = nfsv4root_getreferral(vp, NULL, 0);
1899ec7b004SRick Macklem 		if (refp != NULL) {
1909ec7b004SRick Macklem 			(void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
1919ec7b004SRick Macklem 			    &nd->nd_repstat);
1929ec7b004SRick Macklem 			vput(vp);
1939ec7b004SRick Macklem 			return (0);
1949ec7b004SRick Macklem 		}
1959ec7b004SRick Macklem 		if (!nd->nd_repstat)
1969ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_accchk(vp,
1978da45f2cSRick Macklem 			    VREAD_ATTRIBUTES,
1988da45f2cSRick Macklem 			    nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
1998da45f2cSRick Macklem 			    NFSACCCHK_VPISLOCKED, NULL);
2009ec7b004SRick Macklem 	}
2019ec7b004SRick Macklem 	if (!nd->nd_repstat)
2020cf42b62SRick Macklem 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2039ec7b004SRick Macklem 	if (!nd->nd_repstat) {
2049ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV4) {
2059ec7b004SRick Macklem 			if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
2069ec7b004SRick Macklem 				nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
2079ec7b004SRick Macklem 			if (!nd->nd_repstat)
2089ec7b004SRick Macklem 				nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
2099ec7b004SRick Macklem 				    &nva, &attrbits, nd->nd_cred, p);
2109ec7b004SRick Macklem 			NFSVOPUNLOCK(vp, 0, p);
2119ec7b004SRick Macklem 			if (!nd->nd_repstat)
2129ec7b004SRick Macklem 				(void) nfsvno_fillattr(nd, vp, &nva, &fh,
2139ec7b004SRick Macklem 				    0, &attrbits, nd->nd_cred, p, isdgram, 1);
2149ec7b004SRick Macklem 			vrele(vp);
2159ec7b004SRick Macklem 		} else {
2169ec7b004SRick Macklem 			nfsrv_fillattr(nd, &nva);
2179ec7b004SRick Macklem 			vput(vp);
2189ec7b004SRick Macklem 		}
2199ec7b004SRick Macklem 	} else {
2209ec7b004SRick Macklem 		vput(vp);
2219ec7b004SRick Macklem 	}
2229ec7b004SRick Macklem 	return (0);
2239ec7b004SRick Macklem }
2249ec7b004SRick Macklem 
2259ec7b004SRick Macklem /*
2269ec7b004SRick Macklem  * nfs setattr service
2279ec7b004SRick Macklem  */
2289ec7b004SRick Macklem APPLESTATIC int
2299ec7b004SRick Macklem nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
2309ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2319ec7b004SRick Macklem {
2329ec7b004SRick Macklem 	struct nfsvattr nva, nva2;
2339ec7b004SRick Macklem 	u_int32_t *tl;
2349ec7b004SRick Macklem 	int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
2359ec7b004SRick Macklem 	struct timespec guard = { 0, 0 };
2369ec7b004SRick Macklem 	nfsattrbit_t attrbits, retbits;
2379ec7b004SRick Macklem 	nfsv4stateid_t stateid;
2389ec7b004SRick Macklem 	NFSACL_T *aclp = NULL;
2399ec7b004SRick Macklem 
2409ec7b004SRick Macklem 	if (nd->nd_repstat) {
2419ec7b004SRick Macklem 		nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
2429ec7b004SRick Macklem 		return (0);
2439ec7b004SRick Macklem 	}
2449ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
245c3e22f83SRick Macklem 	aclp = acl_alloc(M_WAITOK);
2469ec7b004SRick Macklem 	aclp->acl_cnt = 0;
2479ec7b004SRick Macklem #endif
2489ec7b004SRick Macklem 	NFSVNO_ATTRINIT(&nva);
2499ec7b004SRick Macklem 	NFSZERO_ATTRBIT(&retbits);
2509ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
2519ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2529ec7b004SRick Macklem 		stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2539ec7b004SRick Macklem 		NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2549ec7b004SRick Macklem 	}
2559ec7b004SRick Macklem 	error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
2569ec7b004SRick Macklem 	if (error)
2579ec7b004SRick Macklem 		goto nfsmout;
2580cf42b62SRick Macklem 	preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1);
2599ec7b004SRick Macklem 	if (!nd->nd_repstat)
2609ec7b004SRick Macklem 		nd->nd_repstat = preat_ret;
2619ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
2629ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2639ec7b004SRick Macklem 		gcheck = fxdr_unsigned(int, *tl);
2649ec7b004SRick Macklem 		if (gcheck) {
2659ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2669ec7b004SRick Macklem 			fxdr_nfsv3time(tl, &guard);
2679ec7b004SRick Macklem 		}
2689ec7b004SRick Macklem 		if (!nd->nd_repstat && gcheck &&
2699ec7b004SRick Macklem 		    (nva2.na_ctime.tv_sec != guard.tv_sec ||
2709ec7b004SRick Macklem 		     nva2.na_ctime.tv_nsec != guard.tv_nsec))
2719ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_NOT_SYNC;
2729ec7b004SRick Macklem 		if (nd->nd_repstat) {
2739ec7b004SRick Macklem 			vput(vp);
2749ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
2759ec7b004SRick Macklem 			acl_free(aclp);
2769ec7b004SRick Macklem #endif
2779ec7b004SRick Macklem 			nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
2789ec7b004SRick Macklem 			return (0);
2799ec7b004SRick Macklem 		}
2809ec7b004SRick Macklem 	} else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
2819ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2829ec7b004SRick Macklem 
2839ec7b004SRick Macklem 	/*
2849ec7b004SRick Macklem 	 * Now that we have all the fields, lets do it.
2859ec7b004SRick Macklem 	 * If the size is being changed write access is required, otherwise
2869ec7b004SRick Macklem 	 * just check for a read only file system.
2879ec7b004SRick Macklem 	 */
2889ec7b004SRick Macklem 	if (!nd->nd_repstat) {
2899ec7b004SRick Macklem 		if (NFSVNO_NOTSETSIZE(&nva)) {
2909ec7b004SRick Macklem 			if (NFSVNO_EXRDONLY(exp) ||
2919ec7b004SRick Macklem 			    (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
2929ec7b004SRick Macklem 				nd->nd_repstat = EROFS;
2939ec7b004SRick Macklem 		} else {
2949ec7b004SRick Macklem 			if (vnode_vtype(vp) != VREG)
2959ec7b004SRick Macklem 				nd->nd_repstat = EINVAL;
2969ec7b004SRick Macklem 			else if (nva2.na_uid != nd->nd_cred->cr_uid ||
2979ec7b004SRick Macklem 			    NFSVNO_EXSTRICTACCESS(exp))
2989ec7b004SRick Macklem 				nd->nd_repstat = nfsvno_accchk(vp,
2998da45f2cSRick Macklem 				    VWRITE, nd->nd_cred, exp, p,
3008da45f2cSRick Macklem 				    NFSACCCHK_NOOVERRIDE,
3018da45f2cSRick Macklem 				    NFSACCCHK_VPISLOCKED, NULL);
3029ec7b004SRick Macklem 		}
3039ec7b004SRick Macklem 	}
3049ec7b004SRick Macklem 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
3059ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
3069ec7b004SRick Macklem 		    &nva, &attrbits, exp, p);
3079ec7b004SRick Macklem 
3089ec7b004SRick Macklem 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
3099ec7b004SRick Macklem 	    /*
3109ec7b004SRick Macklem 	     * For V4, try setting the attrbutes in sets, so that the
3119ec7b004SRick Macklem 	     * reply bitmap will be correct for an error case.
3129ec7b004SRick Macklem 	     */
3139ec7b004SRick Macklem 	    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
3149ec7b004SRick Macklem 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
3159ec7b004SRick Macklem 		NFSVNO_ATTRINIT(&nva2);
3169ec7b004SRick Macklem 		NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
3179ec7b004SRick Macklem 		NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
3189ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
3199ec7b004SRick Macklem 		    exp);
3209ec7b004SRick Macklem 		if (!nd->nd_repstat) {
3219ec7b004SRick Macklem 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
3229ec7b004SRick Macklem 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
3239ec7b004SRick Macklem 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
3249ec7b004SRick Macklem 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
3259ec7b004SRick Macklem 		}
3269ec7b004SRick Macklem 	    }
3279ec7b004SRick Macklem 	    if (!nd->nd_repstat &&
3289ec7b004SRick Macklem 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
3299ec7b004SRick Macklem 		NFSVNO_ATTRINIT(&nva2);
3309ec7b004SRick Macklem 		NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
3319ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
3329ec7b004SRick Macklem 		    exp);
3339ec7b004SRick Macklem 		if (!nd->nd_repstat)
3349ec7b004SRick Macklem 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
3359ec7b004SRick Macklem 	    }
3369ec7b004SRick Macklem 	    if (!nd->nd_repstat &&
3379ec7b004SRick Macklem 		(NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
3389ec7b004SRick Macklem 		 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
3399ec7b004SRick Macklem 		NFSVNO_ATTRINIT(&nva2);
3409ec7b004SRick Macklem 		NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
3419ec7b004SRick Macklem 		NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
3429ec7b004SRick Macklem 		if (nva.na_vaflags & VA_UTIMES_NULL) {
3439ec7b004SRick Macklem 			nva2.na_vaflags |= VA_UTIMES_NULL;
3449ec7b004SRick Macklem 			NFSVNO_SETACTIVE(&nva2, vaflags);
3459ec7b004SRick Macklem 		}
3469ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
3479ec7b004SRick Macklem 		    exp);
3489ec7b004SRick Macklem 		if (!nd->nd_repstat) {
3499ec7b004SRick Macklem 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
3509ec7b004SRick Macklem 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
3519ec7b004SRick Macklem 		    if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
3529ec7b004SRick Macklem 			NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
3539ec7b004SRick Macklem 		}
3549ec7b004SRick Macklem 	    }
3559ec7b004SRick Macklem 	    if (!nd->nd_repstat &&
3569ec7b004SRick Macklem 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) {
3579ec7b004SRick Macklem 		NFSVNO_ATTRINIT(&nva2);
3589ec7b004SRick Macklem 		NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
3599ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
3609ec7b004SRick Macklem 		    exp);
3619ec7b004SRick Macklem 		if (!nd->nd_repstat)
3629ec7b004SRick Macklem 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
3639ec7b004SRick Macklem 	    }
3649ec7b004SRick Macklem 
3659ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
3669ec7b004SRick Macklem 	    if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
3679ec7b004SRick Macklem 		NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
3689ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
3699ec7b004SRick Macklem 		if (!nd->nd_repstat)
3709ec7b004SRick Macklem 		    NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
3719ec7b004SRick Macklem 	    }
3729ec7b004SRick Macklem #endif
3739ec7b004SRick Macklem 	} else if (!nd->nd_repstat) {
3749ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
3759ec7b004SRick Macklem 		    exp);
3769ec7b004SRick Macklem 	}
3779ec7b004SRick Macklem 	if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
3780cf42b62SRick Macklem 		postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
3799ec7b004SRick Macklem 		if (!nd->nd_repstat)
3809ec7b004SRick Macklem 			nd->nd_repstat = postat_ret;
3819ec7b004SRick Macklem 	}
3829ec7b004SRick Macklem 	vput(vp);
3839ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
3849ec7b004SRick Macklem 	acl_free(aclp);
3859ec7b004SRick Macklem #endif
3869ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
3879ec7b004SRick Macklem 		nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
3889ec7b004SRick Macklem 	else if (nd->nd_flag & ND_NFSV4)
3899ec7b004SRick Macklem 		(void) nfsrv_putattrbit(nd, &retbits);
3909ec7b004SRick Macklem 	else if (!nd->nd_repstat)
3919ec7b004SRick Macklem 		nfsrv_fillattr(nd, &nva);
3929ec7b004SRick Macklem 	return (0);
3939ec7b004SRick Macklem nfsmout:
3949ec7b004SRick Macklem 	vput(vp);
3959ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
3969ec7b004SRick Macklem 	acl_free(aclp);
3979ec7b004SRick Macklem #endif
3989ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
3999ec7b004SRick Macklem 		/*
4009ec7b004SRick Macklem 		 * For all nd_repstat, the V4 reply includes a bitmap,
4019ec7b004SRick Macklem 		 * even NFSERR_BADXDR, which is what this will end up
4029ec7b004SRick Macklem 		 * returning.
4039ec7b004SRick Macklem 		 */
4049ec7b004SRick Macklem 		(void) nfsrv_putattrbit(nd, &retbits);
4059ec7b004SRick Macklem 	}
4069ec7b004SRick Macklem 	return (error);
4079ec7b004SRick Macklem }
4089ec7b004SRick Macklem 
4099ec7b004SRick Macklem /*
4109ec7b004SRick Macklem  * nfs lookup rpc
4119ec7b004SRick Macklem  * (Also performs lookup parent for v4)
4129ec7b004SRick Macklem  */
4139ec7b004SRick Macklem APPLESTATIC int
4149ec7b004SRick Macklem nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
4159ec7b004SRick Macklem     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
4169ec7b004SRick Macklem     __unused struct nfsexstuff *exp)
4179ec7b004SRick Macklem {
4189ec7b004SRick Macklem 	struct nameidata named;
4199ec7b004SRick Macklem 	vnode_t vp, dirp = NULL;
4209ec7b004SRick Macklem 	int error, dattr_ret = 1;
4219ec7b004SRick Macklem 	struct nfsvattr nva, dattr;
4229ec7b004SRick Macklem 	char *bufp;
4239ec7b004SRick Macklem 	u_long *hashp;
4249ec7b004SRick Macklem 
4259ec7b004SRick Macklem 	if (nd->nd_repstat) {
4269ec7b004SRick Macklem 		nfsrv_postopattr(nd, dattr_ret, &dattr);
4279ec7b004SRick Macklem 		return (0);
4289ec7b004SRick Macklem 	}
4299ec7b004SRick Macklem 
4309ec7b004SRick Macklem 	/*
4319ec7b004SRick Macklem 	 * For some reason, if dp is a symlink, the error
4329ec7b004SRick Macklem 	 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
4339ec7b004SRick Macklem 	 */
4349ec7b004SRick Macklem 	if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
4359ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_SYMLINK;
4369ec7b004SRick Macklem 		vrele(dp);
4379ec7b004SRick Macklem 		return (0);
4389ec7b004SRick Macklem 	}
4399ec7b004SRick Macklem 
4409ec7b004SRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
4419ec7b004SRick Macklem 	    LOCKLEAF | SAVESTART);
4429ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
4439ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
4449ec7b004SRick Macklem 	if (error) {
4459ec7b004SRick Macklem 		vrele(dp);
4469ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
4479ec7b004SRick Macklem 		return (error);
4489ec7b004SRick Macklem 	}
4499ec7b004SRick Macklem 	if (!nd->nd_repstat) {
4509ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
4519ec7b004SRick Macklem 	} else {
4529ec7b004SRick Macklem 		vrele(dp);
4539ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
4549ec7b004SRick Macklem 	}
4559ec7b004SRick Macklem 	if (nd->nd_repstat) {
4569ec7b004SRick Macklem 		if (dirp) {
4579ec7b004SRick Macklem 			if (nd->nd_flag & ND_NFSV3)
4589ec7b004SRick Macklem 				dattr_ret = nfsvno_getattr(dirp, &dattr,
4590cf42b62SRick Macklem 				    nd->nd_cred, p, 0);
4609ec7b004SRick Macklem 			vrele(dirp);
4619ec7b004SRick Macklem 		}
4629ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
4639ec7b004SRick Macklem 			nfsrv_postopattr(nd, dattr_ret, &dattr);
4649ec7b004SRick Macklem 		return (0);
4659ec7b004SRick Macklem 	}
4669ec7b004SRick Macklem 	if (named.ni_startdir)
4679ec7b004SRick Macklem 		vrele(named.ni_startdir);
4689ec7b004SRick Macklem 	nfsvno_relpathbuf(&named);
4699ec7b004SRick Macklem 	vp = named.ni_vp;
4709ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
4719ec7b004SRick Macklem 	if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
4720cf42b62SRick Macklem 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
473*81f78d99SRick Macklem 	if (vpp != NULL && nd->nd_repstat == 0)
4749ec7b004SRick Macklem 		*vpp = vp;
475*81f78d99SRick Macklem 	else
4769ec7b004SRick Macklem 		vput(vp);
4779ec7b004SRick Macklem 	if (dirp) {
4789ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
4799ec7b004SRick Macklem 			dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred,
4800cf42b62SRick Macklem 			    p, 0);
4819ec7b004SRick Macklem 		vrele(dirp);
4829ec7b004SRick Macklem 	}
4839ec7b004SRick Macklem 	if (nd->nd_repstat) {
4849ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
4859ec7b004SRick Macklem 			nfsrv_postopattr(nd, dattr_ret, &dattr);
4869ec7b004SRick Macklem 		return (0);
4879ec7b004SRick Macklem 	}
4889ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV2) {
4899ec7b004SRick Macklem 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
4909ec7b004SRick Macklem 		nfsrv_fillattr(nd, &nva);
4919ec7b004SRick Macklem 	} else if (nd->nd_flag & ND_NFSV3) {
4929ec7b004SRick Macklem 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
4939ec7b004SRick Macklem 		nfsrv_postopattr(nd, 0, &nva);
4949ec7b004SRick Macklem 		nfsrv_postopattr(nd, dattr_ret, &dattr);
4959ec7b004SRick Macklem 	}
4969ec7b004SRick Macklem 	return (0);
4979ec7b004SRick Macklem }
4989ec7b004SRick Macklem 
4999ec7b004SRick Macklem /*
5009ec7b004SRick Macklem  * nfs readlink service
5019ec7b004SRick Macklem  */
5029ec7b004SRick Macklem APPLESTATIC int
5039ec7b004SRick Macklem nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
5049ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
5059ec7b004SRick Macklem {
5069ec7b004SRick Macklem 	u_int32_t *tl;
5079ec7b004SRick Macklem 	mbuf_t mp = NULL, mpend = NULL;
5089ec7b004SRick Macklem 	int getret = 1, len;
5099ec7b004SRick Macklem 	struct nfsvattr nva;
5109ec7b004SRick Macklem 
5119ec7b004SRick Macklem 	if (nd->nd_repstat) {
5129ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &nva);
5139ec7b004SRick Macklem 		return (0);
5149ec7b004SRick Macklem 	}
5159ec7b004SRick Macklem 	if (vnode_vtype(vp) != VLNK) {
5169ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV2)
5179ec7b004SRick Macklem 			nd->nd_repstat = ENXIO;
5189ec7b004SRick Macklem 		else
5199ec7b004SRick Macklem 			nd->nd_repstat = EINVAL;
5209ec7b004SRick Macklem 	}
5219ec7b004SRick Macklem 	if (!nd->nd_repstat)
5229ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
5239ec7b004SRick Macklem 		    &mp, &mpend, &len);
5249ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
5250cf42b62SRick Macklem 		getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
5269ec7b004SRick Macklem 	vput(vp);
5279ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
5289ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &nva);
5299ec7b004SRick Macklem 	if (nd->nd_repstat)
5309ec7b004SRick Macklem 		return (0);
5319ec7b004SRick Macklem 	NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
5329ec7b004SRick Macklem 	*tl = txdr_unsigned(len);
5339ec7b004SRick Macklem 	mbuf_setnext(nd->nd_mb, mp);
5349ec7b004SRick Macklem 	nd->nd_mb = mpend;
5359ec7b004SRick Macklem 	nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
5369ec7b004SRick Macklem 	return (0);
5379ec7b004SRick Macklem }
5389ec7b004SRick Macklem 
5399ec7b004SRick Macklem /*
5409ec7b004SRick Macklem  * nfs read service
5419ec7b004SRick Macklem  */
5429ec7b004SRick Macklem APPLESTATIC int
5439ec7b004SRick Macklem nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
5449ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
5459ec7b004SRick Macklem {
5469ec7b004SRick Macklem 	u_int32_t *tl;
5479ec7b004SRick Macklem 	int error = 0, cnt, len, getret = 1, reqlen, eof = 0;
5489ec7b004SRick Macklem 	mbuf_t m2, m3;
5499ec7b004SRick Macklem 	struct nfsvattr nva;
5509ec7b004SRick Macklem 	off_t off = 0x0;
5519ec7b004SRick Macklem 	struct nfsstate st, *stp = &st;
5529ec7b004SRick Macklem 	struct nfslock lo, *lop = &lo;
5539ec7b004SRick Macklem 	nfsv4stateid_t stateid;
5549ec7b004SRick Macklem 	nfsquad_t clientid;
5559ec7b004SRick Macklem 
5569ec7b004SRick Macklem 	if (nd->nd_repstat) {
5579ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &nva);
5589ec7b004SRick Macklem 		return (0);
5599ec7b004SRick Macklem 	}
5609ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV2) {
5619ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
5629ec7b004SRick Macklem 		off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
5639ec7b004SRick Macklem 		reqlen = fxdr_unsigned(int, *tl);
5649ec7b004SRick Macklem 	} else if (nd->nd_flag & ND_NFSV3) {
5659ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
5669ec7b004SRick Macklem 		off = fxdr_hyper(tl);
5679ec7b004SRick Macklem 		tl += 2;
5689ec7b004SRick Macklem 		reqlen = fxdr_unsigned(int, *tl);
5699ec7b004SRick Macklem 	} else {
5709ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
5719ec7b004SRick Macklem 		reqlen = fxdr_unsigned(int, *(tl + 6));
5729ec7b004SRick Macklem 	}
5739ec7b004SRick Macklem 	if (reqlen > NFS_SRVMAXDATA(nd)) {
5749ec7b004SRick Macklem 		reqlen = NFS_SRVMAXDATA(nd);
5759ec7b004SRick Macklem 	} else if (reqlen < 0) {
5769ec7b004SRick Macklem 		error = EBADRPC;
5779ec7b004SRick Macklem 		goto nfsmout;
5789ec7b004SRick Macklem 	}
5799ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
5809ec7b004SRick Macklem 		stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
5819ec7b004SRick Macklem 		lop->lo_flags = NFSLCK_READ;
5829ec7b004SRick Macklem 		stp->ls_ownerlen = 0;
5839ec7b004SRick Macklem 		stp->ls_op = NULL;
5849ec7b004SRick Macklem 		stp->ls_uid = nd->nd_cred->cr_uid;
5859ec7b004SRick Macklem 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
5869ec7b004SRick Macklem 		clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
5879ec7b004SRick Macklem 		clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
5889ec7b004SRick Macklem 		if (nd->nd_flag & ND_IMPLIEDCLID) {
5899ec7b004SRick Macklem 			if (nd->nd_clientid.qval != clientid.qval)
5909ec7b004SRick Macklem 				printf("EEK! multiple clids\n");
5919ec7b004SRick Macklem 		} else {
5929ec7b004SRick Macklem 			nd->nd_flag |= ND_IMPLIEDCLID;
5939ec7b004SRick Macklem 			nd->nd_clientid.qval = clientid.qval;
5949ec7b004SRick Macklem 		}
5959ec7b004SRick Macklem 		stp->ls_stateid.other[2] = *tl++;
5969ec7b004SRick Macklem 		off = fxdr_hyper(tl);
5979ec7b004SRick Macklem 		lop->lo_first = off;
5989ec7b004SRick Macklem 		tl += 2;
5999ec7b004SRick Macklem 		lop->lo_end = off + reqlen;
6009ec7b004SRick Macklem 		/*
6019ec7b004SRick Macklem 		 * Paranoia, just in case it wraps around.
6029ec7b004SRick Macklem 		 */
6039ec7b004SRick Macklem 		if (lop->lo_end < off)
6049ec7b004SRick Macklem 			lop->lo_end = NFS64BITSSET;
6059ec7b004SRick Macklem 	}
6069ec7b004SRick Macklem 	if (vnode_vtype(vp) != VREG) {
6079ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
6089ec7b004SRick Macklem 			nd->nd_repstat = EINVAL;
6099ec7b004SRick Macklem 		else
6109ec7b004SRick Macklem 			nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
6119ec7b004SRick Macklem 			    EINVAL;
6129ec7b004SRick Macklem 	}
6130cf42b62SRick Macklem 	getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
6149ec7b004SRick Macklem 	if (!nd->nd_repstat)
6159ec7b004SRick Macklem 		nd->nd_repstat = getret;
6169ec7b004SRick Macklem 	if (!nd->nd_repstat &&
6179ec7b004SRick Macklem 	    (nva.na_uid != nd->nd_cred->cr_uid ||
6189ec7b004SRick Macklem 	     NFSVNO_EXSTRICTACCESS(exp))) {
6198da45f2cSRick Macklem 		nd->nd_repstat = nfsvno_accchk(vp, VREAD,
6209ec7b004SRick Macklem 		    nd->nd_cred, exp, p,
6218da45f2cSRick Macklem 		    NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
6229ec7b004SRick Macklem 		if (nd->nd_repstat)
6238da45f2cSRick Macklem 			nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
6248da45f2cSRick Macklem 			    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
6258da45f2cSRick Macklem 			    NFSACCCHK_VPISLOCKED, NULL);
6269ec7b004SRick Macklem 	}
6279ec7b004SRick Macklem 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
6289ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
6299ec7b004SRick Macklem 		    &stateid, exp, nd, p);
6309ec7b004SRick Macklem 	if (nd->nd_repstat) {
6319ec7b004SRick Macklem 		vput(vp);
6329ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
6339ec7b004SRick Macklem 			nfsrv_postopattr(nd, getret, &nva);
6349ec7b004SRick Macklem 		return (0);
6359ec7b004SRick Macklem 	}
6369ec7b004SRick Macklem 	if (off >= nva.na_size) {
6379ec7b004SRick Macklem 		cnt = 0;
6389ec7b004SRick Macklem 		eof = 1;
6399ec7b004SRick Macklem 	} else if (reqlen == 0)
6409ec7b004SRick Macklem 		cnt = 0;
6419ec7b004SRick Macklem 	else if ((off + reqlen) > nva.na_size)
6429ec7b004SRick Macklem 		cnt = nva.na_size - off;
6439ec7b004SRick Macklem 	else
6449ec7b004SRick Macklem 		cnt = reqlen;
6459ec7b004SRick Macklem 	len = NFSM_RNDUP(cnt);
6469ec7b004SRick Macklem 	m3 = NULL;
6479ec7b004SRick Macklem 	if (cnt > 0) {
6489ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
6499ec7b004SRick Macklem 		    &m3, &m2);
6509ec7b004SRick Macklem 		if (!(nd->nd_flag & ND_NFSV4)) {
6510cf42b62SRick Macklem 			getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
6529ec7b004SRick Macklem 			if (!nd->nd_repstat)
6539ec7b004SRick Macklem 				nd->nd_repstat = getret;
6549ec7b004SRick Macklem 		}
6559ec7b004SRick Macklem 		if (nd->nd_repstat) {
6569ec7b004SRick Macklem 			vput(vp);
6579ec7b004SRick Macklem 			if (m3)
6589ec7b004SRick Macklem 				mbuf_freem(m3);
6599ec7b004SRick Macklem 			if (nd->nd_flag & ND_NFSV3)
6609ec7b004SRick Macklem 				nfsrv_postopattr(nd, getret, &nva);
6619ec7b004SRick Macklem 			return (0);
6629ec7b004SRick Macklem 		}
6639ec7b004SRick Macklem 	}
6649ec7b004SRick Macklem 	vput(vp);
6659ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV2) {
6669ec7b004SRick Macklem 		nfsrv_fillattr(nd, &nva);
6679ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
6689ec7b004SRick Macklem 	} else {
6699ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
6709ec7b004SRick Macklem 			nfsrv_postopattr(nd, getret, &nva);
6719ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
6729ec7b004SRick Macklem 			*tl++ = txdr_unsigned(cnt);
6739ec7b004SRick Macklem 		} else
6749ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
6759ec7b004SRick Macklem 		if (len < reqlen || eof)
6769ec7b004SRick Macklem 			*tl++ = newnfs_true;
6779ec7b004SRick Macklem 		else
6789ec7b004SRick Macklem 			*tl++ = newnfs_false;
6799ec7b004SRick Macklem 	}
6809ec7b004SRick Macklem 	*tl = txdr_unsigned(cnt);
6819ec7b004SRick Macklem 	if (m3) {
6829ec7b004SRick Macklem 		mbuf_setnext(nd->nd_mb, m3);
6839ec7b004SRick Macklem 		nd->nd_mb = m2;
6849ec7b004SRick Macklem 		nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
6859ec7b004SRick Macklem 	}
6869ec7b004SRick Macklem 	return (0);
6879ec7b004SRick Macklem nfsmout:
6889ec7b004SRick Macklem 	vput(vp);
6899ec7b004SRick Macklem 	return (error);
6909ec7b004SRick Macklem }
6919ec7b004SRick Macklem 
6929ec7b004SRick Macklem /*
6939ec7b004SRick Macklem  * nfs write service
6949ec7b004SRick Macklem  */
6959ec7b004SRick Macklem APPLESTATIC int
6969ec7b004SRick Macklem nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
6979ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
6989ec7b004SRick Macklem {
6999ec7b004SRick Macklem 	int i, cnt;
7009ec7b004SRick Macklem 	u_int32_t *tl;
7019ec7b004SRick Macklem 	mbuf_t mp;
7029ec7b004SRick Macklem 	struct nfsvattr nva, forat;
7039ec7b004SRick Macklem 	int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
7049ec7b004SRick Macklem 	int stable = NFSWRITE_FILESYNC;
7059ec7b004SRick Macklem 	off_t off;
7069ec7b004SRick Macklem 	struct nfsstate st, *stp = &st;
7079ec7b004SRick Macklem 	struct nfslock lo, *lop = &lo;
7089ec7b004SRick Macklem 	nfsv4stateid_t stateid;
7099ec7b004SRick Macklem 	nfsquad_t clientid;
7109ec7b004SRick Macklem 
7119ec7b004SRick Macklem 	if (nd->nd_repstat) {
7129ec7b004SRick Macklem 		nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
7139ec7b004SRick Macklem 		return (0);
7149ec7b004SRick Macklem 	}
7159ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV2) {
7169ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
7179ec7b004SRick Macklem 		off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
7189ec7b004SRick Macklem 		tl += 2;
7199ec7b004SRick Macklem 		retlen = len = fxdr_unsigned(int32_t, *tl);
7209ec7b004SRick Macklem 	} else if (nd->nd_flag & ND_NFSV3) {
7219ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
7229ec7b004SRick Macklem 		off = fxdr_hyper(tl);
7239ec7b004SRick Macklem 		tl += 3;
7249ec7b004SRick Macklem 		stable = fxdr_unsigned(int, *tl++);
7259ec7b004SRick Macklem 		retlen = len = fxdr_unsigned(int32_t, *tl);
7269ec7b004SRick Macklem 	} else {
7279ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
7289ec7b004SRick Macklem 		stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
7299ec7b004SRick Macklem 		lop->lo_flags = NFSLCK_WRITE;
7309ec7b004SRick Macklem 		stp->ls_ownerlen = 0;
7319ec7b004SRick Macklem 		stp->ls_op = NULL;
7329ec7b004SRick Macklem 		stp->ls_uid = nd->nd_cred->cr_uid;
7339ec7b004SRick Macklem 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
7349ec7b004SRick Macklem 		clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
7359ec7b004SRick Macklem 		clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
7369ec7b004SRick Macklem 		if (nd->nd_flag & ND_IMPLIEDCLID) {
7379ec7b004SRick Macklem 			if (nd->nd_clientid.qval != clientid.qval)
7389ec7b004SRick Macklem 				printf("EEK! multiple clids\n");
7399ec7b004SRick Macklem 		} else {
7409ec7b004SRick Macklem 			nd->nd_flag |= ND_IMPLIEDCLID;
7419ec7b004SRick Macklem 			nd->nd_clientid.qval = clientid.qval;
7429ec7b004SRick Macklem 		}
7439ec7b004SRick Macklem 		stp->ls_stateid.other[2] = *tl++;
7449ec7b004SRick Macklem 		off = fxdr_hyper(tl);
7459ec7b004SRick Macklem 		lop->lo_first = off;
7469ec7b004SRick Macklem 		tl += 2;
7479ec7b004SRick Macklem 		stable = fxdr_unsigned(int, *tl++);
7489ec7b004SRick Macklem 		retlen = len = fxdr_unsigned(int32_t, *tl);
7499ec7b004SRick Macklem 		lop->lo_end = off + len;
7509ec7b004SRick Macklem 		/*
7519ec7b004SRick Macklem 		 * Paranoia, just in case it wraps around, which shouldn't
7529ec7b004SRick Macklem 		 * ever happen anyhow.
7539ec7b004SRick Macklem 		 */
7549ec7b004SRick Macklem 		if (lop->lo_end < lop->lo_first)
7559ec7b004SRick Macklem 			lop->lo_end = NFS64BITSSET;
7569ec7b004SRick Macklem 	}
7579ec7b004SRick Macklem 
7589ec7b004SRick Macklem 	/*
7599ec7b004SRick Macklem 	 * Loop through the mbuf chain, counting how many mbufs are a
7609ec7b004SRick Macklem 	 * part of this write operation, so the iovec size is known.
7619ec7b004SRick Macklem 	 */
7629ec7b004SRick Macklem 	cnt = 0;
7639ec7b004SRick Macklem 	mp = nd->nd_md;
7649ec7b004SRick Macklem 	i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
7659ec7b004SRick Macklem 	while (len > 0) {
7669ec7b004SRick Macklem 		if (i > 0) {
7679ec7b004SRick Macklem 			len -= i;
7689ec7b004SRick Macklem 			cnt++;
7699ec7b004SRick Macklem 		}
7709ec7b004SRick Macklem 		mp = mbuf_next(mp);
7719ec7b004SRick Macklem 		if (!mp) {
7729ec7b004SRick Macklem 			if (len > 0) {
7739ec7b004SRick Macklem 				error = EBADRPC;
7749ec7b004SRick Macklem 				goto nfsmout;
7759ec7b004SRick Macklem 			}
7769ec7b004SRick Macklem 		} else
7779ec7b004SRick Macklem 			i = mbuf_len(mp);
7789ec7b004SRick Macklem 	}
7799ec7b004SRick Macklem 
7809ec7b004SRick Macklem 	if (retlen > NFS_MAXDATA || retlen < 0)
7819ec7b004SRick Macklem 		nd->nd_repstat = EIO;
7829ec7b004SRick Macklem 	if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
7839ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
7849ec7b004SRick Macklem 			nd->nd_repstat = EINVAL;
7859ec7b004SRick Macklem 		else
7869ec7b004SRick Macklem 			nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
7879ec7b004SRick Macklem 			    EINVAL;
7889ec7b004SRick Macklem 	}
7890cf42b62SRick Macklem 	forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1);
7909ec7b004SRick Macklem 	if (!nd->nd_repstat)
7919ec7b004SRick Macklem 		nd->nd_repstat = forat_ret;
7929ec7b004SRick Macklem 	if (!nd->nd_repstat &&
7939ec7b004SRick Macklem 	    (forat.na_uid != nd->nd_cred->cr_uid ||
7949ec7b004SRick Macklem 	     NFSVNO_EXSTRICTACCESS(exp)))
7958da45f2cSRick Macklem 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
7969ec7b004SRick Macklem 		    nd->nd_cred, exp, p,
7978da45f2cSRick Macklem 		    NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
7989ec7b004SRick Macklem 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
7999ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
8009ec7b004SRick Macklem 		    &stateid, exp, nd, p);
8019ec7b004SRick Macklem 	}
8029ec7b004SRick Macklem 	if (nd->nd_repstat) {
8039ec7b004SRick Macklem 		vput(vp);
8049ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
8059ec7b004SRick Macklem 			nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
8069ec7b004SRick Macklem 		return (0);
8079ec7b004SRick Macklem 	}
8089ec7b004SRick Macklem 
8099ec7b004SRick Macklem 	/*
8109ec7b004SRick Macklem 	 * For NFS Version 2, it is not obvious what a write of zero length
8119ec7b004SRick Macklem 	 * should do, but I might as well be consistent with Version 3,
8129ec7b004SRick Macklem 	 * which is to return ok so long as there are no permission problems.
8139ec7b004SRick Macklem 	 */
8149ec7b004SRick Macklem 	if (retlen > 0) {
8159ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable,
8169ec7b004SRick Macklem 		    nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
8179ec7b004SRick Macklem 		error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
8189ec7b004SRick Macklem 		if (error)
8199ec7b004SRick Macklem 			panic("nfsrv_write mbuf");
8209ec7b004SRick Macklem 	}
8219ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4)
8229ec7b004SRick Macklem 		aftat_ret = 0;
8239ec7b004SRick Macklem 	else
8240cf42b62SRick Macklem 		aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
8259ec7b004SRick Macklem 	vput(vp);
8269ec7b004SRick Macklem 	if (!nd->nd_repstat)
8279ec7b004SRick Macklem 		nd->nd_repstat = aftat_ret;
8289ec7b004SRick Macklem 	if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
8299ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
8309ec7b004SRick Macklem 			nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
8319ec7b004SRick Macklem 		if (nd->nd_repstat)
8329ec7b004SRick Macklem 			return (0);
8339ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
8349ec7b004SRick Macklem 		*tl++ = txdr_unsigned(retlen);
8359ec7b004SRick Macklem 		if (stable == NFSWRITE_UNSTABLE)
8369ec7b004SRick Macklem 			*tl++ = txdr_unsigned(stable);
8379ec7b004SRick Macklem 		else
8389ec7b004SRick Macklem 			*tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
8399ec7b004SRick Macklem 		/*
8409ec7b004SRick Macklem 		 * Actually, there is no need to txdr these fields,
8419ec7b004SRick Macklem 		 * but it may make the values more human readable,
8429ec7b004SRick Macklem 		 * for debugging purposes.
8439ec7b004SRick Macklem 		 */
8449ec7b004SRick Macklem 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
8459ec7b004SRick Macklem 		*tl = txdr_unsigned(nfsboottime.tv_usec);
8469ec7b004SRick Macklem 	} else if (!nd->nd_repstat)
8479ec7b004SRick Macklem 		nfsrv_fillattr(nd, &nva);
8489ec7b004SRick Macklem 	return (0);
8499ec7b004SRick Macklem nfsmout:
8509ec7b004SRick Macklem 	vput(vp);
8519ec7b004SRick Macklem 	return (error);
8529ec7b004SRick Macklem }
8539ec7b004SRick Macklem 
8549ec7b004SRick Macklem /*
8559ec7b004SRick Macklem  * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
8569ec7b004SRick Macklem  * now does a truncate to 0 length via. setattr if it already exists
8579ec7b004SRick Macklem  * The core creation routine has been extracted out into nfsrv_creatsub(),
8589ec7b004SRick Macklem  * so it can also be used by nfsrv_open() for V4.
8599ec7b004SRick Macklem  */
8609ec7b004SRick Macklem APPLESTATIC int
8619ec7b004SRick Macklem nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
8629ec7b004SRick Macklem     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
8639ec7b004SRick Macklem {
8649ec7b004SRick Macklem 	struct nfsvattr nva, dirfor, diraft;
8659ec7b004SRick Macklem 	struct nfsv2_sattr *sp;
8669ec7b004SRick Macklem 	struct nameidata named;
8679ec7b004SRick Macklem 	u_int32_t *tl;
8689ec7b004SRick Macklem 	int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
8699ec7b004SRick Macklem 	int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
8709ec7b004SRick Macklem 	NFSDEV_T rdev = 0;
8719ec7b004SRick Macklem 	vnode_t vp = NULL, dirp = NULL;
8729ec7b004SRick Macklem 	fhandle_t fh;
8739ec7b004SRick Macklem 	char *bufp;
8749ec7b004SRick Macklem 	u_long *hashp;
8759ec7b004SRick Macklem 	enum vtype vtyp;
876086f6e0cSRick Macklem 	int32_t cverf[2], tverf[2] = { 0, 0 };
8779ec7b004SRick Macklem 
8789ec7b004SRick Macklem 	if (nd->nd_repstat) {
8799ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
8809ec7b004SRick Macklem 		return (0);
8819ec7b004SRick Macklem 	}
8829ec7b004SRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
8839ec7b004SRick Macklem 	    LOCKPARENT | LOCKLEAF | SAVESTART);
8849ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
8859ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
8869ec7b004SRick Macklem 	if (error) {
8879ec7b004SRick Macklem 		vput(dp);
8889ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
8899ec7b004SRick Macklem 		return (error);
8909ec7b004SRick Macklem 	}
8919ec7b004SRick Macklem 	if (!nd->nd_repstat) {
8929ec7b004SRick Macklem 		NFSVNO_ATTRINIT(&nva);
8939ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV2) {
8949ec7b004SRick Macklem 			NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
8959ec7b004SRick Macklem 			vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
8969ec7b004SRick Macklem 			if (vtyp == VNON)
8979ec7b004SRick Macklem 				vtyp = VREG;
8989ec7b004SRick Macklem 			NFSVNO_SETATTRVAL(&nva, type, vtyp);
8999ec7b004SRick Macklem 			NFSVNO_SETATTRVAL(&nva, mode,
9009ec7b004SRick Macklem 			    nfstov_mode(sp->sa_mode));
9019ec7b004SRick Macklem 			switch (nva.na_type) {
9029ec7b004SRick Macklem 			case VREG:
9039ec7b004SRick Macklem 				tsize = fxdr_unsigned(int32_t, sp->sa_size);
9049ec7b004SRick Macklem 				if (tsize != -1)
9059ec7b004SRick Macklem 					NFSVNO_SETATTRVAL(&nva, size,
9069ec7b004SRick Macklem 					    (u_quad_t)tsize);
9079ec7b004SRick Macklem 				break;
9089ec7b004SRick Macklem 			case VCHR:
9099ec7b004SRick Macklem 			case VBLK:
9109ec7b004SRick Macklem 			case VFIFO:
9119ec7b004SRick Macklem 				rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
9129ec7b004SRick Macklem 				break;
9139ec7b004SRick Macklem 			default:
9149ec7b004SRick Macklem 				break;
9159ec7b004SRick Macklem 			};
9169ec7b004SRick Macklem 		} else {
9179ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
9189ec7b004SRick Macklem 			how = fxdr_unsigned(int, *tl);
9199ec7b004SRick Macklem 			switch (how) {
9209ec7b004SRick Macklem 			case NFSCREATE_GUARDED:
9219ec7b004SRick Macklem 			case NFSCREATE_UNCHECKED:
9229ec7b004SRick Macklem 				error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
9239ec7b004SRick Macklem 				if (error)
9249ec7b004SRick Macklem 					goto nfsmout;
9259ec7b004SRick Macklem 				break;
9269ec7b004SRick Macklem 			case NFSCREATE_EXCLUSIVE:
927086f6e0cSRick Macklem 				NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
928086f6e0cSRick Macklem 				cverf[0] = *tl++;
929086f6e0cSRick Macklem 				cverf[1] = *tl;
9309ec7b004SRick Macklem 				exclusive_flag = 1;
9319ec7b004SRick Macklem 				break;
9329ec7b004SRick Macklem 			};
9339ec7b004SRick Macklem 			NFSVNO_SETATTRVAL(&nva, type, VREG);
9349ec7b004SRick Macklem 		}
9359ec7b004SRick Macklem 	}
9369ec7b004SRick Macklem 	if (nd->nd_repstat) {
9379ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
9389ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
9399ec7b004SRick Macklem 			dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred,
9400cf42b62SRick Macklem 			    p, 1);
9419ec7b004SRick Macklem 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
9429ec7b004SRick Macklem 			    &diraft);
9439ec7b004SRick Macklem 		}
9449ec7b004SRick Macklem 		vput(dp);
9459ec7b004SRick Macklem 		return (0);
9469ec7b004SRick Macklem 	}
9479ec7b004SRick Macklem 
9489ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
9499ec7b004SRick Macklem 	if (dirp) {
9509ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV2) {
9519ec7b004SRick Macklem 			vrele(dirp);
9529ec7b004SRick Macklem 			dirp = NULL;
9539ec7b004SRick Macklem 		} else {
9549ec7b004SRick Macklem 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
9550cf42b62SRick Macklem 			    p, 0);
9569ec7b004SRick Macklem 		}
9579ec7b004SRick Macklem 	}
9589ec7b004SRick Macklem 	if (nd->nd_repstat) {
9599ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
9609ec7b004SRick Macklem 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
9619ec7b004SRick Macklem 			    &diraft);
9629ec7b004SRick Macklem 		if (dirp)
9639ec7b004SRick Macklem 			vrele(dirp);
9649ec7b004SRick Macklem 		return (0);
9659ec7b004SRick Macklem 	}
9669ec7b004SRick Macklem 
9679ec7b004SRick Macklem 	if (!(nd->nd_flag & ND_NFSV2)) {
9689ec7b004SRick Macklem 		switch (how) {
9699ec7b004SRick Macklem 		case NFSCREATE_GUARDED:
9709ec7b004SRick Macklem 			if (named.ni_vp)
9719ec7b004SRick Macklem 				nd->nd_repstat = EEXIST;
9729ec7b004SRick Macklem 			break;
9739ec7b004SRick Macklem 		case NFSCREATE_UNCHECKED:
9749ec7b004SRick Macklem 			break;
9759ec7b004SRick Macklem 		case NFSCREATE_EXCLUSIVE:
9769ec7b004SRick Macklem 			if (named.ni_vp == NULL)
9779ec7b004SRick Macklem 				NFSVNO_SETATTRVAL(&nva, mode, 0);
9789ec7b004SRick Macklem 			break;
9799ec7b004SRick Macklem 		};
9809ec7b004SRick Macklem 	}
9819ec7b004SRick Macklem 
9829ec7b004SRick Macklem 	/*
9839ec7b004SRick Macklem 	 * Iff doesn't exist, create it
9849ec7b004SRick Macklem 	 * otherwise just truncate to 0 length
9859ec7b004SRick Macklem 	 *   should I set the mode too ?
9869ec7b004SRick Macklem 	 */
9879ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
9889ec7b004SRick Macklem 	    &exclusive_flag, cverf, rdev, p, exp);
9899ec7b004SRick Macklem 
9909ec7b004SRick Macklem 	if (!nd->nd_repstat) {
9919ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
9929ec7b004SRick Macklem 		if (!nd->nd_repstat)
9939ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
9940cf42b62SRick Macklem 			    p, 1);
9959ec7b004SRick Macklem 		vput(vp);
996086f6e0cSRick Macklem 		if (!nd->nd_repstat) {
997086f6e0cSRick Macklem 			tverf[0] = nva.na_atime.tv_sec;
998086f6e0cSRick Macklem 			tverf[1] = nva.na_atime.tv_nsec;
999086f6e0cSRick Macklem 		}
10009ec7b004SRick Macklem 	}
10019ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV2) {
10029ec7b004SRick Macklem 		if (!nd->nd_repstat) {
10039ec7b004SRick Macklem 			(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
10049ec7b004SRick Macklem 			nfsrv_fillattr(nd, &nva);
10059ec7b004SRick Macklem 		}
10069ec7b004SRick Macklem 	} else {
1007086f6e0cSRick Macklem 		if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1008086f6e0cSRick Macklem 		    || cverf[1] != tverf[1]))
10099ec7b004SRick Macklem 			nd->nd_repstat = EEXIST;
10100cf42b62SRick Macklem 		diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
10119ec7b004SRick Macklem 		vrele(dirp);
10129ec7b004SRick Macklem 		if (!nd->nd_repstat) {
10139ec7b004SRick Macklem 			(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
10149ec7b004SRick Macklem 			nfsrv_postopattr(nd, 0, &nva);
10159ec7b004SRick Macklem 		}
10169ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
10179ec7b004SRick Macklem 	}
10189ec7b004SRick Macklem 	return (0);
10199ec7b004SRick Macklem nfsmout:
10209ec7b004SRick Macklem 	vput(dp);
10219ec7b004SRick Macklem 	nfsvno_relpathbuf(&named);
10229ec7b004SRick Macklem 	return (error);
10239ec7b004SRick Macklem }
10249ec7b004SRick Macklem 
10259ec7b004SRick Macklem /*
10269ec7b004SRick Macklem  * nfs v3 mknod service (and v4 create)
10279ec7b004SRick Macklem  */
10289ec7b004SRick Macklem APPLESTATIC int
10299ec7b004SRick Macklem nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
10309ec7b004SRick Macklem     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
10319ec7b004SRick Macklem     struct nfsexstuff *exp)
10329ec7b004SRick Macklem {
10339ec7b004SRick Macklem 	struct nfsvattr nva, dirfor, diraft;
10349ec7b004SRick Macklem 	u_int32_t *tl;
10359ec7b004SRick Macklem 	struct nameidata named;
10369ec7b004SRick Macklem 	int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
10379ec7b004SRick Macklem 	u_int32_t major, minor;
10389ec7b004SRick Macklem 	enum vtype vtyp = VNON;
10399ec7b004SRick Macklem 	nfstype nfs4type = NFNON;
10409ec7b004SRick Macklem 	vnode_t vp, dirp = NULL;
10419ec7b004SRick Macklem 	nfsattrbit_t attrbits;
10429ec7b004SRick Macklem 	char *bufp = NULL, *pathcp = NULL;
10439ec7b004SRick Macklem 	u_long *hashp, cnflags;
10449ec7b004SRick Macklem 	NFSACL_T *aclp = NULL;
10459ec7b004SRick Macklem 
10469ec7b004SRick Macklem 	NFSVNO_ATTRINIT(&nva);
10479ec7b004SRick Macklem 	cnflags = (LOCKPARENT | SAVESTART);
10489ec7b004SRick Macklem 	if (nd->nd_repstat) {
10499ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
10509ec7b004SRick Macklem 		return (0);
10519ec7b004SRick Macklem 	}
10529ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
1053c3e22f83SRick Macklem 	aclp = acl_alloc(M_WAITOK);
10549ec7b004SRick Macklem 	aclp->acl_cnt = 0;
10559ec7b004SRick Macklem #endif
10569ec7b004SRick Macklem 
10579ec7b004SRick Macklem 	/*
10589ec7b004SRick Macklem 	 * For V4, the creation stuff is here, Yuck!
10599ec7b004SRick Macklem 	 */
10609ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
10619ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
10629ec7b004SRick Macklem 		vtyp = nfsv34tov_type(*tl);
10639ec7b004SRick Macklem 		nfs4type = fxdr_unsigned(nfstype, *tl);
10649ec7b004SRick Macklem 		switch (nfs4type) {
10659ec7b004SRick Macklem 		case NFLNK:
10669ec7b004SRick Macklem 			error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
10679ec7b004SRick Macklem 			    &pathlen);
10689ec7b004SRick Macklem 			if (error) {
10699ec7b004SRick Macklem 				vrele(dp);
10709ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
10719ec7b004SRick Macklem 				acl_free(aclp);
10729ec7b004SRick Macklem #endif
10739ec7b004SRick Macklem 				return (error);
10749ec7b004SRick Macklem 			}
10759ec7b004SRick Macklem 			break;
10769ec7b004SRick Macklem 		case NFCHR:
10779ec7b004SRick Macklem 		case NFBLK:
10789ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
10799ec7b004SRick Macklem 			major = fxdr_unsigned(u_int32_t, *tl++);
10809ec7b004SRick Macklem 			minor = fxdr_unsigned(u_int32_t, *tl);
10819ec7b004SRick Macklem 			nva.na_rdev = NFSMAKEDEV(major, minor);
10829ec7b004SRick Macklem 			break;
10839ec7b004SRick Macklem 		case NFSOCK:
10849ec7b004SRick Macklem 		case NFFIFO:
10859ec7b004SRick Macklem 			break;
10869ec7b004SRick Macklem 		case NFDIR:
1087f61786cbSRick Macklem 			cnflags = (LOCKPARENT | SAVENAME);
10889ec7b004SRick Macklem 			break;
10899ec7b004SRick Macklem 		default:
10909ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_BADTYPE;
10919ec7b004SRick Macklem 			vrele(dp);
10929ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
10939ec7b004SRick Macklem 			acl_free(aclp);
10949ec7b004SRick Macklem #endif
10959ec7b004SRick Macklem 			return (0);
10969ec7b004SRick Macklem 		};
10979ec7b004SRick Macklem 	}
10989ec7b004SRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags);
10999ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
11009ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
11019ec7b004SRick Macklem 	if (error) {
11029ec7b004SRick Macklem 		vrele(dp);
11039ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
11049ec7b004SRick Macklem 		acl_free(aclp);
11059ec7b004SRick Macklem #endif
11069ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
11079ec7b004SRick Macklem 		if (pathcp)
11089ec7b004SRick Macklem 			FREE(pathcp, M_TEMP);
11099ec7b004SRick Macklem 		return (error);
11109ec7b004SRick Macklem 	}
11119ec7b004SRick Macklem 	if (!nd->nd_repstat) {
11129ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
11139ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
11149ec7b004SRick Macklem 			vtyp = nfsv34tov_type(*tl);
11159ec7b004SRick Macklem 		}
11169ec7b004SRick Macklem 		error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p);
11179ec7b004SRick Macklem 		if (error) {
11189ec7b004SRick Macklem 			vrele(dp);
11199ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
11209ec7b004SRick Macklem 			acl_free(aclp);
11219ec7b004SRick Macklem #endif
11229ec7b004SRick Macklem 			nfsvno_relpathbuf(&named);
11239ec7b004SRick Macklem 			if (pathcp)
11249ec7b004SRick Macklem 				FREE(pathcp, M_TEMP);
11259ec7b004SRick Macklem 			return (error);
11269ec7b004SRick Macklem 		}
11279ec7b004SRick Macklem 		nva.na_type = vtyp;
11289ec7b004SRick Macklem 		if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
11299ec7b004SRick Macklem 		    (vtyp == VCHR || vtyp == VBLK)) {
11309ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
11319ec7b004SRick Macklem 			major = fxdr_unsigned(u_int32_t, *tl++);
11329ec7b004SRick Macklem 			minor = fxdr_unsigned(u_int32_t, *tl);
11339ec7b004SRick Macklem 			nva.na_rdev = NFSMAKEDEV(major, minor);
11349ec7b004SRick Macklem 		}
11359ec7b004SRick Macklem 	}
11369ec7b004SRick Macklem 
11370cf42b62SRick Macklem 	dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
11389ec7b004SRick Macklem 	if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
11399ec7b004SRick Macklem 		if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
11409ec7b004SRick Macklem 		    dirfor.na_gid == nva.na_gid)
11419ec7b004SRick Macklem 			NFSVNO_UNSET(&nva, gid);
11429ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
11439ec7b004SRick Macklem 	}
11449ec7b004SRick Macklem 	if (nd->nd_repstat) {
11459ec7b004SRick Macklem 		vrele(dp);
11469ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
11479ec7b004SRick Macklem 		acl_free(aclp);
11489ec7b004SRick Macklem #endif
11499ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
11509ec7b004SRick Macklem 		if (pathcp)
11519ec7b004SRick Macklem 			FREE(pathcp, M_TEMP);
11529ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
11539ec7b004SRick Macklem 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
11549ec7b004SRick Macklem 			    &diraft);
11559ec7b004SRick Macklem 		return (0);
11569ec7b004SRick Macklem 	}
11579ec7b004SRick Macklem 
11589ec7b004SRick Macklem 	/*
11599ec7b004SRick Macklem 	 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
11609ec7b004SRick Macklem 	 * in va_mode, so we'll have to set a default here.
11619ec7b004SRick Macklem 	 */
11629ec7b004SRick Macklem 	if (NFSVNO_NOTSETMODE(&nva)) {
11639ec7b004SRick Macklem 		if (vtyp == VLNK)
11649ec7b004SRick Macklem 			nva.na_mode = 0755;
11659ec7b004SRick Macklem 		else
11669ec7b004SRick Macklem 			nva.na_mode = 0400;
11679ec7b004SRick Macklem 	}
11689ec7b004SRick Macklem 
11699ec7b004SRick Macklem 	if (vtyp == VDIR)
11709ec7b004SRick Macklem 		named.ni_cnd.cn_flags |= WILLBEDIR;
11719ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
11729ec7b004SRick Macklem 	if (nd->nd_repstat) {
11739ec7b004SRick Macklem 		if (dirp) {
11749ec7b004SRick Macklem 			if (nd->nd_flag & ND_NFSV3)
11759ec7b004SRick Macklem 				dirfor_ret = nfsvno_getattr(dirp, &dirfor,
11760cf42b62SRick Macklem 				    nd->nd_cred, p, 0);
11779ec7b004SRick Macklem 			vrele(dirp);
11789ec7b004SRick Macklem 		}
11799ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
11809ec7b004SRick Macklem 		acl_free(aclp);
11819ec7b004SRick Macklem #endif
11829ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
11839ec7b004SRick Macklem 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
11849ec7b004SRick Macklem 			    &diraft);
11859ec7b004SRick Macklem 		return (0);
11869ec7b004SRick Macklem 	}
11879ec7b004SRick Macklem 	if (dirp)
11880cf42b62SRick Macklem 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
11899ec7b004SRick Macklem 
11909ec7b004SRick Macklem 	if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
11919ec7b004SRick Macklem 		if (vtyp == VDIR) {
11929ec7b004SRick Macklem 			nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
11939ec7b004SRick Macklem 			    &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
11949ec7b004SRick Macklem 			    exp);
11959ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
11969ec7b004SRick Macklem 			acl_free(aclp);
11979ec7b004SRick Macklem #endif
11989ec7b004SRick Macklem 			return (0);
11999ec7b004SRick Macklem 		} else if (vtyp == VLNK) {
12009ec7b004SRick Macklem 			nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
12019ec7b004SRick Macklem 			    &dirfor, &diraft, &diraft_ret, &attrbits,
12029ec7b004SRick Macklem 			    aclp, p, exp, pathcp, pathlen);
12039ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
12049ec7b004SRick Macklem 			acl_free(aclp);
12059ec7b004SRick Macklem #endif
12069ec7b004SRick Macklem 			FREE(pathcp, M_TEMP);
12079ec7b004SRick Macklem 			return (0);
12089ec7b004SRick Macklem 		}
12099ec7b004SRick Macklem 	}
12109ec7b004SRick Macklem 
12119ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
12129ec7b004SRick Macklem 	if (!nd->nd_repstat) {
12139ec7b004SRick Macklem 		vp = named.ni_vp;
12149ec7b004SRick Macklem 		nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
12159ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
12169ec7b004SRick Macklem 		if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
12179ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
12180cf42b62SRick Macklem 			    p, 1);
1219*81f78d99SRick Macklem 		if (vpp != NULL && nd->nd_repstat == 0) {
1220*81f78d99SRick Macklem 			VOP_UNLOCK(vp, 0);
12219ec7b004SRick Macklem 			*vpp = vp;
1222*81f78d99SRick Macklem 		} else
12239ec7b004SRick Macklem 			vput(vp);
12249ec7b004SRick Macklem 	}
12259ec7b004SRick Macklem 
12260cf42b62SRick Macklem 	diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
12279ec7b004SRick Macklem 	vrele(dirp);
12289ec7b004SRick Macklem 	if (!nd->nd_repstat) {
12299ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
12309ec7b004SRick Macklem 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
12319ec7b004SRick Macklem 			nfsrv_postopattr(nd, 0, &nva);
12329ec7b004SRick Macklem 		} else {
12339ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
12349ec7b004SRick Macklem 			*tl++ = newnfs_false;
12359ec7b004SRick Macklem 			txdr_hyper(dirfor.na_filerev, tl);
12369ec7b004SRick Macklem 			tl += 2;
12379ec7b004SRick Macklem 			txdr_hyper(diraft.na_filerev, tl);
12389ec7b004SRick Macklem 			(void) nfsrv_putattrbit(nd, &attrbits);
12399ec7b004SRick Macklem 		}
12409ec7b004SRick Macklem 	}
12419ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
12429ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
12439ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
12449ec7b004SRick Macklem 	acl_free(aclp);
12459ec7b004SRick Macklem #endif
12469ec7b004SRick Macklem 	return (0);
12479ec7b004SRick Macklem nfsmout:
12489ec7b004SRick Macklem 	vrele(dp);
12499ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
12509ec7b004SRick Macklem 	acl_free(aclp);
12519ec7b004SRick Macklem #endif
12529ec7b004SRick Macklem 	if (bufp)
12539ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
12549ec7b004SRick Macklem 	if (pathcp)
12559ec7b004SRick Macklem 		FREE(pathcp, M_TEMP);
12569ec7b004SRick Macklem 	return (error);
12579ec7b004SRick Macklem }
12589ec7b004SRick Macklem 
12599ec7b004SRick Macklem /*
12609ec7b004SRick Macklem  * nfs remove service
12619ec7b004SRick Macklem  */
12629ec7b004SRick Macklem APPLESTATIC int
12639ec7b004SRick Macklem nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
12649ec7b004SRick Macklem     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
12659ec7b004SRick Macklem {
12669ec7b004SRick Macklem 	struct nameidata named;
12679ec7b004SRick Macklem 	u_int32_t *tl;
12689ec7b004SRick Macklem 	int error, dirfor_ret = 1, diraft_ret = 1;
12699ec7b004SRick Macklem 	vnode_t dirp = NULL;
12709ec7b004SRick Macklem 	struct nfsvattr dirfor, diraft;
12719ec7b004SRick Macklem 	char *bufp;
12729ec7b004SRick Macklem 	u_long *hashp;
12739ec7b004SRick Macklem 
12749ec7b004SRick Macklem 	if (nd->nd_repstat) {
12759ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
12769ec7b004SRick Macklem 		return (0);
12779ec7b004SRick Macklem 	}
12789ec7b004SRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
12799ec7b004SRick Macklem 	    LOCKPARENT | LOCKLEAF);
12809ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
12819ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
12829ec7b004SRick Macklem 	if (error) {
12839ec7b004SRick Macklem 		vput(dp);
12849ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
12859ec7b004SRick Macklem 		return (error);
12869ec7b004SRick Macklem 	}
12879ec7b004SRick Macklem 	if (!nd->nd_repstat) {
12889ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
12899ec7b004SRick Macklem 	} else {
12909ec7b004SRick Macklem 		vput(dp);
12919ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
12929ec7b004SRick Macklem 	}
12939ec7b004SRick Macklem 	if (dirp) {
12949ec7b004SRick Macklem 		if (!(nd->nd_flag & ND_NFSV2)) {
12959ec7b004SRick Macklem 			dirfor_ret = nfsvno_getattr(dirp, &dirfor,
12960cf42b62SRick Macklem 			    nd->nd_cred, p, 0);
12979ec7b004SRick Macklem 		} else {
12989ec7b004SRick Macklem 			vrele(dirp);
12999ec7b004SRick Macklem 			dirp = NULL;
13009ec7b004SRick Macklem 		}
13019ec7b004SRick Macklem 	}
13029ec7b004SRick Macklem 	if (!nd->nd_repstat) {
13039ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV4) {
13049ec7b004SRick Macklem 			if (vnode_vtype(named.ni_vp) == VDIR)
13059ec7b004SRick Macklem 				nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
13069ec7b004SRick Macklem 				    nd->nd_cred, p, exp);
13079ec7b004SRick Macklem 			else
13089ec7b004SRick Macklem 				nd->nd_repstat = nfsvno_removesub(&named, 1,
13099ec7b004SRick Macklem 				    nd->nd_cred, p, exp);
13109ec7b004SRick Macklem 		} else if (nd->nd_procnum == NFSPROC_RMDIR) {
13119ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
13129ec7b004SRick Macklem 			    nd->nd_cred, p, exp);
13139ec7b004SRick Macklem 		} else {
13149ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_removesub(&named, 0,
13159ec7b004SRick Macklem 			    nd->nd_cred, p, exp);
13169ec7b004SRick Macklem 		}
13179ec7b004SRick Macklem 	}
13189ec7b004SRick Macklem 	if (!(nd->nd_flag & ND_NFSV2)) {
13199ec7b004SRick Macklem 		if (dirp) {
13209ec7b004SRick Macklem 			diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred,
13210cf42b62SRick Macklem 			    p, 0);
13229ec7b004SRick Macklem 			vrele(dirp);
13239ec7b004SRick Macklem 		}
13249ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
13259ec7b004SRick Macklem 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
13269ec7b004SRick Macklem 			    &diraft);
13279ec7b004SRick Macklem 		} else if (!nd->nd_repstat) {
13289ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
13299ec7b004SRick Macklem 			*tl++ = newnfs_false;
13309ec7b004SRick Macklem 			txdr_hyper(dirfor.na_filerev, tl);
13319ec7b004SRick Macklem 			tl += 2;
13329ec7b004SRick Macklem 			txdr_hyper(diraft.na_filerev, tl);
13339ec7b004SRick Macklem 		}
13349ec7b004SRick Macklem 	}
13359ec7b004SRick Macklem 	return (0);
13369ec7b004SRick Macklem }
13379ec7b004SRick Macklem 
13389ec7b004SRick Macklem /*
13399ec7b004SRick Macklem  * nfs rename service
13409ec7b004SRick Macklem  */
13419ec7b004SRick Macklem APPLESTATIC int
13429ec7b004SRick Macklem nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
13439ec7b004SRick Macklem     vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp,
13449ec7b004SRick Macklem     struct nfsexstuff *toexp)
13459ec7b004SRick Macklem {
13469ec7b004SRick Macklem 	u_int32_t *tl;
13479ec7b004SRick Macklem 	int error, fdirfor_ret = 1, fdiraft_ret = 1;
13489ec7b004SRick Macklem 	int tdirfor_ret = 1, tdiraft_ret = 1;
13499ec7b004SRick Macklem 	struct nameidata fromnd, tond;
13509ec7b004SRick Macklem 	vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
13519ec7b004SRick Macklem 	struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
13529ec7b004SRick Macklem 	struct nfsexstuff tnes;
13539ec7b004SRick Macklem 	struct nfsrvfh tfh;
13549ec7b004SRick Macklem 	mount_t mp = NULL;
13559ec7b004SRick Macklem 	char *bufp, *tbufp = NULL;
13569ec7b004SRick Macklem 	u_long *hashp;
13579ec7b004SRick Macklem 
13589ec7b004SRick Macklem 	if (nd->nd_repstat) {
13599ec7b004SRick Macklem 		nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
13609ec7b004SRick Macklem 		nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
13619ec7b004SRick Macklem 		return (0);
13629ec7b004SRick Macklem 	}
13639ec7b004SRick Macklem 	if (!(nd->nd_flag & ND_NFSV2))
13640cf42b62SRick Macklem 		fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1);
13659ec7b004SRick Macklem 	tond.ni_cnd.cn_nameiop = 0;
13669ec7b004SRick Macklem 	tond.ni_startdir = NULL;
13679ec7b004SRick Macklem 	NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
13689ec7b004SRick Macklem 	nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
13699ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
13709ec7b004SRick Macklem 	if (error) {
13719ec7b004SRick Macklem 		vput(dp);
13729ec7b004SRick Macklem 		if (todp)
13739ec7b004SRick Macklem 			vrele(todp);
13749ec7b004SRick Macklem 		nfsvno_relpathbuf(&fromnd);
13759ec7b004SRick Macklem 		return (error);
13769ec7b004SRick Macklem 	}
13779ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV4) {
13789ec7b004SRick Macklem 		tdp = todp;
13799ec7b004SRick Macklem 		tnes = *toexp;
13800cf42b62SRick Macklem 		tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, p, 0);
13819ec7b004SRick Macklem 	} else {
13829ec7b004SRick Macklem 		error = nfsrv_mtofh(nd, &tfh);
13839ec7b004SRick Macklem 		if (error) {
13849ec7b004SRick Macklem 			vput(dp);
13859ec7b004SRick Macklem 			/* todp is always NULL except NFSv4 */
13869ec7b004SRick Macklem 			nfsvno_relpathbuf(&fromnd);
13879ec7b004SRick Macklem 			return (error);
13889ec7b004SRick Macklem 		}
13899ec7b004SRick Macklem 		nd->nd_cred->cr_uid = nd->nd_saveduid;
13909ec7b004SRick Macklem 		/* Won't lock vfs if already locked, mp == NULL */
13919ec7b004SRick Macklem 		tnes.nes_vfslocked = exp->nes_vfslocked;
139217891d00SRick Macklem 		nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, &mp, 0, p);
13939ec7b004SRick Macklem 		if (tdp) {
13949ec7b004SRick Macklem 			tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
13950cf42b62SRick Macklem 			    p, 1);
13969ec7b004SRick Macklem 			NFSVOPUNLOCK(tdp, 0, p);
13979ec7b004SRick Macklem 		}
13989ec7b004SRick Macklem 	}
13999ec7b004SRick Macklem 	NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
14009ec7b004SRick Macklem 	nfsvno_setpathbuf(&tond, &tbufp, &hashp);
14019ec7b004SRick Macklem 	if (!nd->nd_repstat) {
14029ec7b004SRick Macklem 		error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
14039ec7b004SRick Macklem 		if (error) {
14049ec7b004SRick Macklem 			if (tdp) {
14059ec7b004SRick Macklem 				if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
14069ec7b004SRick Macklem 				    !(nd->nd_flag & ND_NFSV4))
14079ec7b004SRick Macklem 					nfsvno_unlockvfs(mp);
14089ec7b004SRick Macklem 				vrele(tdp);
14099ec7b004SRick Macklem 			}
14109ec7b004SRick Macklem 			vput(dp);
14119ec7b004SRick Macklem 			nfsvno_relpathbuf(&fromnd);
14129ec7b004SRick Macklem 			nfsvno_relpathbuf(&tond);
14139ec7b004SRick Macklem 			return (error);
14149ec7b004SRick Macklem 		}
14159ec7b004SRick Macklem 	}
14169ec7b004SRick Macklem 	if (nd->nd_repstat) {
14179ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
14189ec7b004SRick Macklem 			nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
14199ec7b004SRick Macklem 			    &fdiraft);
14209ec7b004SRick Macklem 			nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
14219ec7b004SRick Macklem 			    &tdiraft);
14229ec7b004SRick Macklem 		}
14239ec7b004SRick Macklem 		if (tdp) {
14249ec7b004SRick Macklem 			if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
14259ec7b004SRick Macklem 			    !(nd->nd_flag & ND_NFSV4))
14269ec7b004SRick Macklem 				nfsvno_unlockvfs(mp);
14279ec7b004SRick Macklem 			vrele(tdp);
14289ec7b004SRick Macklem 		}
14299ec7b004SRick Macklem 		vput(dp);
14309ec7b004SRick Macklem 		nfsvno_relpathbuf(&fromnd);
14319ec7b004SRick Macklem 		nfsvno_relpathbuf(&tond);
14329ec7b004SRick Macklem 		return (0);
14339ec7b004SRick Macklem 	}
14349ec7b004SRick Macklem 
14359ec7b004SRick Macklem 	/*
14369ec7b004SRick Macklem 	 * Done parsing, now down to business.
14379ec7b004SRick Macklem 	 */
14389ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 1, exp, p, &fdirp);
14399ec7b004SRick Macklem 	if (nd->nd_repstat) {
14409ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
14419ec7b004SRick Macklem 			nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
14429ec7b004SRick Macklem 			    &fdiraft);
14439ec7b004SRick Macklem 			nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
14449ec7b004SRick Macklem 			    &tdiraft);
14459ec7b004SRick Macklem 		}
14469ec7b004SRick Macklem 		if (fdirp)
14479ec7b004SRick Macklem 			vrele(fdirp);
14489ec7b004SRick Macklem 		if (tdp) {
14499ec7b004SRick Macklem 			if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
14509ec7b004SRick Macklem 			    !(nd->nd_flag & ND_NFSV4))
14519ec7b004SRick Macklem 				nfsvno_unlockvfs(mp);
14529ec7b004SRick Macklem 			vrele(tdp);
14539ec7b004SRick Macklem 		}
14549ec7b004SRick Macklem 		nfsvno_relpathbuf(&tond);
14559ec7b004SRick Macklem 		return (0);
14569ec7b004SRick Macklem 	}
14579ec7b004SRick Macklem 	if (vnode_vtype(fromnd.ni_vp) == VDIR)
14589ec7b004SRick Macklem 		tond.ni_cnd.cn_flags |= WILLBEDIR;
14599ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
14609ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
14619ec7b004SRick Macklem 	    nd->nd_flag, nd->nd_cred, p);
14629ec7b004SRick Macklem 	if (fdirp)
14630cf42b62SRick Macklem 		fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
14640cf42b62SRick Macklem 		    0);
14659ec7b004SRick Macklem 	if (tdirp)
14660cf42b62SRick Macklem 		tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
14670cf42b62SRick Macklem 		    0);
14689ec7b004SRick Macklem 	if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
14699ec7b004SRick Macklem 	    !(nd->nd_flag & ND_NFSV4))
14709ec7b004SRick Macklem 		nfsvno_unlockvfs(mp);
14719ec7b004SRick Macklem 	if (fdirp)
14729ec7b004SRick Macklem 		vrele(fdirp);
14739ec7b004SRick Macklem 	if (tdirp)
14749ec7b004SRick Macklem 		vrele(tdirp);
14759ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
14769ec7b004SRick Macklem 		nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
14779ec7b004SRick Macklem 		nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
14789ec7b004SRick Macklem 	} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
14799ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
14809ec7b004SRick Macklem 		*tl++ = newnfs_false;
14819ec7b004SRick Macklem 		txdr_hyper(fdirfor.na_filerev, tl);
14829ec7b004SRick Macklem 		tl += 2;
14839ec7b004SRick Macklem 		txdr_hyper(fdiraft.na_filerev, tl);
14849ec7b004SRick Macklem 		tl += 2;
14859ec7b004SRick Macklem 		*tl++ = newnfs_false;
14869ec7b004SRick Macklem 		txdr_hyper(tdirfor.na_filerev, tl);
14879ec7b004SRick Macklem 		tl += 2;
14889ec7b004SRick Macklem 		txdr_hyper(tdiraft.na_filerev, tl);
14899ec7b004SRick Macklem 	}
14909ec7b004SRick Macklem 	return (0);
14919ec7b004SRick Macklem }
14929ec7b004SRick Macklem 
14939ec7b004SRick Macklem /*
14949ec7b004SRick Macklem  * nfs link service
14959ec7b004SRick Macklem  */
14969ec7b004SRick Macklem APPLESTATIC int
14979ec7b004SRick Macklem nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
14989ec7b004SRick Macklem     vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
14999ec7b004SRick Macklem     struct nfsexstuff *toexp)
15009ec7b004SRick Macklem {
15019ec7b004SRick Macklem 	struct nameidata named;
15029ec7b004SRick Macklem 	u_int32_t *tl;
15039ec7b004SRick Macklem 	int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
15049ec7b004SRick Macklem 	vnode_t dirp = NULL, dp = NULL;
15059ec7b004SRick Macklem 	struct nfsvattr dirfor, diraft, at;
15069ec7b004SRick Macklem 	struct nfsexstuff tnes;
15079ec7b004SRick Macklem 	struct nfsrvfh dfh;
15089ec7b004SRick Macklem 	mount_t mp = NULL;
15099ec7b004SRick Macklem 	char *bufp;
15109ec7b004SRick Macklem 	u_long *hashp;
15119ec7b004SRick Macklem 
15129ec7b004SRick Macklem 	if (nd->nd_repstat) {
15139ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &at);
15149ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
15159ec7b004SRick Macklem 		return (0);
15169ec7b004SRick Macklem 	}
15179ec7b004SRick Macklem 	NFSVOPUNLOCK(vp, 0, p);
15189ec7b004SRick Macklem 	if (vnode_vtype(vp) == VDIR) {
15199ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV4)
15209ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_ISDIR;
15219ec7b004SRick Macklem 		else
15229ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_INVAL;
15239ec7b004SRick Macklem 		if (tovp)
15249ec7b004SRick Macklem 			vrele(tovp);
15259ec7b004SRick Macklem 	} else if (vnode_vtype(vp) == VLNK) {
15269ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV2)
15279ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_INVAL;
15289ec7b004SRick Macklem 		else
15299ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_NOTSUPP;
15309ec7b004SRick Macklem 		if (tovp)
15319ec7b004SRick Macklem 			vrele(tovp);
15329ec7b004SRick Macklem 	}
15339ec7b004SRick Macklem 	if (!nd->nd_repstat) {
15349ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV4) {
15359ec7b004SRick Macklem 			dp = tovp;
15369ec7b004SRick Macklem 			tnes = *toexp;
15379ec7b004SRick Macklem 		} else {
15389ec7b004SRick Macklem 			error = nfsrv_mtofh(nd, &dfh);
15399ec7b004SRick Macklem 			if (error) {
15409ec7b004SRick Macklem 				vrele(vp);
15419ec7b004SRick Macklem 				/* tovp is always NULL unless NFSv4 */
15429ec7b004SRick Macklem 				return (error);
15439ec7b004SRick Macklem 			}
15449ec7b004SRick Macklem 			/* Won't lock vfs if already locked, mp == NULL */
15459ec7b004SRick Macklem 			tnes.nes_vfslocked = exp->nes_vfslocked;
154617891d00SRick Macklem 			nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, &mp, 0,
154717891d00SRick Macklem 			    p);
15489ec7b004SRick Macklem 			if (dp)
15499ec7b004SRick Macklem 				NFSVOPUNLOCK(dp, 0, p);
15509ec7b004SRick Macklem 		}
15519ec7b004SRick Macklem 	}
1552f61786cbSRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1553f61786cbSRick Macklem 	    LOCKPARENT | SAVENAME);
15549ec7b004SRick Macklem 	if (!nd->nd_repstat) {
15559ec7b004SRick Macklem 		nfsvno_setpathbuf(&named, &bufp, &hashp);
15569ec7b004SRick Macklem 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
15579ec7b004SRick Macklem 		if (error) {
15589ec7b004SRick Macklem 			vrele(vp);
15599ec7b004SRick Macklem 			if (dp) {
15609ec7b004SRick Macklem 				if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
15619ec7b004SRick Macklem 				    !(nd->nd_flag & ND_NFSV4))
15629ec7b004SRick Macklem 					nfsvno_unlockvfs(mp);
15639ec7b004SRick Macklem 				vrele(dp);
15649ec7b004SRick Macklem 			}
15659ec7b004SRick Macklem 			nfsvno_relpathbuf(&named);
15669ec7b004SRick Macklem 			return (error);
15679ec7b004SRick Macklem 		}
15689ec7b004SRick Macklem 		if (!nd->nd_repstat) {
15699ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
15709ec7b004SRick Macklem 			    p, &dirp);
15719ec7b004SRick Macklem 		} else {
15729ec7b004SRick Macklem 			if (dp)
15739ec7b004SRick Macklem 				vrele(dp);
15749ec7b004SRick Macklem 			nfsvno_relpathbuf(&named);
15759ec7b004SRick Macklem 		}
15769ec7b004SRick Macklem 	}
15779ec7b004SRick Macklem 	if (dirp) {
15789ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV2) {
15799ec7b004SRick Macklem 			vrele(dirp);
15809ec7b004SRick Macklem 			dirp = NULL;
15819ec7b004SRick Macklem 		} else {
15829ec7b004SRick Macklem 			dirfor_ret = nfsvno_getattr(dirp, &dirfor,
15830cf42b62SRick Macklem 			    nd->nd_cred, p, 0);
15849ec7b004SRick Macklem 		}
15859ec7b004SRick Macklem 	}
15869ec7b004SRick Macklem 	if (!nd->nd_repstat)
15879ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
15889ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
15890cf42b62SRick Macklem 		getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
15909ec7b004SRick Macklem 	if (dirp) {
15910cf42b62SRick Macklem 		diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
15929ec7b004SRick Macklem 		vrele(dirp);
15939ec7b004SRick Macklem 	}
15949ec7b004SRick Macklem 	if (tnes.nes_vfslocked && !exp->nes_vfslocked &&
15959ec7b004SRick Macklem 	    !(nd->nd_flag & ND_NFSV4))
15969ec7b004SRick Macklem 		nfsvno_unlockvfs(mp);
15979ec7b004SRick Macklem 	vrele(vp);
15989ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
15999ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &at);
16009ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
16019ec7b004SRick Macklem 	} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
16029ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
16039ec7b004SRick Macklem 		*tl++ = newnfs_false;
16049ec7b004SRick Macklem 		txdr_hyper(dirfor.na_filerev, tl);
16059ec7b004SRick Macklem 		tl += 2;
16069ec7b004SRick Macklem 		txdr_hyper(diraft.na_filerev, tl);
16079ec7b004SRick Macklem 	}
16089ec7b004SRick Macklem 	return (0);
16099ec7b004SRick Macklem }
16109ec7b004SRick Macklem 
16119ec7b004SRick Macklem /*
16129ec7b004SRick Macklem  * nfs symbolic link service
16139ec7b004SRick Macklem  */
16149ec7b004SRick Macklem APPLESTATIC int
16159ec7b004SRick Macklem nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
16169ec7b004SRick Macklem     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
16179ec7b004SRick Macklem     struct nfsexstuff *exp)
16189ec7b004SRick Macklem {
16199ec7b004SRick Macklem 	struct nfsvattr nva, dirfor, diraft;
16209ec7b004SRick Macklem 	struct nameidata named;
16219ec7b004SRick Macklem 	int error, dirfor_ret = 1, diraft_ret = 1, pathlen;
16229ec7b004SRick Macklem 	vnode_t dirp = NULL;
16239ec7b004SRick Macklem 	char *bufp, *pathcp = NULL;
16249ec7b004SRick Macklem 	u_long *hashp;
16259ec7b004SRick Macklem 
16269ec7b004SRick Macklem 	if (nd->nd_repstat) {
16279ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
16289ec7b004SRick Macklem 		return (0);
16299ec7b004SRick Macklem 	}
16309ec7b004SRick Macklem 	if (vpp)
16319ec7b004SRick Macklem 		*vpp = NULL;
16329ec7b004SRick Macklem 	NFSVNO_ATTRINIT(&nva);
16339ec7b004SRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
16349ec7b004SRick Macklem 	    LOCKPARENT | SAVESTART);
16359ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
16369ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
16379ec7b004SRick Macklem 	if (!error && !nd->nd_repstat)
16389ec7b004SRick Macklem 		error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
16399ec7b004SRick Macklem 	if (error) {
16409ec7b004SRick Macklem 		vrele(dp);
16419ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
16429ec7b004SRick Macklem 		return (error);
16439ec7b004SRick Macklem 	}
16449ec7b004SRick Macklem 	if (!nd->nd_repstat) {
16459ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
16469ec7b004SRick Macklem 	} else {
16479ec7b004SRick Macklem 		vrele(dp);
16489ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
16499ec7b004SRick Macklem 	}
16509ec7b004SRick Macklem 	if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
16519ec7b004SRick Macklem 		vrele(dirp);
16529ec7b004SRick Macklem 		dirp = NULL;
16539ec7b004SRick Macklem 	}
16549ec7b004SRick Macklem 
16559ec7b004SRick Macklem 	/*
16569ec7b004SRick Macklem 	 * And call nfsrvd_symlinksub() to do the common code. It will
16579ec7b004SRick Macklem 	 * return EBADRPC upon a parsing error, 0 otherwise.
16589ec7b004SRick Macklem 	 */
16599ec7b004SRick Macklem 	if (!nd->nd_repstat) {
16609ec7b004SRick Macklem 		if (dirp != NULL)
16619ec7b004SRick Macklem 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
16620cf42b62SRick Macklem 			    p, 0);
16639ec7b004SRick Macklem 		nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
16649ec7b004SRick Macklem 		    &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
16659ec7b004SRick Macklem 		    pathcp, pathlen);
16669ec7b004SRick Macklem 	} else if (dirp != NULL) {
16670cf42b62SRick Macklem 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
16689ec7b004SRick Macklem 		vrele(dirp);
16699ec7b004SRick Macklem 	}
16709ec7b004SRick Macklem 	if (pathcp)
16719ec7b004SRick Macklem 		FREE(pathcp, M_TEMP);
16729ec7b004SRick Macklem 
16739ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
16749ec7b004SRick Macklem 		if (!nd->nd_repstat) {
16759ec7b004SRick Macklem 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
16769ec7b004SRick Macklem 			nfsrv_postopattr(nd, 0, &nva);
16779ec7b004SRick Macklem 		}
16789ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
16799ec7b004SRick Macklem 	}
16809ec7b004SRick Macklem 	return (0);
16819ec7b004SRick Macklem }
16829ec7b004SRick Macklem 
16839ec7b004SRick Macklem /*
16849ec7b004SRick Macklem  * Common code for creating a symbolic link.
16859ec7b004SRick Macklem  */
16869ec7b004SRick Macklem static void
16879ec7b004SRick Macklem nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
16889ec7b004SRick Macklem     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
16899ec7b004SRick Macklem     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
16909ec7b004SRick Macklem     int *diraft_retp, nfsattrbit_t *attrbitp,
16919ec7b004SRick Macklem     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
16929ec7b004SRick Macklem     int pathlen)
16939ec7b004SRick Macklem {
16949ec7b004SRick Macklem 	u_int32_t *tl;
16959ec7b004SRick Macklem 
16969ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
16979ec7b004SRick Macklem 	    !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
16989ec7b004SRick Macklem 	if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
16999ec7b004SRick Macklem 		nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
17009ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
17019ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
17029ec7b004SRick Macklem 			if (!nd->nd_repstat)
17039ec7b004SRick Macklem 				nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
17040cf42b62SRick Macklem 				    nvap, nd->nd_cred, p, 1);
17059ec7b004SRick Macklem 		}
1706*81f78d99SRick Macklem 		if (vpp != NULL && nd->nd_repstat == 0) {
1707*81f78d99SRick Macklem 			VOP_UNLOCK(ndp->ni_vp, 0);
17089ec7b004SRick Macklem 			*vpp = ndp->ni_vp;
1709*81f78d99SRick Macklem 		} else
17109ec7b004SRick Macklem 			vput(ndp->ni_vp);
17119ec7b004SRick Macklem 	}
17129ec7b004SRick Macklem 	if (dirp) {
17130cf42b62SRick Macklem 		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
17149ec7b004SRick Macklem 		vrele(dirp);
17159ec7b004SRick Macklem 	}
17169ec7b004SRick Macklem 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
17179ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
17189ec7b004SRick Macklem 		*tl++ = newnfs_false;
17199ec7b004SRick Macklem 		txdr_hyper(dirforp->na_filerev, tl);
17209ec7b004SRick Macklem 		tl += 2;
17219ec7b004SRick Macklem 		txdr_hyper(diraftp->na_filerev, tl);
17229ec7b004SRick Macklem 		(void) nfsrv_putattrbit(nd, attrbitp);
17239ec7b004SRick Macklem 	}
17249ec7b004SRick Macklem }
17259ec7b004SRick Macklem 
17269ec7b004SRick Macklem /*
17279ec7b004SRick Macklem  * nfs mkdir service
17289ec7b004SRick Macklem  */
17299ec7b004SRick Macklem APPLESTATIC int
17309ec7b004SRick Macklem nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
17319ec7b004SRick Macklem     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
17329ec7b004SRick Macklem     struct nfsexstuff *exp)
17339ec7b004SRick Macklem {
17349ec7b004SRick Macklem 	struct nfsvattr nva, dirfor, diraft;
17359ec7b004SRick Macklem 	struct nameidata named;
17369ec7b004SRick Macklem 	u_int32_t *tl;
17379ec7b004SRick Macklem 	int error, dirfor_ret = 1, diraft_ret = 1;
17389ec7b004SRick Macklem 	vnode_t dirp = NULL;
17399ec7b004SRick Macklem 	char *bufp;
17409ec7b004SRick Macklem 	u_long *hashp;
17419ec7b004SRick Macklem 
17429ec7b004SRick Macklem 	if (nd->nd_repstat) {
17439ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
17449ec7b004SRick Macklem 		return (0);
17459ec7b004SRick Macklem 	}
1746f61786cbSRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1747f61786cbSRick Macklem 	    LOCKPARENT | SAVENAME);
17489ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
17499ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
17509ec7b004SRick Macklem 	if (error) {
17519ec7b004SRick Macklem 		vrele(dp);
17529ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
17539ec7b004SRick Macklem 		return (error);
17549ec7b004SRick Macklem 	}
17559ec7b004SRick Macklem 	if (!nd->nd_repstat) {
17569ec7b004SRick Macklem 		NFSVNO_ATTRINIT(&nva);
17579ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3) {
17589ec7b004SRick Macklem 			error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
17599ec7b004SRick Macklem 			if (error) {
17609ec7b004SRick Macklem 				vrele(dp);
17619ec7b004SRick Macklem 				nfsvno_relpathbuf(&named);
17629ec7b004SRick Macklem 				return (error);
17639ec7b004SRick Macklem 			}
17649ec7b004SRick Macklem 		} else {
17659ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
17669ec7b004SRick Macklem 			nva.na_mode = nfstov_mode(*tl++);
17679ec7b004SRick Macklem 		}
17689ec7b004SRick Macklem 	}
17699ec7b004SRick Macklem 	if (!nd->nd_repstat) {
17709ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
17719ec7b004SRick Macklem 	} else {
17729ec7b004SRick Macklem 		vrele(dp);
17739ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
17749ec7b004SRick Macklem 	}
17759ec7b004SRick Macklem 	if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
17769ec7b004SRick Macklem 		vrele(dirp);
17779ec7b004SRick Macklem 		dirp = NULL;
17789ec7b004SRick Macklem 	}
17799ec7b004SRick Macklem 	if (nd->nd_repstat) {
17809ec7b004SRick Macklem 		if (dirp != NULL) {
17819ec7b004SRick Macklem 			dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
17820cf42b62SRick Macklem 			    p, 0);
17839ec7b004SRick Macklem 			vrele(dirp);
17849ec7b004SRick Macklem 		}
17859ec7b004SRick Macklem 		if (nd->nd_flag & ND_NFSV3)
17869ec7b004SRick Macklem 			nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
17879ec7b004SRick Macklem 			    &diraft);
17889ec7b004SRick Macklem 		return (0);
17899ec7b004SRick Macklem 	}
17909ec7b004SRick Macklem 	if (dirp != NULL)
17910cf42b62SRick Macklem 		dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
17929ec7b004SRick Macklem 
17939ec7b004SRick Macklem 	/*
17949ec7b004SRick Macklem 	 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
17959ec7b004SRick Macklem 	 */
17969ec7b004SRick Macklem 	nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
17979ec7b004SRick Macklem 	    &diraft_ret, NULL, NULL, p, exp);
17989ec7b004SRick Macklem 
17999ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
18009ec7b004SRick Macklem 		if (!nd->nd_repstat) {
18019ec7b004SRick Macklem 			(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
18029ec7b004SRick Macklem 			nfsrv_postopattr(nd, 0, &nva);
18039ec7b004SRick Macklem 		}
18049ec7b004SRick Macklem 		nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
18059ec7b004SRick Macklem 	} else if (!nd->nd_repstat) {
18069ec7b004SRick Macklem 		(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
18079ec7b004SRick Macklem 		nfsrv_fillattr(nd, &nva);
18089ec7b004SRick Macklem 	}
18099ec7b004SRick Macklem 	return (0);
18109ec7b004SRick Macklem nfsmout:
18119ec7b004SRick Macklem 	vrele(dp);
18129ec7b004SRick Macklem 	nfsvno_relpathbuf(&named);
18139ec7b004SRick Macklem 	return (error);
18149ec7b004SRick Macklem }
18159ec7b004SRick Macklem 
18169ec7b004SRick Macklem /*
18179ec7b004SRick Macklem  * Code common to mkdir for V2,3 and 4.
18189ec7b004SRick Macklem  */
18199ec7b004SRick Macklem static void
18209ec7b004SRick Macklem nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
18219ec7b004SRick Macklem     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
18229ec7b004SRick Macklem     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
18239ec7b004SRick Macklem     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
18249ec7b004SRick Macklem     NFSPROC_T *p, struct nfsexstuff *exp)
18259ec7b004SRick Macklem {
18269ec7b004SRick Macklem 	vnode_t vp;
18279ec7b004SRick Macklem 	u_int32_t *tl;
18289ec7b004SRick Macklem 
18299ec7b004SRick Macklem 	NFSVNO_SETATTRVAL(nvap, type, VDIR);
18309ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
18319ec7b004SRick Macklem 	    nd->nd_cred, p, exp);
18329ec7b004SRick Macklem 	if (!nd->nd_repstat) {
18339ec7b004SRick Macklem 		vp = ndp->ni_vp;
18349ec7b004SRick Macklem 		nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
18359ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
18369ec7b004SRick Macklem 		if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
18379ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
18380cf42b62SRick Macklem 			    p, 1);
18399ec7b004SRick Macklem 		if (vpp && !nd->nd_repstat) {
18409ec7b004SRick Macklem 			NFSVOPUNLOCK(vp, 0, p);
18419ec7b004SRick Macklem 			*vpp = vp;
18429ec7b004SRick Macklem 		} else {
18439ec7b004SRick Macklem 			vput(vp);
18449ec7b004SRick Macklem 		}
18459ec7b004SRick Macklem 	}
18469ec7b004SRick Macklem 	if (dirp) {
18470cf42b62SRick Macklem 		*diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
18489ec7b004SRick Macklem 		vrele(dirp);
18499ec7b004SRick Macklem 	}
18509ec7b004SRick Macklem 	if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
18519ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
18529ec7b004SRick Macklem 		*tl++ = newnfs_false;
18539ec7b004SRick Macklem 		txdr_hyper(dirforp->na_filerev, tl);
18549ec7b004SRick Macklem 		tl += 2;
18559ec7b004SRick Macklem 		txdr_hyper(diraftp->na_filerev, tl);
18569ec7b004SRick Macklem 		(void) nfsrv_putattrbit(nd, attrbitp);
18579ec7b004SRick Macklem 	}
18589ec7b004SRick Macklem }
18599ec7b004SRick Macklem 
18609ec7b004SRick Macklem /*
18619ec7b004SRick Macklem  * nfs commit service
18629ec7b004SRick Macklem  */
18639ec7b004SRick Macklem APPLESTATIC int
18649ec7b004SRick Macklem nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
18659ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
18669ec7b004SRick Macklem {
18679ec7b004SRick Macklem 	struct nfsvattr bfor, aft;
18689ec7b004SRick Macklem 	u_int32_t *tl;
18699ec7b004SRick Macklem 	int error = 0, for_ret = 1, aft_ret = 1, cnt;
18709ec7b004SRick Macklem 	u_int64_t off;
18719ec7b004SRick Macklem 
18729ec7b004SRick Macklem 	if (nd->nd_repstat) {
18739ec7b004SRick Macklem 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
18749ec7b004SRick Macklem 		return (0);
18759ec7b004SRick Macklem 	}
18769ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
18779ec7b004SRick Macklem 	/*
18789ec7b004SRick Macklem 	 * XXX At this time VOP_FSYNC() does not accept offset and byte
18799ec7b004SRick Macklem 	 * count parameters, so these arguments are useless (someday maybe).
18809ec7b004SRick Macklem 	 */
18819ec7b004SRick Macklem 	off = fxdr_hyper(tl);
18829ec7b004SRick Macklem 	tl += 2;
18839ec7b004SRick Macklem 	cnt = fxdr_unsigned(int, *tl);
18849ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
18850cf42b62SRick Macklem 		for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
18869ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
18879ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3) {
18880cf42b62SRick Macklem 		aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
18899ec7b004SRick Macklem 		nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
18909ec7b004SRick Macklem 	}
18919ec7b004SRick Macklem 	vput(vp);
18929ec7b004SRick Macklem 	if (!nd->nd_repstat) {
18939ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
18949ec7b004SRick Macklem 		*tl++ = txdr_unsigned(nfsboottime.tv_sec);
18959ec7b004SRick Macklem 		*tl = txdr_unsigned(nfsboottime.tv_usec);
18969ec7b004SRick Macklem 	}
18979ec7b004SRick Macklem 	return (0);
18989ec7b004SRick Macklem nfsmout:
18999ec7b004SRick Macklem 	vput(vp);
19009ec7b004SRick Macklem 	return (error);
19019ec7b004SRick Macklem }
19029ec7b004SRick Macklem 
19039ec7b004SRick Macklem /*
19049ec7b004SRick Macklem  * nfs statfs service
19059ec7b004SRick Macklem  */
19069ec7b004SRick Macklem APPLESTATIC int
19079ec7b004SRick Macklem nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
19089ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
19099ec7b004SRick Macklem {
19109ec7b004SRick Macklem 	struct statfs *sf;
19119ec7b004SRick Macklem 	u_int32_t *tl;
19129ec7b004SRick Macklem 	int getret = 1;
19139ec7b004SRick Macklem 	struct nfsvattr at;
19149ec7b004SRick Macklem 	struct statfs sfs;
19159ec7b004SRick Macklem 	u_quad_t tval;
19169ec7b004SRick Macklem 
19179ec7b004SRick Macklem 	if (nd->nd_repstat) {
19189ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &at);
19199ec7b004SRick Macklem 		return (0);
19209ec7b004SRick Macklem 	}
19219ec7b004SRick Macklem 	sf = &sfs;
1922dfd233edSAttilio Rao 	nd->nd_repstat = nfsvno_statfs(vp, sf);
19230cf42b62SRick Macklem 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
19249ec7b004SRick Macklem 	vput(vp);
19259ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV3)
19269ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &at);
19279ec7b004SRick Macklem 	if (nd->nd_repstat)
19289ec7b004SRick Macklem 		return (0);
19299ec7b004SRick Macklem 	if (nd->nd_flag & ND_NFSV2) {
19309ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
19319ec7b004SRick Macklem 		*tl++ = txdr_unsigned(NFS_V2MAXDATA);
19329ec7b004SRick Macklem 		*tl++ = txdr_unsigned(sf->f_bsize);
19339ec7b004SRick Macklem 		*tl++ = txdr_unsigned(sf->f_blocks);
19349ec7b004SRick Macklem 		*tl++ = txdr_unsigned(sf->f_bfree);
19359ec7b004SRick Macklem 		*tl = txdr_unsigned(sf->f_bavail);
19369ec7b004SRick Macklem 	} else {
19379ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
19389ec7b004SRick Macklem 		tval = (u_quad_t)sf->f_blocks;
19399ec7b004SRick Macklem 		tval *= (u_quad_t)sf->f_bsize;
19409ec7b004SRick Macklem 		txdr_hyper(tval, tl); tl += 2;
19419ec7b004SRick Macklem 		tval = (u_quad_t)sf->f_bfree;
19429ec7b004SRick Macklem 		tval *= (u_quad_t)sf->f_bsize;
19439ec7b004SRick Macklem 		txdr_hyper(tval, tl); tl += 2;
19449ec7b004SRick Macklem 		tval = (u_quad_t)sf->f_bavail;
19459ec7b004SRick Macklem 		tval *= (u_quad_t)sf->f_bsize;
19469ec7b004SRick Macklem 		txdr_hyper(tval, tl); tl += 2;
19479ec7b004SRick Macklem 		tval = (u_quad_t)sf->f_files;
19489ec7b004SRick Macklem 		txdr_hyper(tval, tl); tl += 2;
19499ec7b004SRick Macklem 		tval = (u_quad_t)sf->f_ffree;
19509ec7b004SRick Macklem 		txdr_hyper(tval, tl); tl += 2;
19519ec7b004SRick Macklem 		tval = (u_quad_t)sf->f_ffree;
19529ec7b004SRick Macklem 		txdr_hyper(tval, tl); tl += 2;
19539ec7b004SRick Macklem 		*tl = 0;
19549ec7b004SRick Macklem 	}
19559ec7b004SRick Macklem 	return (0);
19569ec7b004SRick Macklem }
19579ec7b004SRick Macklem 
19589ec7b004SRick Macklem /*
19599ec7b004SRick Macklem  * nfs fsinfo service
19609ec7b004SRick Macklem  */
19619ec7b004SRick Macklem APPLESTATIC int
19629ec7b004SRick Macklem nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
19639ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
19649ec7b004SRick Macklem {
19659ec7b004SRick Macklem 	u_int32_t *tl;
19669ec7b004SRick Macklem 	struct nfsfsinfo fs;
19679ec7b004SRick Macklem 	int getret = 1;
19689ec7b004SRick Macklem 	struct nfsvattr at;
19699ec7b004SRick Macklem 
19709ec7b004SRick Macklem 	if (nd->nd_repstat) {
19719ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &at);
19729ec7b004SRick Macklem 		return (0);
19739ec7b004SRick Macklem 	}
19740cf42b62SRick Macklem 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
19759ec7b004SRick Macklem 	nfsvno_getfs(&fs, isdgram);
19769ec7b004SRick Macklem 	vput(vp);
19779ec7b004SRick Macklem 	nfsrv_postopattr(nd, getret, &at);
19789ec7b004SRick Macklem 	NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
19799ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_rtmax);
19809ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_rtpref);
19819ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_rtmult);
19829ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_wtmax);
19839ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_wtpref);
19849ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_wtmult);
19859ec7b004SRick Macklem 	*tl++ = txdr_unsigned(fs.fs_dtpref);
19869ec7b004SRick Macklem 	txdr_hyper(fs.fs_maxfilesize, tl);
19879ec7b004SRick Macklem 	tl += 2;
19889ec7b004SRick Macklem 	txdr_nfsv3time(&fs.fs_timedelta, tl);
19899ec7b004SRick Macklem 	tl += 2;
19909ec7b004SRick Macklem 	*tl = txdr_unsigned(fs.fs_properties);
19919ec7b004SRick Macklem 	return (0);
19929ec7b004SRick Macklem }
19939ec7b004SRick Macklem 
19949ec7b004SRick Macklem /*
19959ec7b004SRick Macklem  * nfs pathconf service
19969ec7b004SRick Macklem  */
19979ec7b004SRick Macklem APPLESTATIC int
19989ec7b004SRick Macklem nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
19999ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
20009ec7b004SRick Macklem {
20019ec7b004SRick Macklem 	struct nfsv3_pathconf *pc;
20029ec7b004SRick Macklem 	int getret = 1;
20039ec7b004SRick Macklem 	register_t linkmax, namemax, chownres, notrunc;
20049ec7b004SRick Macklem 	struct nfsvattr at;
20059ec7b004SRick Macklem 
20069ec7b004SRick Macklem 	if (nd->nd_repstat) {
20079ec7b004SRick Macklem 		nfsrv_postopattr(nd, getret, &at);
20089ec7b004SRick Macklem 		return (0);
20099ec7b004SRick Macklem 	}
20109ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
20119ec7b004SRick Macklem 	    nd->nd_cred, p);
20129ec7b004SRick Macklem 	if (!nd->nd_repstat)
20139ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
20149ec7b004SRick Macklem 		    nd->nd_cred, p);
20159ec7b004SRick Macklem 	if (!nd->nd_repstat)
20169ec7b004SRick Macklem 		nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
20179ec7b004SRick Macklem 		    &chownres, nd->nd_cred, p);
20189ec7b004SRick Macklem 	if (!nd->nd_repstat)
20199ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, &notrunc,
20209ec7b004SRick Macklem 		    nd->nd_cred, p);
20210cf42b62SRick Macklem 	getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
20229ec7b004SRick Macklem 	vput(vp);
20239ec7b004SRick Macklem 	nfsrv_postopattr(nd, getret, &at);
20249ec7b004SRick Macklem 	if (!nd->nd_repstat) {
20259ec7b004SRick Macklem 		NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
20269ec7b004SRick Macklem 		pc->pc_linkmax = txdr_unsigned(linkmax);
20279ec7b004SRick Macklem 		pc->pc_namemax = txdr_unsigned(namemax);
20289ec7b004SRick Macklem 		pc->pc_notrunc = txdr_unsigned(notrunc);
20299ec7b004SRick Macklem 		pc->pc_chownrestricted = txdr_unsigned(chownres);
20309ec7b004SRick Macklem 
20319ec7b004SRick Macklem 		/*
20329ec7b004SRick Macklem 		 * These should probably be supported by VOP_PATHCONF(), but
20339ec7b004SRick Macklem 		 * until msdosfs is exportable (why would you want to?), the
20349ec7b004SRick Macklem 		 * Unix defaults should be ok.
20359ec7b004SRick Macklem 		 */
20369ec7b004SRick Macklem 		pc->pc_caseinsensitive = newnfs_false;
20379ec7b004SRick Macklem 		pc->pc_casepreserving = newnfs_true;
20389ec7b004SRick Macklem 	}
20399ec7b004SRick Macklem 	return (0);
20409ec7b004SRick Macklem }
20419ec7b004SRick Macklem 
20429ec7b004SRick Macklem /*
20439ec7b004SRick Macklem  * nfsv4 lock service
20449ec7b004SRick Macklem  */
20459ec7b004SRick Macklem APPLESTATIC int
20469ec7b004SRick Macklem nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
20479ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
20489ec7b004SRick Macklem {
20499ec7b004SRick Macklem 	u_int32_t *tl;
20509ec7b004SRick Macklem 	int i;
20519ec7b004SRick Macklem 	struct nfsstate *stp = NULL;
20529ec7b004SRick Macklem 	struct nfslock *lop;
20539ec7b004SRick Macklem 	struct nfslockconflict cf;
20549ec7b004SRick Macklem 	int error = 0;
20559ec7b004SRick Macklem 	u_short flags = NFSLCK_LOCK, lflags;
20569ec7b004SRick Macklem 	u_int64_t offset, len;
20579ec7b004SRick Macklem 	nfsv4stateid_t stateid;
20589ec7b004SRick Macklem 	nfsquad_t clientid;
20599ec7b004SRick Macklem 
20609ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
20619ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl++);
20629ec7b004SRick Macklem 	switch (i) {
20639ec7b004SRick Macklem 	case NFSV4LOCKT_READW:
20649ec7b004SRick Macklem 		flags |= NFSLCK_BLOCKING;
20659ec7b004SRick Macklem 	case NFSV4LOCKT_READ:
20669ec7b004SRick Macklem 		lflags = NFSLCK_READ;
20679ec7b004SRick Macklem 		break;
20689ec7b004SRick Macklem 	case NFSV4LOCKT_WRITEW:
20699ec7b004SRick Macklem 		flags |= NFSLCK_BLOCKING;
20709ec7b004SRick Macklem 	case NFSV4LOCKT_WRITE:
20719ec7b004SRick Macklem 		lflags = NFSLCK_WRITE;
20729ec7b004SRick Macklem 		break;
20739ec7b004SRick Macklem 	default:
20749ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
20759ec7b004SRick Macklem 		goto nfsmout;
20769ec7b004SRick Macklem 	};
20779ec7b004SRick Macklem 	if (*tl++ == newnfs_true)
20789ec7b004SRick Macklem 		flags |= NFSLCK_RECLAIM;
20799ec7b004SRick Macklem 	offset = fxdr_hyper(tl);
20809ec7b004SRick Macklem 	tl += 2;
20819ec7b004SRick Macklem 	len = fxdr_hyper(tl);
20829ec7b004SRick Macklem 	tl += 2;
20839ec7b004SRick Macklem 	if (*tl == newnfs_true)
20849ec7b004SRick Macklem 		flags |= NFSLCK_OPENTOLOCK;
20859ec7b004SRick Macklem 	if (flags & NFSLCK_OPENTOLOCK) {
20869ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
20879ec7b004SRick Macklem 		i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
20882a45247cSRick Macklem 		if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
20892a45247cSRick Macklem 			nd->nd_repstat = NFSERR_BADXDR;
20902a45247cSRick Macklem 			goto nfsmout;
20912a45247cSRick Macklem 		}
20929ec7b004SRick Macklem 		MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
20939ec7b004SRick Macklem 			M_NFSDSTATE, M_WAITOK);
20949ec7b004SRick Macklem 		stp->ls_ownerlen = i;
20959ec7b004SRick Macklem 		stp->ls_op = nd->nd_rp;
20969ec7b004SRick Macklem 		stp->ls_seq = fxdr_unsigned(int, *tl++);
20979ec7b004SRick Macklem 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
20989ec7b004SRick Macklem 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
20999ec7b004SRick Macklem 			NFSX_STATEIDOTHER);
21009ec7b004SRick Macklem 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
21019ec7b004SRick Macklem 		stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
21029ec7b004SRick Macklem 		clientid.lval[0] = *tl++;
21039ec7b004SRick Macklem 		clientid.lval[1] = *tl++;
21049ec7b004SRick Macklem 		if (nd->nd_flag & ND_IMPLIEDCLID) {
21059ec7b004SRick Macklem 			if (nd->nd_clientid.qval != clientid.qval)
21069ec7b004SRick Macklem 				printf("EEK! multiple clids\n");
21079ec7b004SRick Macklem 		} else {
21089ec7b004SRick Macklem 			nd->nd_flag |= ND_IMPLIEDCLID;
21099ec7b004SRick Macklem 			nd->nd_clientid.qval = clientid.qval;
21109ec7b004SRick Macklem 		}
21119ec7b004SRick Macklem 		error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
21129ec7b004SRick Macklem 		if (error)
21139ec7b004SRick Macklem 			goto nfsmout;
21149ec7b004SRick Macklem 	} else {
21159ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
21169ec7b004SRick Macklem 		MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
21179ec7b004SRick Macklem 			M_NFSDSTATE, M_WAITOK);
21189ec7b004SRick Macklem 		stp->ls_ownerlen = 0;
21199ec7b004SRick Macklem 		stp->ls_op = nd->nd_rp;
21209ec7b004SRick Macklem 		stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
21219ec7b004SRick Macklem 		NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
21229ec7b004SRick Macklem 			NFSX_STATEIDOTHER);
21239ec7b004SRick Macklem 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
21249ec7b004SRick Macklem 		stp->ls_seq = fxdr_unsigned(int, *tl);
21259ec7b004SRick Macklem 		clientid.lval[0] = stp->ls_stateid.other[0];
21269ec7b004SRick Macklem 		clientid.lval[1] = stp->ls_stateid.other[1];
21279ec7b004SRick Macklem 		if (nd->nd_flag & ND_IMPLIEDCLID) {
21289ec7b004SRick Macklem 			if (nd->nd_clientid.qval != clientid.qval)
21299ec7b004SRick Macklem 				printf("EEK! multiple clids\n");
21309ec7b004SRick Macklem 		} else {
21319ec7b004SRick Macklem 			nd->nd_flag |= ND_IMPLIEDCLID;
21329ec7b004SRick Macklem 			nd->nd_clientid.qval = clientid.qval;
21339ec7b004SRick Macklem 		}
21349ec7b004SRick Macklem 	}
21359ec7b004SRick Macklem 	MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
21369ec7b004SRick Macklem 		M_NFSDLOCK, M_WAITOK);
21379ec7b004SRick Macklem 	lop->lo_first = offset;
21389ec7b004SRick Macklem 	if (len == NFS64BITSSET) {
21399ec7b004SRick Macklem 		lop->lo_end = NFS64BITSSET;
21409ec7b004SRick Macklem 	} else {
21419ec7b004SRick Macklem 		lop->lo_end = offset + len;
21429ec7b004SRick Macklem 		if (lop->lo_end <= lop->lo_first)
21439ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_INVAL;
21449ec7b004SRick Macklem 	}
21459ec7b004SRick Macklem 	lop->lo_flags = lflags;
21469ec7b004SRick Macklem 	stp->ls_flags = flags;
21479ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
21489ec7b004SRick Macklem 
21499ec7b004SRick Macklem 	/*
21509ec7b004SRick Macklem 	 * Do basic access checking.
21519ec7b004SRick Macklem 	 */
21529ec7b004SRick Macklem 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
21539ec7b004SRick Macklem 	    if (vnode_vtype(vp) == VDIR)
21549ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_ISDIR;
21559ec7b004SRick Macklem 	    else
21569ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
21579ec7b004SRick Macklem 	}
21589ec7b004SRick Macklem 	if (!nd->nd_repstat) {
21599ec7b004SRick Macklem 	    if (lflags & NFSLCK_WRITE) {
21608da45f2cSRick Macklem 		nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
21619ec7b004SRick Macklem 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
21628da45f2cSRick Macklem 		    NFSACCCHK_VPISLOCKED, NULL);
21639ec7b004SRick Macklem 	    } else {
21648da45f2cSRick Macklem 		nd->nd_repstat = nfsvno_accchk(vp, VREAD,
21659ec7b004SRick Macklem 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
21668da45f2cSRick Macklem 		    NFSACCCHK_VPISLOCKED, NULL);
21679ec7b004SRick Macklem 		if (nd->nd_repstat)
21688da45f2cSRick Macklem 		    nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
21699ec7b004SRick Macklem 			nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
21708da45f2cSRick Macklem 			NFSACCCHK_VPISLOCKED, NULL);
21719ec7b004SRick Macklem 	    }
21729ec7b004SRick Macklem 	}
21739ec7b004SRick Macklem 
21749ec7b004SRick Macklem 	/*
21759ec7b004SRick Macklem 	 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
21769ec7b004SRick Macklem 	 * seqid# gets updated. nfsrv_lockctrl() will return the value
21779ec7b004SRick Macklem 	 * of nd_repstat, if it gets that far.
21789ec7b004SRick Macklem 	 */
21799ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
21809ec7b004SRick Macklem 		&stateid, exp, nd, p);
21819ec7b004SRick Macklem 	if (lop)
21829ec7b004SRick Macklem 		FREE((caddr_t)lop, M_NFSDLOCK);
21839ec7b004SRick Macklem 	if (stp)
21849ec7b004SRick Macklem 		FREE((caddr_t)stp, M_NFSDSTATE);
21859ec7b004SRick Macklem 	if (!nd->nd_repstat) {
21869ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
21879ec7b004SRick Macklem 		*tl++ = txdr_unsigned(stateid.seqid);
21889ec7b004SRick Macklem 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
21899ec7b004SRick Macklem 	} else if (nd->nd_repstat == NFSERR_DENIED) {
21909ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
21919ec7b004SRick Macklem 		txdr_hyper(cf.cl_first, tl);
21929ec7b004SRick Macklem 		tl += 2;
21939ec7b004SRick Macklem 		if (cf.cl_end == NFS64BITSSET)
21949ec7b004SRick Macklem 			len = NFS64BITSSET;
21959ec7b004SRick Macklem 		else
21969ec7b004SRick Macklem 			len = cf.cl_end - cf.cl_first;
21979ec7b004SRick Macklem 		txdr_hyper(len, tl);
21989ec7b004SRick Macklem 		tl += 2;
21999ec7b004SRick Macklem 		if (cf.cl_flags == NFSLCK_WRITE)
22009ec7b004SRick Macklem 			*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
22019ec7b004SRick Macklem 		else
22029ec7b004SRick Macklem 			*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
22039ec7b004SRick Macklem 		*tl++ = stateid.other[0];
22049ec7b004SRick Macklem 		*tl = stateid.other[1];
22059ec7b004SRick Macklem 		(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
22069ec7b004SRick Macklem 	}
22079ec7b004SRick Macklem 	vput(vp);
22089ec7b004SRick Macklem 	return (0);
22099ec7b004SRick Macklem nfsmout:
22109ec7b004SRick Macklem 	vput(vp);
22119ec7b004SRick Macklem 	if (stp)
22129ec7b004SRick Macklem 		free((caddr_t)stp, M_NFSDSTATE);
22139ec7b004SRick Macklem 	return (error);
22149ec7b004SRick Macklem }
22159ec7b004SRick Macklem 
22169ec7b004SRick Macklem /*
22179ec7b004SRick Macklem  * nfsv4 lock test service
22189ec7b004SRick Macklem  */
22199ec7b004SRick Macklem APPLESTATIC int
22209ec7b004SRick Macklem nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
22219ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
22229ec7b004SRick Macklem {
22239ec7b004SRick Macklem 	u_int32_t *tl;
22249ec7b004SRick Macklem 	int i;
22259ec7b004SRick Macklem 	struct nfsstate *stp = NULL;
22269ec7b004SRick Macklem 	struct nfslock lo, *lop = &lo;
22279ec7b004SRick Macklem 	struct nfslockconflict cf;
22289ec7b004SRick Macklem 	int error = 0;
22299ec7b004SRick Macklem 	nfsv4stateid_t stateid;
22309ec7b004SRick Macklem 	nfsquad_t clientid;
22319ec7b004SRick Macklem 	u_int64_t len;
22329ec7b004SRick Macklem 
22339ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
22349ec7b004SRick Macklem 	i = fxdr_unsigned(int, *(tl + 7));
22352a45247cSRick Macklem 	if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
22362a45247cSRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
22372a45247cSRick Macklem 		goto nfsmout;
22382a45247cSRick Macklem 	}
22399ec7b004SRick Macklem 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
22409ec7b004SRick Macklem 	    M_NFSDSTATE, M_WAITOK);
22419ec7b004SRick Macklem 	stp->ls_ownerlen = i;
22429ec7b004SRick Macklem 	stp->ls_op = NULL;
22439ec7b004SRick Macklem 	stp->ls_flags = NFSLCK_TEST;
22449ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
22459ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl++);
22469ec7b004SRick Macklem 	switch (i) {
22479ec7b004SRick Macklem 	case NFSV4LOCKT_READW:
22489ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_BLOCKING;
22499ec7b004SRick Macklem 	case NFSV4LOCKT_READ:
22509ec7b004SRick Macklem 		lo.lo_flags = NFSLCK_READ;
22519ec7b004SRick Macklem 		break;
22529ec7b004SRick Macklem 	case NFSV4LOCKT_WRITEW:
22539ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_BLOCKING;
22549ec7b004SRick Macklem 	case NFSV4LOCKT_WRITE:
22559ec7b004SRick Macklem 		lo.lo_flags = NFSLCK_WRITE;
22569ec7b004SRick Macklem 		break;
22579ec7b004SRick Macklem 	default:
22589ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
22599ec7b004SRick Macklem 		goto nfsmout;
22609ec7b004SRick Macklem 	};
22619ec7b004SRick Macklem 	lo.lo_first = fxdr_hyper(tl);
22629ec7b004SRick Macklem 	tl += 2;
22639ec7b004SRick Macklem 	len = fxdr_hyper(tl);
22649ec7b004SRick Macklem 	if (len == NFS64BITSSET) {
22659ec7b004SRick Macklem 		lo.lo_end = NFS64BITSSET;
22669ec7b004SRick Macklem 	} else {
22679ec7b004SRick Macklem 		lo.lo_end = lo.lo_first + len;
22689ec7b004SRick Macklem 		if (lo.lo_end <= lo.lo_first)
22699ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_INVAL;
22709ec7b004SRick Macklem 	}
22719ec7b004SRick Macklem 	tl += 2;
22729ec7b004SRick Macklem 	clientid.lval[0] = *tl++;
22739ec7b004SRick Macklem 	clientid.lval[1] = *tl;
22749ec7b004SRick Macklem 	if (nd->nd_flag & ND_IMPLIEDCLID) {
22759ec7b004SRick Macklem 		if (nd->nd_clientid.qval != clientid.qval)
22769ec7b004SRick Macklem 			printf("EEK! multiple clids\n");
22779ec7b004SRick Macklem 	} else {
22789ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
22799ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
22809ec7b004SRick Macklem 	}
22819ec7b004SRick Macklem 	error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
22829ec7b004SRick Macklem 	if (error)
22839ec7b004SRick Macklem 		goto nfsmout;
22849ec7b004SRick Macklem 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
22859ec7b004SRick Macklem 	    if (vnode_vtype(vp) == VDIR)
22869ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_ISDIR;
22879ec7b004SRick Macklem 	    else
22889ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
22899ec7b004SRick Macklem 	}
22909ec7b004SRick Macklem 	if (!nd->nd_repstat)
22919ec7b004SRick Macklem 	  nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
22929ec7b004SRick Macklem 	    &stateid, exp, nd, p);
22939ec7b004SRick Macklem 	if (stp)
22949ec7b004SRick Macklem 		FREE((caddr_t)stp, M_NFSDSTATE);
22959ec7b004SRick Macklem 	if (nd->nd_repstat) {
22969ec7b004SRick Macklem 	    if (nd->nd_repstat == NFSERR_DENIED) {
22979ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
22989ec7b004SRick Macklem 		txdr_hyper(cf.cl_first, tl);
22999ec7b004SRick Macklem 		tl += 2;
23009ec7b004SRick Macklem 		if (cf.cl_end == NFS64BITSSET)
23019ec7b004SRick Macklem 			len = NFS64BITSSET;
23029ec7b004SRick Macklem 		else
23039ec7b004SRick Macklem 			len = cf.cl_end - cf.cl_first;
23049ec7b004SRick Macklem 		txdr_hyper(len, tl);
23059ec7b004SRick Macklem 		tl += 2;
23069ec7b004SRick Macklem 		if (cf.cl_flags == NFSLCK_WRITE)
23079ec7b004SRick Macklem 			*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
23089ec7b004SRick Macklem 		else
23099ec7b004SRick Macklem 			*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
23109ec7b004SRick Macklem 		*tl++ = stp->ls_stateid.other[0];
23119ec7b004SRick Macklem 		*tl = stp->ls_stateid.other[1];
23129ec7b004SRick Macklem 		(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
23139ec7b004SRick Macklem 	    }
23149ec7b004SRick Macklem 	}
23159ec7b004SRick Macklem 	vput(vp);
23169ec7b004SRick Macklem 	return (0);
23179ec7b004SRick Macklem nfsmout:
23189ec7b004SRick Macklem 	vput(vp);
23199ec7b004SRick Macklem 	if (stp)
23209ec7b004SRick Macklem 		free((caddr_t)stp, M_NFSDSTATE);
23219ec7b004SRick Macklem 	return (error);
23229ec7b004SRick Macklem }
23239ec7b004SRick Macklem 
23249ec7b004SRick Macklem /*
23259ec7b004SRick Macklem  * nfsv4 unlock service
23269ec7b004SRick Macklem  */
23279ec7b004SRick Macklem APPLESTATIC int
23289ec7b004SRick Macklem nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
23299ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
23309ec7b004SRick Macklem {
23319ec7b004SRick Macklem 	u_int32_t *tl;
23329ec7b004SRick Macklem 	int i;
23339ec7b004SRick Macklem 	struct nfsstate *stp;
23349ec7b004SRick Macklem 	struct nfslock *lop;
23359ec7b004SRick Macklem 	int error = 0;
23369ec7b004SRick Macklem 	nfsv4stateid_t stateid;
23379ec7b004SRick Macklem 	nfsquad_t clientid;
23389ec7b004SRick Macklem 	u_int64_t len;
23399ec7b004SRick Macklem 
23409ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
23419ec7b004SRick Macklem 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
23429ec7b004SRick Macklem 	    M_NFSDSTATE, M_WAITOK);
23439ec7b004SRick Macklem 	MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
23449ec7b004SRick Macklem 	    M_NFSDLOCK, M_WAITOK);
23459ec7b004SRick Macklem 	stp->ls_flags = NFSLCK_UNLOCK;
23469ec7b004SRick Macklem 	lop->lo_flags = NFSLCK_UNLOCK;
23479ec7b004SRick Macklem 	stp->ls_op = nd->nd_rp;
23489ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl++);
23499ec7b004SRick Macklem 	switch (i) {
23509ec7b004SRick Macklem 	case NFSV4LOCKT_READW:
23519ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_BLOCKING;
23529ec7b004SRick Macklem 	case NFSV4LOCKT_READ:
23539ec7b004SRick Macklem 		break;
23549ec7b004SRick Macklem 	case NFSV4LOCKT_WRITEW:
23559ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_BLOCKING;
23569ec7b004SRick Macklem 	case NFSV4LOCKT_WRITE:
23579ec7b004SRick Macklem 		break;
23589ec7b004SRick Macklem 	default:
23599ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
23602a45247cSRick Macklem 		free(stp, M_NFSDSTATE);
23612a45247cSRick Macklem 		free(lop, M_NFSDLOCK);
23629ec7b004SRick Macklem 		goto nfsmout;
23639ec7b004SRick Macklem 	};
23649ec7b004SRick Macklem 	stp->ls_ownerlen = 0;
23659ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
23669ec7b004SRick Macklem 	stp->ls_seq = fxdr_unsigned(int, *tl++);
23679ec7b004SRick Macklem 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
23689ec7b004SRick Macklem 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
23699ec7b004SRick Macklem 	    NFSX_STATEIDOTHER);
23709ec7b004SRick Macklem 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
23719ec7b004SRick Macklem 	lop->lo_first = fxdr_hyper(tl);
23729ec7b004SRick Macklem 	tl += 2;
23739ec7b004SRick Macklem 	len = fxdr_hyper(tl);
23749ec7b004SRick Macklem 	if (len == NFS64BITSSET) {
23759ec7b004SRick Macklem 		lop->lo_end = NFS64BITSSET;
23769ec7b004SRick Macklem 	} else {
23779ec7b004SRick Macklem 		lop->lo_end = lop->lo_first + len;
23789ec7b004SRick Macklem 		if (lop->lo_end <= lop->lo_first)
23799ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_INVAL;
23809ec7b004SRick Macklem 	}
23819ec7b004SRick Macklem 	clientid.lval[0] = stp->ls_stateid.other[0];
23829ec7b004SRick Macklem 	clientid.lval[1] = stp->ls_stateid.other[1];
23839ec7b004SRick Macklem 	if (nd->nd_flag & ND_IMPLIEDCLID) {
23849ec7b004SRick Macklem 		if (nd->nd_clientid.qval != clientid.qval)
23859ec7b004SRick Macklem 			printf("EEK! multiple clids\n");
23869ec7b004SRick Macklem 	} else {
23879ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
23889ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
23899ec7b004SRick Macklem 	}
23909ec7b004SRick Macklem 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
23919ec7b004SRick Macklem 	    if (vnode_vtype(vp) == VDIR)
23929ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_ISDIR;
23939ec7b004SRick Macklem 	    else
23949ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
23959ec7b004SRick Macklem 	}
23969ec7b004SRick Macklem 	/*
23979ec7b004SRick Macklem 	 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
23989ec7b004SRick Macklem 	 * seqid# gets incremented. nfsrv_lockctrl() will return the
23999ec7b004SRick Macklem 	 * value of nd_repstat, if it gets that far.
24009ec7b004SRick Macklem 	 */
24019ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
24029ec7b004SRick Macklem 	    &stateid, exp, nd, p);
24039ec7b004SRick Macklem 	if (stp)
24049ec7b004SRick Macklem 		FREE((caddr_t)stp, M_NFSDSTATE);
24059ec7b004SRick Macklem 	if (lop)
24069ec7b004SRick Macklem 		free((caddr_t)lop, M_NFSDLOCK);
24079ec7b004SRick Macklem 	if (!nd->nd_repstat) {
24089ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
24099ec7b004SRick Macklem 		*tl++ = txdr_unsigned(stateid.seqid);
24109ec7b004SRick Macklem 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
24119ec7b004SRick Macklem 	}
24129ec7b004SRick Macklem nfsmout:
24139ec7b004SRick Macklem 	vput(vp);
24149ec7b004SRick Macklem 	return (error);
24159ec7b004SRick Macklem }
24169ec7b004SRick Macklem 
24179ec7b004SRick Macklem /*
24189ec7b004SRick Macklem  * nfsv4 open service
24199ec7b004SRick Macklem  */
24209ec7b004SRick Macklem APPLESTATIC int
24219ec7b004SRick Macklem nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
24229ec7b004SRick Macklem     vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
24239ec7b004SRick Macklem     struct nfsexstuff *exp)
24249ec7b004SRick Macklem {
24259ec7b004SRick Macklem 	u_int32_t *tl;
24269ec7b004SRick Macklem 	int i;
24279ec7b004SRick Macklem 	struct nfsstate *stp = NULL;
24289ec7b004SRick Macklem 	int error = 0, create, claim, exclusive_flag = 0;
24299ec7b004SRick Macklem 	u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
24309ec7b004SRick Macklem 	int how = NFSCREATE_UNCHECKED;
2431086f6e0cSRick Macklem 	int32_t cverf[2], tverf[2] = { 0, 0 };
24329ec7b004SRick Macklem 	vnode_t vp = NULL, dirp = NULL;
24339ec7b004SRick Macklem 	struct nfsvattr nva, dirfor, diraft;
24349ec7b004SRick Macklem 	struct nameidata named;
24359ec7b004SRick Macklem 	nfsv4stateid_t stateid, delegstateid;
24369ec7b004SRick Macklem 	nfsattrbit_t attrbits;
24379ec7b004SRick Macklem 	nfsquad_t clientid;
24389ec7b004SRick Macklem 	char *bufp = NULL;
24399ec7b004SRick Macklem 	u_long *hashp;
24409ec7b004SRick Macklem 	NFSACL_T *aclp = NULL;
24419ec7b004SRick Macklem 
24429ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
2443c3e22f83SRick Macklem 	aclp = acl_alloc(M_WAITOK);
24449ec7b004SRick Macklem 	aclp->acl_cnt = 0;
24459ec7b004SRick Macklem #endif
24469ec7b004SRick Macklem 	NFSZERO_ATTRBIT(&attrbits);
24479ec7b004SRick Macklem 	named.ni_startdir = NULL;
24489ec7b004SRick Macklem 	named.ni_cnd.cn_nameiop = 0;
24499ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
24509ec7b004SRick Macklem 	i = fxdr_unsigned(int, *(tl + 5));
24512a45247cSRick Macklem 	if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
24522a45247cSRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
24532a45247cSRick Macklem 		vrele(dp);
24542a45247cSRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
24552a45247cSRick Macklem 		acl_free(aclp);
24562a45247cSRick Macklem #endif
24572a45247cSRick Macklem 		return (0);
24582a45247cSRick Macklem 	}
24599ec7b004SRick Macklem 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
24609ec7b004SRick Macklem 	    M_NFSDSTATE, M_WAITOK);
24619ec7b004SRick Macklem 	stp->ls_ownerlen = i;
24629ec7b004SRick Macklem 	stp->ls_op = nd->nd_rp;
24639ec7b004SRick Macklem 	stp->ls_flags = NFSLCK_OPEN;
24649ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
24659ec7b004SRick Macklem 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
24669ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl++);
24679ec7b004SRick Macklem 	switch (i) {
24689ec7b004SRick Macklem 	case NFSV4OPEN_ACCESSREAD:
24699ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_READACCESS;
24709ec7b004SRick Macklem 		break;
24719ec7b004SRick Macklem 	case NFSV4OPEN_ACCESSWRITE:
24729ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_WRITEACCESS;
24739ec7b004SRick Macklem 		break;
24749ec7b004SRick Macklem 	case NFSV4OPEN_ACCESSBOTH:
24759ec7b004SRick Macklem 		stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
24769ec7b004SRick Macklem 		break;
24779ec7b004SRick Macklem 	default:
24789ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
24799ec7b004SRick Macklem 	};
24809ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl++);
24819ec7b004SRick Macklem 	switch (i) {
24829ec7b004SRick Macklem 	case NFSV4OPEN_DENYNONE:
24839ec7b004SRick Macklem 		break;
24849ec7b004SRick Macklem 	case NFSV4OPEN_DENYREAD:
24859ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_READDENY;
24869ec7b004SRick Macklem 		break;
24879ec7b004SRick Macklem 	case NFSV4OPEN_DENYWRITE:
24889ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_WRITEDENY;
24899ec7b004SRick Macklem 		break;
24909ec7b004SRick Macklem 	case NFSV4OPEN_DENYBOTH:
24919ec7b004SRick Macklem 		stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
24929ec7b004SRick Macklem 		break;
24939ec7b004SRick Macklem 	default:
24949ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
24959ec7b004SRick Macklem 	};
24969ec7b004SRick Macklem 	clientid.lval[0] = *tl++;
24979ec7b004SRick Macklem 	clientid.lval[1] = *tl;
24989ec7b004SRick Macklem 	if (nd->nd_flag & ND_IMPLIEDCLID) {
24999ec7b004SRick Macklem 		if (nd->nd_clientid.qval != clientid.qval)
25009ec7b004SRick Macklem 			printf("EEK! multiple clids\n");
25019ec7b004SRick Macklem 	} else {
25029ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
25039ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
25049ec7b004SRick Macklem 	}
25059ec7b004SRick Macklem 	error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
25069ec7b004SRick Macklem 	if (error) {
25079ec7b004SRick Macklem 		vrele(dp);
25089ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
25099ec7b004SRick Macklem 		acl_free(aclp);
25109ec7b004SRick Macklem #endif
25119ec7b004SRick Macklem 		FREE((caddr_t)stp, M_NFSDSTATE);
25129ec7b004SRick Macklem 		return (error);
25139ec7b004SRick Macklem 	}
25149ec7b004SRick Macklem 	NFSVNO_ATTRINIT(&nva);
25159ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
25169ec7b004SRick Macklem 	create = fxdr_unsigned(int, *tl);
25179ec7b004SRick Macklem 	if (!nd->nd_repstat)
25180cf42b62SRick Macklem 		nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
25199ec7b004SRick Macklem 	if (create == NFSV4OPEN_CREATE) {
25209ec7b004SRick Macklem 		nva.na_type = VREG;
25219ec7b004SRick Macklem 		nva.na_mode = 0;
25229ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
25239ec7b004SRick Macklem 		how = fxdr_unsigned(int, *tl);
25249ec7b004SRick Macklem 		switch (how) {
25259ec7b004SRick Macklem 		case NFSCREATE_UNCHECKED:
25269ec7b004SRick Macklem 		case NFSCREATE_GUARDED:
25279ec7b004SRick Macklem 			error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
25289ec7b004SRick Macklem 			if (error) {
25299ec7b004SRick Macklem 				vrele(dp);
25309ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
25319ec7b004SRick Macklem 				acl_free(aclp);
25329ec7b004SRick Macklem #endif
25339ec7b004SRick Macklem 				FREE((caddr_t)stp, M_NFSDSTATE);
25349ec7b004SRick Macklem 				return (error);
25359ec7b004SRick Macklem 			}
25369ec7b004SRick Macklem 			/*
25379ec7b004SRick Macklem 			 * If the na_gid being set is the same as that of
25389ec7b004SRick Macklem 			 * the directory it is going in, clear it, since
25399ec7b004SRick Macklem 			 * that is what will be set by default. This allows
25409ec7b004SRick Macklem 			 * a user that isn't in that group to do the create.
25419ec7b004SRick Macklem 			 */
25429ec7b004SRick Macklem 			if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
25439ec7b004SRick Macklem 			    nva.na_gid == dirfor.na_gid)
25449ec7b004SRick Macklem 				NFSVNO_UNSET(&nva, gid);
25459ec7b004SRick Macklem 			if (!nd->nd_repstat)
25469ec7b004SRick Macklem 				nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
25479ec7b004SRick Macklem 			break;
25489ec7b004SRick Macklem 		case NFSCREATE_EXCLUSIVE:
25499ec7b004SRick Macklem 			NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2550086f6e0cSRick Macklem 			cverf[0] = *tl++;
2551086f6e0cSRick Macklem 			cverf[1] = *tl;
25529ec7b004SRick Macklem 			break;
25539ec7b004SRick Macklem 		default:
25549ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_BADXDR;
25559ec7b004SRick Macklem 			vrele(dp);
25569ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
25579ec7b004SRick Macklem 			acl_free(aclp);
25589ec7b004SRick Macklem #endif
25599ec7b004SRick Macklem 			FREE((caddr_t)stp, M_NFSDSTATE);
25609ec7b004SRick Macklem 			return (0);
25619ec7b004SRick Macklem 		};
25629ec7b004SRick Macklem 	} else if (create != NFSV4OPEN_NOCREATE) {
25639ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
25649ec7b004SRick Macklem 		vrele(dp);
25659ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
25669ec7b004SRick Macklem 		acl_free(aclp);
25679ec7b004SRick Macklem #endif
25689ec7b004SRick Macklem 		FREE((caddr_t)stp, M_NFSDSTATE);
25699ec7b004SRick Macklem 		return (0);
25709ec7b004SRick Macklem 	}
25719ec7b004SRick Macklem 
25729ec7b004SRick Macklem 	/*
25739ec7b004SRick Macklem 	 * Now, handle the claim, which usually includes looking up a
25749ec7b004SRick Macklem 	 * name in the directory referenced by dp. The exception is
25759ec7b004SRick Macklem 	 * NFSV4OPEN_CLAIMPREVIOUS.
25769ec7b004SRick Macklem 	 */
25779ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
25789ec7b004SRick Macklem 	claim = fxdr_unsigned(int, *tl);
25799ec7b004SRick Macklem 	if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
25809ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
25819ec7b004SRick Macklem 		stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
25829ec7b004SRick Macklem 		NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
25839ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_DELEGCUR;
25849ec7b004SRick Macklem 	} else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
25859ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_DELEGPREV;
25869ec7b004SRick Macklem 	}
25879ec7b004SRick Macklem 	if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
25889ec7b004SRick Macklem 	    || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
25899ec7b004SRick Macklem 		if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
25909ec7b004SRick Macklem 		    claim != NFSV4OPEN_CLAIMNULL)
25919ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_INVAL;
25929ec7b004SRick Macklem 		if (nd->nd_repstat) {
25939ec7b004SRick Macklem 			nd->nd_repstat = nfsrv_opencheck(clientid,
25949ec7b004SRick Macklem 			    &stateid, stp, NULL, nd, p, nd->nd_repstat);
25959ec7b004SRick Macklem 			vrele(dp);
25969ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
25979ec7b004SRick Macklem 			acl_free(aclp);
25989ec7b004SRick Macklem #endif
25999ec7b004SRick Macklem 			FREE((caddr_t)stp, M_NFSDSTATE);
26009ec7b004SRick Macklem 			return (0);
26019ec7b004SRick Macklem 		}
26029ec7b004SRick Macklem 		if (create == NFSV4OPEN_CREATE)
26039ec7b004SRick Macklem 		    NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
26049ec7b004SRick Macklem 			LOCKPARENT | LOCKLEAF | SAVESTART);
26059ec7b004SRick Macklem 		else
26069ec7b004SRick Macklem 		    NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
26079ec7b004SRick Macklem 			LOCKLEAF | SAVESTART);
26089ec7b004SRick Macklem 		nfsvno_setpathbuf(&named, &bufp, &hashp);
26099ec7b004SRick Macklem 		error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
26109ec7b004SRick Macklem 		if (error) {
26119ec7b004SRick Macklem 			vrele(dp);
26129ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
26139ec7b004SRick Macklem 			acl_free(aclp);
26149ec7b004SRick Macklem #endif
26159ec7b004SRick Macklem 			FREE((caddr_t)stp, M_NFSDSTATE);
26169ec7b004SRick Macklem 			nfsvno_relpathbuf(&named);
26179ec7b004SRick Macklem 			return (error);
26189ec7b004SRick Macklem 		}
26199ec7b004SRick Macklem 		if (!nd->nd_repstat) {
26209ec7b004SRick Macklem 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
26219ec7b004SRick Macklem 			    p, &dirp);
26229ec7b004SRick Macklem 		} else {
26239ec7b004SRick Macklem 			vrele(dp);
26249ec7b004SRick Macklem 			nfsvno_relpathbuf(&named);
26259ec7b004SRick Macklem 		}
26269ec7b004SRick Macklem 		if (create == NFSV4OPEN_CREATE) {
26279ec7b004SRick Macklem 		    switch (how) {
26289ec7b004SRick Macklem 		    case NFSCREATE_UNCHECKED:
26299ec7b004SRick Macklem 			if (named.ni_vp) {
26309ec7b004SRick Macklem 				/*
26319ec7b004SRick Macklem 				 * Clear the setable attribute bits, except
26329ec7b004SRick Macklem 				 * for Size, if it is being truncated.
26339ec7b004SRick Macklem 				 */
26349ec7b004SRick Macklem 				NFSZERO_ATTRBIT(&attrbits);
26359ec7b004SRick Macklem 				if (NFSVNO_ISSETSIZE(&nva))
26369ec7b004SRick Macklem 					NFSSETBIT_ATTRBIT(&attrbits,
26379ec7b004SRick Macklem 					    NFSATTRBIT_SIZE);
26389ec7b004SRick Macklem 			}
26399ec7b004SRick Macklem 			break;
26409ec7b004SRick Macklem 		    case NFSCREATE_GUARDED:
26419ec7b004SRick Macklem 			if (named.ni_vp && !nd->nd_repstat)
26429ec7b004SRick Macklem 				nd->nd_repstat = EEXIST;
26439ec7b004SRick Macklem 			break;
26449ec7b004SRick Macklem 		    case NFSCREATE_EXCLUSIVE:
26459ec7b004SRick Macklem 			exclusive_flag = 1;
26469ec7b004SRick Macklem 			if (!named.ni_vp)
26479ec7b004SRick Macklem 				nva.na_mode = 0;
26489ec7b004SRick Macklem 		    };
26499ec7b004SRick Macklem 		}
26509ec7b004SRick Macklem 		nfsvno_open(nd, &named, clientid, &stateid, stp,
26519ec7b004SRick Macklem 		    &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
26529ec7b004SRick Macklem 		    nd->nd_cred, p, exp, &vp);
26539ec7b004SRick Macklem 	} else if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
26549ec7b004SRick Macklem 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
26559ec7b004SRick Macklem 		i = fxdr_unsigned(int, *tl);
26569ec7b004SRick Macklem 		switch (i) {
26579ec7b004SRick Macklem 		case NFSV4OPEN_DELEGATEREAD:
26589ec7b004SRick Macklem 			stp->ls_flags |= NFSLCK_DELEGREAD;
26599ec7b004SRick Macklem 			break;
26609ec7b004SRick Macklem 		case NFSV4OPEN_DELEGATEWRITE:
26619ec7b004SRick Macklem 			stp->ls_flags |= NFSLCK_DELEGWRITE;
26629ec7b004SRick Macklem 		case NFSV4OPEN_DELEGATENONE:
26639ec7b004SRick Macklem 			break;
26649ec7b004SRick Macklem 		default:
26659ec7b004SRick Macklem 			nd->nd_repstat = NFSERR_BADXDR;
26669ec7b004SRick Macklem 			vrele(dp);
26679ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
26689ec7b004SRick Macklem 			acl_free(aclp);
26699ec7b004SRick Macklem #endif
26709ec7b004SRick Macklem 			FREE((caddr_t)stp, M_NFSDSTATE);
26719ec7b004SRick Macklem 			return (0);
26729ec7b004SRick Macklem 		};
26739ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_RECLAIM;
26749ec7b004SRick Macklem 		vp = dp;
2675629fa50eSRick Macklem 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2676629fa50eSRick Macklem 		if ((vp->v_iflag & VI_DOOMED) == 0)
2677629fa50eSRick Macklem 			nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
2678629fa50eSRick Macklem 			    stp, vp, nd, p, nd->nd_repstat);
2679629fa50eSRick Macklem 		else
2680629fa50eSRick Macklem 			nd->nd_repstat = NFSERR_PERM;
26819ec7b004SRick Macklem 	} else {
26829ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
26839ec7b004SRick Macklem 		vrele(dp);
26849ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
26859ec7b004SRick Macklem 		acl_free(aclp);
26869ec7b004SRick Macklem #endif
26879ec7b004SRick Macklem 		FREE((caddr_t)stp, M_NFSDSTATE);
26889ec7b004SRick Macklem 		return (0);
26899ec7b004SRick Macklem 	}
26909ec7b004SRick Macklem 
26919ec7b004SRick Macklem 	/*
26929ec7b004SRick Macklem 	 * Do basic access checking.
26939ec7b004SRick Macklem 	 */
26949ec7b004SRick Macklem 	if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
26959ec7b004SRick Macklem 	    if (vnode_vtype(vp) == VDIR)
26969ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_ISDIR;
26979ec7b004SRick Macklem 	    else if (vnode_vtype(vp) == VLNK)
26989ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_SYMLINK;
26999ec7b004SRick Macklem 	    else
27009ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_INVAL;
27019ec7b004SRick Macklem 	}
27029ec7b004SRick Macklem 	if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
27038da45f2cSRick Macklem 	    nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
27048da45f2cSRick Macklem 	        exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
27059ec7b004SRick Macklem 	if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
27068da45f2cSRick Macklem 	    nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
27078da45f2cSRick Macklem 	        exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
27089ec7b004SRick Macklem 	    if (nd->nd_repstat)
27098da45f2cSRick Macklem 		nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
27109ec7b004SRick Macklem 		    nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
27118da45f2cSRick Macklem 		    NFSACCCHK_VPISLOCKED, NULL);
27129ec7b004SRick Macklem 	}
27139ec7b004SRick Macklem 
2714086f6e0cSRick Macklem 	if (!nd->nd_repstat) {
27150cf42b62SRick Macklem 		nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2716086f6e0cSRick Macklem 		if (!nd->nd_repstat) {
2717086f6e0cSRick Macklem 			tverf[0] = nva.na_atime.tv_sec;
2718086f6e0cSRick Macklem 			tverf[1] = nva.na_atime.tv_nsec;
2719086f6e0cSRick Macklem 		}
2720086f6e0cSRick Macklem 	}
2721086f6e0cSRick Macklem 	if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
2722086f6e0cSRick Macklem 	    cverf[1] != tverf[1]))
27239ec7b004SRick Macklem 		nd->nd_repstat = EEXIST;
27249ec7b004SRick Macklem 	/*
27259ec7b004SRick Macklem 	 * Do the open locking/delegation stuff.
27269ec7b004SRick Macklem 	 */
27279ec7b004SRick Macklem 	if (!nd->nd_repstat)
27289ec7b004SRick Macklem 	    nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
27299ec7b004SRick Macklem 		&delegstateid, &rflags, exp, p, nva.na_filerev);
27309ec7b004SRick Macklem 
27319ec7b004SRick Macklem 	/*
27329ec7b004SRick Macklem 	 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
27339ec7b004SRick Macklem 	 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
27349ec7b004SRick Macklem 	 * (ie: Leave the NFSVOPUNLOCK() about here.)
27359ec7b004SRick Macklem 	 */
27369ec7b004SRick Macklem 	if (vp)
27379ec7b004SRick Macklem 		NFSVOPUNLOCK(vp, 0, p);
27389ec7b004SRick Macklem 	if (stp)
27399ec7b004SRick Macklem 		FREE((caddr_t)stp, M_NFSDSTATE);
27409ec7b004SRick Macklem 	if (!nd->nd_repstat && dirp)
27410cf42b62SRick Macklem 		nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
27420cf42b62SRick Macklem 		    0);
27439ec7b004SRick Macklem 	if (!nd->nd_repstat) {
27449ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
27459ec7b004SRick Macklem 		*tl++ = txdr_unsigned(stateid.seqid);
27469ec7b004SRick Macklem 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
27479ec7b004SRick Macklem 		tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
27489ec7b004SRick Macklem 		if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
27499ec7b004SRick Macklem 			*tl++ = newnfs_true;
27509ec7b004SRick Macklem 			*tl++ = 0;
27519ec7b004SRick Macklem 			*tl++ = 0;
27529ec7b004SRick Macklem 			*tl++ = 0;
27539ec7b004SRick Macklem 			*tl++ = 0;
27549ec7b004SRick Macklem 		} else {
27559ec7b004SRick Macklem 			*tl++ = newnfs_false;	/* Since dirp is not locked */
27569ec7b004SRick Macklem 			txdr_hyper(dirfor.na_filerev, tl);
27579ec7b004SRick Macklem 			tl += 2;
27589ec7b004SRick Macklem 			txdr_hyper(diraft.na_filerev, tl);
27599ec7b004SRick Macklem 			tl += 2;
27609ec7b004SRick Macklem 		}
27619ec7b004SRick Macklem 		*tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
27629ec7b004SRick Macklem 		(void) nfsrv_putattrbit(nd, &attrbits);
27639ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
27649ec7b004SRick Macklem 		if (rflags & NFSV4OPEN_READDELEGATE)
27659ec7b004SRick Macklem 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
27669ec7b004SRick Macklem 		else if (rflags & NFSV4OPEN_WRITEDELEGATE)
27679ec7b004SRick Macklem 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
27689ec7b004SRick Macklem 		else
27699ec7b004SRick Macklem 			*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
27709ec7b004SRick Macklem 		if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
27719ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
27729ec7b004SRick Macklem 			*tl++ = txdr_unsigned(delegstateid.seqid);
27739ec7b004SRick Macklem 			NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
27749ec7b004SRick Macklem 			    NFSX_STATEIDOTHER);
27759ec7b004SRick Macklem 			tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
27769ec7b004SRick Macklem 			if (rflags & NFSV4OPEN_RECALL)
27779ec7b004SRick Macklem 				*tl = newnfs_true;
27789ec7b004SRick Macklem 			else
27799ec7b004SRick Macklem 				*tl = newnfs_false;
27809ec7b004SRick Macklem 			if (rflags & NFSV4OPEN_WRITEDELEGATE) {
27819ec7b004SRick Macklem 				NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
27829ec7b004SRick Macklem 				*tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
27839ec7b004SRick Macklem 				txdr_hyper(nva.na_size, tl);
27849ec7b004SRick Macklem 			}
27859ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
27869ec7b004SRick Macklem 			*tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
27879ec7b004SRick Macklem 			*tl++ = txdr_unsigned(0x0);
27889ec7b004SRick Macklem 			acemask = NFSV4ACE_ALLFILESMASK;
27899ec7b004SRick Macklem 			if (nva.na_mode & S_IRUSR)
27909ec7b004SRick Macklem 			    acemask |= NFSV4ACE_READMASK;
27919ec7b004SRick Macklem 			if (nva.na_mode & S_IWUSR)
27929ec7b004SRick Macklem 			    acemask |= NFSV4ACE_WRITEMASK;
27939ec7b004SRick Macklem 			if (nva.na_mode & S_IXUSR)
27949ec7b004SRick Macklem 			    acemask |= NFSV4ACE_EXECUTEMASK;
27959ec7b004SRick Macklem 			*tl = txdr_unsigned(acemask);
27969ec7b004SRick Macklem 			(void) nfsm_strtom(nd, "OWNER@", 6);
27979ec7b004SRick Macklem 		}
27989ec7b004SRick Macklem 		*vpp = vp;
27999ec7b004SRick Macklem 	} else if (vp) {
28009ec7b004SRick Macklem 		vrele(vp);
28019ec7b004SRick Macklem 	}
28029ec7b004SRick Macklem 	if (dirp)
28039ec7b004SRick Macklem 		vrele(dirp);
28049ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
28059ec7b004SRick Macklem 	acl_free(aclp);
28069ec7b004SRick Macklem #endif
28079ec7b004SRick Macklem 	return (0);
28089ec7b004SRick Macklem nfsmout:
28099ec7b004SRick Macklem 	vrele(dp);
28109ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME
28119ec7b004SRick Macklem 	acl_free(aclp);
28129ec7b004SRick Macklem #endif
28139ec7b004SRick Macklem 	if (stp)
28149ec7b004SRick Macklem 		FREE((caddr_t)stp, M_NFSDSTATE);
28159ec7b004SRick Macklem 	return (error);
28169ec7b004SRick Macklem }
28179ec7b004SRick Macklem 
28189ec7b004SRick Macklem /*
28199ec7b004SRick Macklem  * nfsv4 close service
28209ec7b004SRick Macklem  */
28219ec7b004SRick Macklem APPLESTATIC int
28229ec7b004SRick Macklem nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
28239ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
28249ec7b004SRick Macklem {
28259ec7b004SRick Macklem 	u_int32_t *tl;
28269ec7b004SRick Macklem 	struct nfsstate st, *stp = &st;
28279ec7b004SRick Macklem 	int error = 0;
28289ec7b004SRick Macklem 	nfsv4stateid_t stateid;
28299ec7b004SRick Macklem 	nfsquad_t clientid;
28309ec7b004SRick Macklem 
28319ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
28329ec7b004SRick Macklem 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
28339ec7b004SRick Macklem 	stp->ls_ownerlen = 0;
28349ec7b004SRick Macklem 	stp->ls_op = nd->nd_rp;
28359ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
28369ec7b004SRick Macklem 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
28379ec7b004SRick Macklem 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
28389ec7b004SRick Macklem 	    NFSX_STATEIDOTHER);
28399ec7b004SRick Macklem 	stp->ls_flags = NFSLCK_CLOSE;
28409ec7b004SRick Macklem 	clientid.lval[0] = stp->ls_stateid.other[0];
28419ec7b004SRick Macklem 	clientid.lval[1] = stp->ls_stateid.other[1];
28429ec7b004SRick Macklem 	if (nd->nd_flag & ND_IMPLIEDCLID) {
28439ec7b004SRick Macklem 		if (nd->nd_clientid.qval != clientid.qval)
28449ec7b004SRick Macklem 			printf("EEK! multiple clids\n");
28459ec7b004SRick Macklem 	} else {
28469ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
28479ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
28489ec7b004SRick Macklem 	}
28499ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
28509ec7b004SRick Macklem 	vput(vp);
28519ec7b004SRick Macklem 	if (!nd->nd_repstat) {
28529ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
28539ec7b004SRick Macklem 		*tl++ = txdr_unsigned(stateid.seqid);
28549ec7b004SRick Macklem 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
28559ec7b004SRick Macklem 	}
28569ec7b004SRick Macklem 	return (0);
28579ec7b004SRick Macklem nfsmout:
28589ec7b004SRick Macklem 	vput(vp);
28599ec7b004SRick Macklem 	return (error);
28609ec7b004SRick Macklem }
28619ec7b004SRick Macklem 
28629ec7b004SRick Macklem /*
28639ec7b004SRick Macklem  * nfsv4 delegpurge service
28649ec7b004SRick Macklem  */
28659ec7b004SRick Macklem APPLESTATIC int
28669ec7b004SRick Macklem nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
28679ec7b004SRick Macklem     __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
28689ec7b004SRick Macklem {
28699ec7b004SRick Macklem 	u_int32_t *tl;
28709ec7b004SRick Macklem 	int error = 0;
28719ec7b004SRick Macklem 	nfsquad_t clientid;
28729ec7b004SRick Macklem 
2873c9aad40fSRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
2874b1cfc0d9SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
2875b1cfc0d9SRick Macklem 		return (0);
2876b1cfc0d9SRick Macklem 	}
28779ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
28789ec7b004SRick Macklem 	clientid.lval[0] = *tl++;
28799ec7b004SRick Macklem 	clientid.lval[1] = *tl;
28809ec7b004SRick Macklem 	if (nd->nd_flag & ND_IMPLIEDCLID) {
28819ec7b004SRick Macklem 		if (nd->nd_clientid.qval != clientid.qval)
28829ec7b004SRick Macklem 			printf("EEK! multiple clids\n");
28839ec7b004SRick Macklem 	} else {
28849ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
28859ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
28869ec7b004SRick Macklem 	}
28879ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL,
28889ec7b004SRick Macklem 	    NFSV4OP_DELEGPURGE, nd->nd_cred, p);
28899ec7b004SRick Macklem nfsmout:
28909ec7b004SRick Macklem 	return (error);
28919ec7b004SRick Macklem }
28929ec7b004SRick Macklem 
28939ec7b004SRick Macklem /*
28949ec7b004SRick Macklem  * nfsv4 delegreturn service
28959ec7b004SRick Macklem  */
28969ec7b004SRick Macklem APPLESTATIC int
28979ec7b004SRick Macklem nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
28989ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
28999ec7b004SRick Macklem {
29009ec7b004SRick Macklem 	u_int32_t *tl;
29019ec7b004SRick Macklem 	int error = 0;
29029ec7b004SRick Macklem 	nfsv4stateid_t stateid;
29039ec7b004SRick Macklem 	nfsquad_t clientid;
29049ec7b004SRick Macklem 
29059ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
29069ec7b004SRick Macklem 	stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
29079ec7b004SRick Macklem 	NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
29089ec7b004SRick Macklem 	clientid.lval[0] = stateid.other[0];
29099ec7b004SRick Macklem 	clientid.lval[1] = stateid.other[1];
29109ec7b004SRick Macklem 	if (nd->nd_flag & ND_IMPLIEDCLID) {
29119ec7b004SRick Macklem 		if (nd->nd_clientid.qval != clientid.qval)
29129ec7b004SRick Macklem 			printf("EEK! multiple clids\n");
29139ec7b004SRick Macklem 	} else {
29149ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
29159ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
29169ec7b004SRick Macklem 	}
29179ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp,
29189ec7b004SRick Macklem 	    NFSV4OP_DELEGRETURN, nd->nd_cred, p);
29199ec7b004SRick Macklem nfsmout:
29209ec7b004SRick Macklem 	vput(vp);
29219ec7b004SRick Macklem 	return (error);
29229ec7b004SRick Macklem }
29239ec7b004SRick Macklem 
29249ec7b004SRick Macklem /*
29259ec7b004SRick Macklem  * nfsv4 get file handle service
29269ec7b004SRick Macklem  */
29279ec7b004SRick Macklem APPLESTATIC int
29289ec7b004SRick Macklem nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
29299ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
29309ec7b004SRick Macklem {
29319ec7b004SRick Macklem 	fhandle_t fh;
29329ec7b004SRick Macklem 
29339ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
29349ec7b004SRick Macklem 	vput(vp);
29359ec7b004SRick Macklem 	if (!nd->nd_repstat)
29369ec7b004SRick Macklem 		(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
29379ec7b004SRick Macklem 	return (0);
29389ec7b004SRick Macklem }
29399ec7b004SRick Macklem 
29409ec7b004SRick Macklem /*
29419ec7b004SRick Macklem  * nfsv4 open confirm service
29429ec7b004SRick Macklem  */
29439ec7b004SRick Macklem APPLESTATIC int
29449ec7b004SRick Macklem nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
29459ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
29469ec7b004SRick Macklem {
29479ec7b004SRick Macklem 	u_int32_t *tl;
29489ec7b004SRick Macklem 	struct nfsstate st, *stp = &st;
29499ec7b004SRick Macklem 	int error = 0;
29509ec7b004SRick Macklem 	nfsv4stateid_t stateid;
29519ec7b004SRick Macklem 	nfsquad_t clientid;
29529ec7b004SRick Macklem 
29539ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
29549ec7b004SRick Macklem 	stp->ls_ownerlen = 0;
29559ec7b004SRick Macklem 	stp->ls_op = nd->nd_rp;
29569ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
29579ec7b004SRick Macklem 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
29589ec7b004SRick Macklem 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
29599ec7b004SRick Macklem 	    NFSX_STATEIDOTHER);
29609ec7b004SRick Macklem 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
29619ec7b004SRick Macklem 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
29629ec7b004SRick Macklem 	stp->ls_flags = NFSLCK_CONFIRM;
29639ec7b004SRick Macklem 	clientid.lval[0] = stp->ls_stateid.other[0];
29649ec7b004SRick Macklem 	clientid.lval[1] = stp->ls_stateid.other[1];
29659ec7b004SRick Macklem 	if (nd->nd_flag & ND_IMPLIEDCLID) {
29669ec7b004SRick Macklem 		if (nd->nd_clientid.qval != clientid.qval)
29679ec7b004SRick Macklem 			printf("EEK! multiple clids\n");
29689ec7b004SRick Macklem 	} else {
29699ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
29709ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
29719ec7b004SRick Macklem 	}
29729ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
29739ec7b004SRick Macklem 	if (!nd->nd_repstat) {
29749ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
29759ec7b004SRick Macklem 		*tl++ = txdr_unsigned(stateid.seqid);
29769ec7b004SRick Macklem 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
29779ec7b004SRick Macklem 	}
29789ec7b004SRick Macklem nfsmout:
29799ec7b004SRick Macklem 	vput(vp);
29809ec7b004SRick Macklem 	return (error);
29819ec7b004SRick Macklem }
29829ec7b004SRick Macklem 
29839ec7b004SRick Macklem /*
29849ec7b004SRick Macklem  * nfsv4 open downgrade service
29859ec7b004SRick Macklem  */
29869ec7b004SRick Macklem APPLESTATIC int
29879ec7b004SRick Macklem nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
29889ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
29899ec7b004SRick Macklem {
29909ec7b004SRick Macklem 	u_int32_t *tl;
29919ec7b004SRick Macklem 	int i;
29929ec7b004SRick Macklem 	struct nfsstate st, *stp = &st;
29939ec7b004SRick Macklem 	int error = 0;
29949ec7b004SRick Macklem 	nfsv4stateid_t stateid;
29959ec7b004SRick Macklem 	nfsquad_t clientid;
29969ec7b004SRick Macklem 
29979ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
29989ec7b004SRick Macklem 	stp->ls_ownerlen = 0;
29999ec7b004SRick Macklem 	stp->ls_op = nd->nd_rp;
30009ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
30019ec7b004SRick Macklem 	stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
30029ec7b004SRick Macklem 	NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
30039ec7b004SRick Macklem 	    NFSX_STATEIDOTHER);
30049ec7b004SRick Macklem 	tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
30059ec7b004SRick Macklem 	stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
30069ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl++);
30079ec7b004SRick Macklem 	switch (i) {
30089ec7b004SRick Macklem 	case NFSV4OPEN_ACCESSREAD:
30099ec7b004SRick Macklem 		stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
30109ec7b004SRick Macklem 		break;
30119ec7b004SRick Macklem 	case NFSV4OPEN_ACCESSWRITE:
30129ec7b004SRick Macklem 		stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
30139ec7b004SRick Macklem 		break;
30149ec7b004SRick Macklem 	case NFSV4OPEN_ACCESSBOTH:
30159ec7b004SRick Macklem 		stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
30169ec7b004SRick Macklem 		    NFSLCK_DOWNGRADE);
30179ec7b004SRick Macklem 		break;
30189ec7b004SRick Macklem 	default:
30199ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
30209ec7b004SRick Macklem 	};
30219ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl);
30229ec7b004SRick Macklem 	switch (i) {
30239ec7b004SRick Macklem 	case NFSV4OPEN_DENYNONE:
30249ec7b004SRick Macklem 		break;
30259ec7b004SRick Macklem 	case NFSV4OPEN_DENYREAD:
30269ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_READDENY;
30279ec7b004SRick Macklem 		break;
30289ec7b004SRick Macklem 	case NFSV4OPEN_DENYWRITE:
30299ec7b004SRick Macklem 		stp->ls_flags |= NFSLCK_WRITEDENY;
30309ec7b004SRick Macklem 		break;
30319ec7b004SRick Macklem 	case NFSV4OPEN_DENYBOTH:
30329ec7b004SRick Macklem 		stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
30339ec7b004SRick Macklem 		break;
30349ec7b004SRick Macklem 	default:
30359ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
30369ec7b004SRick Macklem 	};
30379ec7b004SRick Macklem 
30389ec7b004SRick Macklem 	clientid.lval[0] = stp->ls_stateid.other[0];
30399ec7b004SRick Macklem 	clientid.lval[1] = stp->ls_stateid.other[1];
30409ec7b004SRick Macklem 	if (nd->nd_flag & ND_IMPLIEDCLID) {
30419ec7b004SRick Macklem 		if (nd->nd_clientid.qval != clientid.qval)
30429ec7b004SRick Macklem 			printf("EEK! multiple clids\n");
30439ec7b004SRick Macklem 	} else {
30449ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
30459ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
30469ec7b004SRick Macklem 	}
30479ec7b004SRick Macklem 	if (!nd->nd_repstat)
30489ec7b004SRick Macklem 		nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
30499ec7b004SRick Macklem 		    nd, p);
30509ec7b004SRick Macklem 	if (!nd->nd_repstat) {
30519ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
30529ec7b004SRick Macklem 		*tl++ = txdr_unsigned(stateid.seqid);
30539ec7b004SRick Macklem 		NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
30549ec7b004SRick Macklem 	}
30559ec7b004SRick Macklem nfsmout:
30569ec7b004SRick Macklem 	vput(vp);
30579ec7b004SRick Macklem 	return (error);
30589ec7b004SRick Macklem }
30599ec7b004SRick Macklem 
30609ec7b004SRick Macklem /*
30619ec7b004SRick Macklem  * nfsv4 renew lease service
30629ec7b004SRick Macklem  */
30639ec7b004SRick Macklem APPLESTATIC int
30649ec7b004SRick Macklem nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
30659ec7b004SRick Macklem     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
30669ec7b004SRick Macklem {
30679ec7b004SRick Macklem 	u_int32_t *tl;
30689ec7b004SRick Macklem 	int error = 0;
30699ec7b004SRick Macklem 	nfsquad_t clientid;
30709ec7b004SRick Macklem 
3071c9aad40fSRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3072b1cfc0d9SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
3073b1cfc0d9SRick Macklem 		return (0);
3074b1cfc0d9SRick Macklem 	}
30759ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
30769ec7b004SRick Macklem 	clientid.lval[0] = *tl++;
30779ec7b004SRick Macklem 	clientid.lval[1] = *tl;
30789ec7b004SRick Macklem 	if (nd->nd_flag & ND_IMPLIEDCLID) {
30799ec7b004SRick Macklem 		if (nd->nd_clientid.qval != clientid.qval)
30809ec7b004SRick Macklem 			printf("EEK! multiple clids\n");
30819ec7b004SRick Macklem 	} else {
30829ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
30839ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
30849ec7b004SRick Macklem 	}
30859ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
30869ec7b004SRick Macklem 	    NULL, (nfsquad_t)((u_quad_t)0), nd, p);
30879ec7b004SRick Macklem nfsmout:
30889ec7b004SRick Macklem 	return (error);
30899ec7b004SRick Macklem }
30909ec7b004SRick Macklem 
30919ec7b004SRick Macklem /*
30929ec7b004SRick Macklem  * nfsv4 security info service
30939ec7b004SRick Macklem  */
30949ec7b004SRick Macklem APPLESTATIC int
30959ec7b004SRick Macklem nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
30969ec7b004SRick Macklem     vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
30979ec7b004SRick Macklem {
30989ec7b004SRick Macklem 	u_int32_t *tl;
30999ec7b004SRick Macklem 	int len;
31009ec7b004SRick Macklem 	struct nameidata named;
31019ec7b004SRick Macklem 	vnode_t dirp = NULL, vp;
31029ec7b004SRick Macklem 	struct nfsrvfh fh;
31039ec7b004SRick Macklem 	struct nfsexstuff retnes;
31049ec7b004SRick Macklem 	mount_t mp;
31059ec7b004SRick Macklem 	u_int32_t *sizp;
31069ec7b004SRick Macklem 	int error, savflag, i;
31079ec7b004SRick Macklem 	char *bufp;
31089ec7b004SRick Macklem 	u_long *hashp;
31099ec7b004SRick Macklem 
31109ec7b004SRick Macklem 	/*
31119ec7b004SRick Macklem 	 * All this just to get the export flags for the name.
31129ec7b004SRick Macklem 	 */
31139ec7b004SRick Macklem 	NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
31149ec7b004SRick Macklem 	    LOCKLEAF | SAVESTART);
31159ec7b004SRick Macklem 	nfsvno_setpathbuf(&named, &bufp, &hashp);
31169ec7b004SRick Macklem 	error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
31179ec7b004SRick Macklem 	if (error) {
31189ec7b004SRick Macklem 		vput(dp);
31199ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
31209ec7b004SRick Macklem 		return (error);
31219ec7b004SRick Macklem 	}
31229ec7b004SRick Macklem 	if (!nd->nd_repstat) {
31239ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
31249ec7b004SRick Macklem 	} else {
31259ec7b004SRick Macklem 		vput(dp);
31269ec7b004SRick Macklem 		nfsvno_relpathbuf(&named);
31279ec7b004SRick Macklem 	}
31289ec7b004SRick Macklem 	if (dirp)
31299ec7b004SRick Macklem 		vrele(dirp);
31309ec7b004SRick Macklem 	if (nd->nd_repstat)
31319ec7b004SRick Macklem 		return (0);
31329ec7b004SRick Macklem 	vrele(named.ni_startdir);
31339ec7b004SRick Macklem 	nfsvno_relpathbuf(&named);
31349ec7b004SRick Macklem 	fh.nfsrvfh_len = NFSX_MYFH;
31359ec7b004SRick Macklem 	vp = named.ni_vp;
31369ec7b004SRick Macklem 	nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
31379ec7b004SRick Macklem 	mp = vnode_mount(vp);	/* so it won't try to re-lock filesys */
31389ec7b004SRick Macklem 	retnes.nes_vfslocked = exp->nes_vfslocked;
31399ec7b004SRick Macklem 	vput(vp);
31409ec7b004SRick Macklem 	savflag = nd->nd_flag;
31419ec7b004SRick Macklem 	if (!nd->nd_repstat) {
314217891d00SRick Macklem 		nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, &mp, 0, p);
31439ec7b004SRick Macklem 		if (vp)
31449ec7b004SRick Macklem 			vput(vp);
31459ec7b004SRick Macklem 	}
31469ec7b004SRick Macklem 	nd->nd_flag = savflag;
31479ec7b004SRick Macklem 	if (nd->nd_repstat)
31489ec7b004SRick Macklem 		return (0);
31499ec7b004SRick Macklem 
31509ec7b004SRick Macklem 	/*
31519ec7b004SRick Macklem 	 * Finally have the export flags for name, so we can create
31529ec7b004SRick Macklem 	 * the security info.
31539ec7b004SRick Macklem 	 */
31549ec7b004SRick Macklem 	len = 0;
31559ec7b004SRick Macklem 	NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
315698ad4453SRick Macklem 	for (i = 0; i < retnes.nes_numsecflavor; i++) {
315798ad4453SRick Macklem 		if (retnes.nes_secflavors[i] == AUTH_SYS) {
31589ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
31599ec7b004SRick Macklem 			*tl = txdr_unsigned(RPCAUTH_UNIX);
31609ec7b004SRick Macklem 			len++;
316198ad4453SRick Macklem 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
31629ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
31639ec7b004SRick Macklem 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
31649ec7b004SRick Macklem 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
31659ec7b004SRick Macklem 			    nfsgss_mechlist[KERBV_MECH].len);
31669ec7b004SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
31679ec7b004SRick Macklem 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
316898ad4453SRick Macklem 			*tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
31699ec7b004SRick Macklem 			len++;
317098ad4453SRick Macklem 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
317198ad4453SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
317298ad4453SRick Macklem 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
317398ad4453SRick Macklem 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
317498ad4453SRick Macklem 			    nfsgss_mechlist[KERBV_MECH].len);
317598ad4453SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
317698ad4453SRick Macklem 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
317798ad4453SRick Macklem 			*tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
317898ad4453SRick Macklem 			len++;
317998ad4453SRick Macklem 		} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
318098ad4453SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
318198ad4453SRick Macklem 			*tl++ = txdr_unsigned(RPCAUTH_GSS);
318298ad4453SRick Macklem 			(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
318398ad4453SRick Macklem 			    nfsgss_mechlist[KERBV_MECH].len);
318498ad4453SRick Macklem 			NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
318598ad4453SRick Macklem 			*tl++ = txdr_unsigned(GSS_KERBV_QOP);
318698ad4453SRick Macklem 			*tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
318798ad4453SRick Macklem 			len++;
318898ad4453SRick Macklem 		}
31899ec7b004SRick Macklem 	}
31909ec7b004SRick Macklem 	*sizp = txdr_unsigned(len);
31919ec7b004SRick Macklem 	return (0);
31929ec7b004SRick Macklem }
31939ec7b004SRick Macklem 
31949ec7b004SRick Macklem /*
31959ec7b004SRick Macklem  * nfsv4 set client id service
31969ec7b004SRick Macklem  */
31979ec7b004SRick Macklem APPLESTATIC int
31989ec7b004SRick Macklem nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
31999ec7b004SRick Macklem     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
32009ec7b004SRick Macklem {
32019ec7b004SRick Macklem 	u_int32_t *tl;
32029ec7b004SRick Macklem 	int i;
32039ec7b004SRick Macklem 	int error = 0, idlen;
32049ec7b004SRick Macklem 	struct nfsclient *clp = NULL;
32059ec7b004SRick Macklem 	struct sockaddr_in *rad;
32069ec7b004SRick Macklem 	u_char *verf, *ucp, *ucp2, addrbuf[24];
32079ec7b004SRick Macklem 	nfsquad_t clientid, confirm;
32089ec7b004SRick Macklem 
3209c9aad40fSRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
32109ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
32119ec7b004SRick Macklem 		return (0);
32129ec7b004SRick Macklem 	}
32139ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
32149ec7b004SRick Macklem 	verf = (u_char *)tl;
32159ec7b004SRick Macklem 	tl += (NFSX_VERF / NFSX_UNSIGNED);
32169ec7b004SRick Macklem 	i = fxdr_unsigned(int, *tl);
32179ec7b004SRick Macklem 	if (i > NFSV4_OPAQUELIMIT || i <= 0) {
32189ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
32199ec7b004SRick Macklem 		return (error);
32209ec7b004SRick Macklem 	}
32219ec7b004SRick Macklem 	idlen = i;
32229ec7b004SRick Macklem 	if (nd->nd_flag & ND_GSS)
32239ec7b004SRick Macklem 		i += nd->nd_princlen;
32249ec7b004SRick Macklem 	MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i,
32259ec7b004SRick Macklem 	    M_NFSDCLIENT, M_WAITOK);
32269ec7b004SRick Macklem 	NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i);
32279ec7b004SRick Macklem 	NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
32289ec7b004SRick Macklem 	NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
32299ec7b004SRick Macklem 	NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
32309ec7b004SRick Macklem 	clp->lc_req.nr_cred = NULL;
32319ec7b004SRick Macklem 	NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
32329ec7b004SRick Macklem 	clp->lc_idlen = idlen;
32339ec7b004SRick Macklem 	error = nfsrv_mtostr(nd, clp->lc_id, idlen);
32349ec7b004SRick Macklem 	if (error)
32359ec7b004SRick Macklem 		goto nfsmout;
32369ec7b004SRick Macklem 	if (nd->nd_flag & ND_GSS) {
32379ec7b004SRick Macklem 		clp->lc_flags = LCL_GSS;
32389ec7b004SRick Macklem 		if (nd->nd_flag & ND_GSSINTEGRITY)
32399ec7b004SRick Macklem 			clp->lc_flags |= LCL_GSSINTEGRITY;
32409ec7b004SRick Macklem 		else if (nd->nd_flag & ND_GSSPRIVACY)
32419ec7b004SRick Macklem 			clp->lc_flags |= LCL_GSSPRIVACY;
32429ec7b004SRick Macklem 	} else {
32439ec7b004SRick Macklem 		clp->lc_flags = 0;
32449ec7b004SRick Macklem 	}
32459ec7b004SRick Macklem 	if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
32469ec7b004SRick Macklem 		clp->lc_flags |= LCL_NAME;
32479ec7b004SRick Macklem 		clp->lc_namelen = nd->nd_princlen;
32489ec7b004SRick Macklem 		clp->lc_name = &clp->lc_id[idlen];
32499ec7b004SRick Macklem 		NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
32509ec7b004SRick Macklem 	} else {
32519ec7b004SRick Macklem 		clp->lc_uid = nd->nd_cred->cr_uid;
32529ec7b004SRick Macklem 		clp->lc_gid = nd->nd_cred->cr_gid;
32539ec7b004SRick Macklem 	}
32549ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
32559ec7b004SRick Macklem 	clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
32569ec7b004SRick Macklem 	error = nfsrv_getclientipaddr(nd, clp);
32579ec7b004SRick Macklem 	if (error)
32589ec7b004SRick Macklem 		goto nfsmout;
32599ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
32609ec7b004SRick Macklem 	clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
32619ec7b004SRick Macklem 
32629ec7b004SRick Macklem 	/*
32639ec7b004SRick Macklem 	 * nfsrv_setclient() does the actual work of adding it to the
32649ec7b004SRick Macklem 	 * client list. If there is no error, the structure has been
32659ec7b004SRick Macklem 	 * linked into the client list and clp should no longer be used
32669ec7b004SRick Macklem 	 * here. When an error is returned, it has not been linked in,
32679ec7b004SRick Macklem 	 * so it should be free'd.
32689ec7b004SRick Macklem 	 */
32699ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
32709ec7b004SRick Macklem 	if (nd->nd_repstat == NFSERR_CLIDINUSE) {
32719ec7b004SRick Macklem 		if (clp->lc_flags & LCL_TCPCALLBACK)
32729ec7b004SRick Macklem 			(void) nfsm_strtom(nd, "tcp", 3);
32739ec7b004SRick Macklem 		else
32749ec7b004SRick Macklem 			(void) nfsm_strtom(nd, "udp", 3);
32759ec7b004SRick Macklem 		rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
32769ec7b004SRick Macklem 		ucp = (u_char *)&rad->sin_addr.s_addr;
32779ec7b004SRick Macklem 		ucp2 = (u_char *)&rad->sin_port;
32789ec7b004SRick Macklem 		sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
32799ec7b004SRick Macklem 		    ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
32809ec7b004SRick Macklem 		    ucp2[0] & 0xff, ucp2[1] & 0xff);
32819ec7b004SRick Macklem 		(void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
32829ec7b004SRick Macklem 	}
32839ec7b004SRick Macklem 	if (clp) {
32849ec7b004SRick Macklem 		NFSSOCKADDRFREE(clp->lc_req.nr_nam);
32859ec7b004SRick Macklem 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
32869ec7b004SRick Macklem 		free((caddr_t)clp, M_NFSDCLIENT);
32879ec7b004SRick Macklem 	}
32889ec7b004SRick Macklem 	if (!nd->nd_repstat) {
32899ec7b004SRick Macklem 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
32909ec7b004SRick Macklem 		*tl++ = clientid.lval[0];
32919ec7b004SRick Macklem 		*tl++ = clientid.lval[1];
32929ec7b004SRick Macklem 		*tl++ = confirm.lval[0];
32939ec7b004SRick Macklem 		*tl = confirm.lval[1];
32949ec7b004SRick Macklem 	}
32959ec7b004SRick Macklem 	return (0);
32969ec7b004SRick Macklem nfsmout:
32979ec7b004SRick Macklem 	if (clp) {
32989ec7b004SRick Macklem 		NFSSOCKADDRFREE(clp->lc_req.nr_nam);
32999ec7b004SRick Macklem 		NFSFREEMUTEX(&clp->lc_req.nr_mtx);
33009ec7b004SRick Macklem 		free((caddr_t)clp, M_NFSDCLIENT);
33019ec7b004SRick Macklem 	}
33029ec7b004SRick Macklem 	return (error);
33039ec7b004SRick Macklem }
33049ec7b004SRick Macklem 
33059ec7b004SRick Macklem /*
33069ec7b004SRick Macklem  * nfsv4 set client id confirm service
33079ec7b004SRick Macklem  */
33089ec7b004SRick Macklem APPLESTATIC int
33099ec7b004SRick Macklem nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
33109ec7b004SRick Macklem     __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
33119ec7b004SRick Macklem     __unused struct nfsexstuff *exp)
33129ec7b004SRick Macklem {
33139ec7b004SRick Macklem 	u_int32_t *tl;
33149ec7b004SRick Macklem 	int error = 0;
33159ec7b004SRick Macklem 	nfsquad_t clientid, confirm;
33169ec7b004SRick Macklem 
3317c9aad40fSRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
33189ec7b004SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
33199ec7b004SRick Macklem 		return (0);
33209ec7b004SRick Macklem 	}
33219ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
33229ec7b004SRick Macklem 	clientid.lval[0] = *tl++;
33239ec7b004SRick Macklem 	clientid.lval[1] = *tl++;
33249ec7b004SRick Macklem 	confirm.lval[0] = *tl++;
33259ec7b004SRick Macklem 	confirm.lval[1] = *tl;
33269ec7b004SRick Macklem 
33279ec7b004SRick Macklem 	/*
33289ec7b004SRick Macklem 	 * nfsrv_getclient() searches the client list for a match and
33299ec7b004SRick Macklem 	 * returns the appropriate NFSERR status.
33309ec7b004SRick Macklem 	 */
33319ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
33329ec7b004SRick Macklem 	    NULL, confirm, nd, p);
33339ec7b004SRick Macklem nfsmout:
33349ec7b004SRick Macklem 	return (error);
33359ec7b004SRick Macklem }
33369ec7b004SRick Macklem 
33379ec7b004SRick Macklem /*
33389ec7b004SRick Macklem  * nfsv4 verify service
33399ec7b004SRick Macklem  */
33409ec7b004SRick Macklem APPLESTATIC int
33419ec7b004SRick Macklem nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
33429ec7b004SRick Macklem     vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
33439ec7b004SRick Macklem {
33449ec7b004SRick Macklem 	int error = 0, ret, fhsize = NFSX_MYFH;
33459ec7b004SRick Macklem 	struct nfsvattr nva;
33469ec7b004SRick Macklem 	struct statfs sf;
33479ec7b004SRick Macklem 	struct nfsfsinfo fs;
33489ec7b004SRick Macklem 	fhandle_t fh;
33499ec7b004SRick Macklem 
33500cf42b62SRick Macklem 	nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
33519ec7b004SRick Macklem 	if (!nd->nd_repstat)
3352dfd233edSAttilio Rao 		nd->nd_repstat = nfsvno_statfs(vp, &sf);
33539ec7b004SRick Macklem 	if (!nd->nd_repstat)
33549ec7b004SRick Macklem 		nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
33559ec7b004SRick Macklem 	if (!nd->nd_repstat) {
33569ec7b004SRick Macklem 		nfsvno_getfs(&fs, isdgram);
33579ec7b004SRick Macklem 		error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
33589ec7b004SRick Macklem 		    &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
33599ec7b004SRick Macklem 		if (!error) {
33609ec7b004SRick Macklem 			if (nd->nd_procnum == NFSV4OP_NVERIFY) {
33619ec7b004SRick Macklem 				if (ret == 0)
33629ec7b004SRick Macklem 					nd->nd_repstat = NFSERR_SAME;
33639ec7b004SRick Macklem 				else if (ret != NFSERR_NOTSAME)
33649ec7b004SRick Macklem 					nd->nd_repstat = ret;
33659ec7b004SRick Macklem 			} else if (ret)
33669ec7b004SRick Macklem 				nd->nd_repstat = ret;
33679ec7b004SRick Macklem 		}
33689ec7b004SRick Macklem 	}
33699ec7b004SRick Macklem 	vput(vp);
33709ec7b004SRick Macklem 	return (error);
33719ec7b004SRick Macklem }
33729ec7b004SRick Macklem 
33739ec7b004SRick Macklem /*
33749ec7b004SRick Macklem  * nfs openattr rpc
33759ec7b004SRick Macklem  */
33769ec7b004SRick Macklem APPLESTATIC int
33779ec7b004SRick Macklem nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
33789ec7b004SRick Macklem     vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
33799ec7b004SRick Macklem     __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
33809ec7b004SRick Macklem {
33819ec7b004SRick Macklem 	u_int32_t *tl;
33829ec7b004SRick Macklem 	int error = 0, createdir;
33839ec7b004SRick Macklem 
33849ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
33859ec7b004SRick Macklem 	createdir = fxdr_unsigned(int, *tl);
33869ec7b004SRick Macklem 	nd->nd_repstat = NFSERR_NOTSUPP;
33879ec7b004SRick Macklem nfsmout:
33889ec7b004SRick Macklem 	vrele(dp);
33899ec7b004SRick Macklem 	return (error);
33909ec7b004SRick Macklem }
33919ec7b004SRick Macklem 
33929ec7b004SRick Macklem /*
33939ec7b004SRick Macklem  * nfsv4 release lock owner service
33949ec7b004SRick Macklem  */
33959ec7b004SRick Macklem APPLESTATIC int
33969ec7b004SRick Macklem nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
33979ec7b004SRick Macklem     __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
33989ec7b004SRick Macklem {
33999ec7b004SRick Macklem 	u_int32_t *tl;
34009ec7b004SRick Macklem 	struct nfsstate *stp = NULL;
34019ec7b004SRick Macklem 	int error = 0, len;
34029ec7b004SRick Macklem 	nfsquad_t clientid;
34039ec7b004SRick Macklem 
3404c9aad40fSRick Macklem 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3405b1cfc0d9SRick Macklem 		nd->nd_repstat = NFSERR_WRONGSEC;
3406b1cfc0d9SRick Macklem 		return (0);
3407b1cfc0d9SRick Macklem 	}
34089ec7b004SRick Macklem 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
34099ec7b004SRick Macklem 	len = fxdr_unsigned(int, *(tl + 2));
34102a45247cSRick Macklem 	if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
34112a45247cSRick Macklem 		nd->nd_repstat = NFSERR_BADXDR;
34122a45247cSRick Macklem 		return (0);
34132a45247cSRick Macklem 	}
34149ec7b004SRick Macklem 	MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
34159ec7b004SRick Macklem 	    M_NFSDSTATE, M_WAITOK);
34169ec7b004SRick Macklem 	stp->ls_ownerlen = len;
34179ec7b004SRick Macklem 	stp->ls_op = NULL;
34189ec7b004SRick Macklem 	stp->ls_flags = NFSLCK_RELEASE;
34199ec7b004SRick Macklem 	stp->ls_uid = nd->nd_cred->cr_uid;
34209ec7b004SRick Macklem 	clientid.lval[0] = *tl++;
34219ec7b004SRick Macklem 	clientid.lval[1] = *tl;
34229ec7b004SRick Macklem 	if (nd->nd_flag & ND_IMPLIEDCLID) {
34239ec7b004SRick Macklem 		if (nd->nd_clientid.qval != clientid.qval)
34249ec7b004SRick Macklem 			printf("EEK! multiple clids\n");
34259ec7b004SRick Macklem 	} else {
34269ec7b004SRick Macklem 		nd->nd_flag |= ND_IMPLIEDCLID;
34279ec7b004SRick Macklem 		nd->nd_clientid.qval = clientid.qval;
34289ec7b004SRick Macklem 	}
34299ec7b004SRick Macklem 	error = nfsrv_mtostr(nd, stp->ls_owner, len);
34309ec7b004SRick Macklem 	if (error)
34319ec7b004SRick Macklem 		goto nfsmout;
34329ec7b004SRick Macklem 	nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
34339ec7b004SRick Macklem 	FREE((caddr_t)stp, M_NFSDSTATE);
34349ec7b004SRick Macklem 	return (0);
34359ec7b004SRick Macklem nfsmout:
34369ec7b004SRick Macklem 	if (stp)
34379ec7b004SRick Macklem 		free((caddr_t)stp, M_NFSDSTATE);
34389ec7b004SRick Macklem 	return (error);
34399ec7b004SRick Macklem }
3440