1*481d3881Srin /* $NetBSD: nfs_nfsdserv.c,v 1.6 2024/07/05 04:31:52 rin Exp $ */
26ca35587Sdholland /*-
36ca35587Sdholland * Copyright (c) 1989, 1993
46ca35587Sdholland * The Regents of the University of California. All rights reserved.
56ca35587Sdholland *
66ca35587Sdholland * This code is derived from software contributed to Berkeley by
76ca35587Sdholland * Rick Macklem at The University of Guelph.
86ca35587Sdholland *
96ca35587Sdholland * Redistribution and use in source and binary forms, with or without
106ca35587Sdholland * modification, are permitted provided that the following conditions
116ca35587Sdholland * are met:
126ca35587Sdholland * 1. Redistributions of source code must retain the above copyright
136ca35587Sdholland * notice, this list of conditions and the following disclaimer.
146ca35587Sdholland * 2. Redistributions in binary form must reproduce the above copyright
156ca35587Sdholland * notice, this list of conditions and the following disclaimer in the
166ca35587Sdholland * documentation and/or other materials provided with the distribution.
176ca35587Sdholland * 4. Neither the name of the University nor the names of its contributors
186ca35587Sdholland * may be used to endorse or promote products derived from this software
196ca35587Sdholland * without specific prior written permission.
206ca35587Sdholland *
216ca35587Sdholland * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
226ca35587Sdholland * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
236ca35587Sdholland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
246ca35587Sdholland * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
256ca35587Sdholland * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
266ca35587Sdholland * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
276ca35587Sdholland * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
286ca35587Sdholland * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
296ca35587Sdholland * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
306ca35587Sdholland * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
316ca35587Sdholland * SUCH DAMAGE.
326ca35587Sdholland *
336ca35587Sdholland */
346ca35587Sdholland
356ca35587Sdholland #include <sys/cdefs.h>
362d39560cSpgoyette /* __FBSDID("FreeBSD: head/sys/fs/nfsserver/nfs_nfsdserv.c 299514 2016-05-12 05:03:12Z cem "); */
37*481d3881Srin __RCSID("$NetBSD: nfs_nfsdserv.c,v 1.6 2024/07/05 04:31:52 rin Exp $");
386ca35587Sdholland
396ca35587Sdholland /*
406ca35587Sdholland * nfs version 2, 3 and 4 server calls to vnode ops
416ca35587Sdholland * - these routines generally have 3 phases
426ca35587Sdholland * 1 - break down and validate rpc request in mbuf list
436ca35587Sdholland * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
446ca35587Sdholland * function in nfsd_port.c
456ca35587Sdholland * 3 - build the rpc reply in an mbuf list
466ca35587Sdholland * For nfsv4, these functions are called for each Op within the Compound RPC.
476ca35587Sdholland */
486ca35587Sdholland
496ca35587Sdholland #ifndef APPLEKEXT
50c10f8b50Spgoyette #include <fs/nfs/common/nfsport.h>
516ca35587Sdholland
526ca35587Sdholland /* Global vars */
536ca35587Sdholland extern u_int32_t newnfs_false, newnfs_true;
546ca35587Sdholland extern enum vtype nv34tov_type[8];
556ca35587Sdholland extern struct timeval nfsboottime;
566ca35587Sdholland extern int nfs_rootfhset;
576ca35587Sdholland extern int nfsrv_enable_crossmntpt;
582d39560cSpgoyette extern int nfsrv_statehashsize;
596ca35587Sdholland #endif /* !APPLEKEXT */
606ca35587Sdholland
616ca35587Sdholland static int nfs_async = 0;
626ca35587Sdholland SYSCTL_DECL(_vfs_nfsd);
636ca35587Sdholland SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
646ca35587Sdholland "Tell client that writes were synced even though they were not");
656ca35587Sdholland
666ca35587Sdholland /*
676ca35587Sdholland * This list defines the GSS mechanisms supported.
686ca35587Sdholland * (Don't ask me how you get these strings from the RFC stuff like
696ca35587Sdholland * iso(1), org(3)... but someone did it, so I don't need to know.)
706ca35587Sdholland */
716ca35587Sdholland static struct nfsgss_mechlist nfsgss_mechlist[] = {
726ca35587Sdholland { 9, "\052\206\110\206\367\022\001\002\002", 11 },
736ca35587Sdholland { 0, "", 0 },
746ca35587Sdholland };
756ca35587Sdholland
766ca35587Sdholland /* local functions */
776ca35587Sdholland static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
786ca35587Sdholland struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
796ca35587Sdholland vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
806ca35587Sdholland int *diraft_retp, nfsattrbit_t *attrbitp,
816ca35587Sdholland NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
826ca35587Sdholland int pathlen);
836ca35587Sdholland static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
846ca35587Sdholland struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
856ca35587Sdholland vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
866ca35587Sdholland int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
876ca35587Sdholland NFSPROC_T *p, struct nfsexstuff *exp);
886ca35587Sdholland
896ca35587Sdholland /*
906ca35587Sdholland * nfs access service (not a part of NFS V2)
916ca35587Sdholland */
926ca35587Sdholland APPLESTATIC int
nfsrvd_access(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,NFSPROC_T * p,struct nfsexstuff * exp)936ca35587Sdholland nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
946ca35587Sdholland vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
956ca35587Sdholland {
966ca35587Sdholland u_int32_t *tl;
976ca35587Sdholland int getret, error = 0;
986ca35587Sdholland struct nfsvattr nva;
996ca35587Sdholland u_int32_t testmode, nfsmode, supported = 0;
1006ca35587Sdholland accmode_t deletebit;
1016ca35587Sdholland
1026ca35587Sdholland if (nd->nd_repstat) {
1036ca35587Sdholland nfsrv_postopattr(nd, 1, &nva);
1046ca35587Sdholland goto out;
1056ca35587Sdholland }
1066ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1076ca35587Sdholland nfsmode = fxdr_unsigned(u_int32_t, *tl);
1086ca35587Sdholland if ((nd->nd_flag & ND_NFSV4) &&
1096ca35587Sdholland (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
1106ca35587Sdholland NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
1116ca35587Sdholland NFSACCESS_EXECUTE))) {
1126ca35587Sdholland nd->nd_repstat = NFSERR_INVAL;
1136ca35587Sdholland vput(vp);
1146ca35587Sdholland goto out;
1156ca35587Sdholland }
1166ca35587Sdholland if (nfsmode & NFSACCESS_READ) {
1176ca35587Sdholland supported |= NFSACCESS_READ;
1186ca35587Sdholland if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
1196ca35587Sdholland NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
1206ca35587Sdholland nfsmode &= ~NFSACCESS_READ;
1216ca35587Sdholland }
1226ca35587Sdholland if (nfsmode & NFSACCESS_MODIFY) {
1236ca35587Sdholland supported |= NFSACCESS_MODIFY;
1246ca35587Sdholland if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
1256ca35587Sdholland NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
1266ca35587Sdholland nfsmode &= ~NFSACCESS_MODIFY;
1276ca35587Sdholland }
1286ca35587Sdholland if (nfsmode & NFSACCESS_EXTEND) {
1296ca35587Sdholland supported |= NFSACCESS_EXTEND;
1306ca35587Sdholland if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
1316ca35587Sdholland NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
1326ca35587Sdholland nfsmode &= ~NFSACCESS_EXTEND;
1336ca35587Sdholland }
1346ca35587Sdholland if (nfsmode & NFSACCESS_DELETE) {
1356ca35587Sdholland supported |= NFSACCESS_DELETE;
1366ca35587Sdholland if (vp->v_type == VDIR)
1376ca35587Sdholland deletebit = VDELETE_CHILD;
1386ca35587Sdholland else
1396ca35587Sdholland deletebit = VDELETE;
1406ca35587Sdholland if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
1416ca35587Sdholland NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
1426ca35587Sdholland nfsmode &= ~NFSACCESS_DELETE;
1436ca35587Sdholland }
1446ca35587Sdholland if (vnode_vtype(vp) == VDIR)
1456ca35587Sdholland testmode = NFSACCESS_LOOKUP;
1466ca35587Sdholland else
1476ca35587Sdholland testmode = NFSACCESS_EXECUTE;
1486ca35587Sdholland if (nfsmode & testmode) {
1496ca35587Sdholland supported |= (nfsmode & testmode);
1506ca35587Sdholland if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
1516ca35587Sdholland NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
1526ca35587Sdholland nfsmode &= ~testmode;
1536ca35587Sdholland }
1546ca35587Sdholland nfsmode &= supported;
1556ca35587Sdholland if (nd->nd_flag & ND_NFSV3) {
1566ca35587Sdholland getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
1576ca35587Sdholland nfsrv_postopattr(nd, getret, &nva);
1586ca35587Sdholland }
1596ca35587Sdholland vput(vp);
1606ca35587Sdholland if (nd->nd_flag & ND_NFSV4) {
1616ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1626ca35587Sdholland *tl++ = txdr_unsigned(supported);
1636ca35587Sdholland } else
1646ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
1656ca35587Sdholland *tl = txdr_unsigned(nfsmode);
1666ca35587Sdholland
1676ca35587Sdholland out:
1686ca35587Sdholland NFSEXITCODE2(0, nd);
1696ca35587Sdholland return (0);
1706ca35587Sdholland nfsmout:
1716ca35587Sdholland vput(vp);
1726ca35587Sdholland NFSEXITCODE2(error, nd);
1736ca35587Sdholland return (error);
1746ca35587Sdholland }
1756ca35587Sdholland
1766ca35587Sdholland /*
1776ca35587Sdholland * nfs getattr service
1786ca35587Sdholland */
1796ca35587Sdholland APPLESTATIC int
nfsrvd_getattr(struct nfsrv_descript * nd,int isdgram,vnode_t vp,NFSPROC_T * p,__unused struct nfsexstuff * exp)1806ca35587Sdholland nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
1816ca35587Sdholland vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1826ca35587Sdholland {
1836ca35587Sdholland struct nfsvattr nva;
1846ca35587Sdholland fhandle_t fh;
1856ca35587Sdholland int at_root = 0, error = 0, supports_nfsv4acls;
1866ca35587Sdholland struct nfsreferral *refp;
1876ca35587Sdholland nfsattrbit_t attrbits, tmpbits;
1886ca35587Sdholland struct mount *mp;
1896ca35587Sdholland struct vnode *tvp = NULL;
1906ca35587Sdholland struct vattr va;
1916ca35587Sdholland uint64_t mounted_on_fileno = 0;
1926ca35587Sdholland accmode_t accmode;
1936ca35587Sdholland
1946ca35587Sdholland if (nd->nd_repstat)
1956ca35587Sdholland goto out;
1966ca35587Sdholland if (nd->nd_flag & ND_NFSV4) {
1976ca35587Sdholland error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
1986ca35587Sdholland if (error) {
1996ca35587Sdholland vput(vp);
2006ca35587Sdholland goto out;
2016ca35587Sdholland }
2026ca35587Sdholland
2036ca35587Sdholland /*
2046ca35587Sdholland * Check for a referral.
2056ca35587Sdholland */
2066ca35587Sdholland refp = nfsv4root_getreferral(vp, NULL, 0);
2076ca35587Sdholland if (refp != NULL) {
2086ca35587Sdholland (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
2096ca35587Sdholland &nd->nd_repstat);
2106ca35587Sdholland vput(vp);
2116ca35587Sdholland goto out;
2126ca35587Sdholland }
2136ca35587Sdholland if (nd->nd_repstat == 0) {
2146ca35587Sdholland accmode = 0;
2156ca35587Sdholland NFSSET_ATTRBIT(&tmpbits, &attrbits);
2162d39560cSpgoyette
2172d39560cSpgoyette /*
2182d39560cSpgoyette * GETATTR with write-only attr time_access_set and time_modify_set
2192d39560cSpgoyette * should return NFS4ERR_INVAL.
2202d39560cSpgoyette */
2212d39560cSpgoyette if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) ||
2222d39560cSpgoyette NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){
2232d39560cSpgoyette error = NFSERR_INVAL;
2242d39560cSpgoyette vput(vp);
2252d39560cSpgoyette goto out;
2262d39560cSpgoyette }
2276ca35587Sdholland if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
2286ca35587Sdholland NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
2296ca35587Sdholland accmode |= VREAD_ACL;
2306ca35587Sdholland }
2316ca35587Sdholland if (NFSNONZERO_ATTRBIT(&tmpbits))
2326ca35587Sdholland accmode |= VREAD_ATTRIBUTES;
2336ca35587Sdholland if (accmode != 0)
2346ca35587Sdholland nd->nd_repstat = nfsvno_accchk(vp, accmode,
2356ca35587Sdholland nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
2366ca35587Sdholland NFSACCCHK_VPISLOCKED, NULL);
2376ca35587Sdholland }
2386ca35587Sdholland }
2396ca35587Sdholland if (!nd->nd_repstat)
2406ca35587Sdholland nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2416ca35587Sdholland if (!nd->nd_repstat) {
2426ca35587Sdholland if (nd->nd_flag & ND_NFSV4) {
2436ca35587Sdholland if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
2446ca35587Sdholland nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
2456ca35587Sdholland if (!nd->nd_repstat)
2466ca35587Sdholland nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
2476ca35587Sdholland &nva, &attrbits, nd->nd_cred, p);
2486ca35587Sdholland if (nd->nd_repstat == 0) {
2496ca35587Sdholland supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
2506ca35587Sdholland mp = vp->v_mount;
2516ca35587Sdholland if (nfsrv_enable_crossmntpt != 0 &&
2526ca35587Sdholland vp->v_type == VDIR &&
2536ca35587Sdholland (vp->v_vflag & VV_ROOT) != 0 &&
2546ca35587Sdholland vp != rootvnode) {
2556ca35587Sdholland tvp = mp->mnt_vnodecovered;
2566ca35587Sdholland VREF(tvp);
2576ca35587Sdholland at_root = 1;
2586ca35587Sdholland } else
2596ca35587Sdholland at_root = 0;
2606ca35587Sdholland vfs_ref(mp);
2616ca35587Sdholland NFSVOPUNLOCK(vp, 0);
2626ca35587Sdholland if (at_root != 0) {
2636ca35587Sdholland if ((nd->nd_repstat =
2646ca35587Sdholland NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
2656ca35587Sdholland nd->nd_repstat = VOP_GETATTR(
2666ca35587Sdholland tvp, &va, nd->nd_cred);
2676ca35587Sdholland vput(tvp);
2686ca35587Sdholland } else
2696ca35587Sdholland vrele(tvp);
2706ca35587Sdholland if (nd->nd_repstat == 0)
2716ca35587Sdholland mounted_on_fileno = (uint64_t)
2726ca35587Sdholland va.va_fileid;
2736ca35587Sdholland else
2746ca35587Sdholland at_root = 0;
2756ca35587Sdholland }
2766ca35587Sdholland if (nd->nd_repstat == 0)
2776ca35587Sdholland nd->nd_repstat = vfs_busy(mp, 0);
2786ca35587Sdholland vfs_rel(mp);
2796ca35587Sdholland if (nd->nd_repstat == 0) {
2806ca35587Sdholland (void)nfsvno_fillattr(nd, mp, vp, &nva,
2816ca35587Sdholland &fh, 0, &attrbits, nd->nd_cred, p,
2826ca35587Sdholland isdgram, 1, supports_nfsv4acls,
2836ca35587Sdholland at_root, mounted_on_fileno);
2846ca35587Sdholland vfs_unbusy(mp);
2856ca35587Sdholland }
2866ca35587Sdholland vrele(vp);
2876ca35587Sdholland } else
2886ca35587Sdholland vput(vp);
2896ca35587Sdholland } else {
2906ca35587Sdholland nfsrv_fillattr(nd, &nva);
2916ca35587Sdholland vput(vp);
2926ca35587Sdholland }
2936ca35587Sdholland } else {
2946ca35587Sdholland vput(vp);
2956ca35587Sdholland }
2966ca35587Sdholland
2976ca35587Sdholland out:
2986ca35587Sdholland NFSEXITCODE2(error, nd);
2996ca35587Sdholland return (error);
3006ca35587Sdholland }
3016ca35587Sdholland
3026ca35587Sdholland /*
3036ca35587Sdholland * nfs setattr service
3046ca35587Sdholland */
3056ca35587Sdholland APPLESTATIC int
nfsrvd_setattr(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,NFSPROC_T * p,struct nfsexstuff * exp)3066ca35587Sdholland nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
3076ca35587Sdholland vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
3086ca35587Sdholland {
3096ca35587Sdholland struct nfsvattr nva, nva2;
3106ca35587Sdholland u_int32_t *tl;
3116ca35587Sdholland int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
3126ca35587Sdholland struct timespec guard = { 0, 0 };
3136ca35587Sdholland nfsattrbit_t attrbits, retbits;
3146ca35587Sdholland nfsv4stateid_t stateid;
3156ca35587Sdholland NFSACL_T *aclp = NULL;
3166ca35587Sdholland
3176ca35587Sdholland if (nd->nd_repstat) {
3186ca35587Sdholland nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
3196ca35587Sdholland goto out;
3206ca35587Sdholland }
3216ca35587Sdholland #ifdef NFS4_ACL_EXTATTR_NAME
3226ca35587Sdholland aclp = acl_alloc(M_WAITOK);
3236ca35587Sdholland aclp->acl_cnt = 0;
3246ca35587Sdholland #endif
3256ca35587Sdholland NFSVNO_ATTRINIT(&nva);
3266ca35587Sdholland NFSZERO_ATTRBIT(&retbits);
3276ca35587Sdholland if (nd->nd_flag & ND_NFSV4) {
3286ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3296ca35587Sdholland stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3306ca35587Sdholland NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
3316ca35587Sdholland }
3322d39560cSpgoyette error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p);
3336ca35587Sdholland if (error)
3346ca35587Sdholland goto nfsmout;
3356ca35587Sdholland preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1);
3366ca35587Sdholland if (!nd->nd_repstat)
3376ca35587Sdholland nd->nd_repstat = preat_ret;
3386ca35587Sdholland if (nd->nd_flag & ND_NFSV3) {
3396ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3406ca35587Sdholland gcheck = fxdr_unsigned(int, *tl);
3416ca35587Sdholland if (gcheck) {
3426ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3436ca35587Sdholland fxdr_nfsv3time(tl, &guard);
3446ca35587Sdholland }
3456ca35587Sdholland if (!nd->nd_repstat && gcheck &&
3466ca35587Sdholland (nva2.na_ctime.tv_sec != guard.tv_sec ||
3476ca35587Sdholland nva2.na_ctime.tv_nsec != guard.tv_nsec))
3486ca35587Sdholland nd->nd_repstat = NFSERR_NOT_SYNC;
3496ca35587Sdholland if (nd->nd_repstat) {
3506ca35587Sdholland vput(vp);
3516ca35587Sdholland #ifdef NFS4_ACL_EXTATTR_NAME
3526ca35587Sdholland acl_free(aclp);
3536ca35587Sdholland #endif
3546ca35587Sdholland nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
3556ca35587Sdholland goto out;
3566ca35587Sdholland }
3576ca35587Sdholland } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
3586ca35587Sdholland nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
3596ca35587Sdholland
3606ca35587Sdholland /*
3616ca35587Sdholland * Now that we have all the fields, lets do it.
3626ca35587Sdholland * If the size is being changed write access is required, otherwise
3636ca35587Sdholland * just check for a read only file system.
3646ca35587Sdholland */
3656ca35587Sdholland if (!nd->nd_repstat) {
3666ca35587Sdholland if (NFSVNO_NOTSETSIZE(&nva)) {
3676ca35587Sdholland if (NFSVNO_EXRDONLY(exp) ||
3686ca35587Sdholland (vfs_flags(vnode_mount(vp)) & MNT_RDONLY))
3696ca35587Sdholland nd->nd_repstat = EROFS;
3706ca35587Sdholland } else {
3716ca35587Sdholland if (vnode_vtype(vp) != VREG)
3726ca35587Sdholland nd->nd_repstat = EINVAL;
3736ca35587Sdholland else if (nva2.na_uid != nd->nd_cred->cr_uid ||
3746ca35587Sdholland NFSVNO_EXSTRICTACCESS(exp))
3756ca35587Sdholland nd->nd_repstat = nfsvno_accchk(vp,
3766ca35587Sdholland VWRITE, nd->nd_cred, exp, p,
3776ca35587Sdholland NFSACCCHK_NOOVERRIDE,
3786ca35587Sdholland NFSACCCHK_VPISLOCKED, NULL);
3796ca35587Sdholland }
3806ca35587Sdholland }
3816ca35587Sdholland if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
3826ca35587Sdholland nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
3836ca35587Sdholland &nva, &attrbits, exp, p);
3846ca35587Sdholland
3856ca35587Sdholland if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
3866ca35587Sdholland /*
38782bba4e9Sandvar * For V4, try setting the attributes in sets, so that the
3886ca35587Sdholland * reply bitmap will be correct for an error case.
3896ca35587Sdholland */
3906ca35587Sdholland if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
3916ca35587Sdholland NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
3926ca35587Sdholland NFSVNO_ATTRINIT(&nva2);
3936ca35587Sdholland NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
3946ca35587Sdholland NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
3956ca35587Sdholland nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
3966ca35587Sdholland exp);
3976ca35587Sdholland if (!nd->nd_repstat) {
3986ca35587Sdholland if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
3996ca35587Sdholland NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
4006ca35587Sdholland if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
4016ca35587Sdholland NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
4026ca35587Sdholland }
4036ca35587Sdholland }
4046ca35587Sdholland if (!nd->nd_repstat &&
4056ca35587Sdholland NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
4066ca35587Sdholland NFSVNO_ATTRINIT(&nva2);
4076ca35587Sdholland NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
4086ca35587Sdholland nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
4096ca35587Sdholland exp);
4106ca35587Sdholland if (!nd->nd_repstat)
4116ca35587Sdholland NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
4126ca35587Sdholland }
4136ca35587Sdholland if (!nd->nd_repstat &&
4146ca35587Sdholland (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
4156ca35587Sdholland NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
4166ca35587Sdholland NFSVNO_ATTRINIT(&nva2);
4176ca35587Sdholland NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
4186ca35587Sdholland NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
4196ca35587Sdholland if (nva.na_vaflags & VA_UTIMES_NULL) {
4206ca35587Sdholland nva2.na_vaflags |= VA_UTIMES_NULL;
4216ca35587Sdholland NFSVNO_SETACTIVE(&nva2, vaflags);
4226ca35587Sdholland }
4236ca35587Sdholland nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
4246ca35587Sdholland exp);
4256ca35587Sdholland if (!nd->nd_repstat) {
4266ca35587Sdholland if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
4276ca35587Sdholland NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
4286ca35587Sdholland if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
4296ca35587Sdholland NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
4306ca35587Sdholland }
4316ca35587Sdholland }
4326ca35587Sdholland if (!nd->nd_repstat &&
4336ca35587Sdholland NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) {
4346ca35587Sdholland NFSVNO_ATTRINIT(&nva2);
4356ca35587Sdholland NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
4366ca35587Sdholland nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
4376ca35587Sdholland exp);
4386ca35587Sdholland if (!nd->nd_repstat)
4396ca35587Sdholland NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
4406ca35587Sdholland }
4416ca35587Sdholland
4426ca35587Sdholland #ifdef NFS4_ACL_EXTATTR_NAME
4436ca35587Sdholland if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
4446ca35587Sdholland NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
4456ca35587Sdholland nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
4466ca35587Sdholland if (!nd->nd_repstat)
4476ca35587Sdholland NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
4486ca35587Sdholland }
4496ca35587Sdholland #endif
4506ca35587Sdholland } else if (!nd->nd_repstat) {
4516ca35587Sdholland nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
4526ca35587Sdholland exp);
4536ca35587Sdholland }
4546ca35587Sdholland if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
4556ca35587Sdholland postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
4566ca35587Sdholland if (!nd->nd_repstat)
4576ca35587Sdholland nd->nd_repstat = postat_ret;
4586ca35587Sdholland }
4596ca35587Sdholland vput(vp);
4606ca35587Sdholland #ifdef NFS4_ACL_EXTATTR_NAME
4616ca35587Sdholland acl_free(aclp);
4626ca35587Sdholland #endif
4636ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
4646ca35587Sdholland nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
4656ca35587Sdholland else if (nd->nd_flag & ND_NFSV4)
4666ca35587Sdholland (void) nfsrv_putattrbit(nd, &retbits);
4676ca35587Sdholland else if (!nd->nd_repstat)
4686ca35587Sdholland nfsrv_fillattr(nd, &nva);
4696ca35587Sdholland
4706ca35587Sdholland out:
4716ca35587Sdholland NFSEXITCODE2(0, nd);
4726ca35587Sdholland return (0);
4736ca35587Sdholland nfsmout:
4746ca35587Sdholland vput(vp);
4756ca35587Sdholland #ifdef NFS4_ACL_EXTATTR_NAME
4766ca35587Sdholland acl_free(aclp);
4776ca35587Sdholland #endif
4786ca35587Sdholland if (nd->nd_flag & ND_NFSV4) {
4796ca35587Sdholland /*
4806ca35587Sdholland * For all nd_repstat, the V4 reply includes a bitmap,
4816ca35587Sdholland * even NFSERR_BADXDR, which is what this will end up
4826ca35587Sdholland * returning.
4836ca35587Sdholland */
4846ca35587Sdholland (void) nfsrv_putattrbit(nd, &retbits);
4856ca35587Sdholland }
4866ca35587Sdholland NFSEXITCODE2(error, nd);
4876ca35587Sdholland return (error);
4886ca35587Sdholland }
4896ca35587Sdholland
4906ca35587Sdholland /*
4916ca35587Sdholland * nfs lookup rpc
4926ca35587Sdholland * (Also performs lookup parent for v4)
4936ca35587Sdholland */
4946ca35587Sdholland APPLESTATIC int
nfsrvd_lookup(struct nfsrv_descript * nd,__unused int isdgram,vnode_t dp,vnode_t * vpp,fhandle_t * fhp,NFSPROC_T * p,struct nfsexstuff * exp)4956ca35587Sdholland nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
4966ca35587Sdholland vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
4976ca35587Sdholland struct nfsexstuff *exp)
4986ca35587Sdholland {
4996ca35587Sdholland struct nameidata named;
5006ca35587Sdholland vnode_t vp, dirp = NULL;
5016ca35587Sdholland int error = 0, dattr_ret = 1;
5026ca35587Sdholland struct nfsvattr nva, dattr;
5036ca35587Sdholland char *bufp;
5046ca35587Sdholland u_long *hashp;
5056ca35587Sdholland
5066ca35587Sdholland if (nd->nd_repstat) {
5076ca35587Sdholland nfsrv_postopattr(nd, dattr_ret, &dattr);
5086ca35587Sdholland goto out;
5096ca35587Sdholland }
5106ca35587Sdholland
5116ca35587Sdholland /*
5126ca35587Sdholland * For some reason, if dp is a symlink, the error
5136ca35587Sdholland * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
5146ca35587Sdholland */
5156ca35587Sdholland if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
5166ca35587Sdholland nd->nd_repstat = NFSERR_SYMLINK;
5176ca35587Sdholland vrele(dp);
5186ca35587Sdholland goto out;
5196ca35587Sdholland }
5206ca35587Sdholland
5216ca35587Sdholland NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
5226ca35587Sdholland LOCKLEAF | SAVESTART);
5236ca35587Sdholland nfsvno_setpathbuf(&named, &bufp, &hashp);
5246ca35587Sdholland error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
5256ca35587Sdholland if (error) {
5266ca35587Sdholland vrele(dp);
5276ca35587Sdholland nfsvno_relpathbuf(&named);
5286ca35587Sdholland goto out;
5296ca35587Sdholland }
5306ca35587Sdholland if (!nd->nd_repstat) {
5316ca35587Sdholland nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
5326ca35587Sdholland } else {
5336ca35587Sdholland vrele(dp);
5346ca35587Sdholland nfsvno_relpathbuf(&named);
5356ca35587Sdholland }
5366ca35587Sdholland if (nd->nd_repstat) {
5376ca35587Sdholland if (dirp) {
5386ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
5396ca35587Sdholland dattr_ret = nfsvno_getattr(dirp, &dattr,
5406ca35587Sdholland nd->nd_cred, p, 0);
5416ca35587Sdholland vrele(dirp);
5426ca35587Sdholland }
5436ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
5446ca35587Sdholland nfsrv_postopattr(nd, dattr_ret, &dattr);
5456ca35587Sdholland goto out;
5466ca35587Sdholland }
5476ca35587Sdholland if (named.ni_startdir)
5486ca35587Sdholland vrele(named.ni_startdir);
5496ca35587Sdholland nfsvno_relpathbuf(&named);
5506ca35587Sdholland vp = named.ni_vp;
5516ca35587Sdholland if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
5526ca35587Sdholland vp->v_type != VDIR && vp->v_type != VLNK)
5536ca35587Sdholland /*
5546ca35587Sdholland * Only allow lookup of VDIR and VLNK for traversal of
5556ca35587Sdholland * non-exported volumes during NFSv4 mounting.
5566ca35587Sdholland */
5576ca35587Sdholland nd->nd_repstat = ENOENT;
5586ca35587Sdholland if (nd->nd_repstat == 0)
5596ca35587Sdholland nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
5606ca35587Sdholland if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
5616ca35587Sdholland nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
5626ca35587Sdholland if (vpp != NULL && nd->nd_repstat == 0)
5636ca35587Sdholland *vpp = vp;
5646ca35587Sdholland else
5656ca35587Sdholland vput(vp);
5666ca35587Sdholland if (dirp) {
5676ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
5686ca35587Sdholland dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred,
5696ca35587Sdholland p, 0);
5706ca35587Sdholland vrele(dirp);
5716ca35587Sdholland }
5726ca35587Sdholland if (nd->nd_repstat) {
5736ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
5746ca35587Sdholland nfsrv_postopattr(nd, dattr_ret, &dattr);
5756ca35587Sdholland goto out;
5766ca35587Sdholland }
5776ca35587Sdholland if (nd->nd_flag & ND_NFSV2) {
5786ca35587Sdholland (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
5796ca35587Sdholland nfsrv_fillattr(nd, &nva);
5806ca35587Sdholland } else if (nd->nd_flag & ND_NFSV3) {
5816ca35587Sdholland (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
5826ca35587Sdholland nfsrv_postopattr(nd, 0, &nva);
5836ca35587Sdholland nfsrv_postopattr(nd, dattr_ret, &dattr);
5846ca35587Sdholland }
5856ca35587Sdholland
5866ca35587Sdholland out:
5876ca35587Sdholland NFSEXITCODE2(error, nd);
5886ca35587Sdholland return (error);
5896ca35587Sdholland }
5906ca35587Sdholland
5916ca35587Sdholland /*
5926ca35587Sdholland * nfs readlink service
5936ca35587Sdholland */
5946ca35587Sdholland APPLESTATIC int
nfsrvd_readlink(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,NFSPROC_T * p,__unused struct nfsexstuff * exp)5956ca35587Sdholland nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
5966ca35587Sdholland vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
5976ca35587Sdholland {
5986ca35587Sdholland u_int32_t *tl;
5996ca35587Sdholland mbuf_t mp = NULL, mpend = NULL;
6006ca35587Sdholland int getret = 1, len;
6016ca35587Sdholland struct nfsvattr nva;
6026ca35587Sdholland
6036ca35587Sdholland if (nd->nd_repstat) {
6046ca35587Sdholland nfsrv_postopattr(nd, getret, &nva);
6056ca35587Sdholland goto out;
6066ca35587Sdholland }
6076ca35587Sdholland if (vnode_vtype(vp) != VLNK) {
6086ca35587Sdholland if (nd->nd_flag & ND_NFSV2)
6096ca35587Sdholland nd->nd_repstat = ENXIO;
6106ca35587Sdholland else
6116ca35587Sdholland nd->nd_repstat = EINVAL;
6126ca35587Sdholland }
6136ca35587Sdholland if (!nd->nd_repstat)
6146ca35587Sdholland nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p,
6156ca35587Sdholland &mp, &mpend, &len);
6166ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
6176ca35587Sdholland getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
6186ca35587Sdholland vput(vp);
6196ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
6206ca35587Sdholland nfsrv_postopattr(nd, getret, &nva);
6216ca35587Sdholland if (nd->nd_repstat)
6226ca35587Sdholland goto out;
6236ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
6246ca35587Sdholland *tl = txdr_unsigned(len);
6256ca35587Sdholland mbuf_setnext(nd->nd_mb, mp);
6266ca35587Sdholland nd->nd_mb = mpend;
6276ca35587Sdholland nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend);
6286ca35587Sdholland
6296ca35587Sdholland out:
6306ca35587Sdholland NFSEXITCODE2(0, nd);
6316ca35587Sdholland return (0);
6326ca35587Sdholland }
6336ca35587Sdholland
6346ca35587Sdholland /*
6356ca35587Sdholland * nfs read service
6366ca35587Sdholland */
6376ca35587Sdholland APPLESTATIC int
nfsrvd_read(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,NFSPROC_T * p,struct nfsexstuff * exp)6386ca35587Sdholland nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
6396ca35587Sdholland vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
6406ca35587Sdholland {
6416ca35587Sdholland u_int32_t *tl;
6426ca35587Sdholland int error = 0, cnt, getret = 1, reqlen, eof = 0;
6436ca35587Sdholland mbuf_t m2, m3;
6446ca35587Sdholland struct nfsvattr nva;
6456ca35587Sdholland off_t off = 0x0;
6466ca35587Sdholland struct nfsstate st, *stp = &st;
6476ca35587Sdholland struct nfslock lo, *lop = &lo;
6486ca35587Sdholland nfsv4stateid_t stateid;
6496ca35587Sdholland nfsquad_t clientid;
6506ca35587Sdholland
6516ca35587Sdholland if (nd->nd_repstat) {
6526ca35587Sdholland nfsrv_postopattr(nd, getret, &nva);
6536ca35587Sdholland goto out;
6546ca35587Sdholland }
6556ca35587Sdholland if (nd->nd_flag & ND_NFSV2) {
6566ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
6576ca35587Sdholland off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
6586ca35587Sdholland reqlen = fxdr_unsigned(int, *tl);
6596ca35587Sdholland } else if (nd->nd_flag & ND_NFSV3) {
6606ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
6616ca35587Sdholland off = fxdr_hyper(tl);
6626ca35587Sdholland tl += 2;
6636ca35587Sdholland reqlen = fxdr_unsigned(int, *tl);
6646ca35587Sdholland } else {
6656ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
6666ca35587Sdholland reqlen = fxdr_unsigned(int, *(tl + 6));
6676ca35587Sdholland }
6686ca35587Sdholland if (reqlen > NFS_SRVMAXDATA(nd)) {
6696ca35587Sdholland reqlen = NFS_SRVMAXDATA(nd);
6706ca35587Sdholland } else if (reqlen < 0) {
6716ca35587Sdholland error = EBADRPC;
6726ca35587Sdholland goto nfsmout;
6736ca35587Sdholland }
6746ca35587Sdholland if (nd->nd_flag & ND_NFSV4) {
6756ca35587Sdholland stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
6766ca35587Sdholland lop->lo_flags = NFSLCK_READ;
6776ca35587Sdholland stp->ls_ownerlen = 0;
6786ca35587Sdholland stp->ls_op = NULL;
6796ca35587Sdholland stp->ls_uid = nd->nd_cred->cr_uid;
6806ca35587Sdholland stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
6816ca35587Sdholland clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
6826ca35587Sdholland clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
6832d39560cSpgoyette if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
6842d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
6852d39560cSpgoyette clientid.qval = nd->nd_clientid.qval;
6862d39560cSpgoyette else if (nd->nd_clientid.qval != clientid.qval)
6872d39560cSpgoyette printf("EEK1 multiple clids\n");
6886ca35587Sdholland } else {
6892d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
6902d39560cSpgoyette printf("EEK! no clientid from session\n");
6916ca35587Sdholland nd->nd_flag |= ND_IMPLIEDCLID;
6926ca35587Sdholland nd->nd_clientid.qval = clientid.qval;
6936ca35587Sdholland }
6946ca35587Sdholland stp->ls_stateid.other[2] = *tl++;
6956ca35587Sdholland off = fxdr_hyper(tl);
6966ca35587Sdholland lop->lo_first = off;
6976ca35587Sdholland tl += 2;
6986ca35587Sdholland lop->lo_end = off + reqlen;
6996ca35587Sdholland /*
7006ca35587Sdholland * Paranoia, just in case it wraps around.
7016ca35587Sdholland */
7026ca35587Sdholland if (lop->lo_end < off)
7036ca35587Sdholland lop->lo_end = NFS64BITSSET;
7046ca35587Sdholland }
7056ca35587Sdholland if (vnode_vtype(vp) != VREG) {
7066ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
7076ca35587Sdholland nd->nd_repstat = EINVAL;
7086ca35587Sdholland else
7096ca35587Sdholland nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
7106ca35587Sdholland EINVAL;
7116ca35587Sdholland }
7126ca35587Sdholland getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
7136ca35587Sdholland if (!nd->nd_repstat)
7146ca35587Sdholland nd->nd_repstat = getret;
7156ca35587Sdholland if (!nd->nd_repstat &&
7166ca35587Sdholland (nva.na_uid != nd->nd_cred->cr_uid ||
7176ca35587Sdholland NFSVNO_EXSTRICTACCESS(exp))) {
7186ca35587Sdholland nd->nd_repstat = nfsvno_accchk(vp, VREAD,
7196ca35587Sdholland nd->nd_cred, exp, p,
7206ca35587Sdholland NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
7216ca35587Sdholland if (nd->nd_repstat)
7226ca35587Sdholland nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
7236ca35587Sdholland nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
7246ca35587Sdholland NFSACCCHK_VPISLOCKED, NULL);
7256ca35587Sdholland }
7266ca35587Sdholland if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
7276ca35587Sdholland nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
7286ca35587Sdholland &stateid, exp, nd, p);
7296ca35587Sdholland if (nd->nd_repstat) {
7306ca35587Sdholland vput(vp);
7316ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
7326ca35587Sdholland nfsrv_postopattr(nd, getret, &nva);
7336ca35587Sdholland goto out;
7346ca35587Sdholland }
7356ca35587Sdholland if (off >= nva.na_size) {
7366ca35587Sdholland cnt = 0;
7376ca35587Sdholland eof = 1;
7386ca35587Sdholland } else if (reqlen == 0)
7396ca35587Sdholland cnt = 0;
7406ca35587Sdholland else if ((off + reqlen) >= nva.na_size) {
7416ca35587Sdholland cnt = nva.na_size - off;
7426ca35587Sdholland eof = 1;
7436ca35587Sdholland } else
7446ca35587Sdholland cnt = reqlen;
7456ca35587Sdholland m3 = NULL;
7466ca35587Sdholland if (cnt > 0) {
7476ca35587Sdholland nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p,
7486ca35587Sdholland &m3, &m2);
7496ca35587Sdholland if (!(nd->nd_flag & ND_NFSV4)) {
7506ca35587Sdholland getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
7516ca35587Sdholland if (!nd->nd_repstat)
7526ca35587Sdholland nd->nd_repstat = getret;
7536ca35587Sdholland }
7546ca35587Sdholland if (nd->nd_repstat) {
7556ca35587Sdholland vput(vp);
7566ca35587Sdholland mbuf_freem(m3);
7576ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
7586ca35587Sdholland nfsrv_postopattr(nd, getret, &nva);
7596ca35587Sdholland goto out;
7606ca35587Sdholland }
7616ca35587Sdholland }
7626ca35587Sdholland vput(vp);
7636ca35587Sdholland if (nd->nd_flag & ND_NFSV2) {
7646ca35587Sdholland nfsrv_fillattr(nd, &nva);
7656ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
7666ca35587Sdholland } else {
7676ca35587Sdholland if (nd->nd_flag & ND_NFSV3) {
7686ca35587Sdholland nfsrv_postopattr(nd, getret, &nva);
7696ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
7706ca35587Sdholland *tl++ = txdr_unsigned(cnt);
7716ca35587Sdholland } else
7726ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
7736ca35587Sdholland if (eof)
7746ca35587Sdholland *tl++ = newnfs_true;
7756ca35587Sdholland else
7766ca35587Sdholland *tl++ = newnfs_false;
7776ca35587Sdholland }
7786ca35587Sdholland *tl = txdr_unsigned(cnt);
7796ca35587Sdholland if (m3) {
7806ca35587Sdholland mbuf_setnext(nd->nd_mb, m3);
7816ca35587Sdholland nd->nd_mb = m2;
7826ca35587Sdholland nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
7836ca35587Sdholland }
7846ca35587Sdholland
7856ca35587Sdholland out:
7866ca35587Sdholland NFSEXITCODE2(0, nd);
7876ca35587Sdholland return (0);
7886ca35587Sdholland nfsmout:
7896ca35587Sdholland vput(vp);
7906ca35587Sdholland NFSEXITCODE2(error, nd);
7916ca35587Sdholland return (error);
7926ca35587Sdholland }
7936ca35587Sdholland
7946ca35587Sdholland /*
7956ca35587Sdholland * nfs write service
7966ca35587Sdholland */
7976ca35587Sdholland APPLESTATIC int
nfsrvd_write(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,NFSPROC_T * p,struct nfsexstuff * exp)7986ca35587Sdholland nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
7996ca35587Sdholland vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
8006ca35587Sdholland {
8016ca35587Sdholland int i, cnt;
8026ca35587Sdholland u_int32_t *tl;
8036ca35587Sdholland mbuf_t mp;
8046ca35587Sdholland struct nfsvattr nva, forat;
8056ca35587Sdholland int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
8066ca35587Sdholland int stable = NFSWRITE_FILESYNC;
8076ca35587Sdholland off_t off;
8086ca35587Sdholland struct nfsstate st, *stp = &st;
8096ca35587Sdholland struct nfslock lo, *lop = &lo;
8106ca35587Sdholland nfsv4stateid_t stateid;
8116ca35587Sdholland nfsquad_t clientid;
8126ca35587Sdholland
8136ca35587Sdholland if (nd->nd_repstat) {
8146ca35587Sdholland nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
8156ca35587Sdholland goto out;
8166ca35587Sdholland }
8176ca35587Sdholland if (nd->nd_flag & ND_NFSV2) {
8186ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
8196ca35587Sdholland off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
8206ca35587Sdholland tl += 2;
8216ca35587Sdholland retlen = len = fxdr_unsigned(int32_t, *tl);
8226ca35587Sdholland } else if (nd->nd_flag & ND_NFSV3) {
8236ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
8246ca35587Sdholland off = fxdr_hyper(tl);
8256ca35587Sdholland tl += 3;
8266ca35587Sdholland stable = fxdr_unsigned(int, *tl++);
8276ca35587Sdholland retlen = len = fxdr_unsigned(int32_t, *tl);
8286ca35587Sdholland } else {
8296ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
8306ca35587Sdholland stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
8316ca35587Sdholland lop->lo_flags = NFSLCK_WRITE;
8326ca35587Sdholland stp->ls_ownerlen = 0;
8336ca35587Sdholland stp->ls_op = NULL;
8346ca35587Sdholland stp->ls_uid = nd->nd_cred->cr_uid;
8356ca35587Sdholland stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
8366ca35587Sdholland clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
8376ca35587Sdholland clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
8382d39560cSpgoyette if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
8392d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
8402d39560cSpgoyette clientid.qval = nd->nd_clientid.qval;
8412d39560cSpgoyette else if (nd->nd_clientid.qval != clientid.qval)
8422d39560cSpgoyette printf("EEK2 multiple clids\n");
8436ca35587Sdholland } else {
8442d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
8452d39560cSpgoyette printf("EEK! no clientid from session\n");
8466ca35587Sdholland nd->nd_flag |= ND_IMPLIEDCLID;
8476ca35587Sdholland nd->nd_clientid.qval = clientid.qval;
8486ca35587Sdholland }
8496ca35587Sdholland stp->ls_stateid.other[2] = *tl++;
8506ca35587Sdholland off = fxdr_hyper(tl);
8516ca35587Sdholland lop->lo_first = off;
8526ca35587Sdholland tl += 2;
8536ca35587Sdholland stable = fxdr_unsigned(int, *tl++);
8546ca35587Sdholland retlen = len = fxdr_unsigned(int32_t, *tl);
8556ca35587Sdholland lop->lo_end = off + len;
8566ca35587Sdholland /*
8576ca35587Sdholland * Paranoia, just in case it wraps around, which shouldn't
8586ca35587Sdholland * ever happen anyhow.
8596ca35587Sdholland */
8606ca35587Sdholland if (lop->lo_end < lop->lo_first)
8616ca35587Sdholland lop->lo_end = NFS64BITSSET;
8626ca35587Sdholland }
8636ca35587Sdholland
8646ca35587Sdholland /*
8656ca35587Sdholland * Loop through the mbuf chain, counting how many mbufs are a
8666ca35587Sdholland * part of this write operation, so the iovec size is known.
8676ca35587Sdholland */
8686ca35587Sdholland cnt = 0;
8696ca35587Sdholland mp = nd->nd_md;
8706ca35587Sdholland i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos;
8716ca35587Sdholland while (len > 0) {
8726ca35587Sdholland if (i > 0) {
8736ca35587Sdholland len -= i;
8746ca35587Sdholland cnt++;
8756ca35587Sdholland }
8766ca35587Sdholland mp = mbuf_next(mp);
8776ca35587Sdholland if (!mp) {
8786ca35587Sdholland if (len > 0) {
8796ca35587Sdholland error = EBADRPC;
8806ca35587Sdholland goto nfsmout;
8816ca35587Sdholland }
8826ca35587Sdholland } else
8836ca35587Sdholland i = mbuf_len(mp);
8846ca35587Sdholland }
8856ca35587Sdholland
8862d39560cSpgoyette if (retlen > NFS_SRVMAXIO || retlen < 0)
8876ca35587Sdholland nd->nd_repstat = EIO;
8886ca35587Sdholland if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
8896ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
8906ca35587Sdholland nd->nd_repstat = EINVAL;
8916ca35587Sdholland else
8926ca35587Sdholland nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
8936ca35587Sdholland EINVAL;
8946ca35587Sdholland }
8956ca35587Sdholland forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1);
8966ca35587Sdholland if (!nd->nd_repstat)
8976ca35587Sdholland nd->nd_repstat = forat_ret;
8986ca35587Sdholland if (!nd->nd_repstat &&
8996ca35587Sdholland (forat.na_uid != nd->nd_cred->cr_uid ||
9006ca35587Sdholland NFSVNO_EXSTRICTACCESS(exp)))
9016ca35587Sdholland nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
9026ca35587Sdholland nd->nd_cred, exp, p,
9036ca35587Sdholland NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
9046ca35587Sdholland if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
9056ca35587Sdholland nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
9066ca35587Sdholland &stateid, exp, nd, p);
9076ca35587Sdholland }
9086ca35587Sdholland if (nd->nd_repstat) {
9096ca35587Sdholland vput(vp);
9106ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
9116ca35587Sdholland nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
9126ca35587Sdholland goto out;
9136ca35587Sdholland }
9146ca35587Sdholland
9156ca35587Sdholland /*
9166ca35587Sdholland * For NFS Version 2, it is not obvious what a write of zero length
9176ca35587Sdholland * should do, but I might as well be consistent with Version 3,
9186ca35587Sdholland * which is to return ok so long as there are no permission problems.
9196ca35587Sdholland */
9206ca35587Sdholland if (retlen > 0) {
9216ca35587Sdholland nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable,
9226ca35587Sdholland nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
9236ca35587Sdholland error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
9246ca35587Sdholland if (error)
9256ca35587Sdholland panic("nfsrv_write mbuf");
9266ca35587Sdholland }
9276ca35587Sdholland if (nd->nd_flag & ND_NFSV4)
9286ca35587Sdholland aftat_ret = 0;
9296ca35587Sdholland else
9306ca35587Sdholland aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
9316ca35587Sdholland vput(vp);
9326ca35587Sdholland if (!nd->nd_repstat)
9336ca35587Sdholland nd->nd_repstat = aftat_ret;
9346ca35587Sdholland if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
9356ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
9366ca35587Sdholland nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
9376ca35587Sdholland if (nd->nd_repstat)
9386ca35587Sdholland goto out;
9396ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
9406ca35587Sdholland *tl++ = txdr_unsigned(retlen);
9416ca35587Sdholland /*
9426ca35587Sdholland * If nfs_async is set, then pretend the write was FILESYNC.
9436ca35587Sdholland * Warning: Doing this violates RFC1813 and runs a risk
9446ca35587Sdholland * of data written by a client being lost when the server
9456ca35587Sdholland * crashes/reboots.
9466ca35587Sdholland */
9476ca35587Sdholland if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
9486ca35587Sdholland *tl++ = txdr_unsigned(stable);
9496ca35587Sdholland else
9506ca35587Sdholland *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
9516ca35587Sdholland /*
9526ca35587Sdholland * Actually, there is no need to txdr these fields,
9536ca35587Sdholland * but it may make the values more human readable,
9546ca35587Sdholland * for debugging purposes.
9556ca35587Sdholland */
9566ca35587Sdholland *tl++ = txdr_unsigned(nfsboottime.tv_sec);
9576ca35587Sdholland *tl = txdr_unsigned(nfsboottime.tv_usec);
9586ca35587Sdholland } else if (!nd->nd_repstat)
9596ca35587Sdholland nfsrv_fillattr(nd, &nva);
9606ca35587Sdholland
9616ca35587Sdholland out:
9626ca35587Sdholland NFSEXITCODE2(0, nd);
9636ca35587Sdholland return (0);
9646ca35587Sdholland nfsmout:
9656ca35587Sdholland vput(vp);
9666ca35587Sdholland NFSEXITCODE2(error, nd);
9676ca35587Sdholland return (error);
9686ca35587Sdholland }
9696ca35587Sdholland
9706ca35587Sdholland /*
9716ca35587Sdholland * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
9726ca35587Sdholland * now does a truncate to 0 length via. setattr if it already exists
9736ca35587Sdholland * The core creation routine has been extracted out into nfsrv_creatsub(),
9746ca35587Sdholland * so it can also be used by nfsrv_open() for V4.
9756ca35587Sdholland */
9766ca35587Sdholland APPLESTATIC int
nfsrvd_create(struct nfsrv_descript * nd,__unused int isdgram,vnode_t dp,NFSPROC_T * p,struct nfsexstuff * exp)9776ca35587Sdholland nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
9786ca35587Sdholland vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
9796ca35587Sdholland {
9806ca35587Sdholland struct nfsvattr nva, dirfor, diraft;
9816ca35587Sdholland struct nfsv2_sattr *sp;
9826ca35587Sdholland struct nameidata named;
9836ca35587Sdholland u_int32_t *tl;
9846ca35587Sdholland int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
9856ca35587Sdholland int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
9866ca35587Sdholland NFSDEV_T rdev = 0;
9876ca35587Sdholland vnode_t vp = NULL, dirp = NULL;
9886ca35587Sdholland fhandle_t fh;
9896ca35587Sdholland char *bufp;
9906ca35587Sdholland u_long *hashp;
9916ca35587Sdholland enum vtype vtyp;
9926ca35587Sdholland int32_t cverf[2], tverf[2] = { 0, 0 };
9936ca35587Sdholland
9946ca35587Sdholland if (nd->nd_repstat) {
9956ca35587Sdholland nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
9966ca35587Sdholland goto out;
9976ca35587Sdholland }
9986ca35587Sdholland NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
9992d39560cSpgoyette LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
10006ca35587Sdholland nfsvno_setpathbuf(&named, &bufp, &hashp);
10016ca35587Sdholland error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
10026ca35587Sdholland if (error)
10036ca35587Sdholland goto nfsmout;
10046ca35587Sdholland if (!nd->nd_repstat) {
10056ca35587Sdholland NFSVNO_ATTRINIT(&nva);
10066ca35587Sdholland if (nd->nd_flag & ND_NFSV2) {
10076ca35587Sdholland NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
10086ca35587Sdholland vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
10096ca35587Sdholland if (vtyp == VNON)
10106ca35587Sdholland vtyp = VREG;
10116ca35587Sdholland NFSVNO_SETATTRVAL(&nva, type, vtyp);
10126ca35587Sdholland NFSVNO_SETATTRVAL(&nva, mode,
10136ca35587Sdholland nfstov_mode(sp->sa_mode));
10146ca35587Sdholland switch (nva.na_type) {
10156ca35587Sdholland case VREG:
10166ca35587Sdholland tsize = fxdr_unsigned(int32_t, sp->sa_size);
10176ca35587Sdholland if (tsize != -1)
10186ca35587Sdholland NFSVNO_SETATTRVAL(&nva, size,
10196ca35587Sdholland (u_quad_t)tsize);
10206ca35587Sdholland break;
10216ca35587Sdholland case VCHR:
10226ca35587Sdholland case VBLK:
10236ca35587Sdholland case VFIFO:
10246ca35587Sdholland rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
10256ca35587Sdholland break;
10266ca35587Sdholland default:
10276ca35587Sdholland break;
10282d39560cSpgoyette }
10296ca35587Sdholland } else {
10306ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
10316ca35587Sdholland how = fxdr_unsigned(int, *tl);
10326ca35587Sdholland switch (how) {
10336ca35587Sdholland case NFSCREATE_GUARDED:
10346ca35587Sdholland case NFSCREATE_UNCHECKED:
10352d39560cSpgoyette error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
10366ca35587Sdholland if (error)
10376ca35587Sdholland goto nfsmout;
10386ca35587Sdholland break;
10396ca35587Sdholland case NFSCREATE_EXCLUSIVE:
10406ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
10416ca35587Sdholland cverf[0] = *tl++;
10426ca35587Sdholland cverf[1] = *tl;
10436ca35587Sdholland exclusive_flag = 1;
10446ca35587Sdholland break;
10452d39560cSpgoyette }
10466ca35587Sdholland NFSVNO_SETATTRVAL(&nva, type, VREG);
10476ca35587Sdholland }
10486ca35587Sdholland }
10496ca35587Sdholland if (nd->nd_repstat) {
10506ca35587Sdholland nfsvno_relpathbuf(&named);
10516ca35587Sdholland if (nd->nd_flag & ND_NFSV3) {
10526ca35587Sdholland dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred,
10536ca35587Sdholland p, 1);
10546ca35587Sdholland nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
10556ca35587Sdholland &diraft);
10566ca35587Sdholland }
10576ca35587Sdholland vput(dp);
10586ca35587Sdholland goto out;
10596ca35587Sdholland }
10606ca35587Sdholland
10616ca35587Sdholland nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
10626ca35587Sdholland if (dirp) {
10636ca35587Sdholland if (nd->nd_flag & ND_NFSV2) {
10646ca35587Sdholland vrele(dirp);
10656ca35587Sdholland dirp = NULL;
10666ca35587Sdholland } else {
10676ca35587Sdholland dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
10686ca35587Sdholland p, 0);
10696ca35587Sdholland }
10706ca35587Sdholland }
10716ca35587Sdholland if (nd->nd_repstat) {
10726ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
10736ca35587Sdholland nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
10746ca35587Sdholland &diraft);
10756ca35587Sdholland if (dirp)
10766ca35587Sdholland vrele(dirp);
10776ca35587Sdholland goto out;
10786ca35587Sdholland }
10796ca35587Sdholland
10806ca35587Sdholland if (!(nd->nd_flag & ND_NFSV2)) {
10816ca35587Sdholland switch (how) {
10826ca35587Sdholland case NFSCREATE_GUARDED:
10836ca35587Sdholland if (named.ni_vp)
10846ca35587Sdholland nd->nd_repstat = EEXIST;
10856ca35587Sdholland break;
10866ca35587Sdholland case NFSCREATE_UNCHECKED:
10876ca35587Sdholland break;
10886ca35587Sdholland case NFSCREATE_EXCLUSIVE:
10896ca35587Sdholland if (named.ni_vp == NULL)
10906ca35587Sdholland NFSVNO_SETATTRVAL(&nva, mode, 0);
10916ca35587Sdholland break;
10922d39560cSpgoyette }
10936ca35587Sdholland }
10946ca35587Sdholland
10956ca35587Sdholland /*
10966ca35587Sdholland * Iff doesn't exist, create it
10976ca35587Sdholland * otherwise just truncate to 0 length
10986ca35587Sdholland * should I set the mode too ?
10996ca35587Sdholland */
11006ca35587Sdholland nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
11016ca35587Sdholland &exclusive_flag, cverf, rdev, p, exp);
11026ca35587Sdholland
11036ca35587Sdholland if (!nd->nd_repstat) {
11046ca35587Sdholland nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
11056ca35587Sdholland if (!nd->nd_repstat)
11066ca35587Sdholland nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
11076ca35587Sdholland p, 1);
11086ca35587Sdholland vput(vp);
11096ca35587Sdholland if (!nd->nd_repstat) {
11106ca35587Sdholland tverf[0] = nva.na_atime.tv_sec;
11116ca35587Sdholland tverf[1] = nva.na_atime.tv_nsec;
11126ca35587Sdholland }
11136ca35587Sdholland }
11146ca35587Sdholland if (nd->nd_flag & ND_NFSV2) {
11156ca35587Sdholland if (!nd->nd_repstat) {
11166ca35587Sdholland (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
11176ca35587Sdholland nfsrv_fillattr(nd, &nva);
11186ca35587Sdholland }
11196ca35587Sdholland } else {
11206ca35587Sdholland if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
11216ca35587Sdholland || cverf[1] != tverf[1]))
11226ca35587Sdholland nd->nd_repstat = EEXIST;
11236ca35587Sdholland diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
11246ca35587Sdholland vrele(dirp);
11256ca35587Sdholland if (!nd->nd_repstat) {
11266ca35587Sdholland (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
11276ca35587Sdholland nfsrv_postopattr(nd, 0, &nva);
11286ca35587Sdholland }
11296ca35587Sdholland nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
11306ca35587Sdholland }
11316ca35587Sdholland
11326ca35587Sdholland out:
11336ca35587Sdholland NFSEXITCODE2(0, nd);
11346ca35587Sdholland return (0);
11356ca35587Sdholland nfsmout:
11366ca35587Sdholland vput(dp);
11376ca35587Sdholland nfsvno_relpathbuf(&named);
11386ca35587Sdholland NFSEXITCODE2(error, nd);
11396ca35587Sdholland return (error);
11406ca35587Sdholland }
11416ca35587Sdholland
11426ca35587Sdholland /*
11436ca35587Sdholland * nfs v3 mknod service (and v4 create)
11446ca35587Sdholland */
11456ca35587Sdholland APPLESTATIC int
nfsrvd_mknod(struct nfsrv_descript * nd,__unused int isdgram,vnode_t dp,vnode_t * vpp,fhandle_t * fhp,NFSPROC_T * p,struct nfsexstuff * exp)11466ca35587Sdholland nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
11476ca35587Sdholland vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
11486ca35587Sdholland struct nfsexstuff *exp)
11496ca35587Sdholland {
11506ca35587Sdholland struct nfsvattr nva, dirfor, diraft;
11516ca35587Sdholland u_int32_t *tl;
11526ca35587Sdholland struct nameidata named;
11536ca35587Sdholland int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
11546ca35587Sdholland u_int32_t major, minor;
11556ca35587Sdholland enum vtype vtyp = VNON;
11566ca35587Sdholland nfstype nfs4type = NFNON;
11576ca35587Sdholland vnode_t vp, dirp = NULL;
11586ca35587Sdholland nfsattrbit_t attrbits;
11596ca35587Sdholland char *bufp = NULL, *pathcp = NULL;
11606ca35587Sdholland u_long *hashp, cnflags;
11616ca35587Sdholland NFSACL_T *aclp = NULL;
11626ca35587Sdholland
11636ca35587Sdholland NFSVNO_ATTRINIT(&nva);
11646ca35587Sdholland cnflags = (LOCKPARENT | SAVESTART);
11656ca35587Sdholland if (nd->nd_repstat) {
11666ca35587Sdholland nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
11676ca35587Sdholland goto out;
11686ca35587Sdholland }
11696ca35587Sdholland #ifdef NFS4_ACL_EXTATTR_NAME
11706ca35587Sdholland aclp = acl_alloc(M_WAITOK);
11716ca35587Sdholland aclp->acl_cnt = 0;
11726ca35587Sdholland #endif
11736ca35587Sdholland
11746ca35587Sdholland /*
11756ca35587Sdholland * For V4, the creation stuff is here, Yuck!
11766ca35587Sdholland */
11776ca35587Sdholland if (nd->nd_flag & ND_NFSV4) {
11786ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
11796ca35587Sdholland vtyp = nfsv34tov_type(*tl);
11806ca35587Sdholland nfs4type = fxdr_unsigned(nfstype, *tl);
11816ca35587Sdholland switch (nfs4type) {
11826ca35587Sdholland case NFLNK:
11836ca35587Sdholland error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
11846ca35587Sdholland &pathlen);
11856ca35587Sdholland if (error)
11866ca35587Sdholland goto nfsmout;
11876ca35587Sdholland break;
11886ca35587Sdholland case NFCHR:
11896ca35587Sdholland case NFBLK:
11906ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
11916ca35587Sdholland major = fxdr_unsigned(u_int32_t, *tl++);
11926ca35587Sdholland minor = fxdr_unsigned(u_int32_t, *tl);
11936ca35587Sdholland nva.na_rdev = NFSMAKEDEV(major, minor);
11946ca35587Sdholland break;
11956ca35587Sdholland case NFSOCK:
11966ca35587Sdholland case NFFIFO:
11976ca35587Sdholland break;
11986ca35587Sdholland case NFDIR:
11996ca35587Sdholland cnflags = (LOCKPARENT | SAVENAME);
12006ca35587Sdholland break;
12016ca35587Sdholland default:
12026ca35587Sdholland nd->nd_repstat = NFSERR_BADTYPE;
12036ca35587Sdholland vrele(dp);
12046ca35587Sdholland #ifdef NFS4_ACL_EXTATTR_NAME
12056ca35587Sdholland acl_free(aclp);
12066ca35587Sdholland #endif
12076ca35587Sdholland goto out;
12086ca35587Sdholland }
12096ca35587Sdholland }
12102d39560cSpgoyette NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE);
12116ca35587Sdholland nfsvno_setpathbuf(&named, &bufp, &hashp);
12126ca35587Sdholland error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
12136ca35587Sdholland if (error)
12146ca35587Sdholland goto nfsmout;
12156ca35587Sdholland if (!nd->nd_repstat) {
12166ca35587Sdholland if (nd->nd_flag & ND_NFSV3) {
12176ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
12186ca35587Sdholland vtyp = nfsv34tov_type(*tl);
12196ca35587Sdholland }
12202d39560cSpgoyette error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p);
12216ca35587Sdholland if (error)
12226ca35587Sdholland goto nfsmout;
12236ca35587Sdholland nva.na_type = vtyp;
12246ca35587Sdholland if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
12256ca35587Sdholland (vtyp == VCHR || vtyp == VBLK)) {
12266ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
12276ca35587Sdholland major = fxdr_unsigned(u_int32_t, *tl++);
12286ca35587Sdholland minor = fxdr_unsigned(u_int32_t, *tl);
12296ca35587Sdholland nva.na_rdev = NFSMAKEDEV(major, minor);
12306ca35587Sdholland }
12316ca35587Sdholland }
12326ca35587Sdholland
12336ca35587Sdholland dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
12346ca35587Sdholland if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
12356ca35587Sdholland if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
12366ca35587Sdholland dirfor.na_gid == nva.na_gid)
12376ca35587Sdholland NFSVNO_UNSET(&nva, gid);
12386ca35587Sdholland nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
12396ca35587Sdholland }
12406ca35587Sdholland if (nd->nd_repstat) {
12416ca35587Sdholland vrele(dp);
12426ca35587Sdholland #ifdef NFS4_ACL_EXTATTR_NAME
12436ca35587Sdholland acl_free(aclp);
12446ca35587Sdholland #endif
12456ca35587Sdholland nfsvno_relpathbuf(&named);
12466ca35587Sdholland if (pathcp)
12476ca35587Sdholland FREE(pathcp, M_TEMP);
12486ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
12496ca35587Sdholland nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
12506ca35587Sdholland &diraft);
12516ca35587Sdholland goto out;
12526ca35587Sdholland }
12536ca35587Sdholland
12546ca35587Sdholland /*
12556ca35587Sdholland * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
12566ca35587Sdholland * in va_mode, so we'll have to set a default here.
12576ca35587Sdholland */
12586ca35587Sdholland if (NFSVNO_NOTSETMODE(&nva)) {
12596ca35587Sdholland if (vtyp == VLNK)
12606ca35587Sdholland nva.na_mode = 0755;
12616ca35587Sdholland else
12626ca35587Sdholland nva.na_mode = 0400;
12636ca35587Sdholland }
12646ca35587Sdholland
12656ca35587Sdholland if (vtyp == VDIR)
12666ca35587Sdholland named.ni_cnd.cn_flags |= WILLBEDIR;
12676ca35587Sdholland nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
12686ca35587Sdholland if (nd->nd_repstat) {
12696ca35587Sdholland if (dirp) {
12706ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
12716ca35587Sdholland dirfor_ret = nfsvno_getattr(dirp, &dirfor,
12726ca35587Sdholland nd->nd_cred, p, 0);
12736ca35587Sdholland vrele(dirp);
12746ca35587Sdholland }
12756ca35587Sdholland #ifdef NFS4_ACL_EXTATTR_NAME
12766ca35587Sdholland acl_free(aclp);
12776ca35587Sdholland #endif
12786ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
12796ca35587Sdholland nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
12806ca35587Sdholland &diraft);
12816ca35587Sdholland goto out;
12826ca35587Sdholland }
12836ca35587Sdholland if (dirp)
12846ca35587Sdholland dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
12856ca35587Sdholland
12866ca35587Sdholland if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
12876ca35587Sdholland if (vtyp == VDIR) {
12886ca35587Sdholland nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
12896ca35587Sdholland &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
12906ca35587Sdholland exp);
12916ca35587Sdholland #ifdef NFS4_ACL_EXTATTR_NAME
12926ca35587Sdholland acl_free(aclp);
12936ca35587Sdholland #endif
12946ca35587Sdholland goto out;
12956ca35587Sdholland } else if (vtyp == VLNK) {
12966ca35587Sdholland nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
12976ca35587Sdholland &dirfor, &diraft, &diraft_ret, &attrbits,
12986ca35587Sdholland aclp, p, exp, pathcp, pathlen);
12996ca35587Sdholland #ifdef NFS4_ACL_EXTATTR_NAME
13006ca35587Sdholland acl_free(aclp);
13016ca35587Sdholland #endif
13026ca35587Sdholland FREE(pathcp, M_TEMP);
13036ca35587Sdholland goto out;
13046ca35587Sdholland }
13056ca35587Sdholland }
13066ca35587Sdholland
13076ca35587Sdholland nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
13086ca35587Sdholland if (!nd->nd_repstat) {
13096ca35587Sdholland vp = named.ni_vp;
13106ca35587Sdholland nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
13116ca35587Sdholland nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
13126ca35587Sdholland if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
13136ca35587Sdholland nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred,
13146ca35587Sdholland p, 1);
13156ca35587Sdholland if (vpp != NULL && nd->nd_repstat == 0) {
13166ca35587Sdholland NFSVOPUNLOCK(vp, 0);
13176ca35587Sdholland *vpp = vp;
13186ca35587Sdholland } else
13196ca35587Sdholland vput(vp);
13206ca35587Sdholland }
13216ca35587Sdholland
13226ca35587Sdholland diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
13236ca35587Sdholland vrele(dirp);
13246ca35587Sdholland if (!nd->nd_repstat) {
13256ca35587Sdholland if (nd->nd_flag & ND_NFSV3) {
13266ca35587Sdholland (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
13276ca35587Sdholland nfsrv_postopattr(nd, 0, &nva);
13286ca35587Sdholland } else {
13296ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
13306ca35587Sdholland *tl++ = newnfs_false;
13316ca35587Sdholland txdr_hyper(dirfor.na_filerev, tl);
13326ca35587Sdholland tl += 2;
13336ca35587Sdholland txdr_hyper(diraft.na_filerev, tl);
13346ca35587Sdholland (void) nfsrv_putattrbit(nd, &attrbits);
13356ca35587Sdholland }
13366ca35587Sdholland }
13376ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
13386ca35587Sdholland nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
13396ca35587Sdholland #ifdef NFS4_ACL_EXTATTR_NAME
13406ca35587Sdholland acl_free(aclp);
13416ca35587Sdholland #endif
13426ca35587Sdholland
13436ca35587Sdholland out:
13446ca35587Sdholland NFSEXITCODE2(0, nd);
13456ca35587Sdholland return (0);
13466ca35587Sdholland nfsmout:
13476ca35587Sdholland vrele(dp);
13486ca35587Sdholland #ifdef NFS4_ACL_EXTATTR_NAME
13496ca35587Sdholland acl_free(aclp);
13506ca35587Sdholland #endif
13516ca35587Sdholland if (bufp)
13526ca35587Sdholland nfsvno_relpathbuf(&named);
13536ca35587Sdholland if (pathcp)
13546ca35587Sdholland FREE(pathcp, M_TEMP);
13556ca35587Sdholland
13566ca35587Sdholland NFSEXITCODE2(error, nd);
13576ca35587Sdholland return (error);
13586ca35587Sdholland }
13596ca35587Sdholland
13606ca35587Sdholland /*
13616ca35587Sdholland * nfs remove service
13626ca35587Sdholland */
13636ca35587Sdholland APPLESTATIC int
nfsrvd_remove(struct nfsrv_descript * nd,__unused int isdgram,vnode_t dp,NFSPROC_T * p,struct nfsexstuff * exp)13646ca35587Sdholland nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
13656ca35587Sdholland vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
13666ca35587Sdholland {
13676ca35587Sdholland struct nameidata named;
13686ca35587Sdholland u_int32_t *tl;
13696ca35587Sdholland int error = 0, dirfor_ret = 1, diraft_ret = 1;
13706ca35587Sdholland vnode_t dirp = NULL;
13716ca35587Sdholland struct nfsvattr dirfor, diraft;
13726ca35587Sdholland char *bufp;
13736ca35587Sdholland u_long *hashp;
13746ca35587Sdholland
13756ca35587Sdholland if (nd->nd_repstat) {
13766ca35587Sdholland nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
13776ca35587Sdholland goto out;
13786ca35587Sdholland }
13796ca35587Sdholland NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
13806ca35587Sdholland LOCKPARENT | LOCKLEAF);
13816ca35587Sdholland nfsvno_setpathbuf(&named, &bufp, &hashp);
13826ca35587Sdholland error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
13836ca35587Sdholland if (error) {
13846ca35587Sdholland vput(dp);
13856ca35587Sdholland nfsvno_relpathbuf(&named);
13866ca35587Sdholland goto out;
13876ca35587Sdholland }
13886ca35587Sdholland if (!nd->nd_repstat) {
13896ca35587Sdholland nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
13906ca35587Sdholland } else {
13916ca35587Sdholland vput(dp);
13926ca35587Sdholland nfsvno_relpathbuf(&named);
13936ca35587Sdholland }
13946ca35587Sdholland if (dirp) {
13956ca35587Sdholland if (!(nd->nd_flag & ND_NFSV2)) {
13966ca35587Sdholland dirfor_ret = nfsvno_getattr(dirp, &dirfor,
13976ca35587Sdholland nd->nd_cred, p, 0);
13986ca35587Sdholland } else {
13996ca35587Sdholland vrele(dirp);
14006ca35587Sdholland dirp = NULL;
14016ca35587Sdholland }
14026ca35587Sdholland }
14036ca35587Sdholland if (!nd->nd_repstat) {
14046ca35587Sdholland if (nd->nd_flag & ND_NFSV4) {
14056ca35587Sdholland if (vnode_vtype(named.ni_vp) == VDIR)
14066ca35587Sdholland nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
14076ca35587Sdholland nd->nd_cred, p, exp);
14086ca35587Sdholland else
14096ca35587Sdholland nd->nd_repstat = nfsvno_removesub(&named, 1,
14106ca35587Sdholland nd->nd_cred, p, exp);
14116ca35587Sdholland } else if (nd->nd_procnum == NFSPROC_RMDIR) {
14126ca35587Sdholland nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
14136ca35587Sdholland nd->nd_cred, p, exp);
14146ca35587Sdholland } else {
14156ca35587Sdholland nd->nd_repstat = nfsvno_removesub(&named, 0,
14166ca35587Sdholland nd->nd_cred, p, exp);
14176ca35587Sdholland }
14186ca35587Sdholland }
14196ca35587Sdholland if (!(nd->nd_flag & ND_NFSV2)) {
14206ca35587Sdholland if (dirp) {
14216ca35587Sdholland diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred,
14226ca35587Sdholland p, 0);
14236ca35587Sdholland vrele(dirp);
14246ca35587Sdholland }
14256ca35587Sdholland if (nd->nd_flag & ND_NFSV3) {
14266ca35587Sdholland nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
14276ca35587Sdholland &diraft);
14286ca35587Sdholland } else if (!nd->nd_repstat) {
14296ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
14306ca35587Sdholland *tl++ = newnfs_false;
14316ca35587Sdholland txdr_hyper(dirfor.na_filerev, tl);
14326ca35587Sdholland tl += 2;
14336ca35587Sdholland txdr_hyper(diraft.na_filerev, tl);
14346ca35587Sdholland }
14356ca35587Sdholland }
14366ca35587Sdholland
14376ca35587Sdholland out:
14386ca35587Sdholland NFSEXITCODE2(error, nd);
14396ca35587Sdholland return (error);
14406ca35587Sdholland }
14416ca35587Sdholland
14426ca35587Sdholland /*
14436ca35587Sdholland * nfs rename service
14446ca35587Sdholland */
14456ca35587Sdholland APPLESTATIC int
nfsrvd_rename(struct nfsrv_descript * nd,int isdgram,vnode_t dp,vnode_t todp,NFSPROC_T * p,struct nfsexstuff * exp,struct nfsexstuff * toexp)14466ca35587Sdholland nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
14476ca35587Sdholland vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp,
14486ca35587Sdholland struct nfsexstuff *toexp)
14496ca35587Sdholland {
14506ca35587Sdholland u_int32_t *tl;
14516ca35587Sdholland int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
14526ca35587Sdholland int tdirfor_ret = 1, tdiraft_ret = 1;
14536ca35587Sdholland struct nameidata fromnd, tond;
14546ca35587Sdholland vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
14556ca35587Sdholland struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
14566ca35587Sdholland struct nfsexstuff tnes;
14576ca35587Sdholland struct nfsrvfh tfh;
14586ca35587Sdholland char *bufp, *tbufp = NULL;
14596ca35587Sdholland u_long *hashp;
14606ca35587Sdholland fhandle_t fh;
14616ca35587Sdholland
14626ca35587Sdholland if (nd->nd_repstat) {
14636ca35587Sdholland nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
14646ca35587Sdholland nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
14656ca35587Sdholland goto out;
14666ca35587Sdholland }
14676ca35587Sdholland if (!(nd->nd_flag & ND_NFSV2))
14686ca35587Sdholland fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1);
14696ca35587Sdholland tond.ni_cnd.cn_nameiop = 0;
14706ca35587Sdholland tond.ni_startdir = NULL;
14716ca35587Sdholland NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
14726ca35587Sdholland nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
14736ca35587Sdholland error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
14746ca35587Sdholland if (error) {
14756ca35587Sdholland vput(dp);
14766ca35587Sdholland if (todp)
14776ca35587Sdholland vrele(todp);
14786ca35587Sdholland nfsvno_relpathbuf(&fromnd);
14796ca35587Sdholland goto out;
14806ca35587Sdholland }
14812d39560cSpgoyette /*
14822d39560cSpgoyette * Unlock dp in this code section, so it is unlocked before
14832d39560cSpgoyette * tdp gets locked. This avoids a potential LOR if tdp is the
14842d39560cSpgoyette * parent directory of dp.
14852d39560cSpgoyette */
14866ca35587Sdholland if (nd->nd_flag & ND_NFSV4) {
14876ca35587Sdholland tdp = todp;
14886ca35587Sdholland tnes = *toexp;
14892d39560cSpgoyette if (dp != tdp) {
14902d39560cSpgoyette NFSVOPUNLOCK(dp, 0);
14912d39560cSpgoyette tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
14922d39560cSpgoyette p, 0); /* Might lock tdp. */
14932d39560cSpgoyette } else {
14942d39560cSpgoyette tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
14952d39560cSpgoyette p, 1);
14962d39560cSpgoyette NFSVOPUNLOCK(dp, 0);
14972d39560cSpgoyette }
14986ca35587Sdholland } else {
14996ca35587Sdholland tfh.nfsrvfh_len = 0;
15006ca35587Sdholland error = nfsrv_mtofh(nd, &tfh);
15016ca35587Sdholland if (error == 0)
15026ca35587Sdholland error = nfsvno_getfh(dp, &fh, p);
15036ca35587Sdholland if (error) {
15046ca35587Sdholland vput(dp);
15056ca35587Sdholland /* todp is always NULL except NFSv4 */
15066ca35587Sdholland nfsvno_relpathbuf(&fromnd);
15076ca35587Sdholland goto out;
15086ca35587Sdholland }
15096ca35587Sdholland
15106ca35587Sdholland /* If this is the same file handle, just VREF() the vnode. */
15116ca35587Sdholland if (tfh.nfsrvfh_len == NFSX_MYFH &&
15126ca35587Sdholland !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
15136ca35587Sdholland VREF(dp);
15146ca35587Sdholland tdp = dp;
15156ca35587Sdholland tnes = *exp;
15166ca35587Sdholland tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
15176ca35587Sdholland p, 1);
15182d39560cSpgoyette NFSVOPUNLOCK(dp, 0);
15196ca35587Sdholland } else {
15202d39560cSpgoyette NFSVOPUNLOCK(dp, 0);
15216ca35587Sdholland nd->nd_cred->cr_uid = nd->nd_saveduid;
15226ca35587Sdholland nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
15232d39560cSpgoyette 0, p); /* Locks tdp. */
15246ca35587Sdholland if (tdp) {
15256ca35587Sdholland tdirfor_ret = nfsvno_getattr(tdp, &tdirfor,
15266ca35587Sdholland nd->nd_cred, p, 1);
15276ca35587Sdholland NFSVOPUNLOCK(tdp, 0);
15286ca35587Sdholland }
15296ca35587Sdholland }
15306ca35587Sdholland }
15316ca35587Sdholland NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
15326ca35587Sdholland nfsvno_setpathbuf(&tond, &tbufp, &hashp);
15336ca35587Sdholland if (!nd->nd_repstat) {
15346ca35587Sdholland error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
15356ca35587Sdholland if (error) {
15366ca35587Sdholland if (tdp)
15376ca35587Sdholland vrele(tdp);
15382d39560cSpgoyette vrele(dp);
15396ca35587Sdholland nfsvno_relpathbuf(&fromnd);
15406ca35587Sdholland nfsvno_relpathbuf(&tond);
15416ca35587Sdholland goto out;
15426ca35587Sdholland }
15436ca35587Sdholland }
15446ca35587Sdholland if (nd->nd_repstat) {
15456ca35587Sdholland if (nd->nd_flag & ND_NFSV3) {
15466ca35587Sdholland nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
15476ca35587Sdholland &fdiraft);
15486ca35587Sdholland nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
15496ca35587Sdholland &tdiraft);
15506ca35587Sdholland }
15516ca35587Sdholland if (tdp)
15526ca35587Sdholland vrele(tdp);
15532d39560cSpgoyette vrele(dp);
15546ca35587Sdholland nfsvno_relpathbuf(&fromnd);
15556ca35587Sdholland nfsvno_relpathbuf(&tond);
15566ca35587Sdholland goto out;
15576ca35587Sdholland }
15586ca35587Sdholland
15596ca35587Sdholland /*
15606ca35587Sdholland * Done parsing, now down to business.
15616ca35587Sdholland */
15622d39560cSpgoyette nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
15636ca35587Sdholland if (nd->nd_repstat) {
15646ca35587Sdholland if (nd->nd_flag & ND_NFSV3) {
15656ca35587Sdholland nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
15666ca35587Sdholland &fdiraft);
15676ca35587Sdholland nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
15686ca35587Sdholland &tdiraft);
15696ca35587Sdholland }
15706ca35587Sdholland if (fdirp)
15716ca35587Sdholland vrele(fdirp);
15726ca35587Sdholland if (tdp)
15736ca35587Sdholland vrele(tdp);
15746ca35587Sdholland nfsvno_relpathbuf(&tond);
15756ca35587Sdholland goto out;
15766ca35587Sdholland }
15776ca35587Sdholland if (vnode_vtype(fromnd.ni_vp) == VDIR)
15786ca35587Sdholland tond.ni_cnd.cn_flags |= WILLBEDIR;
15796ca35587Sdholland nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
15806ca35587Sdholland nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
15816ca35587Sdholland nd->nd_flag, nd->nd_cred, p);
15826ca35587Sdholland if (fdirp)
15836ca35587Sdholland fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
15846ca35587Sdholland 0);
15856ca35587Sdholland if (tdirp)
15866ca35587Sdholland tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
15876ca35587Sdholland 0);
15886ca35587Sdholland if (fdirp)
15896ca35587Sdholland vrele(fdirp);
15906ca35587Sdholland if (tdirp)
15916ca35587Sdholland vrele(tdirp);
15926ca35587Sdholland if (nd->nd_flag & ND_NFSV3) {
15936ca35587Sdholland nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
15946ca35587Sdholland nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
15956ca35587Sdholland } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
15966ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
15976ca35587Sdholland *tl++ = newnfs_false;
15986ca35587Sdholland txdr_hyper(fdirfor.na_filerev, tl);
15996ca35587Sdholland tl += 2;
16006ca35587Sdholland txdr_hyper(fdiraft.na_filerev, tl);
16016ca35587Sdholland tl += 2;
16026ca35587Sdholland *tl++ = newnfs_false;
16036ca35587Sdholland txdr_hyper(tdirfor.na_filerev, tl);
16046ca35587Sdholland tl += 2;
16056ca35587Sdholland txdr_hyper(tdiraft.na_filerev, tl);
16066ca35587Sdholland }
16076ca35587Sdholland
16086ca35587Sdholland out:
16096ca35587Sdholland NFSEXITCODE2(error, nd);
16106ca35587Sdholland return (error);
16116ca35587Sdholland }
16126ca35587Sdholland
16136ca35587Sdholland /*
16146ca35587Sdholland * nfs link service
16156ca35587Sdholland */
16166ca35587Sdholland APPLESTATIC int
nfsrvd_link(struct nfsrv_descript * nd,int isdgram,vnode_t vp,vnode_t tovp,NFSPROC_T * p,struct nfsexstuff * exp,struct nfsexstuff * toexp)16176ca35587Sdholland nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
16186ca35587Sdholland vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
16196ca35587Sdholland struct nfsexstuff *toexp)
16206ca35587Sdholland {
16216ca35587Sdholland struct nameidata named;
16226ca35587Sdholland u_int32_t *tl;
16236ca35587Sdholland int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
16246ca35587Sdholland vnode_t dirp = NULL, dp = NULL;
16256ca35587Sdholland struct nfsvattr dirfor, diraft, at;
16266ca35587Sdholland struct nfsexstuff tnes;
16276ca35587Sdholland struct nfsrvfh dfh;
16286ca35587Sdholland char *bufp;
16296ca35587Sdholland u_long *hashp;
16306ca35587Sdholland
16316ca35587Sdholland if (nd->nd_repstat) {
16326ca35587Sdholland nfsrv_postopattr(nd, getret, &at);
16336ca35587Sdholland nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
16346ca35587Sdholland goto out;
16356ca35587Sdholland }
16366ca35587Sdholland NFSVOPUNLOCK(vp, 0);
16376ca35587Sdholland if (vnode_vtype(vp) == VDIR) {
16386ca35587Sdholland if (nd->nd_flag & ND_NFSV4)
16396ca35587Sdholland nd->nd_repstat = NFSERR_ISDIR;
16406ca35587Sdholland else
16416ca35587Sdholland nd->nd_repstat = NFSERR_INVAL;
16426ca35587Sdholland if (tovp)
16436ca35587Sdholland vrele(tovp);
16446ca35587Sdholland }
16456ca35587Sdholland if (!nd->nd_repstat) {
16466ca35587Sdholland if (nd->nd_flag & ND_NFSV4) {
16476ca35587Sdholland dp = tovp;
16486ca35587Sdholland tnes = *toexp;
16496ca35587Sdholland } else {
16506ca35587Sdholland error = nfsrv_mtofh(nd, &dfh);
16516ca35587Sdholland if (error) {
16526ca35587Sdholland vrele(vp);
16536ca35587Sdholland /* tovp is always NULL unless NFSv4 */
16546ca35587Sdholland goto out;
16556ca35587Sdholland }
16566ca35587Sdholland nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0,
16576ca35587Sdholland p);
16586ca35587Sdholland if (dp)
16596ca35587Sdholland NFSVOPUNLOCK(dp, 0);
16606ca35587Sdholland }
16616ca35587Sdholland }
16626ca35587Sdholland NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
16632d39560cSpgoyette LOCKPARENT | SAVENAME | NOCACHE);
16646ca35587Sdholland if (!nd->nd_repstat) {
16656ca35587Sdholland nfsvno_setpathbuf(&named, &bufp, &hashp);
16666ca35587Sdholland error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
16676ca35587Sdholland if (error) {
16686ca35587Sdholland vrele(vp);
16696ca35587Sdholland if (dp)
16706ca35587Sdholland vrele(dp);
16716ca35587Sdholland nfsvno_relpathbuf(&named);
16726ca35587Sdholland goto out;
16736ca35587Sdholland }
16746ca35587Sdholland if (!nd->nd_repstat) {
16756ca35587Sdholland nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
16766ca35587Sdholland p, &dirp);
16776ca35587Sdholland } else {
16786ca35587Sdholland if (dp)
16796ca35587Sdholland vrele(dp);
16806ca35587Sdholland nfsvno_relpathbuf(&named);
16816ca35587Sdholland }
16826ca35587Sdholland }
16836ca35587Sdholland if (dirp) {
16846ca35587Sdholland if (nd->nd_flag & ND_NFSV2) {
16856ca35587Sdholland vrele(dirp);
16866ca35587Sdholland dirp = NULL;
16876ca35587Sdholland } else {
16886ca35587Sdholland dirfor_ret = nfsvno_getattr(dirp, &dirfor,
16896ca35587Sdholland nd->nd_cred, p, 0);
16906ca35587Sdholland }
16916ca35587Sdholland }
16926ca35587Sdholland if (!nd->nd_repstat)
16936ca35587Sdholland nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
16946ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
16956ca35587Sdholland getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
16966ca35587Sdholland if (dirp) {
16976ca35587Sdholland diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
16986ca35587Sdholland vrele(dirp);
16996ca35587Sdholland }
17006ca35587Sdholland vrele(vp);
17016ca35587Sdholland if (nd->nd_flag & ND_NFSV3) {
17026ca35587Sdholland nfsrv_postopattr(nd, getret, &at);
17036ca35587Sdholland nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
17046ca35587Sdholland } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
17056ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
17066ca35587Sdholland *tl++ = newnfs_false;
17076ca35587Sdholland txdr_hyper(dirfor.na_filerev, tl);
17086ca35587Sdholland tl += 2;
17096ca35587Sdholland txdr_hyper(diraft.na_filerev, tl);
17106ca35587Sdholland }
17116ca35587Sdholland
17126ca35587Sdholland out:
17136ca35587Sdholland NFSEXITCODE2(error, nd);
17146ca35587Sdholland return (error);
17156ca35587Sdholland }
17166ca35587Sdholland
17176ca35587Sdholland /*
17186ca35587Sdholland * nfs symbolic link service
17196ca35587Sdholland */
17206ca35587Sdholland APPLESTATIC int
nfsrvd_symlink(struct nfsrv_descript * nd,__unused int isdgram,vnode_t dp,vnode_t * vpp,fhandle_t * fhp,NFSPROC_T * p,struct nfsexstuff * exp)17216ca35587Sdholland nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
17226ca35587Sdholland vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
17236ca35587Sdholland struct nfsexstuff *exp)
17246ca35587Sdholland {
17256ca35587Sdholland struct nfsvattr nva, dirfor, diraft;
17266ca35587Sdholland struct nameidata named;
17276ca35587Sdholland int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
17286ca35587Sdholland vnode_t dirp = NULL;
17296ca35587Sdholland char *bufp, *pathcp = NULL;
17306ca35587Sdholland u_long *hashp;
17316ca35587Sdholland
17326ca35587Sdholland if (nd->nd_repstat) {
17336ca35587Sdholland nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
17346ca35587Sdholland goto out;
17356ca35587Sdholland }
17366ca35587Sdholland if (vpp)
17376ca35587Sdholland *vpp = NULL;
17386ca35587Sdholland NFSVNO_ATTRINIT(&nva);
17396ca35587Sdholland NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
17402d39560cSpgoyette LOCKPARENT | SAVESTART | NOCACHE);
17416ca35587Sdholland nfsvno_setpathbuf(&named, &bufp, &hashp);
17426ca35587Sdholland error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
17436ca35587Sdholland if (!error && !nd->nd_repstat)
17446ca35587Sdholland error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
17456ca35587Sdholland if (error) {
17466ca35587Sdholland vrele(dp);
17476ca35587Sdholland nfsvno_relpathbuf(&named);
17486ca35587Sdholland goto out;
17496ca35587Sdholland }
17506ca35587Sdholland if (!nd->nd_repstat) {
17516ca35587Sdholland nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
17526ca35587Sdholland } else {
17536ca35587Sdholland vrele(dp);
17546ca35587Sdholland nfsvno_relpathbuf(&named);
17556ca35587Sdholland }
17566ca35587Sdholland if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
17576ca35587Sdholland vrele(dirp);
17586ca35587Sdholland dirp = NULL;
17596ca35587Sdholland }
17606ca35587Sdholland
17616ca35587Sdholland /*
17626ca35587Sdholland * And call nfsrvd_symlinksub() to do the common code. It will
17636ca35587Sdholland * return EBADRPC upon a parsing error, 0 otherwise.
17646ca35587Sdholland */
17656ca35587Sdholland if (!nd->nd_repstat) {
17666ca35587Sdholland if (dirp != NULL)
17676ca35587Sdholland dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
17686ca35587Sdholland p, 0);
17696ca35587Sdholland nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
17706ca35587Sdholland &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
17716ca35587Sdholland pathcp, pathlen);
17726ca35587Sdholland } else if (dirp != NULL) {
17736ca35587Sdholland dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
17746ca35587Sdholland vrele(dirp);
17756ca35587Sdholland }
17766ca35587Sdholland if (pathcp)
17776ca35587Sdholland FREE(pathcp, M_TEMP);
17786ca35587Sdholland
17796ca35587Sdholland if (nd->nd_flag & ND_NFSV3) {
17806ca35587Sdholland if (!nd->nd_repstat) {
17816ca35587Sdholland (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
17826ca35587Sdholland nfsrv_postopattr(nd, 0, &nva);
17836ca35587Sdholland }
17846ca35587Sdholland nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
17856ca35587Sdholland }
17866ca35587Sdholland
17876ca35587Sdholland out:
17886ca35587Sdholland NFSEXITCODE2(error, nd);
17896ca35587Sdholland return (error);
17906ca35587Sdholland }
17916ca35587Sdholland
17926ca35587Sdholland /*
17936ca35587Sdholland * Common code for creating a symbolic link.
17946ca35587Sdholland */
17956ca35587Sdholland static void
nfsrvd_symlinksub(struct nfsrv_descript * nd,struct nameidata * ndp,struct nfsvattr * nvap,fhandle_t * fhp,vnode_t * vpp,vnode_t dirp,struct nfsvattr * dirforp,struct nfsvattr * diraftp,int * diraft_retp,nfsattrbit_t * attrbitp,NFSACL_T * aclp,NFSPROC_T * p,struct nfsexstuff * exp,char * pathcp,int pathlen)17966ca35587Sdholland nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
17976ca35587Sdholland struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
17986ca35587Sdholland vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
17996ca35587Sdholland int *diraft_retp, nfsattrbit_t *attrbitp,
18006ca35587Sdholland NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
18016ca35587Sdholland int pathlen)
18026ca35587Sdholland {
18036ca35587Sdholland u_int32_t *tl;
18046ca35587Sdholland
18056ca35587Sdholland nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
18066ca35587Sdholland !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
18076ca35587Sdholland if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
18086ca35587Sdholland nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
18096ca35587Sdholland if (nd->nd_flag & ND_NFSV3) {
18106ca35587Sdholland nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
18116ca35587Sdholland if (!nd->nd_repstat)
18126ca35587Sdholland nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
18136ca35587Sdholland nvap, nd->nd_cred, p, 1);
18146ca35587Sdholland }
18156ca35587Sdholland if (vpp != NULL && nd->nd_repstat == 0) {
18166ca35587Sdholland NFSVOPUNLOCK(ndp->ni_vp, 0);
18176ca35587Sdholland *vpp = ndp->ni_vp;
18186ca35587Sdholland } else
18196ca35587Sdholland vput(ndp->ni_vp);
18206ca35587Sdholland }
18216ca35587Sdholland if (dirp) {
18226ca35587Sdholland *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
18236ca35587Sdholland vrele(dirp);
18246ca35587Sdholland }
18256ca35587Sdholland if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
18266ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
18276ca35587Sdholland *tl++ = newnfs_false;
18286ca35587Sdholland txdr_hyper(dirforp->na_filerev, tl);
18296ca35587Sdholland tl += 2;
18306ca35587Sdholland txdr_hyper(diraftp->na_filerev, tl);
18316ca35587Sdholland (void) nfsrv_putattrbit(nd, attrbitp);
18326ca35587Sdholland }
18336ca35587Sdholland
18346ca35587Sdholland NFSEXITCODE2(0, nd);
18356ca35587Sdholland }
18366ca35587Sdholland
18376ca35587Sdholland /*
18386ca35587Sdholland * nfs mkdir service
18396ca35587Sdholland */
18406ca35587Sdholland APPLESTATIC int
nfsrvd_mkdir(struct nfsrv_descript * nd,__unused int isdgram,vnode_t dp,vnode_t * vpp,fhandle_t * fhp,NFSPROC_T * p,struct nfsexstuff * exp)18416ca35587Sdholland nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
18426ca35587Sdholland vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
18436ca35587Sdholland struct nfsexstuff *exp)
18446ca35587Sdholland {
18456ca35587Sdholland struct nfsvattr nva, dirfor, diraft;
18466ca35587Sdholland struct nameidata named;
18476ca35587Sdholland u_int32_t *tl;
18486ca35587Sdholland int error = 0, dirfor_ret = 1, diraft_ret = 1;
18496ca35587Sdholland vnode_t dirp = NULL;
18506ca35587Sdholland char *bufp;
18516ca35587Sdholland u_long *hashp;
18526ca35587Sdholland
18536ca35587Sdholland if (nd->nd_repstat) {
18546ca35587Sdholland nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
18556ca35587Sdholland goto out;
18566ca35587Sdholland }
18576ca35587Sdholland NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
18582d39560cSpgoyette LOCKPARENT | SAVENAME | NOCACHE);
18596ca35587Sdholland nfsvno_setpathbuf(&named, &bufp, &hashp);
18606ca35587Sdholland error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
18616ca35587Sdholland if (error)
18626ca35587Sdholland goto nfsmout;
18636ca35587Sdholland if (!nd->nd_repstat) {
18646ca35587Sdholland NFSVNO_ATTRINIT(&nva);
18656ca35587Sdholland if (nd->nd_flag & ND_NFSV3) {
18662d39560cSpgoyette error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
18676ca35587Sdholland if (error)
18686ca35587Sdholland goto nfsmout;
18696ca35587Sdholland } else {
18706ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
18716ca35587Sdholland nva.na_mode = nfstov_mode(*tl++);
18726ca35587Sdholland }
18736ca35587Sdholland }
18746ca35587Sdholland if (!nd->nd_repstat) {
18756ca35587Sdholland nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
18766ca35587Sdholland } else {
18776ca35587Sdholland vrele(dp);
18786ca35587Sdholland nfsvno_relpathbuf(&named);
18796ca35587Sdholland }
18806ca35587Sdholland if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
18816ca35587Sdholland vrele(dirp);
18826ca35587Sdholland dirp = NULL;
18836ca35587Sdholland }
18846ca35587Sdholland if (nd->nd_repstat) {
18856ca35587Sdholland if (dirp != NULL) {
18866ca35587Sdholland dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
18876ca35587Sdholland p, 0);
18886ca35587Sdholland vrele(dirp);
18896ca35587Sdholland }
18906ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
18916ca35587Sdholland nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
18926ca35587Sdholland &diraft);
18936ca35587Sdholland goto out;
18946ca35587Sdholland }
18956ca35587Sdholland if (dirp != NULL)
18966ca35587Sdholland dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
18976ca35587Sdholland
18986ca35587Sdholland /*
18996ca35587Sdholland * Call nfsrvd_mkdirsub() for the code common to V4 as well.
19006ca35587Sdholland */
19016ca35587Sdholland nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
19026ca35587Sdholland &diraft_ret, NULL, NULL, p, exp);
19036ca35587Sdholland
19046ca35587Sdholland if (nd->nd_flag & ND_NFSV3) {
19056ca35587Sdholland if (!nd->nd_repstat) {
19066ca35587Sdholland (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
19076ca35587Sdholland nfsrv_postopattr(nd, 0, &nva);
19086ca35587Sdholland }
19096ca35587Sdholland nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
19106ca35587Sdholland } else if (!nd->nd_repstat) {
19116ca35587Sdholland (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
19126ca35587Sdholland nfsrv_fillattr(nd, &nva);
19136ca35587Sdholland }
19146ca35587Sdholland
19156ca35587Sdholland out:
19166ca35587Sdholland NFSEXITCODE2(0, nd);
19176ca35587Sdholland return (0);
19186ca35587Sdholland nfsmout:
19196ca35587Sdholland vrele(dp);
19206ca35587Sdholland nfsvno_relpathbuf(&named);
19216ca35587Sdholland NFSEXITCODE2(error, nd);
19226ca35587Sdholland return (error);
19236ca35587Sdholland }
19246ca35587Sdholland
19256ca35587Sdholland /*
19266ca35587Sdholland * Code common to mkdir for V2,3 and 4.
19276ca35587Sdholland */
19286ca35587Sdholland static void
nfsrvd_mkdirsub(struct nfsrv_descript * nd,struct nameidata * ndp,struct nfsvattr * nvap,fhandle_t * fhp,vnode_t * vpp,vnode_t dirp,struct nfsvattr * dirforp,struct nfsvattr * diraftp,int * diraft_retp,nfsattrbit_t * attrbitp,NFSACL_T * aclp,NFSPROC_T * p,struct nfsexstuff * exp)19296ca35587Sdholland nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
19306ca35587Sdholland struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
19316ca35587Sdholland vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
19326ca35587Sdholland int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
19336ca35587Sdholland NFSPROC_T *p, struct nfsexstuff *exp)
19346ca35587Sdholland {
19356ca35587Sdholland vnode_t vp;
19366ca35587Sdholland u_int32_t *tl;
19376ca35587Sdholland
19386ca35587Sdholland NFSVNO_SETATTRVAL(nvap, type, VDIR);
19396ca35587Sdholland nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
19406ca35587Sdholland nd->nd_cred, p, exp);
19416ca35587Sdholland if (!nd->nd_repstat) {
19426ca35587Sdholland vp = ndp->ni_vp;
19436ca35587Sdholland nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
19446ca35587Sdholland nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
19456ca35587Sdholland if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
19466ca35587Sdholland nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
19476ca35587Sdholland p, 1);
19486ca35587Sdholland if (vpp && !nd->nd_repstat) {
19496ca35587Sdholland NFSVOPUNLOCK(vp, 0);
19506ca35587Sdholland *vpp = vp;
19516ca35587Sdholland } else {
19526ca35587Sdholland vput(vp);
19536ca35587Sdholland }
19546ca35587Sdholland }
19556ca35587Sdholland if (dirp) {
19566ca35587Sdholland *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
19576ca35587Sdholland vrele(dirp);
19586ca35587Sdholland }
19596ca35587Sdholland if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
19606ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
19616ca35587Sdholland *tl++ = newnfs_false;
19626ca35587Sdholland txdr_hyper(dirforp->na_filerev, tl);
19636ca35587Sdholland tl += 2;
19646ca35587Sdholland txdr_hyper(diraftp->na_filerev, tl);
19656ca35587Sdholland (void) nfsrv_putattrbit(nd, attrbitp);
19666ca35587Sdholland }
19676ca35587Sdholland
19686ca35587Sdholland NFSEXITCODE2(0, nd);
19696ca35587Sdholland }
19706ca35587Sdholland
19716ca35587Sdholland /*
19726ca35587Sdholland * nfs commit service
19736ca35587Sdholland */
19746ca35587Sdholland APPLESTATIC int
nfsrvd_commit(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,NFSPROC_T * p,__unused struct nfsexstuff * exp)19756ca35587Sdholland nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
19766ca35587Sdholland vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
19776ca35587Sdholland {
19786ca35587Sdholland struct nfsvattr bfor, aft;
19796ca35587Sdholland u_int32_t *tl;
19806ca35587Sdholland int error = 0, for_ret = 1, aft_ret = 1, cnt;
19816ca35587Sdholland u_int64_t off;
19826ca35587Sdholland
19836ca35587Sdholland if (nd->nd_repstat) {
19846ca35587Sdholland nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
19856ca35587Sdholland goto out;
19866ca35587Sdholland }
19872d39560cSpgoyette
19882d39560cSpgoyette /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */
19892d39560cSpgoyette if (vp->v_type != VREG) {
19902d39560cSpgoyette if (nd->nd_flag & ND_NFSV3)
19912d39560cSpgoyette error = NFSERR_NOTSUPP;
19922d39560cSpgoyette else
19932d39560cSpgoyette error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL;
19942d39560cSpgoyette goto nfsmout;
19952d39560cSpgoyette }
19966ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
19972d39560cSpgoyette
19986ca35587Sdholland /*
19996ca35587Sdholland * XXX At this time VOP_FSYNC() does not accept offset and byte
20006ca35587Sdholland * count parameters, so these arguments are useless (someday maybe).
20016ca35587Sdholland */
20026ca35587Sdholland off = fxdr_hyper(tl);
20036ca35587Sdholland tl += 2;
20046ca35587Sdholland cnt = fxdr_unsigned(int, *tl);
20056ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
20066ca35587Sdholland for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
20076ca35587Sdholland nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
20086ca35587Sdholland if (nd->nd_flag & ND_NFSV3) {
20096ca35587Sdholland aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
20106ca35587Sdholland nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
20116ca35587Sdholland }
20126ca35587Sdholland vput(vp);
20136ca35587Sdholland if (!nd->nd_repstat) {
20146ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
20156ca35587Sdholland *tl++ = txdr_unsigned(nfsboottime.tv_sec);
20166ca35587Sdholland *tl = txdr_unsigned(nfsboottime.tv_usec);
20176ca35587Sdholland }
20186ca35587Sdholland
20196ca35587Sdholland out:
20206ca35587Sdholland NFSEXITCODE2(0, nd);
20216ca35587Sdholland return (0);
20226ca35587Sdholland nfsmout:
20236ca35587Sdholland vput(vp);
20246ca35587Sdholland NFSEXITCODE2(error, nd);
20256ca35587Sdholland return (error);
20266ca35587Sdholland }
20276ca35587Sdholland
20286ca35587Sdholland /*
20296ca35587Sdholland * nfs statfs service
20306ca35587Sdholland */
20316ca35587Sdholland APPLESTATIC int
nfsrvd_statfs(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,NFSPROC_T * p,__unused struct nfsexstuff * exp)20326ca35587Sdholland nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
20336ca35587Sdholland vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
20346ca35587Sdholland {
20356ca35587Sdholland struct statfs *sf;
20366ca35587Sdholland u_int32_t *tl;
20376ca35587Sdholland int getret = 1;
20386ca35587Sdholland struct nfsvattr at;
20396ca35587Sdholland struct statfs sfs;
20406ca35587Sdholland u_quad_t tval;
20416ca35587Sdholland
20426ca35587Sdholland if (nd->nd_repstat) {
20436ca35587Sdholland nfsrv_postopattr(nd, getret, &at);
20446ca35587Sdholland goto out;
20456ca35587Sdholland }
20466ca35587Sdholland sf = &sfs;
20476ca35587Sdholland nd->nd_repstat = nfsvno_statfs(vp, sf);
20486ca35587Sdholland getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
20496ca35587Sdholland vput(vp);
20506ca35587Sdholland if (nd->nd_flag & ND_NFSV3)
20516ca35587Sdholland nfsrv_postopattr(nd, getret, &at);
20526ca35587Sdholland if (nd->nd_repstat)
20536ca35587Sdholland goto out;
20546ca35587Sdholland if (nd->nd_flag & ND_NFSV2) {
20556ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
20566ca35587Sdholland *tl++ = txdr_unsigned(NFS_V2MAXDATA);
20576ca35587Sdholland *tl++ = txdr_unsigned(sf->f_bsize);
20586ca35587Sdholland *tl++ = txdr_unsigned(sf->f_blocks);
20596ca35587Sdholland *tl++ = txdr_unsigned(sf->f_bfree);
20606ca35587Sdholland *tl = txdr_unsigned(sf->f_bavail);
20616ca35587Sdholland } else {
20626ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
20636ca35587Sdholland tval = (u_quad_t)sf->f_blocks;
20646ca35587Sdholland tval *= (u_quad_t)sf->f_bsize;
20656ca35587Sdholland txdr_hyper(tval, tl); tl += 2;
20666ca35587Sdholland tval = (u_quad_t)sf->f_bfree;
20676ca35587Sdholland tval *= (u_quad_t)sf->f_bsize;
20686ca35587Sdholland txdr_hyper(tval, tl); tl += 2;
20696ca35587Sdholland tval = (u_quad_t)sf->f_bavail;
20706ca35587Sdholland tval *= (u_quad_t)sf->f_bsize;
20716ca35587Sdholland txdr_hyper(tval, tl); tl += 2;
20726ca35587Sdholland tval = (u_quad_t)sf->f_files;
20736ca35587Sdholland txdr_hyper(tval, tl); tl += 2;
20746ca35587Sdholland tval = (u_quad_t)sf->f_ffree;
20756ca35587Sdholland txdr_hyper(tval, tl); tl += 2;
20766ca35587Sdholland tval = (u_quad_t)sf->f_ffree;
20776ca35587Sdholland txdr_hyper(tval, tl); tl += 2;
20786ca35587Sdholland *tl = 0;
20796ca35587Sdholland }
20806ca35587Sdholland
20816ca35587Sdholland out:
20826ca35587Sdholland NFSEXITCODE2(0, nd);
20836ca35587Sdholland return (0);
20846ca35587Sdholland }
20856ca35587Sdholland
20866ca35587Sdholland /*
20876ca35587Sdholland * nfs fsinfo service
20886ca35587Sdholland */
20896ca35587Sdholland APPLESTATIC int
nfsrvd_fsinfo(struct nfsrv_descript * nd,int isdgram,vnode_t vp,NFSPROC_T * p,__unused struct nfsexstuff * exp)20906ca35587Sdholland nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
20916ca35587Sdholland vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
20926ca35587Sdholland {
20936ca35587Sdholland u_int32_t *tl;
20946ca35587Sdholland struct nfsfsinfo fs;
20956ca35587Sdholland int getret = 1;
20966ca35587Sdholland struct nfsvattr at;
20976ca35587Sdholland
20986ca35587Sdholland if (nd->nd_repstat) {
20996ca35587Sdholland nfsrv_postopattr(nd, getret, &at);
21006ca35587Sdholland goto out;
21016ca35587Sdholland }
21026ca35587Sdholland getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
21036ca35587Sdholland nfsvno_getfs(&fs, isdgram);
21046ca35587Sdholland vput(vp);
21056ca35587Sdholland nfsrv_postopattr(nd, getret, &at);
21066ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
21076ca35587Sdholland *tl++ = txdr_unsigned(fs.fs_rtmax);
21086ca35587Sdholland *tl++ = txdr_unsigned(fs.fs_rtpref);
21096ca35587Sdholland *tl++ = txdr_unsigned(fs.fs_rtmult);
21106ca35587Sdholland *tl++ = txdr_unsigned(fs.fs_wtmax);
21116ca35587Sdholland *tl++ = txdr_unsigned(fs.fs_wtpref);
21126ca35587Sdholland *tl++ = txdr_unsigned(fs.fs_wtmult);
21136ca35587Sdholland *tl++ = txdr_unsigned(fs.fs_dtpref);
21146ca35587Sdholland txdr_hyper(fs.fs_maxfilesize, tl);
21156ca35587Sdholland tl += 2;
21166ca35587Sdholland txdr_nfsv3time(&fs.fs_timedelta, tl);
21176ca35587Sdholland tl += 2;
21186ca35587Sdholland *tl = txdr_unsigned(fs.fs_properties);
21196ca35587Sdholland
21206ca35587Sdholland out:
21216ca35587Sdholland NFSEXITCODE2(0, nd);
21226ca35587Sdholland return (0);
21236ca35587Sdholland }
21246ca35587Sdholland
21256ca35587Sdholland /*
21266ca35587Sdholland * nfs pathconf service
21276ca35587Sdholland */
21286ca35587Sdholland APPLESTATIC int
nfsrvd_pathconf(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,NFSPROC_T * p,__unused struct nfsexstuff * exp)21296ca35587Sdholland nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
21306ca35587Sdholland vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
21316ca35587Sdholland {
21326ca35587Sdholland struct nfsv3_pathconf *pc;
21336ca35587Sdholland int getret = 1;
21346ca35587Sdholland register_t linkmax, namemax, chownres, notrunc;
21356ca35587Sdholland struct nfsvattr at;
21366ca35587Sdholland
21376ca35587Sdholland if (nd->nd_repstat) {
21386ca35587Sdholland nfsrv_postopattr(nd, getret, &at);
21396ca35587Sdholland goto out;
21406ca35587Sdholland }
21416ca35587Sdholland nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
21426ca35587Sdholland nd->nd_cred, p);
21436ca35587Sdholland if (!nd->nd_repstat)
21446ca35587Sdholland nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
21456ca35587Sdholland nd->nd_cred, p);
21466ca35587Sdholland if (!nd->nd_repstat)
21476ca35587Sdholland nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
21486ca35587Sdholland &chownres, nd->nd_cred, p);
21496ca35587Sdholland if (!nd->nd_repstat)
21506ca35587Sdholland nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
21516ca35587Sdholland nd->nd_cred, p);
21526ca35587Sdholland getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
21536ca35587Sdholland vput(vp);
21546ca35587Sdholland nfsrv_postopattr(nd, getret, &at);
21556ca35587Sdholland if (!nd->nd_repstat) {
21566ca35587Sdholland NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
21576ca35587Sdholland pc->pc_linkmax = txdr_unsigned(linkmax);
21586ca35587Sdholland pc->pc_namemax = txdr_unsigned(namemax);
21596ca35587Sdholland pc->pc_notrunc = txdr_unsigned(notrunc);
21606ca35587Sdholland pc->pc_chownrestricted = txdr_unsigned(chownres);
21616ca35587Sdholland
21626ca35587Sdholland /*
21636ca35587Sdholland * These should probably be supported by VOP_PATHCONF(), but
21646ca35587Sdholland * until msdosfs is exportable (why would you want to?), the
21656ca35587Sdholland * Unix defaults should be ok.
21666ca35587Sdholland */
21676ca35587Sdholland pc->pc_caseinsensitive = newnfs_false;
21686ca35587Sdholland pc->pc_casepreserving = newnfs_true;
21696ca35587Sdholland }
21706ca35587Sdholland
21716ca35587Sdholland out:
21726ca35587Sdholland NFSEXITCODE2(0, nd);
21736ca35587Sdholland return (0);
21746ca35587Sdholland }
21756ca35587Sdholland
21766ca35587Sdholland /*
21776ca35587Sdholland * nfsv4 lock service
21786ca35587Sdholland */
21796ca35587Sdholland APPLESTATIC int
nfsrvd_lock(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,NFSPROC_T * p,struct nfsexstuff * exp)21806ca35587Sdholland nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
21816ca35587Sdholland vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
21826ca35587Sdholland {
21836ca35587Sdholland u_int32_t *tl;
21846ca35587Sdholland int i;
21856ca35587Sdholland struct nfsstate *stp = NULL;
21866ca35587Sdholland struct nfslock *lop;
21876ca35587Sdholland struct nfslockconflict cf;
21886ca35587Sdholland int error = 0;
21896ca35587Sdholland u_short flags = NFSLCK_LOCK, lflags;
21906ca35587Sdholland u_int64_t offset, len;
21916ca35587Sdholland nfsv4stateid_t stateid;
21926ca35587Sdholland nfsquad_t clientid;
21936ca35587Sdholland
21946ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
21956ca35587Sdholland i = fxdr_unsigned(int, *tl++);
21966ca35587Sdholland switch (i) {
21976ca35587Sdholland case NFSV4LOCKT_READW:
21986ca35587Sdholland flags |= NFSLCK_BLOCKING;
21996ca35587Sdholland case NFSV4LOCKT_READ:
22006ca35587Sdholland lflags = NFSLCK_READ;
22016ca35587Sdholland break;
22026ca35587Sdholland case NFSV4LOCKT_WRITEW:
22036ca35587Sdholland flags |= NFSLCK_BLOCKING;
22046ca35587Sdholland case NFSV4LOCKT_WRITE:
22056ca35587Sdholland lflags = NFSLCK_WRITE;
22066ca35587Sdholland break;
22076ca35587Sdholland default:
22086ca35587Sdholland nd->nd_repstat = NFSERR_BADXDR;
22096ca35587Sdholland goto nfsmout;
22102d39560cSpgoyette }
22116ca35587Sdholland if (*tl++ == newnfs_true)
22126ca35587Sdholland flags |= NFSLCK_RECLAIM;
22136ca35587Sdholland offset = fxdr_hyper(tl);
22146ca35587Sdholland tl += 2;
22156ca35587Sdholland len = fxdr_hyper(tl);
22166ca35587Sdholland tl += 2;
22176ca35587Sdholland if (*tl == newnfs_true)
22186ca35587Sdholland flags |= NFSLCK_OPENTOLOCK;
22196ca35587Sdholland if (flags & NFSLCK_OPENTOLOCK) {
22206ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
22216ca35587Sdholland i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
22226ca35587Sdholland if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
22236ca35587Sdholland nd->nd_repstat = NFSERR_BADXDR;
22246ca35587Sdholland goto nfsmout;
22256ca35587Sdholland }
22266ca35587Sdholland MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
22276ca35587Sdholland M_NFSDSTATE, M_WAITOK);
22286ca35587Sdholland stp->ls_ownerlen = i;
22296ca35587Sdholland stp->ls_op = nd->nd_rp;
22306ca35587Sdholland stp->ls_seq = fxdr_unsigned(int, *tl++);
22316ca35587Sdholland stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
22326ca35587Sdholland NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
22336ca35587Sdholland NFSX_STATEIDOTHER);
22346ca35587Sdholland tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
22356ca35587Sdholland stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
22366ca35587Sdholland clientid.lval[0] = *tl++;
22376ca35587Sdholland clientid.lval[1] = *tl++;
22382d39560cSpgoyette if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
22392d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
22402d39560cSpgoyette clientid.qval = nd->nd_clientid.qval;
22412d39560cSpgoyette else if (nd->nd_clientid.qval != clientid.qval)
22422d39560cSpgoyette printf("EEK3 multiple clids\n");
22436ca35587Sdholland } else {
22442d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
22452d39560cSpgoyette printf("EEK! no clientid from session\n");
22466ca35587Sdholland nd->nd_flag |= ND_IMPLIEDCLID;
22476ca35587Sdholland nd->nd_clientid.qval = clientid.qval;
22486ca35587Sdholland }
22496ca35587Sdholland error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
22506ca35587Sdholland if (error)
22516ca35587Sdholland goto nfsmout;
22526ca35587Sdholland } else {
22536ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
22546ca35587Sdholland MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
22556ca35587Sdholland M_NFSDSTATE, M_WAITOK);
22566ca35587Sdholland stp->ls_ownerlen = 0;
22576ca35587Sdholland stp->ls_op = nd->nd_rp;
22586ca35587Sdholland stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
22596ca35587Sdholland NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
22606ca35587Sdholland NFSX_STATEIDOTHER);
22616ca35587Sdholland tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
22626ca35587Sdholland stp->ls_seq = fxdr_unsigned(int, *tl);
22636ca35587Sdholland clientid.lval[0] = stp->ls_stateid.other[0];
22646ca35587Sdholland clientid.lval[1] = stp->ls_stateid.other[1];
22652d39560cSpgoyette if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
22662d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
22672d39560cSpgoyette clientid.qval = nd->nd_clientid.qval;
22682d39560cSpgoyette else if (nd->nd_clientid.qval != clientid.qval)
22692d39560cSpgoyette printf("EEK4 multiple clids\n");
22706ca35587Sdholland } else {
22712d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
22722d39560cSpgoyette printf("EEK! no clientid from session\n");
22736ca35587Sdholland nd->nd_flag |= ND_IMPLIEDCLID;
22746ca35587Sdholland nd->nd_clientid.qval = clientid.qval;
22756ca35587Sdholland }
22766ca35587Sdholland }
22776ca35587Sdholland MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
22786ca35587Sdholland M_NFSDLOCK, M_WAITOK);
22796ca35587Sdholland lop->lo_first = offset;
22806ca35587Sdholland if (len == NFS64BITSSET) {
22816ca35587Sdholland lop->lo_end = NFS64BITSSET;
22826ca35587Sdholland } else {
22836ca35587Sdholland lop->lo_end = offset + len;
22846ca35587Sdholland if (lop->lo_end <= lop->lo_first)
22856ca35587Sdholland nd->nd_repstat = NFSERR_INVAL;
22866ca35587Sdholland }
22876ca35587Sdholland lop->lo_flags = lflags;
22886ca35587Sdholland stp->ls_flags = flags;
22896ca35587Sdholland stp->ls_uid = nd->nd_cred->cr_uid;
22906ca35587Sdholland
22916ca35587Sdholland /*
22926ca35587Sdholland * Do basic access checking.
22936ca35587Sdholland */
22946ca35587Sdholland if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
22956ca35587Sdholland if (vnode_vtype(vp) == VDIR)
22966ca35587Sdholland nd->nd_repstat = NFSERR_ISDIR;
22976ca35587Sdholland else
22986ca35587Sdholland nd->nd_repstat = NFSERR_INVAL;
22996ca35587Sdholland }
23006ca35587Sdholland if (!nd->nd_repstat) {
23016ca35587Sdholland if (lflags & NFSLCK_WRITE) {
23026ca35587Sdholland nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
23036ca35587Sdholland nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
23046ca35587Sdholland NFSACCCHK_VPISLOCKED, NULL);
23056ca35587Sdholland } else {
23066ca35587Sdholland nd->nd_repstat = nfsvno_accchk(vp, VREAD,
23076ca35587Sdholland nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
23086ca35587Sdholland NFSACCCHK_VPISLOCKED, NULL);
23096ca35587Sdholland if (nd->nd_repstat)
23106ca35587Sdholland nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
23116ca35587Sdholland nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
23126ca35587Sdholland NFSACCCHK_VPISLOCKED, NULL);
23136ca35587Sdholland }
23146ca35587Sdholland }
23156ca35587Sdholland
23166ca35587Sdholland /*
23176ca35587Sdholland * We call nfsrv_lockctrl() even if nd_repstat set, so that the
23186ca35587Sdholland * seqid# gets updated. nfsrv_lockctrl() will return the value
23196ca35587Sdholland * of nd_repstat, if it gets that far.
23206ca35587Sdholland */
23216ca35587Sdholland nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
23226ca35587Sdholland &stateid, exp, nd, p);
23236ca35587Sdholland if (lop)
23246ca35587Sdholland FREE((caddr_t)lop, M_NFSDLOCK);
23256ca35587Sdholland if (stp)
23266ca35587Sdholland FREE((caddr_t)stp, M_NFSDSTATE);
23276ca35587Sdholland if (!nd->nd_repstat) {
23286ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
23296ca35587Sdholland *tl++ = txdr_unsigned(stateid.seqid);
23306ca35587Sdholland NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
23316ca35587Sdholland } else if (nd->nd_repstat == NFSERR_DENIED) {
23326ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
23336ca35587Sdholland txdr_hyper(cf.cl_first, tl);
23346ca35587Sdholland tl += 2;
23356ca35587Sdholland if (cf.cl_end == NFS64BITSSET)
23366ca35587Sdholland len = NFS64BITSSET;
23376ca35587Sdholland else
23386ca35587Sdholland len = cf.cl_end - cf.cl_first;
23396ca35587Sdholland txdr_hyper(len, tl);
23406ca35587Sdholland tl += 2;
23416ca35587Sdholland if (cf.cl_flags == NFSLCK_WRITE)
23426ca35587Sdholland *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
23436ca35587Sdholland else
23446ca35587Sdholland *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
23456ca35587Sdholland *tl++ = stateid.other[0];
23466ca35587Sdholland *tl = stateid.other[1];
23476ca35587Sdholland (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
23486ca35587Sdholland }
23496ca35587Sdholland vput(vp);
23506ca35587Sdholland NFSEXITCODE2(0, nd);
23516ca35587Sdholland return (0);
23526ca35587Sdholland nfsmout:
23536ca35587Sdholland vput(vp);
23546ca35587Sdholland if (stp)
23556ca35587Sdholland free((caddr_t)stp, M_NFSDSTATE);
23566ca35587Sdholland NFSEXITCODE2(error, nd);
23576ca35587Sdholland return (error);
23586ca35587Sdholland }
23596ca35587Sdholland
23606ca35587Sdholland /*
23616ca35587Sdholland * nfsv4 lock test service
23626ca35587Sdholland */
23636ca35587Sdholland APPLESTATIC int
nfsrvd_lockt(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,NFSPROC_T * p,struct nfsexstuff * exp)23646ca35587Sdholland nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
23656ca35587Sdholland vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
23666ca35587Sdholland {
23676ca35587Sdholland u_int32_t *tl;
23686ca35587Sdholland int i;
23696ca35587Sdholland struct nfsstate *stp = NULL;
23706ca35587Sdholland struct nfslock lo, *lop = &lo;
23716ca35587Sdholland struct nfslockconflict cf;
23726ca35587Sdholland int error = 0;
23736ca35587Sdholland nfsv4stateid_t stateid;
23746ca35587Sdholland nfsquad_t clientid;
23756ca35587Sdholland u_int64_t len;
23766ca35587Sdholland
23776ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
23786ca35587Sdholland i = fxdr_unsigned(int, *(tl + 7));
23796ca35587Sdholland if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
23806ca35587Sdholland nd->nd_repstat = NFSERR_BADXDR;
23816ca35587Sdholland goto nfsmout;
23826ca35587Sdholland }
23836ca35587Sdholland MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
23846ca35587Sdholland M_NFSDSTATE, M_WAITOK);
23856ca35587Sdholland stp->ls_ownerlen = i;
23866ca35587Sdholland stp->ls_op = NULL;
23876ca35587Sdholland stp->ls_flags = NFSLCK_TEST;
23886ca35587Sdholland stp->ls_uid = nd->nd_cred->cr_uid;
23896ca35587Sdholland i = fxdr_unsigned(int, *tl++);
23906ca35587Sdholland switch (i) {
23916ca35587Sdholland case NFSV4LOCKT_READW:
23926ca35587Sdholland stp->ls_flags |= NFSLCK_BLOCKING;
23936ca35587Sdholland case NFSV4LOCKT_READ:
23946ca35587Sdholland lo.lo_flags = NFSLCK_READ;
23956ca35587Sdholland break;
23966ca35587Sdholland case NFSV4LOCKT_WRITEW:
23976ca35587Sdholland stp->ls_flags |= NFSLCK_BLOCKING;
23986ca35587Sdholland case NFSV4LOCKT_WRITE:
23996ca35587Sdholland lo.lo_flags = NFSLCK_WRITE;
24006ca35587Sdholland break;
24016ca35587Sdholland default:
24026ca35587Sdholland nd->nd_repstat = NFSERR_BADXDR;
24036ca35587Sdholland goto nfsmout;
24042d39560cSpgoyette }
24056ca35587Sdholland lo.lo_first = fxdr_hyper(tl);
24066ca35587Sdholland tl += 2;
24076ca35587Sdholland len = fxdr_hyper(tl);
24086ca35587Sdholland if (len == NFS64BITSSET) {
24096ca35587Sdholland lo.lo_end = NFS64BITSSET;
24106ca35587Sdholland } else {
24116ca35587Sdholland lo.lo_end = lo.lo_first + len;
24126ca35587Sdholland if (lo.lo_end <= lo.lo_first)
24136ca35587Sdholland nd->nd_repstat = NFSERR_INVAL;
24146ca35587Sdholland }
24156ca35587Sdholland tl += 2;
24166ca35587Sdholland clientid.lval[0] = *tl++;
24176ca35587Sdholland clientid.lval[1] = *tl;
24182d39560cSpgoyette if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
24192d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
24202d39560cSpgoyette clientid.qval = nd->nd_clientid.qval;
24212d39560cSpgoyette else if (nd->nd_clientid.qval != clientid.qval)
24222d39560cSpgoyette printf("EEK5 multiple clids\n");
24236ca35587Sdholland } else {
24242d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
24252d39560cSpgoyette printf("EEK! no clientid from session\n");
24266ca35587Sdholland nd->nd_flag |= ND_IMPLIEDCLID;
24276ca35587Sdholland nd->nd_clientid.qval = clientid.qval;
24286ca35587Sdholland }
24296ca35587Sdholland error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
24306ca35587Sdholland if (error)
24316ca35587Sdholland goto nfsmout;
24326ca35587Sdholland if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
24336ca35587Sdholland if (vnode_vtype(vp) == VDIR)
24346ca35587Sdholland nd->nd_repstat = NFSERR_ISDIR;
24356ca35587Sdholland else
24366ca35587Sdholland nd->nd_repstat = NFSERR_INVAL;
24376ca35587Sdholland }
24386ca35587Sdholland if (!nd->nd_repstat)
24396ca35587Sdholland nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
24406ca35587Sdholland &stateid, exp, nd, p);
24416ca35587Sdholland if (nd->nd_repstat) {
24426ca35587Sdholland if (nd->nd_repstat == NFSERR_DENIED) {
24436ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
24446ca35587Sdholland txdr_hyper(cf.cl_first, tl);
24456ca35587Sdholland tl += 2;
24466ca35587Sdholland if (cf.cl_end == NFS64BITSSET)
24476ca35587Sdholland len = NFS64BITSSET;
24486ca35587Sdholland else
24496ca35587Sdholland len = cf.cl_end - cf.cl_first;
24506ca35587Sdholland txdr_hyper(len, tl);
24516ca35587Sdholland tl += 2;
24526ca35587Sdholland if (cf.cl_flags == NFSLCK_WRITE)
24536ca35587Sdholland *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
24546ca35587Sdholland else
24556ca35587Sdholland *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
24566ca35587Sdholland *tl++ = stp->ls_stateid.other[0];
24576ca35587Sdholland *tl = stp->ls_stateid.other[1];
24586ca35587Sdholland (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
24596ca35587Sdholland }
24606ca35587Sdholland }
24616ca35587Sdholland vput(vp);
24622d39560cSpgoyette if (stp)
24632d39560cSpgoyette FREE((caddr_t)stp, M_NFSDSTATE);
24646ca35587Sdholland NFSEXITCODE2(0, nd);
24656ca35587Sdholland return (0);
24666ca35587Sdholland nfsmout:
24676ca35587Sdholland vput(vp);
24686ca35587Sdholland if (stp)
24696ca35587Sdholland free((caddr_t)stp, M_NFSDSTATE);
24706ca35587Sdholland NFSEXITCODE2(error, nd);
24716ca35587Sdholland return (error);
24726ca35587Sdholland }
24736ca35587Sdholland
24746ca35587Sdholland /*
24756ca35587Sdholland * nfsv4 unlock service
24766ca35587Sdholland */
24776ca35587Sdholland APPLESTATIC int
nfsrvd_locku(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,NFSPROC_T * p,struct nfsexstuff * exp)24786ca35587Sdholland nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
24796ca35587Sdholland vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
24806ca35587Sdholland {
24816ca35587Sdholland u_int32_t *tl;
24826ca35587Sdholland int i;
24836ca35587Sdholland struct nfsstate *stp;
24846ca35587Sdholland struct nfslock *lop;
24856ca35587Sdholland int error = 0;
24866ca35587Sdholland nfsv4stateid_t stateid;
24876ca35587Sdholland nfsquad_t clientid;
24886ca35587Sdholland u_int64_t len;
24896ca35587Sdholland
24906ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
24916ca35587Sdholland MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
24926ca35587Sdholland M_NFSDSTATE, M_WAITOK);
24936ca35587Sdholland MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
24946ca35587Sdholland M_NFSDLOCK, M_WAITOK);
24956ca35587Sdholland stp->ls_flags = NFSLCK_UNLOCK;
24966ca35587Sdholland lop->lo_flags = NFSLCK_UNLOCK;
24976ca35587Sdholland stp->ls_op = nd->nd_rp;
24986ca35587Sdholland i = fxdr_unsigned(int, *tl++);
24996ca35587Sdholland switch (i) {
25006ca35587Sdholland case NFSV4LOCKT_READW:
25016ca35587Sdholland stp->ls_flags |= NFSLCK_BLOCKING;
25026ca35587Sdholland case NFSV4LOCKT_READ:
25036ca35587Sdholland break;
25046ca35587Sdholland case NFSV4LOCKT_WRITEW:
25056ca35587Sdholland stp->ls_flags |= NFSLCK_BLOCKING;
25066ca35587Sdholland case NFSV4LOCKT_WRITE:
25076ca35587Sdholland break;
25086ca35587Sdholland default:
25096ca35587Sdholland nd->nd_repstat = NFSERR_BADXDR;
25106ca35587Sdholland free(stp, M_NFSDSTATE);
25116ca35587Sdholland free(lop, M_NFSDLOCK);
25126ca35587Sdholland goto nfsmout;
25132d39560cSpgoyette }
25146ca35587Sdholland stp->ls_ownerlen = 0;
25156ca35587Sdholland stp->ls_uid = nd->nd_cred->cr_uid;
25166ca35587Sdholland stp->ls_seq = fxdr_unsigned(int, *tl++);
25176ca35587Sdholland stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
25186ca35587Sdholland NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
25196ca35587Sdholland NFSX_STATEIDOTHER);
25206ca35587Sdholland tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
25216ca35587Sdholland lop->lo_first = fxdr_hyper(tl);
25226ca35587Sdholland tl += 2;
25236ca35587Sdholland len = fxdr_hyper(tl);
25246ca35587Sdholland if (len == NFS64BITSSET) {
25256ca35587Sdholland lop->lo_end = NFS64BITSSET;
25266ca35587Sdholland } else {
25276ca35587Sdholland lop->lo_end = lop->lo_first + len;
25286ca35587Sdholland if (lop->lo_end <= lop->lo_first)
25296ca35587Sdholland nd->nd_repstat = NFSERR_INVAL;
25306ca35587Sdholland }
25316ca35587Sdholland clientid.lval[0] = stp->ls_stateid.other[0];
25326ca35587Sdholland clientid.lval[1] = stp->ls_stateid.other[1];
25332d39560cSpgoyette if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
25342d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
25352d39560cSpgoyette clientid.qval = nd->nd_clientid.qval;
25362d39560cSpgoyette else if (nd->nd_clientid.qval != clientid.qval)
25372d39560cSpgoyette printf("EEK6 multiple clids\n");
25386ca35587Sdholland } else {
25392d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
25402d39560cSpgoyette printf("EEK! no clientid from session\n");
25416ca35587Sdholland nd->nd_flag |= ND_IMPLIEDCLID;
25426ca35587Sdholland nd->nd_clientid.qval = clientid.qval;
25436ca35587Sdholland }
25446ca35587Sdholland if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
25456ca35587Sdholland if (vnode_vtype(vp) == VDIR)
25466ca35587Sdholland nd->nd_repstat = NFSERR_ISDIR;
25476ca35587Sdholland else
25486ca35587Sdholland nd->nd_repstat = NFSERR_INVAL;
25496ca35587Sdholland }
25506ca35587Sdholland /*
25516ca35587Sdholland * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
25526ca35587Sdholland * seqid# gets incremented. nfsrv_lockctrl() will return the
25536ca35587Sdholland * value of nd_repstat, if it gets that far.
25546ca35587Sdholland */
25556ca35587Sdholland nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
25566ca35587Sdholland &stateid, exp, nd, p);
25576ca35587Sdholland if (stp)
25586ca35587Sdholland FREE((caddr_t)stp, M_NFSDSTATE);
25596ca35587Sdholland if (lop)
25606ca35587Sdholland free((caddr_t)lop, M_NFSDLOCK);
25616ca35587Sdholland if (!nd->nd_repstat) {
25626ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
25636ca35587Sdholland *tl++ = txdr_unsigned(stateid.seqid);
25646ca35587Sdholland NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
25656ca35587Sdholland }
25666ca35587Sdholland nfsmout:
25676ca35587Sdholland vput(vp);
25686ca35587Sdholland NFSEXITCODE2(error, nd);
25696ca35587Sdholland return (error);
25706ca35587Sdholland }
25716ca35587Sdholland
25726ca35587Sdholland /*
25736ca35587Sdholland * nfsv4 open service
25746ca35587Sdholland */
25756ca35587Sdholland APPLESTATIC int
nfsrvd_open(struct nfsrv_descript * nd,__unused int isdgram,vnode_t dp,vnode_t * vpp,__unused fhandle_t * fhp,NFSPROC_T * p,struct nfsexstuff * exp)25766ca35587Sdholland nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
25776ca35587Sdholland vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
25786ca35587Sdholland struct nfsexstuff *exp)
25796ca35587Sdholland {
25806ca35587Sdholland u_int32_t *tl;
25812d39560cSpgoyette int i, retext;
25826ca35587Sdholland struct nfsstate *stp = NULL;
25836ca35587Sdholland int error = 0, create, claim, exclusive_flag = 0;
25846ca35587Sdholland u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
25856ca35587Sdholland int how = NFSCREATE_UNCHECKED;
25866ca35587Sdholland int32_t cverf[2], tverf[2] = { 0, 0 };
25876ca35587Sdholland vnode_t vp = NULL, dirp = NULL;
25886ca35587Sdholland struct nfsvattr nva, dirfor, diraft;
25896ca35587Sdholland struct nameidata named;
25906ca35587Sdholland nfsv4stateid_t stateid, delegstateid;
25916ca35587Sdholland nfsattrbit_t attrbits;
25926ca35587Sdholland nfsquad_t clientid;
25936ca35587Sdholland char *bufp = NULL;
25946ca35587Sdholland u_long *hashp;
25956ca35587Sdholland NFSACL_T *aclp = NULL;
25966ca35587Sdholland
25976ca35587Sdholland #ifdef NFS4_ACL_EXTATTR_NAME
25986ca35587Sdholland aclp = acl_alloc(M_WAITOK);
25996ca35587Sdholland aclp->acl_cnt = 0;
26006ca35587Sdholland #endif
26016ca35587Sdholland NFSZERO_ATTRBIT(&attrbits);
26026ca35587Sdholland named.ni_startdir = NULL;
26036ca35587Sdholland named.ni_cnd.cn_nameiop = 0;
26046ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
26056ca35587Sdholland i = fxdr_unsigned(int, *(tl + 5));
26066ca35587Sdholland if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
26076ca35587Sdholland nd->nd_repstat = NFSERR_BADXDR;
26086ca35587Sdholland goto nfsmout;
26096ca35587Sdholland }
26106ca35587Sdholland MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
26116ca35587Sdholland M_NFSDSTATE, M_WAITOK);
26126ca35587Sdholland stp->ls_ownerlen = i;
26136ca35587Sdholland stp->ls_op = nd->nd_rp;
26146ca35587Sdholland stp->ls_flags = NFSLCK_OPEN;
26156ca35587Sdholland stp->ls_uid = nd->nd_cred->cr_uid;
26166ca35587Sdholland stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
26176ca35587Sdholland i = fxdr_unsigned(int, *tl++);
26182d39560cSpgoyette retext = 0;
26192d39560cSpgoyette if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
26202d39560cSpgoyette NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
26212d39560cSpgoyette retext = 1;
26222d39560cSpgoyette /* For now, ignore these. */
26232d39560cSpgoyette i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
26242d39560cSpgoyette switch (i & NFSV4OPEN_WANTDELEGMASK) {
26252d39560cSpgoyette case NFSV4OPEN_WANTANYDELEG:
26262d39560cSpgoyette stp->ls_flags |= (NFSLCK_WANTRDELEG |
26272d39560cSpgoyette NFSLCK_WANTWDELEG);
26282d39560cSpgoyette i &= ~NFSV4OPEN_WANTDELEGMASK;
26292d39560cSpgoyette break;
26302d39560cSpgoyette case NFSV4OPEN_WANTREADDELEG:
26312d39560cSpgoyette stp->ls_flags |= NFSLCK_WANTRDELEG;
26322d39560cSpgoyette i &= ~NFSV4OPEN_WANTDELEGMASK;
26332d39560cSpgoyette break;
26342d39560cSpgoyette case NFSV4OPEN_WANTWRITEDELEG:
26352d39560cSpgoyette stp->ls_flags |= NFSLCK_WANTWDELEG;
26362d39560cSpgoyette i &= ~NFSV4OPEN_WANTDELEGMASK;
26372d39560cSpgoyette break;
26382d39560cSpgoyette case NFSV4OPEN_WANTNODELEG:
26392d39560cSpgoyette stp->ls_flags |= NFSLCK_WANTNODELEG;
26402d39560cSpgoyette i &= ~NFSV4OPEN_WANTDELEGMASK;
26412d39560cSpgoyette break;
26422d39560cSpgoyette case NFSV4OPEN_WANTCANCEL:
26432d39560cSpgoyette printf("NFSv4: ignore Open WantCancel\n");
26442d39560cSpgoyette i &= ~NFSV4OPEN_WANTDELEGMASK;
26452d39560cSpgoyette break;
26462d39560cSpgoyette default:
26472d39560cSpgoyette /* nd_repstat will be set to NFSERR_INVAL below. */
26482d39560cSpgoyette break;
26492d39560cSpgoyette }
26502d39560cSpgoyette }
26516ca35587Sdholland switch (i) {
26526ca35587Sdholland case NFSV4OPEN_ACCESSREAD:
26536ca35587Sdholland stp->ls_flags |= NFSLCK_READACCESS;
26546ca35587Sdholland break;
26556ca35587Sdholland case NFSV4OPEN_ACCESSWRITE:
26566ca35587Sdholland stp->ls_flags |= NFSLCK_WRITEACCESS;
26576ca35587Sdholland break;
26586ca35587Sdholland case NFSV4OPEN_ACCESSBOTH:
26596ca35587Sdholland stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
26606ca35587Sdholland break;
26616ca35587Sdholland default:
26626ca35587Sdholland nd->nd_repstat = NFSERR_INVAL;
26632d39560cSpgoyette }
26646ca35587Sdholland i = fxdr_unsigned(int, *tl++);
26656ca35587Sdholland switch (i) {
26666ca35587Sdholland case NFSV4OPEN_DENYNONE:
26676ca35587Sdholland break;
26686ca35587Sdholland case NFSV4OPEN_DENYREAD:
26696ca35587Sdholland stp->ls_flags |= NFSLCK_READDENY;
26706ca35587Sdholland break;
26716ca35587Sdholland case NFSV4OPEN_DENYWRITE:
26726ca35587Sdholland stp->ls_flags |= NFSLCK_WRITEDENY;
26736ca35587Sdholland break;
26746ca35587Sdholland case NFSV4OPEN_DENYBOTH:
26756ca35587Sdholland stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
26766ca35587Sdholland break;
26776ca35587Sdholland default:
26786ca35587Sdholland nd->nd_repstat = NFSERR_INVAL;
26792d39560cSpgoyette }
26806ca35587Sdholland clientid.lval[0] = *tl++;
26816ca35587Sdholland clientid.lval[1] = *tl;
26822d39560cSpgoyette if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
26832d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
26842d39560cSpgoyette clientid.qval = nd->nd_clientid.qval;
26852d39560cSpgoyette else if (nd->nd_clientid.qval != clientid.qval)
26862d39560cSpgoyette printf("EEK7 multiple clids\n");
26876ca35587Sdholland } else {
26882d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
26892d39560cSpgoyette printf("EEK! no clientid from session\n");
26906ca35587Sdholland nd->nd_flag |= ND_IMPLIEDCLID;
26916ca35587Sdholland nd->nd_clientid.qval = clientid.qval;
26926ca35587Sdholland }
26936ca35587Sdholland error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
26946ca35587Sdholland if (error)
26956ca35587Sdholland goto nfsmout;
26966ca35587Sdholland NFSVNO_ATTRINIT(&nva);
26976ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
26986ca35587Sdholland create = fxdr_unsigned(int, *tl);
26996ca35587Sdholland if (!nd->nd_repstat)
27006ca35587Sdholland nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
27016ca35587Sdholland if (create == NFSV4OPEN_CREATE) {
27026ca35587Sdholland nva.na_type = VREG;
27036ca35587Sdholland nva.na_mode = 0;
27046ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
27056ca35587Sdholland how = fxdr_unsigned(int, *tl);
27066ca35587Sdholland switch (how) {
27076ca35587Sdholland case NFSCREATE_UNCHECKED:
27086ca35587Sdholland case NFSCREATE_GUARDED:
27092d39560cSpgoyette error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
27106ca35587Sdholland if (error)
27116ca35587Sdholland goto nfsmout;
27126ca35587Sdholland /*
27136ca35587Sdholland * If the na_gid being set is the same as that of
27146ca35587Sdholland * the directory it is going in, clear it, since
27156ca35587Sdholland * that is what will be set by default. This allows
27166ca35587Sdholland * a user that isn't in that group to do the create.
27176ca35587Sdholland */
27186ca35587Sdholland if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
27196ca35587Sdholland nva.na_gid == dirfor.na_gid)
27206ca35587Sdholland NFSVNO_UNSET(&nva, gid);
27216ca35587Sdholland if (!nd->nd_repstat)
27226ca35587Sdholland nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
27236ca35587Sdholland break;
27246ca35587Sdholland case NFSCREATE_EXCLUSIVE:
27256ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
27266ca35587Sdholland cverf[0] = *tl++;
27276ca35587Sdholland cverf[1] = *tl;
27286ca35587Sdholland break;
27292d39560cSpgoyette case NFSCREATE_EXCLUSIVE41:
27302d39560cSpgoyette NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
27312d39560cSpgoyette cverf[0] = *tl++;
27322d39560cSpgoyette cverf[1] = *tl;
27332d39560cSpgoyette error = nfsv4_sattr(nd, vp, &nva, &attrbits, aclp, p);
27342d39560cSpgoyette if (error != 0)
27352d39560cSpgoyette goto nfsmout;
27362d39560cSpgoyette if (NFSISSET_ATTRBIT(&attrbits,
27372d39560cSpgoyette NFSATTRBIT_TIMEACCESSSET))
27382d39560cSpgoyette nd->nd_repstat = NFSERR_INVAL;
27392d39560cSpgoyette /*
27402d39560cSpgoyette * If the na_gid being set is the same as that of
27412d39560cSpgoyette * the directory it is going in, clear it, since
27422d39560cSpgoyette * that is what will be set by default. This allows
27432d39560cSpgoyette * a user that isn't in that group to do the create.
27442d39560cSpgoyette */
27452d39560cSpgoyette if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
27462d39560cSpgoyette nva.na_gid == dirfor.na_gid)
27472d39560cSpgoyette NFSVNO_UNSET(&nva, gid);
27482d39560cSpgoyette if (nd->nd_repstat == 0)
27492d39560cSpgoyette nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
27502d39560cSpgoyette break;
27516ca35587Sdholland default:
27526ca35587Sdholland nd->nd_repstat = NFSERR_BADXDR;
27536ca35587Sdholland goto nfsmout;
27542d39560cSpgoyette }
27556ca35587Sdholland } else if (create != NFSV4OPEN_NOCREATE) {
27566ca35587Sdholland nd->nd_repstat = NFSERR_BADXDR;
27576ca35587Sdholland goto nfsmout;
27586ca35587Sdholland }
27596ca35587Sdholland
27606ca35587Sdholland /*
27616ca35587Sdholland * Now, handle the claim, which usually includes looking up a
27626ca35587Sdholland * name in the directory referenced by dp. The exception is
27636ca35587Sdholland * NFSV4OPEN_CLAIMPREVIOUS.
27646ca35587Sdholland */
27656ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
27666ca35587Sdholland claim = fxdr_unsigned(int, *tl);
27676ca35587Sdholland if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
27686ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
27696ca35587Sdholland stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
27706ca35587Sdholland NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
27716ca35587Sdholland stp->ls_flags |= NFSLCK_DELEGCUR;
27726ca35587Sdholland } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
27736ca35587Sdholland stp->ls_flags |= NFSLCK_DELEGPREV;
27746ca35587Sdholland }
27756ca35587Sdholland if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
27766ca35587Sdholland || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
27776ca35587Sdholland if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
27786ca35587Sdholland claim != NFSV4OPEN_CLAIMNULL)
27796ca35587Sdholland nd->nd_repstat = NFSERR_INVAL;
27806ca35587Sdholland if (nd->nd_repstat) {
27816ca35587Sdholland nd->nd_repstat = nfsrv_opencheck(clientid,
27826ca35587Sdholland &stateid, stp, NULL, nd, p, nd->nd_repstat);
27836ca35587Sdholland goto nfsmout;
27846ca35587Sdholland }
27856ca35587Sdholland if (create == NFSV4OPEN_CREATE)
27866ca35587Sdholland NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
27872d39560cSpgoyette LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
27886ca35587Sdholland else
27896ca35587Sdholland NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
27906ca35587Sdholland LOCKLEAF | SAVESTART);
27916ca35587Sdholland nfsvno_setpathbuf(&named, &bufp, &hashp);
27926ca35587Sdholland error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
27936ca35587Sdholland if (error) {
27946ca35587Sdholland vrele(dp);
27956ca35587Sdholland #ifdef NFS4_ACL_EXTATTR_NAME
27966ca35587Sdholland acl_free(aclp);
27976ca35587Sdholland #endif
27986ca35587Sdholland FREE((caddr_t)stp, M_NFSDSTATE);
27996ca35587Sdholland nfsvno_relpathbuf(&named);
28006ca35587Sdholland NFSEXITCODE2(error, nd);
28016ca35587Sdholland return (error);
28026ca35587Sdholland }
28036ca35587Sdholland if (!nd->nd_repstat) {
28046ca35587Sdholland nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
28056ca35587Sdholland p, &dirp);
28066ca35587Sdholland } else {
28076ca35587Sdholland vrele(dp);
28086ca35587Sdholland nfsvno_relpathbuf(&named);
28096ca35587Sdholland }
28106ca35587Sdholland if (create == NFSV4OPEN_CREATE) {
28116ca35587Sdholland switch (how) {
28126ca35587Sdholland case NFSCREATE_UNCHECKED:
28136ca35587Sdholland if (named.ni_vp) {
28146ca35587Sdholland /*
28156ca35587Sdholland * Clear the setable attribute bits, except
28166ca35587Sdholland * for Size, if it is being truncated.
28176ca35587Sdholland */
28186ca35587Sdholland NFSZERO_ATTRBIT(&attrbits);
28196ca35587Sdholland if (NFSVNO_ISSETSIZE(&nva))
28206ca35587Sdholland NFSSETBIT_ATTRBIT(&attrbits,
28216ca35587Sdholland NFSATTRBIT_SIZE);
28226ca35587Sdholland }
28236ca35587Sdholland break;
28246ca35587Sdholland case NFSCREATE_GUARDED:
28256ca35587Sdholland if (named.ni_vp && !nd->nd_repstat)
28266ca35587Sdholland nd->nd_repstat = EEXIST;
28276ca35587Sdholland break;
28286ca35587Sdholland case NFSCREATE_EXCLUSIVE:
28296ca35587Sdholland exclusive_flag = 1;
28306ca35587Sdholland if (!named.ni_vp)
28316ca35587Sdholland nva.na_mode = 0;
28322d39560cSpgoyette break;
28332d39560cSpgoyette case NFSCREATE_EXCLUSIVE41:
28342d39560cSpgoyette exclusive_flag = 1;
28352d39560cSpgoyette break;
28362d39560cSpgoyette }
28376ca35587Sdholland }
28386ca35587Sdholland nfsvno_open(nd, &named, clientid, &stateid, stp,
28396ca35587Sdholland &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
28406ca35587Sdholland nd->nd_cred, p, exp, &vp);
28412d39560cSpgoyette } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
28422d39560cSpgoyette NFSV4OPEN_CLAIMFH) {
28432d39560cSpgoyette if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
28446ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
28456ca35587Sdholland i = fxdr_unsigned(int, *tl);
28466ca35587Sdholland switch (i) {
28476ca35587Sdholland case NFSV4OPEN_DELEGATEREAD:
28486ca35587Sdholland stp->ls_flags |= NFSLCK_DELEGREAD;
28496ca35587Sdholland break;
28506ca35587Sdholland case NFSV4OPEN_DELEGATEWRITE:
28516ca35587Sdholland stp->ls_flags |= NFSLCK_DELEGWRITE;
28526ca35587Sdholland case NFSV4OPEN_DELEGATENONE:
28536ca35587Sdholland break;
28546ca35587Sdholland default:
28556ca35587Sdholland nd->nd_repstat = NFSERR_BADXDR;
28566ca35587Sdholland goto nfsmout;
28572d39560cSpgoyette }
28586ca35587Sdholland stp->ls_flags |= NFSLCK_RECLAIM;
28592d39560cSpgoyette } else {
28602d39560cSpgoyette /* CLAIM_NULL_FH */
28612d39560cSpgoyette if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
28622d39560cSpgoyette nd->nd_repstat = NFSERR_INVAL;
28632d39560cSpgoyette }
28646ca35587Sdholland vp = dp;
28656ca35587Sdholland NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
28666ca35587Sdholland if ((vp->v_iflag & VI_DOOMED) == 0)
28676ca35587Sdholland nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
28686ca35587Sdholland stp, vp, nd, p, nd->nd_repstat);
28696ca35587Sdholland else
28706ca35587Sdholland nd->nd_repstat = NFSERR_PERM;
28716ca35587Sdholland } else {
28726ca35587Sdholland nd->nd_repstat = NFSERR_BADXDR;
28736ca35587Sdholland goto nfsmout;
28746ca35587Sdholland }
28756ca35587Sdholland
28766ca35587Sdholland /*
28776ca35587Sdholland * Do basic access checking.
28786ca35587Sdholland */
28796ca35587Sdholland if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
28806ca35587Sdholland /*
28816ca35587Sdholland * The IETF working group decided that this is the correct
28826ca35587Sdholland * error return for all non-regular files.
28836ca35587Sdholland */
28842d39560cSpgoyette nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
28856ca35587Sdholland }
28866ca35587Sdholland if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
28876ca35587Sdholland nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
28886ca35587Sdholland exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
28896ca35587Sdholland if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
28906ca35587Sdholland nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
28916ca35587Sdholland exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
28926ca35587Sdholland if (nd->nd_repstat)
28936ca35587Sdholland nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
28946ca35587Sdholland nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
28956ca35587Sdholland NFSACCCHK_VPISLOCKED, NULL);
28966ca35587Sdholland }
28976ca35587Sdholland
28986ca35587Sdholland if (!nd->nd_repstat) {
28996ca35587Sdholland nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
29006ca35587Sdholland if (!nd->nd_repstat) {
29016ca35587Sdholland tverf[0] = nva.na_atime.tv_sec;
29026ca35587Sdholland tverf[1] = nva.na_atime.tv_nsec;
29036ca35587Sdholland }
29046ca35587Sdholland }
29056ca35587Sdholland if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
29066ca35587Sdholland cverf[1] != tverf[1]))
29076ca35587Sdholland nd->nd_repstat = EEXIST;
29086ca35587Sdholland /*
29096ca35587Sdholland * Do the open locking/delegation stuff.
29106ca35587Sdholland */
29116ca35587Sdholland if (!nd->nd_repstat)
29126ca35587Sdholland nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
29136ca35587Sdholland &delegstateid, &rflags, exp, p, nva.na_filerev);
29146ca35587Sdholland
29156ca35587Sdholland /*
29166ca35587Sdholland * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
29176ca35587Sdholland * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
29186ca35587Sdholland * (ie: Leave the NFSVOPUNLOCK() about here.)
29196ca35587Sdholland */
29206ca35587Sdholland if (vp)
29216ca35587Sdholland NFSVOPUNLOCK(vp, 0);
29226ca35587Sdholland if (stp)
29236ca35587Sdholland FREE((caddr_t)stp, M_NFSDSTATE);
29246ca35587Sdholland if (!nd->nd_repstat && dirp)
29256ca35587Sdholland nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
29266ca35587Sdholland 0);
29276ca35587Sdholland if (!nd->nd_repstat) {
29286ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
29296ca35587Sdholland *tl++ = txdr_unsigned(stateid.seqid);
29306ca35587Sdholland NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
29316ca35587Sdholland tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
29326ca35587Sdholland if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
29336ca35587Sdholland *tl++ = newnfs_true;
29346ca35587Sdholland *tl++ = 0;
29356ca35587Sdholland *tl++ = 0;
29366ca35587Sdholland *tl++ = 0;
29376ca35587Sdholland *tl++ = 0;
29386ca35587Sdholland } else {
29396ca35587Sdholland *tl++ = newnfs_false; /* Since dirp is not locked */
29406ca35587Sdholland txdr_hyper(dirfor.na_filerev, tl);
29416ca35587Sdholland tl += 2;
29426ca35587Sdholland txdr_hyper(diraft.na_filerev, tl);
29436ca35587Sdholland tl += 2;
29446ca35587Sdholland }
29456ca35587Sdholland *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
29466ca35587Sdholland (void) nfsrv_putattrbit(nd, &attrbits);
29476ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
29486ca35587Sdholland if (rflags & NFSV4OPEN_READDELEGATE)
29496ca35587Sdholland *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
29506ca35587Sdholland else if (rflags & NFSV4OPEN_WRITEDELEGATE)
29516ca35587Sdholland *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
29522d39560cSpgoyette else if (retext != 0) {
29532d39560cSpgoyette *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
29542d39560cSpgoyette if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
29552d39560cSpgoyette NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
29562d39560cSpgoyette *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
29572d39560cSpgoyette *tl = newnfs_false;
29582d39560cSpgoyette } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
29592d39560cSpgoyette NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
29602d39560cSpgoyette *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
29612d39560cSpgoyette *tl = newnfs_false;
29622d39560cSpgoyette } else {
29632d39560cSpgoyette NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
29642d39560cSpgoyette *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
29652d39560cSpgoyette }
29662d39560cSpgoyette } else
29676ca35587Sdholland *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
29686ca35587Sdholland if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
29696ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
29706ca35587Sdholland *tl++ = txdr_unsigned(delegstateid.seqid);
29716ca35587Sdholland NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
29726ca35587Sdholland NFSX_STATEIDOTHER);
29736ca35587Sdholland tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
29746ca35587Sdholland if (rflags & NFSV4OPEN_RECALL)
29756ca35587Sdholland *tl = newnfs_true;
29766ca35587Sdholland else
29776ca35587Sdholland *tl = newnfs_false;
29786ca35587Sdholland if (rflags & NFSV4OPEN_WRITEDELEGATE) {
29796ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
29806ca35587Sdholland *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
29816ca35587Sdholland txdr_hyper(nva.na_size, tl);
29826ca35587Sdholland }
29836ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
29846ca35587Sdholland *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
29856ca35587Sdholland *tl++ = txdr_unsigned(0x0);
29866ca35587Sdholland acemask = NFSV4ACE_ALLFILESMASK;
29876ca35587Sdholland if (nva.na_mode & S_IRUSR)
29886ca35587Sdholland acemask |= NFSV4ACE_READMASK;
29896ca35587Sdholland if (nva.na_mode & S_IWUSR)
29906ca35587Sdholland acemask |= NFSV4ACE_WRITEMASK;
29916ca35587Sdholland if (nva.na_mode & S_IXUSR)
29926ca35587Sdholland acemask |= NFSV4ACE_EXECUTEMASK;
29936ca35587Sdholland *tl = txdr_unsigned(acemask);
29946ca35587Sdholland (void) nfsm_strtom(nd, "OWNER@", 6);
29956ca35587Sdholland }
29966ca35587Sdholland *vpp = vp;
29976ca35587Sdholland } else if (vp) {
29986ca35587Sdholland vrele(vp);
29996ca35587Sdholland }
30006ca35587Sdholland if (dirp)
30016ca35587Sdholland vrele(dirp);
30026ca35587Sdholland #ifdef NFS4_ACL_EXTATTR_NAME
30036ca35587Sdholland acl_free(aclp);
30046ca35587Sdholland #endif
30056ca35587Sdholland NFSEXITCODE2(0, nd);
30066ca35587Sdholland return (0);
30076ca35587Sdholland nfsmout:
30086ca35587Sdholland vrele(dp);
30096ca35587Sdholland #ifdef NFS4_ACL_EXTATTR_NAME
30106ca35587Sdholland acl_free(aclp);
30116ca35587Sdholland #endif
30126ca35587Sdholland if (stp)
30136ca35587Sdholland FREE((caddr_t)stp, M_NFSDSTATE);
30146ca35587Sdholland NFSEXITCODE2(error, nd);
30156ca35587Sdholland return (error);
30166ca35587Sdholland }
30176ca35587Sdholland
30186ca35587Sdholland /*
30196ca35587Sdholland * nfsv4 close service
30206ca35587Sdholland */
30216ca35587Sdholland APPLESTATIC int
nfsrvd_close(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,NFSPROC_T * p,__unused struct nfsexstuff * exp)30226ca35587Sdholland nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
30236ca35587Sdholland vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
30246ca35587Sdholland {
30256ca35587Sdholland u_int32_t *tl;
30266ca35587Sdholland struct nfsstate st, *stp = &st;
30276ca35587Sdholland int error = 0;
30286ca35587Sdholland nfsv4stateid_t stateid;
30296ca35587Sdholland nfsquad_t clientid;
30306ca35587Sdholland
30316ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
30326ca35587Sdholland stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
30336ca35587Sdholland stp->ls_ownerlen = 0;
30346ca35587Sdholland stp->ls_op = nd->nd_rp;
30356ca35587Sdholland stp->ls_uid = nd->nd_cred->cr_uid;
30366ca35587Sdholland stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
30376ca35587Sdholland NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
30386ca35587Sdholland NFSX_STATEIDOTHER);
30396ca35587Sdholland stp->ls_flags = NFSLCK_CLOSE;
30406ca35587Sdholland clientid.lval[0] = stp->ls_stateid.other[0];
30416ca35587Sdholland clientid.lval[1] = stp->ls_stateid.other[1];
30422d39560cSpgoyette if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
30432d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
30442d39560cSpgoyette clientid.qval = nd->nd_clientid.qval;
30452d39560cSpgoyette else if (nd->nd_clientid.qval != clientid.qval)
30462d39560cSpgoyette printf("EEK8 multiple clids\n");
30476ca35587Sdholland } else {
30482d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
30492d39560cSpgoyette printf("EEK! no clientid from session\n");
30506ca35587Sdholland nd->nd_flag |= ND_IMPLIEDCLID;
30516ca35587Sdholland nd->nd_clientid.qval = clientid.qval;
30526ca35587Sdholland }
30536ca35587Sdholland nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
30546ca35587Sdholland vput(vp);
30556ca35587Sdholland if (!nd->nd_repstat) {
30566ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
30576ca35587Sdholland *tl++ = txdr_unsigned(stateid.seqid);
30586ca35587Sdholland NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
30596ca35587Sdholland }
30606ca35587Sdholland NFSEXITCODE2(0, nd);
30616ca35587Sdholland return (0);
30626ca35587Sdholland nfsmout:
30636ca35587Sdholland vput(vp);
30646ca35587Sdholland NFSEXITCODE2(error, nd);
30656ca35587Sdholland return (error);
30666ca35587Sdholland }
30676ca35587Sdholland
30686ca35587Sdholland /*
30696ca35587Sdholland * nfsv4 delegpurge service
30706ca35587Sdholland */
30716ca35587Sdholland APPLESTATIC int
nfsrvd_delegpurge(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused NFSPROC_T * p,__unused struct nfsexstuff * exp)30726ca35587Sdholland nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
30736ca35587Sdholland __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
30746ca35587Sdholland {
30756ca35587Sdholland u_int32_t *tl;
30766ca35587Sdholland int error = 0;
30776ca35587Sdholland nfsquad_t clientid;
30786ca35587Sdholland
30796ca35587Sdholland if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
30806ca35587Sdholland nd->nd_repstat = NFSERR_WRONGSEC;
30816ca35587Sdholland goto nfsmout;
30826ca35587Sdholland }
30836ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
30846ca35587Sdholland clientid.lval[0] = *tl++;
30856ca35587Sdholland clientid.lval[1] = *tl;
30862d39560cSpgoyette if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
30872d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
30882d39560cSpgoyette clientid.qval = nd->nd_clientid.qval;
30892d39560cSpgoyette else if (nd->nd_clientid.qval != clientid.qval)
30902d39560cSpgoyette printf("EEK9 multiple clids\n");
30916ca35587Sdholland } else {
30922d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
30932d39560cSpgoyette printf("EEK! no clientid from session\n");
30946ca35587Sdholland nd->nd_flag |= ND_IMPLIEDCLID;
30956ca35587Sdholland nd->nd_clientid.qval = clientid.qval;
30966ca35587Sdholland }
30972d39560cSpgoyette nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
30986ca35587Sdholland NFSV4OP_DELEGPURGE, nd->nd_cred, p);
30996ca35587Sdholland nfsmout:
31006ca35587Sdholland NFSEXITCODE2(error, nd);
31016ca35587Sdholland return (error);
31026ca35587Sdholland }
31036ca35587Sdholland
31046ca35587Sdholland /*
31056ca35587Sdholland * nfsv4 delegreturn service
31066ca35587Sdholland */
31076ca35587Sdholland APPLESTATIC int
nfsrvd_delegreturn(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,NFSPROC_T * p,__unused struct nfsexstuff * exp)31086ca35587Sdholland nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
31096ca35587Sdholland vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
31106ca35587Sdholland {
31116ca35587Sdholland u_int32_t *tl;
31126ca35587Sdholland int error = 0;
31136ca35587Sdholland nfsv4stateid_t stateid;
31146ca35587Sdholland nfsquad_t clientid;
31156ca35587Sdholland
31166ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
31176ca35587Sdholland stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
31186ca35587Sdholland NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
31196ca35587Sdholland clientid.lval[0] = stateid.other[0];
31206ca35587Sdholland clientid.lval[1] = stateid.other[1];
31212d39560cSpgoyette if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
31222d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
31232d39560cSpgoyette clientid.qval = nd->nd_clientid.qval;
31242d39560cSpgoyette else if (nd->nd_clientid.qval != clientid.qval)
31252d39560cSpgoyette printf("EEK10 multiple clids\n");
31266ca35587Sdholland } else {
31272d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
31282d39560cSpgoyette printf("EEK! no clientid from session\n");
31296ca35587Sdholland nd->nd_flag |= ND_IMPLIEDCLID;
31306ca35587Sdholland nd->nd_clientid.qval = clientid.qval;
31316ca35587Sdholland }
31322d39560cSpgoyette nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
31336ca35587Sdholland NFSV4OP_DELEGRETURN, nd->nd_cred, p);
31346ca35587Sdholland nfsmout:
31356ca35587Sdholland vput(vp);
31366ca35587Sdholland NFSEXITCODE2(error, nd);
31376ca35587Sdholland return (error);
31386ca35587Sdholland }
31396ca35587Sdholland
31406ca35587Sdholland /*
31416ca35587Sdholland * nfsv4 get file handle service
31426ca35587Sdholland */
31436ca35587Sdholland APPLESTATIC int
nfsrvd_getfh(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,NFSPROC_T * p,__unused struct nfsexstuff * exp)31446ca35587Sdholland nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
31456ca35587Sdholland vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
31466ca35587Sdholland {
31476ca35587Sdholland fhandle_t fh;
31486ca35587Sdholland
31496ca35587Sdholland nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
31506ca35587Sdholland vput(vp);
31516ca35587Sdholland if (!nd->nd_repstat)
31526ca35587Sdholland (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
31536ca35587Sdholland NFSEXITCODE2(0, nd);
31546ca35587Sdholland return (0);
31556ca35587Sdholland }
31566ca35587Sdholland
31576ca35587Sdholland /*
31586ca35587Sdholland * nfsv4 open confirm service
31596ca35587Sdholland */
31606ca35587Sdholland APPLESTATIC int
nfsrvd_openconfirm(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,NFSPROC_T * p,__unused struct nfsexstuff * exp)31616ca35587Sdholland nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
31626ca35587Sdholland vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
31636ca35587Sdholland {
31646ca35587Sdholland u_int32_t *tl;
31656ca35587Sdholland struct nfsstate st, *stp = &st;
31666ca35587Sdholland int error = 0;
31676ca35587Sdholland nfsv4stateid_t stateid;
31686ca35587Sdholland nfsquad_t clientid;
31696ca35587Sdholland
31702d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0) {
31712d39560cSpgoyette nd->nd_repstat = NFSERR_NOTSUPP;
31722d39560cSpgoyette goto nfsmout;
31732d39560cSpgoyette }
31746ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
31756ca35587Sdholland stp->ls_ownerlen = 0;
31766ca35587Sdholland stp->ls_op = nd->nd_rp;
31776ca35587Sdholland stp->ls_uid = nd->nd_cred->cr_uid;
31786ca35587Sdholland stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
31796ca35587Sdholland NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
31806ca35587Sdholland NFSX_STATEIDOTHER);
31816ca35587Sdholland tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
31826ca35587Sdholland stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
31836ca35587Sdholland stp->ls_flags = NFSLCK_CONFIRM;
31846ca35587Sdholland clientid.lval[0] = stp->ls_stateid.other[0];
31856ca35587Sdholland clientid.lval[1] = stp->ls_stateid.other[1];
31862d39560cSpgoyette if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
31872d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
31882d39560cSpgoyette clientid.qval = nd->nd_clientid.qval;
31892d39560cSpgoyette else if (nd->nd_clientid.qval != clientid.qval)
31902d39560cSpgoyette printf("EEK11 multiple clids\n");
31916ca35587Sdholland } else {
31922d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
31932d39560cSpgoyette printf("EEK! no clientid from session\n");
31946ca35587Sdholland nd->nd_flag |= ND_IMPLIEDCLID;
31956ca35587Sdholland nd->nd_clientid.qval = clientid.qval;
31966ca35587Sdholland }
31976ca35587Sdholland nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
31986ca35587Sdholland if (!nd->nd_repstat) {
31996ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
32006ca35587Sdholland *tl++ = txdr_unsigned(stateid.seqid);
32016ca35587Sdholland NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
32026ca35587Sdholland }
32036ca35587Sdholland nfsmout:
32046ca35587Sdholland vput(vp);
32056ca35587Sdholland NFSEXITCODE2(error, nd);
32066ca35587Sdholland return (error);
32076ca35587Sdholland }
32086ca35587Sdholland
32096ca35587Sdholland /*
32106ca35587Sdholland * nfsv4 open downgrade service
32116ca35587Sdholland */
32126ca35587Sdholland APPLESTATIC int
nfsrvd_opendowngrade(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,NFSPROC_T * p,__unused struct nfsexstuff * exp)32136ca35587Sdholland nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
32146ca35587Sdholland vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
32156ca35587Sdholland {
32166ca35587Sdholland u_int32_t *tl;
32176ca35587Sdholland int i;
32186ca35587Sdholland struct nfsstate st, *stp = &st;
32196ca35587Sdholland int error = 0;
32206ca35587Sdholland nfsv4stateid_t stateid;
32216ca35587Sdholland nfsquad_t clientid;
32226ca35587Sdholland
32232d39560cSpgoyette /* opendowngrade can only work on a file object.*/
32242d39560cSpgoyette if (vp->v_type != VREG) {
32252d39560cSpgoyette error = NFSERR_INVAL;
32262d39560cSpgoyette goto nfsmout;
32272d39560cSpgoyette }
32286ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
32296ca35587Sdholland stp->ls_ownerlen = 0;
32306ca35587Sdholland stp->ls_op = nd->nd_rp;
32316ca35587Sdholland stp->ls_uid = nd->nd_cred->cr_uid;
32326ca35587Sdholland stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
32336ca35587Sdholland NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
32346ca35587Sdholland NFSX_STATEIDOTHER);
32356ca35587Sdholland tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
32366ca35587Sdholland stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
32376ca35587Sdholland i = fxdr_unsigned(int, *tl++);
32386ca35587Sdholland switch (i) {
32396ca35587Sdholland case NFSV4OPEN_ACCESSREAD:
32406ca35587Sdholland stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
32416ca35587Sdholland break;
32426ca35587Sdholland case NFSV4OPEN_ACCESSWRITE:
32436ca35587Sdholland stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
32446ca35587Sdholland break;
32456ca35587Sdholland case NFSV4OPEN_ACCESSBOTH:
32466ca35587Sdholland stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
32476ca35587Sdholland NFSLCK_DOWNGRADE);
32486ca35587Sdholland break;
32496ca35587Sdholland default:
32506ca35587Sdholland nd->nd_repstat = NFSERR_BADXDR;
32512d39560cSpgoyette }
32526ca35587Sdholland i = fxdr_unsigned(int, *tl);
32536ca35587Sdholland switch (i) {
32546ca35587Sdholland case NFSV4OPEN_DENYNONE:
32556ca35587Sdholland break;
32566ca35587Sdholland case NFSV4OPEN_DENYREAD:
32576ca35587Sdholland stp->ls_flags |= NFSLCK_READDENY;
32586ca35587Sdholland break;
32596ca35587Sdholland case NFSV4OPEN_DENYWRITE:
32606ca35587Sdholland stp->ls_flags |= NFSLCK_WRITEDENY;
32616ca35587Sdholland break;
32626ca35587Sdholland case NFSV4OPEN_DENYBOTH:
32636ca35587Sdholland stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
32646ca35587Sdholland break;
32656ca35587Sdholland default:
32666ca35587Sdholland nd->nd_repstat = NFSERR_BADXDR;
32672d39560cSpgoyette }
32686ca35587Sdholland
32696ca35587Sdholland clientid.lval[0] = stp->ls_stateid.other[0];
32706ca35587Sdholland clientid.lval[1] = stp->ls_stateid.other[1];
32712d39560cSpgoyette if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
32722d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
32732d39560cSpgoyette clientid.qval = nd->nd_clientid.qval;
32742d39560cSpgoyette else if (nd->nd_clientid.qval != clientid.qval)
32752d39560cSpgoyette printf("EEK12 multiple clids\n");
32766ca35587Sdholland } else {
32772d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
32782d39560cSpgoyette printf("EEK! no clientid from session\n");
32796ca35587Sdholland nd->nd_flag |= ND_IMPLIEDCLID;
32806ca35587Sdholland nd->nd_clientid.qval = clientid.qval;
32816ca35587Sdholland }
32826ca35587Sdholland if (!nd->nd_repstat)
32836ca35587Sdholland nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
32846ca35587Sdholland nd, p);
32856ca35587Sdholland if (!nd->nd_repstat) {
32866ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
32876ca35587Sdholland *tl++ = txdr_unsigned(stateid.seqid);
32886ca35587Sdholland NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
32896ca35587Sdholland }
32906ca35587Sdholland nfsmout:
32916ca35587Sdholland vput(vp);
32926ca35587Sdholland NFSEXITCODE2(error, nd);
32936ca35587Sdholland return (error);
32946ca35587Sdholland }
32956ca35587Sdholland
32966ca35587Sdholland /*
32976ca35587Sdholland * nfsv4 renew lease service
32986ca35587Sdholland */
32996ca35587Sdholland APPLESTATIC int
nfsrvd_renew(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,NFSPROC_T * p,__unused struct nfsexstuff * exp)33006ca35587Sdholland nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
33016ca35587Sdholland __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
33026ca35587Sdholland {
33036ca35587Sdholland u_int32_t *tl;
33046ca35587Sdholland int error = 0;
33056ca35587Sdholland nfsquad_t clientid;
33066ca35587Sdholland
33072d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0) {
33082d39560cSpgoyette nd->nd_repstat = NFSERR_NOTSUPP;
33092d39560cSpgoyette goto nfsmout;
33102d39560cSpgoyette }
33116ca35587Sdholland if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
33126ca35587Sdholland nd->nd_repstat = NFSERR_WRONGSEC;
33136ca35587Sdholland goto nfsmout;
33146ca35587Sdholland }
33156ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
33166ca35587Sdholland clientid.lval[0] = *tl++;
33176ca35587Sdholland clientid.lval[1] = *tl;
33182d39560cSpgoyette if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
33192d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
33202d39560cSpgoyette clientid.qval = nd->nd_clientid.qval;
33212d39560cSpgoyette else if (nd->nd_clientid.qval != clientid.qval)
33222d39560cSpgoyette printf("EEK13 multiple clids\n");
33236ca35587Sdholland } else {
33242d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
33252d39560cSpgoyette printf("EEK! no clientid from session\n");
33266ca35587Sdholland nd->nd_flag |= ND_IMPLIEDCLID;
33276ca35587Sdholland nd->nd_clientid.qval = clientid.qval;
33286ca35587Sdholland }
33296ca35587Sdholland nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
33302d39560cSpgoyette NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
33316ca35587Sdholland nfsmout:
33326ca35587Sdholland NFSEXITCODE2(error, nd);
33336ca35587Sdholland return (error);
33346ca35587Sdholland }
33356ca35587Sdholland
33366ca35587Sdholland /*
33376ca35587Sdholland * nfsv4 security info service
33386ca35587Sdholland */
33396ca35587Sdholland APPLESTATIC int
nfsrvd_secinfo(struct nfsrv_descript * nd,int isdgram,vnode_t dp,NFSPROC_T * p,struct nfsexstuff * exp)33406ca35587Sdholland nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
33416ca35587Sdholland vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
33426ca35587Sdholland {
33436ca35587Sdholland u_int32_t *tl;
33446ca35587Sdholland int len;
33456ca35587Sdholland struct nameidata named;
33466ca35587Sdholland vnode_t dirp = NULL, vp;
33476ca35587Sdholland struct nfsrvfh fh;
33486ca35587Sdholland struct nfsexstuff retnes;
33496ca35587Sdholland u_int32_t *sizp;
33506ca35587Sdholland int error = 0, savflag, i;
33516ca35587Sdholland char *bufp;
33526ca35587Sdholland u_long *hashp;
33536ca35587Sdholland
33546ca35587Sdholland /*
33556ca35587Sdholland * All this just to get the export flags for the name.
33566ca35587Sdholland */
33576ca35587Sdholland NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
33586ca35587Sdholland LOCKLEAF | SAVESTART);
33596ca35587Sdholland nfsvno_setpathbuf(&named, &bufp, &hashp);
33606ca35587Sdholland error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
33616ca35587Sdholland if (error) {
33626ca35587Sdholland vput(dp);
33636ca35587Sdholland nfsvno_relpathbuf(&named);
33646ca35587Sdholland goto out;
33656ca35587Sdholland }
33666ca35587Sdholland if (!nd->nd_repstat) {
33676ca35587Sdholland nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
33686ca35587Sdholland } else {
33696ca35587Sdholland vput(dp);
33706ca35587Sdholland nfsvno_relpathbuf(&named);
33716ca35587Sdholland }
33726ca35587Sdholland if (dirp)
33736ca35587Sdholland vrele(dirp);
33746ca35587Sdholland if (nd->nd_repstat)
33756ca35587Sdholland goto out;
33766ca35587Sdholland vrele(named.ni_startdir);
33776ca35587Sdholland nfsvno_relpathbuf(&named);
33786ca35587Sdholland fh.nfsrvfh_len = NFSX_MYFH;
33796ca35587Sdholland vp = named.ni_vp;
33806ca35587Sdholland nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
33816ca35587Sdholland vput(vp);
33826ca35587Sdholland savflag = nd->nd_flag;
33836ca35587Sdholland if (!nd->nd_repstat) {
33846ca35587Sdholland nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
33856ca35587Sdholland if (vp)
33866ca35587Sdholland vput(vp);
33876ca35587Sdholland }
33886ca35587Sdholland nd->nd_flag = savflag;
33896ca35587Sdholland if (nd->nd_repstat)
33906ca35587Sdholland goto out;
33916ca35587Sdholland
33926ca35587Sdholland /*
33936ca35587Sdholland * Finally have the export flags for name, so we can create
33946ca35587Sdholland * the security info.
33956ca35587Sdholland */
33966ca35587Sdholland len = 0;
33976ca35587Sdholland NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
33986ca35587Sdholland for (i = 0; i < retnes.nes_numsecflavor; i++) {
33996ca35587Sdholland if (retnes.nes_secflavors[i] == AUTH_SYS) {
34006ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
34016ca35587Sdholland *tl = txdr_unsigned(RPCAUTH_UNIX);
34026ca35587Sdholland len++;
34036ca35587Sdholland } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
34046ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
34056ca35587Sdholland *tl++ = txdr_unsigned(RPCAUTH_GSS);
34066ca35587Sdholland (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
34076ca35587Sdholland nfsgss_mechlist[KERBV_MECH].len);
34086ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
34096ca35587Sdholland *tl++ = txdr_unsigned(GSS_KERBV_QOP);
34106ca35587Sdholland *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
34116ca35587Sdholland len++;
34126ca35587Sdholland } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
34136ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
34146ca35587Sdholland *tl++ = txdr_unsigned(RPCAUTH_GSS);
34156ca35587Sdholland (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
34166ca35587Sdholland nfsgss_mechlist[KERBV_MECH].len);
34176ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
34186ca35587Sdholland *tl++ = txdr_unsigned(GSS_KERBV_QOP);
34196ca35587Sdholland *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
34206ca35587Sdholland len++;
34216ca35587Sdholland } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
34226ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
34236ca35587Sdholland *tl++ = txdr_unsigned(RPCAUTH_GSS);
34246ca35587Sdholland (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
34256ca35587Sdholland nfsgss_mechlist[KERBV_MECH].len);
34266ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
34276ca35587Sdholland *tl++ = txdr_unsigned(GSS_KERBV_QOP);
34286ca35587Sdholland *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
34296ca35587Sdholland len++;
34306ca35587Sdholland }
34316ca35587Sdholland }
34326ca35587Sdholland *sizp = txdr_unsigned(len);
34336ca35587Sdholland
34346ca35587Sdholland out:
34356ca35587Sdholland NFSEXITCODE2(error, nd);
34366ca35587Sdholland return (error);
34376ca35587Sdholland }
34386ca35587Sdholland
34396ca35587Sdholland /*
34406ca35587Sdholland * nfsv4 set client id service
34416ca35587Sdholland */
34426ca35587Sdholland APPLESTATIC int
nfsrvd_setclientid(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,NFSPROC_T * p,__unused struct nfsexstuff * exp)34436ca35587Sdholland nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
34446ca35587Sdholland __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
34456ca35587Sdholland {
34466ca35587Sdholland u_int32_t *tl;
34476ca35587Sdholland int i;
34486ca35587Sdholland int error = 0, idlen;
34496ca35587Sdholland struct nfsclient *clp = NULL;
34506ca35587Sdholland struct sockaddr_in *rad;
34516ca35587Sdholland u_char *verf, *ucp, *ucp2, addrbuf[24];
34526ca35587Sdholland nfsquad_t clientid, confirm;
34536ca35587Sdholland
34542d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0) {
34552d39560cSpgoyette nd->nd_repstat = NFSERR_NOTSUPP;
34562d39560cSpgoyette goto nfsmout;
34572d39560cSpgoyette }
34586ca35587Sdholland if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
34596ca35587Sdholland nd->nd_repstat = NFSERR_WRONGSEC;
34606ca35587Sdholland goto out;
34616ca35587Sdholland }
34626ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
34636ca35587Sdholland verf = (u_char *)tl;
34646ca35587Sdholland tl += (NFSX_VERF / NFSX_UNSIGNED);
34656ca35587Sdholland i = fxdr_unsigned(int, *tl);
34666ca35587Sdholland if (i > NFSV4_OPAQUELIMIT || i <= 0) {
34676ca35587Sdholland nd->nd_repstat = NFSERR_BADXDR;
34686ca35587Sdholland goto nfsmout;
34696ca35587Sdholland }
34706ca35587Sdholland idlen = i;
34716ca35587Sdholland if (nd->nd_flag & ND_GSS)
34726ca35587Sdholland i += nd->nd_princlen;
34732d39560cSpgoyette clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
34742d39560cSpgoyette M_ZERO);
34752d39560cSpgoyette clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
34762d39560cSpgoyette nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
34776ca35587Sdholland NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
34786ca35587Sdholland NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
34796ca35587Sdholland NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
34806ca35587Sdholland clp->lc_req.nr_cred = NULL;
34816ca35587Sdholland NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
34826ca35587Sdholland clp->lc_idlen = idlen;
34836ca35587Sdholland error = nfsrv_mtostr(nd, clp->lc_id, idlen);
34846ca35587Sdholland if (error)
34856ca35587Sdholland goto nfsmout;
34866ca35587Sdholland if (nd->nd_flag & ND_GSS) {
34876ca35587Sdholland clp->lc_flags = LCL_GSS;
34886ca35587Sdholland if (nd->nd_flag & ND_GSSINTEGRITY)
34896ca35587Sdholland clp->lc_flags |= LCL_GSSINTEGRITY;
34906ca35587Sdholland else if (nd->nd_flag & ND_GSSPRIVACY)
34916ca35587Sdholland clp->lc_flags |= LCL_GSSPRIVACY;
34926ca35587Sdholland } else {
34936ca35587Sdholland clp->lc_flags = 0;
34946ca35587Sdholland }
34956ca35587Sdholland if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
34966ca35587Sdholland clp->lc_flags |= LCL_NAME;
34976ca35587Sdholland clp->lc_namelen = nd->nd_princlen;
34986ca35587Sdholland clp->lc_name = &clp->lc_id[idlen];
34996ca35587Sdholland NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
35006ca35587Sdholland } else {
35016ca35587Sdholland clp->lc_uid = nd->nd_cred->cr_uid;
35026ca35587Sdholland clp->lc_gid = nd->nd_cred->cr_gid;
35036ca35587Sdholland }
35046ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
35056ca35587Sdholland clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
35066ca35587Sdholland error = nfsrv_getclientipaddr(nd, clp);
35076ca35587Sdholland if (error)
35086ca35587Sdholland goto nfsmout;
35096ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
35106ca35587Sdholland clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
35116ca35587Sdholland
35126ca35587Sdholland /*
35136ca35587Sdholland * nfsrv_setclient() does the actual work of adding it to the
35146ca35587Sdholland * client list. If there is no error, the structure has been
35156ca35587Sdholland * linked into the client list and clp should no longer be used
35166ca35587Sdholland * here. When an error is returned, it has not been linked in,
35176ca35587Sdholland * so it should be free'd.
35186ca35587Sdholland */
35196ca35587Sdholland nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
35206ca35587Sdholland if (nd->nd_repstat == NFSERR_CLIDINUSE) {
35216ca35587Sdholland if (clp->lc_flags & LCL_TCPCALLBACK)
35226ca35587Sdholland (void) nfsm_strtom(nd, "tcp", 3);
35236ca35587Sdholland else
35246ca35587Sdholland (void) nfsm_strtom(nd, "udp", 3);
35256ca35587Sdholland rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
35266ca35587Sdholland ucp = (u_char *)&rad->sin_addr.s_addr;
35276ca35587Sdholland ucp2 = (u_char *)&rad->sin_port;
352866873a20Schristos snprintf(addrbuf, sizeof(addrbuf), "%d.%d.%d.%d.%d.%d",
352966873a20Schristos ucp[0] & 0xff, ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
35306ca35587Sdholland ucp2[0] & 0xff, ucp2[1] & 0xff);
35316ca35587Sdholland (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
35326ca35587Sdholland }
35336ca35587Sdholland if (clp) {
35346ca35587Sdholland NFSSOCKADDRFREE(clp->lc_req.nr_nam);
35356ca35587Sdholland NFSFREEMUTEX(&clp->lc_req.nr_mtx);
35362d39560cSpgoyette free(clp->lc_stateid, M_NFSDCLIENT);
35372d39560cSpgoyette free(clp, M_NFSDCLIENT);
35386ca35587Sdholland }
35396ca35587Sdholland if (!nd->nd_repstat) {
35406ca35587Sdholland NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
35416ca35587Sdholland *tl++ = clientid.lval[0];
35426ca35587Sdholland *tl++ = clientid.lval[1];
35436ca35587Sdholland *tl++ = confirm.lval[0];
35446ca35587Sdholland *tl = confirm.lval[1];
35456ca35587Sdholland }
35466ca35587Sdholland
35476ca35587Sdholland out:
35486ca35587Sdholland NFSEXITCODE2(0, nd);
35496ca35587Sdholland return (0);
35506ca35587Sdholland nfsmout:
35516ca35587Sdholland if (clp) {
35526ca35587Sdholland NFSSOCKADDRFREE(clp->lc_req.nr_nam);
35536ca35587Sdholland NFSFREEMUTEX(&clp->lc_req.nr_mtx);
35542d39560cSpgoyette free(clp->lc_stateid, M_NFSDCLIENT);
35552d39560cSpgoyette free(clp, M_NFSDCLIENT);
35566ca35587Sdholland }
35576ca35587Sdholland NFSEXITCODE2(error, nd);
35586ca35587Sdholland return (error);
35596ca35587Sdholland }
35606ca35587Sdholland
35616ca35587Sdholland /*
35626ca35587Sdholland * nfsv4 set client id confirm service
35636ca35587Sdholland */
35646ca35587Sdholland APPLESTATIC int
nfsrvd_setclientidcfrm(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,NFSPROC_T * p,__unused struct nfsexstuff * exp)35656ca35587Sdholland nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
35666ca35587Sdholland __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
35676ca35587Sdholland __unused struct nfsexstuff *exp)
35686ca35587Sdholland {
35696ca35587Sdholland u_int32_t *tl;
35706ca35587Sdholland int error = 0;
35716ca35587Sdholland nfsquad_t clientid, confirm;
35726ca35587Sdholland
35732d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0) {
35742d39560cSpgoyette nd->nd_repstat = NFSERR_NOTSUPP;
35752d39560cSpgoyette goto nfsmout;
35762d39560cSpgoyette }
35776ca35587Sdholland if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
35786ca35587Sdholland nd->nd_repstat = NFSERR_WRONGSEC;
35796ca35587Sdholland goto nfsmout;
35806ca35587Sdholland }
35816ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
35826ca35587Sdholland clientid.lval[0] = *tl++;
35836ca35587Sdholland clientid.lval[1] = *tl++;
35846ca35587Sdholland confirm.lval[0] = *tl++;
35856ca35587Sdholland confirm.lval[1] = *tl;
35866ca35587Sdholland
35876ca35587Sdholland /*
35886ca35587Sdholland * nfsrv_getclient() searches the client list for a match and
35896ca35587Sdholland * returns the appropriate NFSERR status.
35906ca35587Sdholland */
35916ca35587Sdholland nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
35922d39560cSpgoyette NULL, NULL, confirm, 0, nd, p);
35936ca35587Sdholland nfsmout:
35946ca35587Sdholland NFSEXITCODE2(error, nd);
35956ca35587Sdholland return (error);
35966ca35587Sdholland }
35976ca35587Sdholland
35986ca35587Sdholland /*
35996ca35587Sdholland * nfsv4 verify service
36006ca35587Sdholland */
36016ca35587Sdholland APPLESTATIC int
nfsrvd_verify(struct nfsrv_descript * nd,int isdgram,vnode_t vp,NFSPROC_T * p,__unused struct nfsexstuff * exp)36026ca35587Sdholland nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
36036ca35587Sdholland vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
36046ca35587Sdholland {
36056ca35587Sdholland int error = 0, ret, fhsize = NFSX_MYFH;
36066ca35587Sdholland struct nfsvattr nva;
36076ca35587Sdholland struct statfs sf;
36086ca35587Sdholland struct nfsfsinfo fs;
36096ca35587Sdholland fhandle_t fh;
36106ca35587Sdholland
36116ca35587Sdholland nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
36126ca35587Sdholland if (!nd->nd_repstat)
36136ca35587Sdholland nd->nd_repstat = nfsvno_statfs(vp, &sf);
36146ca35587Sdholland if (!nd->nd_repstat)
36156ca35587Sdholland nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
36166ca35587Sdholland if (!nd->nd_repstat) {
36176ca35587Sdholland nfsvno_getfs(&fs, isdgram);
36186ca35587Sdholland error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
36196ca35587Sdholland &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
36206ca35587Sdholland if (!error) {
36216ca35587Sdholland if (nd->nd_procnum == NFSV4OP_NVERIFY) {
36226ca35587Sdholland if (ret == 0)
36236ca35587Sdholland nd->nd_repstat = NFSERR_SAME;
36246ca35587Sdholland else if (ret != NFSERR_NOTSAME)
36256ca35587Sdholland nd->nd_repstat = ret;
36266ca35587Sdholland } else if (ret)
36276ca35587Sdholland nd->nd_repstat = ret;
36286ca35587Sdholland }
36296ca35587Sdholland }
36306ca35587Sdholland vput(vp);
36316ca35587Sdholland NFSEXITCODE2(error, nd);
36326ca35587Sdholland return (error);
36336ca35587Sdholland }
36346ca35587Sdholland
36356ca35587Sdholland /*
36366ca35587Sdholland * nfs openattr rpc
36376ca35587Sdholland */
36386ca35587Sdholland APPLESTATIC int
nfsrvd_openattr(struct nfsrv_descript * nd,__unused int isdgram,vnode_t dp,__unused vnode_t * vpp,__unused fhandle_t * fhp,__unused NFSPROC_T * p,__unused struct nfsexstuff * exp)36396ca35587Sdholland nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
36406ca35587Sdholland vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
36416ca35587Sdholland __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
36426ca35587Sdholland {
36436ca35587Sdholland u_int32_t *tl;
36446ca35587Sdholland int error = 0, createdir;
36456ca35587Sdholland
36466ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
36476ca35587Sdholland createdir = fxdr_unsigned(int, *tl);
36486ca35587Sdholland nd->nd_repstat = NFSERR_NOTSUPP;
36496ca35587Sdholland nfsmout:
36506ca35587Sdholland vrele(dp);
36516ca35587Sdholland NFSEXITCODE2(error, nd);
36526ca35587Sdholland return (error);
36536ca35587Sdholland }
36546ca35587Sdholland
36556ca35587Sdholland /*
36566ca35587Sdholland * nfsv4 release lock owner service
36576ca35587Sdholland */
36586ca35587Sdholland APPLESTATIC int
nfsrvd_releaselckown(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,NFSPROC_T * p,__unused struct nfsexstuff * exp)36596ca35587Sdholland nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
36606ca35587Sdholland __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
36616ca35587Sdholland {
36626ca35587Sdholland u_int32_t *tl;
36636ca35587Sdholland struct nfsstate *stp = NULL;
36646ca35587Sdholland int error = 0, len;
36656ca35587Sdholland nfsquad_t clientid;
36666ca35587Sdholland
36672d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0) {
36682d39560cSpgoyette nd->nd_repstat = NFSERR_NOTSUPP;
36692d39560cSpgoyette goto nfsmout;
36702d39560cSpgoyette }
36716ca35587Sdholland if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
36726ca35587Sdholland nd->nd_repstat = NFSERR_WRONGSEC;
36736ca35587Sdholland goto nfsmout;
36746ca35587Sdholland }
36756ca35587Sdholland NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
36766ca35587Sdholland len = fxdr_unsigned(int, *(tl + 2));
36776ca35587Sdholland if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
36786ca35587Sdholland nd->nd_repstat = NFSERR_BADXDR;
36796ca35587Sdholland goto nfsmout;
36806ca35587Sdholland }
36816ca35587Sdholland MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
36826ca35587Sdholland M_NFSDSTATE, M_WAITOK);
36836ca35587Sdholland stp->ls_ownerlen = len;
36846ca35587Sdholland stp->ls_op = NULL;
36856ca35587Sdholland stp->ls_flags = NFSLCK_RELEASE;
36866ca35587Sdholland stp->ls_uid = nd->nd_cred->cr_uid;
36876ca35587Sdholland clientid.lval[0] = *tl++;
36886ca35587Sdholland clientid.lval[1] = *tl;
36892d39560cSpgoyette if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
36902d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
36912d39560cSpgoyette clientid.qval = nd->nd_clientid.qval;
36922d39560cSpgoyette else if (nd->nd_clientid.qval != clientid.qval)
36932d39560cSpgoyette printf("EEK14 multiple clids\n");
36946ca35587Sdholland } else {
36952d39560cSpgoyette if ((nd->nd_flag & ND_NFSV41) != 0)
36962d39560cSpgoyette printf("EEK! no clientid from session\n");
36976ca35587Sdholland nd->nd_flag |= ND_IMPLIEDCLID;
36986ca35587Sdholland nd->nd_clientid.qval = clientid.qval;
36996ca35587Sdholland }
37006ca35587Sdholland error = nfsrv_mtostr(nd, stp->ls_owner, len);
37016ca35587Sdholland if (error)
37026ca35587Sdholland goto nfsmout;
37036ca35587Sdholland nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
37046ca35587Sdholland FREE((caddr_t)stp, M_NFSDSTATE);
37056ca35587Sdholland
37066ca35587Sdholland NFSEXITCODE2(0, nd);
37076ca35587Sdholland return (0);
37086ca35587Sdholland nfsmout:
37096ca35587Sdholland if (stp)
37106ca35587Sdholland free((caddr_t)stp, M_NFSDSTATE);
37116ca35587Sdholland NFSEXITCODE2(error, nd);
37126ca35587Sdholland return (error);
37136ca35587Sdholland }
37142d39560cSpgoyette
37152d39560cSpgoyette /*
37162d39560cSpgoyette * nfsv4 exchange_id service
37172d39560cSpgoyette */
37182d39560cSpgoyette APPLESTATIC int
nfsrvd_exchangeid(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,NFSPROC_T * p,__unused struct nfsexstuff * exp)37192d39560cSpgoyette nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
37202d39560cSpgoyette __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
37212d39560cSpgoyette {
37222d39560cSpgoyette uint32_t *tl;
37232d39560cSpgoyette int error = 0, i, idlen;
37242d39560cSpgoyette struct nfsclient *clp = NULL;
37252d39560cSpgoyette nfsquad_t clientid, confirm;
37262d39560cSpgoyette uint8_t *verf;
37272d39560cSpgoyette uint32_t sp4type, v41flags;
37282d39560cSpgoyette uint64_t owner_minor;
37292d39560cSpgoyette struct timespec verstime;
37302d39560cSpgoyette
37312d39560cSpgoyette if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
37322d39560cSpgoyette nd->nd_repstat = NFSERR_WRONGSEC;
37332d39560cSpgoyette goto nfsmout;
37342d39560cSpgoyette }
37352d39560cSpgoyette NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
37362d39560cSpgoyette verf = (uint8_t *)tl;
37372d39560cSpgoyette tl += (NFSX_VERF / NFSX_UNSIGNED);
37382d39560cSpgoyette i = fxdr_unsigned(int, *tl);
37392d39560cSpgoyette if (i > NFSV4_OPAQUELIMIT || i <= 0) {
37402d39560cSpgoyette nd->nd_repstat = NFSERR_BADXDR;
37412d39560cSpgoyette goto nfsmout;
37422d39560cSpgoyette }
37432d39560cSpgoyette idlen = i;
37442d39560cSpgoyette if (nd->nd_flag & ND_GSS)
37452d39560cSpgoyette i += nd->nd_princlen;
37462d39560cSpgoyette clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
37472d39560cSpgoyette M_ZERO);
37482d39560cSpgoyette clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
37492d39560cSpgoyette nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
37502d39560cSpgoyette NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
37512d39560cSpgoyette NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
37522d39560cSpgoyette NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
37532d39560cSpgoyette clp->lc_req.nr_cred = NULL;
37542d39560cSpgoyette NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
37552d39560cSpgoyette clp->lc_idlen = idlen;
37562d39560cSpgoyette error = nfsrv_mtostr(nd, clp->lc_id, idlen);
37572d39560cSpgoyette if (error != 0)
37582d39560cSpgoyette goto nfsmout;
37592d39560cSpgoyette if ((nd->nd_flag & ND_GSS) != 0) {
37602d39560cSpgoyette clp->lc_flags = LCL_GSS | LCL_NFSV41;
37612d39560cSpgoyette if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
37622d39560cSpgoyette clp->lc_flags |= LCL_GSSINTEGRITY;
37632d39560cSpgoyette else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
37642d39560cSpgoyette clp->lc_flags |= LCL_GSSPRIVACY;
37652d39560cSpgoyette } else
37662d39560cSpgoyette clp->lc_flags = LCL_NFSV41;
37672d39560cSpgoyette if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
37682d39560cSpgoyette clp->lc_flags |= LCL_NAME;
37692d39560cSpgoyette clp->lc_namelen = nd->nd_princlen;
37702d39560cSpgoyette clp->lc_name = &clp->lc_id[idlen];
37712d39560cSpgoyette NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
37722d39560cSpgoyette } else {
37732d39560cSpgoyette clp->lc_uid = nd->nd_cred->cr_uid;
37742d39560cSpgoyette clp->lc_gid = nd->nd_cred->cr_gid;
37752d39560cSpgoyette }
37762d39560cSpgoyette NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
37772d39560cSpgoyette v41flags = fxdr_unsigned(uint32_t, *tl++);
37782d39560cSpgoyette if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
37792d39560cSpgoyette NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
37802d39560cSpgoyette NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
37812d39560cSpgoyette nd->nd_repstat = NFSERR_INVAL;
37822d39560cSpgoyette goto nfsmout;
37832d39560cSpgoyette }
37842d39560cSpgoyette if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
37852d39560cSpgoyette confirm.lval[1] = 1;
37862d39560cSpgoyette else
37872d39560cSpgoyette confirm.lval[1] = 0;
37882d39560cSpgoyette v41flags = NFSV4EXCH_USENONPNFS;
37892d39560cSpgoyette sp4type = fxdr_unsigned(uint32_t, *tl);
37902d39560cSpgoyette if (sp4type != NFSV4EXCH_SP4NONE) {
37912d39560cSpgoyette nd->nd_repstat = NFSERR_NOTSUPP;
37922d39560cSpgoyette goto nfsmout;
37932d39560cSpgoyette }
37942d39560cSpgoyette
37952d39560cSpgoyette /*
37962d39560cSpgoyette * nfsrv_setclient() does the actual work of adding it to the
37972d39560cSpgoyette * client list. If there is no error, the structure has been
37982d39560cSpgoyette * linked into the client list and clp should no longer be used
37992d39560cSpgoyette * here. When an error is returned, it has not been linked in,
38002d39560cSpgoyette * so it should be free'd.
38012d39560cSpgoyette */
38022d39560cSpgoyette nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
38032d39560cSpgoyette if (clp != NULL) {
38042d39560cSpgoyette NFSSOCKADDRFREE(clp->lc_req.nr_nam);
38052d39560cSpgoyette NFSFREEMUTEX(&clp->lc_req.nr_mtx);
38062d39560cSpgoyette free(clp->lc_stateid, M_NFSDCLIENT);
38072d39560cSpgoyette free(clp, M_NFSDCLIENT);
38082d39560cSpgoyette }
38092d39560cSpgoyette if (nd->nd_repstat == 0) {
38102d39560cSpgoyette if (confirm.lval[1] != 0)
38112d39560cSpgoyette v41flags |= NFSV4EXCH_CONFIRMEDR;
38122d39560cSpgoyette NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
38132d39560cSpgoyette *tl++ = clientid.lval[0]; /* ClientID */
38142d39560cSpgoyette *tl++ = clientid.lval[1];
38152d39560cSpgoyette *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */
38162d39560cSpgoyette *tl++ = txdr_unsigned(v41flags); /* Exch flags */
38172d39560cSpgoyette *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */
38182d39560cSpgoyette owner_minor = 0; /* Owner */
38192d39560cSpgoyette txdr_hyper(owner_minor, tl); /* Minor */
38202d39560cSpgoyette (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid,
38212d39560cSpgoyette strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */
38222d39560cSpgoyette NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
38232d39560cSpgoyette *tl++ = txdr_unsigned(NFSX_UNSIGNED);
38242d39560cSpgoyette *tl++ = time_uptime; /* Make scope a unique value. */
38252d39560cSpgoyette *tl = txdr_unsigned(1);
38262d39560cSpgoyette (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
38272d39560cSpgoyette (void)nfsm_strtom(nd, version, strlen(version));
38282d39560cSpgoyette NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
38292d39560cSpgoyette verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
38302d39560cSpgoyette verstime.tv_nsec = 0;
38312d39560cSpgoyette txdr_nfsv4time(&verstime, tl);
38322d39560cSpgoyette }
38332d39560cSpgoyette NFSEXITCODE2(0, nd);
38342d39560cSpgoyette return (0);
38352d39560cSpgoyette nfsmout:
38362d39560cSpgoyette if (clp != NULL) {
38372d39560cSpgoyette NFSSOCKADDRFREE(clp->lc_req.nr_nam);
38382d39560cSpgoyette NFSFREEMUTEX(&clp->lc_req.nr_mtx);
38392d39560cSpgoyette free(clp->lc_stateid, M_NFSDCLIENT);
38402d39560cSpgoyette free(clp, M_NFSDCLIENT);
38412d39560cSpgoyette }
38422d39560cSpgoyette NFSEXITCODE2(error, nd);
38432d39560cSpgoyette return (error);
38442d39560cSpgoyette }
38452d39560cSpgoyette
38462d39560cSpgoyette /*
38472d39560cSpgoyette * nfsv4 create session service
38482d39560cSpgoyette */
38492d39560cSpgoyette APPLESTATIC int
nfsrvd_createsession(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,NFSPROC_T * p,__unused struct nfsexstuff * exp)38502d39560cSpgoyette nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
38512d39560cSpgoyette __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
38522d39560cSpgoyette {
38532d39560cSpgoyette uint32_t *tl;
38542d39560cSpgoyette int error = 0;
38552d39560cSpgoyette nfsquad_t clientid, confirm;
38562d39560cSpgoyette struct nfsdsession *sep = NULL;
38572d39560cSpgoyette uint32_t rdmacnt;
38582d39560cSpgoyette
38592d39560cSpgoyette if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
38602d39560cSpgoyette nd->nd_repstat = NFSERR_WRONGSEC;
38612d39560cSpgoyette goto nfsmout;
38622d39560cSpgoyette }
38632d39560cSpgoyette sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
38642d39560cSpgoyette M_NFSDSESSION, M_WAITOK | M_ZERO);
38652d39560cSpgoyette sep->sess_refcnt = 1;
38662d39560cSpgoyette mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
38672d39560cSpgoyette NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
38682d39560cSpgoyette clientid.lval[0] = *tl++;
38692d39560cSpgoyette clientid.lval[1] = *tl++;
38702d39560cSpgoyette confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
38712d39560cSpgoyette sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
38722d39560cSpgoyette /* Persistent sessions and RDMA are not supported. */
38732d39560cSpgoyette sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
38742d39560cSpgoyette
38752d39560cSpgoyette /* Fore channel attributes. */
38762d39560cSpgoyette NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
38772d39560cSpgoyette tl++; /* Header pad always 0. */
38782d39560cSpgoyette sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
38792d39560cSpgoyette sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
38802d39560cSpgoyette sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
38812d39560cSpgoyette sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
38822d39560cSpgoyette sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
38832d39560cSpgoyette if (sep->sess_maxslots > NFSV4_SLOTS)
38842d39560cSpgoyette sep->sess_maxslots = NFSV4_SLOTS;
38852d39560cSpgoyette rdmacnt = fxdr_unsigned(uint32_t, *tl);
38862d39560cSpgoyette if (rdmacnt > 1) {
38872d39560cSpgoyette nd->nd_repstat = NFSERR_BADXDR;
38882d39560cSpgoyette goto nfsmout;
38892d39560cSpgoyette } else if (rdmacnt == 1)
38902d39560cSpgoyette NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
38912d39560cSpgoyette
38922d39560cSpgoyette /* Back channel attributes. */
38932d39560cSpgoyette NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
38942d39560cSpgoyette tl++; /* Header pad always 0. */
38952d39560cSpgoyette sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
38962d39560cSpgoyette sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
38972d39560cSpgoyette sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
38982d39560cSpgoyette sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
38992d39560cSpgoyette sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
39002d39560cSpgoyette rdmacnt = fxdr_unsigned(uint32_t, *tl);
39012d39560cSpgoyette if (rdmacnt > 1) {
39022d39560cSpgoyette nd->nd_repstat = NFSERR_BADXDR;
39032d39560cSpgoyette goto nfsmout;
39042d39560cSpgoyette } else if (rdmacnt == 1)
39052d39560cSpgoyette NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
39062d39560cSpgoyette
39072d39560cSpgoyette NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
39082d39560cSpgoyette sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
39092d39560cSpgoyette
39102d39560cSpgoyette /*
39112d39560cSpgoyette * nfsrv_getclient() searches the client list for a match and
39122d39560cSpgoyette * returns the appropriate NFSERR status.
39132d39560cSpgoyette */
39142d39560cSpgoyette nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
39152d39560cSpgoyette NULL, sep, confirm, sep->sess_cbprogram, nd, p);
39162d39560cSpgoyette if (nd->nd_repstat == 0) {
39172d39560cSpgoyette NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
39182d39560cSpgoyette NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
39192d39560cSpgoyette NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
39202d39560cSpgoyette *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */
39212d39560cSpgoyette *tl++ = txdr_unsigned(sep->sess_crflags);
39222d39560cSpgoyette
39232d39560cSpgoyette /* Fore channel attributes. */
39242d39560cSpgoyette *tl++ = 0;
39252d39560cSpgoyette *tl++ = txdr_unsigned(sep->sess_maxreq);
39262d39560cSpgoyette *tl++ = txdr_unsigned(sep->sess_maxresp);
39272d39560cSpgoyette *tl++ = txdr_unsigned(sep->sess_maxrespcached);
39282d39560cSpgoyette *tl++ = txdr_unsigned(sep->sess_maxops);
39292d39560cSpgoyette *tl++ = txdr_unsigned(sep->sess_maxslots);
39302d39560cSpgoyette *tl++ = txdr_unsigned(1);
39312d39560cSpgoyette *tl++ = txdr_unsigned(0); /* No RDMA. */
39322d39560cSpgoyette
39332d39560cSpgoyette /* Back channel attributes. */
39342d39560cSpgoyette *tl++ = 0;
39352d39560cSpgoyette *tl++ = txdr_unsigned(sep->sess_cbmaxreq);
39362d39560cSpgoyette *tl++ = txdr_unsigned(sep->sess_cbmaxresp);
39372d39560cSpgoyette *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
39382d39560cSpgoyette *tl++ = txdr_unsigned(sep->sess_cbmaxops);
39392d39560cSpgoyette *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
39402d39560cSpgoyette *tl++ = txdr_unsigned(1);
39412d39560cSpgoyette *tl = txdr_unsigned(0); /* No RDMA. */
39422d39560cSpgoyette }
39432d39560cSpgoyette nfsmout:
39442d39560cSpgoyette if (nd->nd_repstat != 0 && sep != NULL)
39452d39560cSpgoyette free(sep, M_NFSDSESSION);
39462d39560cSpgoyette NFSEXITCODE2(error, nd);
39472d39560cSpgoyette return (error);
39482d39560cSpgoyette }
39492d39560cSpgoyette
39502d39560cSpgoyette /*
39512d39560cSpgoyette * nfsv4 sequence service
39522d39560cSpgoyette */
39532d39560cSpgoyette APPLESTATIC int
nfsrvd_sequence(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused NFSPROC_T * p,__unused struct nfsexstuff * exp)39542d39560cSpgoyette nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
39552d39560cSpgoyette __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
39562d39560cSpgoyette {
39572d39560cSpgoyette uint32_t *tl;
39582d39560cSpgoyette uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
39592d39560cSpgoyette int cache_this, error = 0;
39602d39560cSpgoyette
39612d39560cSpgoyette if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
39622d39560cSpgoyette nd->nd_repstat = NFSERR_WRONGSEC;
39632d39560cSpgoyette goto nfsmout;
39642d39560cSpgoyette }
39652d39560cSpgoyette NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
39662d39560cSpgoyette NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
39672d39560cSpgoyette NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
39682d39560cSpgoyette sequenceid = fxdr_unsigned(uint32_t, *tl++);
39692d39560cSpgoyette nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
39702d39560cSpgoyette highest_slotid = fxdr_unsigned(uint32_t, *tl++);
39712d39560cSpgoyette if (*tl == newnfs_true)
39722d39560cSpgoyette cache_this = 1;
39732d39560cSpgoyette else
39742d39560cSpgoyette cache_this = 0;
39752d39560cSpgoyette nd->nd_flag |= ND_HASSEQUENCE;
39762d39560cSpgoyette nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
39772d39560cSpgoyette &target_highest_slotid, cache_this, &sflags, p);
39782d39560cSpgoyette if (nd->nd_repstat == 0) {
39792d39560cSpgoyette NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
39802d39560cSpgoyette NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
39812d39560cSpgoyette NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
39822d39560cSpgoyette *tl++ = txdr_unsigned(sequenceid);
39832d39560cSpgoyette *tl++ = txdr_unsigned(nd->nd_slotid);
39842d39560cSpgoyette *tl++ = txdr_unsigned(highest_slotid);
39852d39560cSpgoyette *tl++ = txdr_unsigned(target_highest_slotid);
39862d39560cSpgoyette *tl = txdr_unsigned(sflags);
39872d39560cSpgoyette }
39882d39560cSpgoyette nfsmout:
39892d39560cSpgoyette NFSEXITCODE2(error, nd);
39902d39560cSpgoyette return (error);
39912d39560cSpgoyette }
39922d39560cSpgoyette
39932d39560cSpgoyette /*
39942d39560cSpgoyette * nfsv4 reclaim complete service
39952d39560cSpgoyette */
39962d39560cSpgoyette APPLESTATIC int
nfsrvd_reclaimcomplete(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused NFSPROC_T * p,__unused struct nfsexstuff * exp)39972d39560cSpgoyette nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
39982d39560cSpgoyette __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
39992d39560cSpgoyette {
40002d39560cSpgoyette uint32_t *tl;
40012d39560cSpgoyette int error = 0;
40022d39560cSpgoyette
40032d39560cSpgoyette if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
40042d39560cSpgoyette nd->nd_repstat = NFSERR_WRONGSEC;
40052d39560cSpgoyette goto nfsmout;
40062d39560cSpgoyette }
40072d39560cSpgoyette NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
40082d39560cSpgoyette if (*tl == newnfs_true)
40092d39560cSpgoyette nd->nd_repstat = NFSERR_NOTSUPP;
40102d39560cSpgoyette else
40112d39560cSpgoyette nd->nd_repstat = nfsrv_checkreclaimcomplete(nd);
40122d39560cSpgoyette nfsmout:
40132d39560cSpgoyette NFSEXITCODE2(error, nd);
40142d39560cSpgoyette return (error);
40152d39560cSpgoyette }
40162d39560cSpgoyette
40172d39560cSpgoyette /*
40182d39560cSpgoyette * nfsv4 destroy clientid service
40192d39560cSpgoyette */
40202d39560cSpgoyette APPLESTATIC int
nfsrvd_destroyclientid(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,NFSPROC_T * p,__unused struct nfsexstuff * exp)40212d39560cSpgoyette nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
40222d39560cSpgoyette __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
40232d39560cSpgoyette {
40242d39560cSpgoyette uint32_t *tl;
40252d39560cSpgoyette nfsquad_t clientid;
40262d39560cSpgoyette int error = 0;
40272d39560cSpgoyette
40282d39560cSpgoyette if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
40292d39560cSpgoyette nd->nd_repstat = NFSERR_WRONGSEC;
40302d39560cSpgoyette goto nfsmout;
40312d39560cSpgoyette }
40322d39560cSpgoyette NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
40332d39560cSpgoyette clientid.lval[0] = *tl++;
40342d39560cSpgoyette clientid.lval[1] = *tl;
40352d39560cSpgoyette nd->nd_repstat = nfsrv_destroyclient(clientid, p);
40362d39560cSpgoyette nfsmout:
40372d39560cSpgoyette NFSEXITCODE2(error, nd);
40382d39560cSpgoyette return (error);
40392d39560cSpgoyette }
40402d39560cSpgoyette
40412d39560cSpgoyette /*
40422d39560cSpgoyette * nfsv4 destroy session service
40432d39560cSpgoyette */
40442d39560cSpgoyette APPLESTATIC int
nfsrvd_destroysession(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused NFSPROC_T * p,__unused struct nfsexstuff * exp)40452d39560cSpgoyette nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
40462d39560cSpgoyette __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
40472d39560cSpgoyette {
40482d39560cSpgoyette uint8_t *cp, sessid[NFSX_V4SESSIONID];
40492d39560cSpgoyette int error = 0;
40502d39560cSpgoyette
40512d39560cSpgoyette if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
40522d39560cSpgoyette nd->nd_repstat = NFSERR_WRONGSEC;
40532d39560cSpgoyette goto nfsmout;
40542d39560cSpgoyette }
40552d39560cSpgoyette NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
40562d39560cSpgoyette NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
40572d39560cSpgoyette nd->nd_repstat = nfsrv_destroysession(nd, sessid);
40582d39560cSpgoyette nfsmout:
40592d39560cSpgoyette NFSEXITCODE2(error, nd);
40602d39560cSpgoyette return (error);
40612d39560cSpgoyette }
40622d39560cSpgoyette
40632d39560cSpgoyette /*
40642d39560cSpgoyette * nfsv4 free stateid service
40652d39560cSpgoyette */
40662d39560cSpgoyette APPLESTATIC int
nfsrvd_freestateid(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,NFSPROC_T * p,__unused struct nfsexstuff * exp)40672d39560cSpgoyette nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
40682d39560cSpgoyette __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
40692d39560cSpgoyette {
40702d39560cSpgoyette uint32_t *tl;
40712d39560cSpgoyette nfsv4stateid_t stateid;
40722d39560cSpgoyette int error = 0;
40732d39560cSpgoyette
40742d39560cSpgoyette if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
40752d39560cSpgoyette nd->nd_repstat = NFSERR_WRONGSEC;
40762d39560cSpgoyette goto nfsmout;
40772d39560cSpgoyette }
40782d39560cSpgoyette NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
40792d39560cSpgoyette stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
40802d39560cSpgoyette NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
40812d39560cSpgoyette nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
40822d39560cSpgoyette nfsmout:
40832d39560cSpgoyette NFSEXITCODE2(error, nd);
40842d39560cSpgoyette return (error);
40852d39560cSpgoyette }
40862d39560cSpgoyette
40872d39560cSpgoyette /*
40882d39560cSpgoyette * nfsv4 service not supported
40892d39560cSpgoyette */
40902d39560cSpgoyette APPLESTATIC int
nfsrvd_notsupp(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused NFSPROC_T * p,__unused struct nfsexstuff * exp)40912d39560cSpgoyette nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
40922d39560cSpgoyette __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
40932d39560cSpgoyette {
40942d39560cSpgoyette
40952d39560cSpgoyette nd->nd_repstat = NFSERR_NOTSUPP;
40962d39560cSpgoyette NFSEXITCODE2(0, nd);
40972d39560cSpgoyette return (0);
40982d39560cSpgoyette }
40992d39560cSpgoyette
4100