19ec7b004SRick Macklem /*- 29ec7b004SRick Macklem * Copyright (c) 1989, 1993 39ec7b004SRick Macklem * The Regents of the University of California. All rights reserved. 49ec7b004SRick Macklem * 59ec7b004SRick Macklem * This code is derived from software contributed to Berkeley by 69ec7b004SRick Macklem * Rick Macklem at The University of Guelph. 79ec7b004SRick Macklem * 89ec7b004SRick Macklem * Redistribution and use in source and binary forms, with or without 99ec7b004SRick Macklem * modification, are permitted provided that the following conditions 109ec7b004SRick Macklem * are met: 119ec7b004SRick Macklem * 1. Redistributions of source code must retain the above copyright 129ec7b004SRick Macklem * notice, this list of conditions and the following disclaimer. 139ec7b004SRick Macklem * 2. Redistributions in binary form must reproduce the above copyright 149ec7b004SRick Macklem * notice, this list of conditions and the following disclaimer in the 159ec7b004SRick Macklem * documentation and/or other materials provided with the distribution. 169ec7b004SRick Macklem * 4. Neither the name of the University nor the names of its contributors 179ec7b004SRick Macklem * may be used to endorse or promote products derived from this software 189ec7b004SRick Macklem * without specific prior written permission. 199ec7b004SRick Macklem * 209ec7b004SRick Macklem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 219ec7b004SRick Macklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 229ec7b004SRick Macklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 239ec7b004SRick Macklem * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 249ec7b004SRick Macklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 259ec7b004SRick Macklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 269ec7b004SRick Macklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 279ec7b004SRick Macklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 289ec7b004SRick Macklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 299ec7b004SRick Macklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 309ec7b004SRick Macklem * SUCH DAMAGE. 319ec7b004SRick Macklem * 329ec7b004SRick Macklem */ 339ec7b004SRick Macklem 349ec7b004SRick Macklem #include <sys/cdefs.h> 359ec7b004SRick Macklem __FBSDID("$FreeBSD$"); 369ec7b004SRick Macklem 379ec7b004SRick Macklem /* 389ec7b004SRick Macklem * nfs version 2, 3 and 4 server calls to vnode ops 399ec7b004SRick Macklem * - these routines generally have 3 phases 409ec7b004SRick Macklem * 1 - break down and validate rpc request in mbuf list 419ec7b004SRick Macklem * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX() 429ec7b004SRick Macklem * function in nfsd_port.c 439ec7b004SRick Macklem * 3 - build the rpc reply in an mbuf list 449ec7b004SRick Macklem * For nfsv4, these functions are called for each Op within the Compound RPC. 459ec7b004SRick Macklem */ 469ec7b004SRick Macklem 479ec7b004SRick Macklem #ifndef APPLEKEXT 489ec7b004SRick Macklem #include <fs/nfs/nfsport.h> 499ec7b004SRick Macklem 509ec7b004SRick Macklem /* Global vars */ 519ec7b004SRick Macklem extern u_int32_t newnfs_false, newnfs_true; 529ec7b004SRick Macklem extern enum vtype nv34tov_type[8]; 539ec7b004SRick Macklem extern struct timeval nfsboottime; 54c9aad40fSRick Macklem extern int nfs_rootfhset; 5507c0c166SRick Macklem extern int nfsrv_enable_crossmntpt; 569ec7b004SRick Macklem #endif /* !APPLEKEXT */ 579ec7b004SRick Macklem 58e4558aacSXin LI static int nfs_async = 0; 59e4558aacSXin LI SYSCTL_DECL(_vfs_nfsd); 60e4558aacSXin LI SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0, 61e4558aacSXin LI "Tell client that writes were synced even though they were not"); 62e4558aacSXin LI 639ec7b004SRick Macklem /* 649ec7b004SRick Macklem * This list defines the GSS mechanisms supported. 659ec7b004SRick Macklem * (Don't ask me how you get these strings from the RFC stuff like 669ec7b004SRick Macklem * iso(1), org(3)... but someone did it, so I don't need to know.) 679ec7b004SRick Macklem */ 689ec7b004SRick Macklem static struct nfsgss_mechlist nfsgss_mechlist[] = { 699ec7b004SRick Macklem { 9, "\052\206\110\206\367\022\001\002\002", 11 }, 709ec7b004SRick Macklem { 0, "", 0 }, 719ec7b004SRick Macklem }; 729ec7b004SRick Macklem 739ec7b004SRick Macklem /* local functions */ 749ec7b004SRick Macklem static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 759ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 769ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 779ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, 789ec7b004SRick Macklem NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 799ec7b004SRick Macklem int pathlen); 809ec7b004SRick Macklem static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 819ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 829ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 839ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 849ec7b004SRick Macklem NFSPROC_T *p, struct nfsexstuff *exp); 859ec7b004SRick Macklem 869ec7b004SRick Macklem /* 879ec7b004SRick Macklem * nfs access service (not a part of NFS V2) 889ec7b004SRick Macklem */ 899ec7b004SRick Macklem APPLESTATIC int 909ec7b004SRick Macklem nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram, 919ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 929ec7b004SRick Macklem { 939ec7b004SRick Macklem u_int32_t *tl; 949ec7b004SRick Macklem int getret, error = 0; 959ec7b004SRick Macklem struct nfsvattr nva; 969ec7b004SRick Macklem u_int32_t testmode, nfsmode, supported = 0; 978da45f2cSRick Macklem accmode_t deletebit; 989ec7b004SRick Macklem 999ec7b004SRick Macklem if (nd->nd_repstat) { 1009ec7b004SRick Macklem nfsrv_postopattr(nd, 1, &nva); 101a9285ae5SZack Kirsch goto out; 1029ec7b004SRick Macklem } 1039ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1049ec7b004SRick Macklem nfsmode = fxdr_unsigned(u_int32_t, *tl); 1059ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && 1069ec7b004SRick Macklem (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP | 1079ec7b004SRick Macklem NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE | 1089ec7b004SRick Macklem NFSACCESS_EXECUTE))) { 1099ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 1109ec7b004SRick Macklem vput(vp); 111a9285ae5SZack Kirsch goto out; 1129ec7b004SRick Macklem } 1139ec7b004SRick Macklem if (nfsmode & NFSACCESS_READ) { 1149ec7b004SRick Macklem supported |= NFSACCESS_READ; 1158da45f2cSRick Macklem if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, 1168da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1179ec7b004SRick Macklem nfsmode &= ~NFSACCESS_READ; 1189ec7b004SRick Macklem } 1199ec7b004SRick Macklem if (nfsmode & NFSACCESS_MODIFY) { 1209ec7b004SRick Macklem supported |= NFSACCESS_MODIFY; 1218da45f2cSRick Macklem if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, 1228da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1239ec7b004SRick Macklem nfsmode &= ~NFSACCESS_MODIFY; 1249ec7b004SRick Macklem } 1259ec7b004SRick Macklem if (nfsmode & NFSACCESS_EXTEND) { 1269ec7b004SRick Macklem supported |= NFSACCESS_EXTEND; 1278da45f2cSRick Macklem if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p, 1288da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1299ec7b004SRick Macklem nfsmode &= ~NFSACCESS_EXTEND; 1309ec7b004SRick Macklem } 1319ec7b004SRick Macklem if (nfsmode & NFSACCESS_DELETE) { 1329ec7b004SRick Macklem supported |= NFSACCESS_DELETE; 1338da45f2cSRick Macklem if (vp->v_type == VDIR) 1348da45f2cSRick Macklem deletebit = VDELETE_CHILD; 1358da45f2cSRick Macklem else 1368da45f2cSRick Macklem deletebit = VDELETE; 1378da45f2cSRick Macklem if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p, 1388da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1399ec7b004SRick Macklem nfsmode &= ~NFSACCESS_DELETE; 1409ec7b004SRick Macklem } 1419ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 1429ec7b004SRick Macklem testmode = NFSACCESS_LOOKUP; 1439ec7b004SRick Macklem else 1449ec7b004SRick Macklem testmode = NFSACCESS_EXECUTE; 1459ec7b004SRick Macklem if (nfsmode & testmode) { 1469ec7b004SRick Macklem supported |= (nfsmode & testmode); 1478da45f2cSRick Macklem if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p, 1488da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1499ec7b004SRick Macklem nfsmode &= ~testmode; 1509ec7b004SRick Macklem } 1519ec7b004SRick Macklem nfsmode &= supported; 1529ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 1530cf42b62SRick Macklem getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 1549ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 1559ec7b004SRick Macklem } 1569ec7b004SRick Macklem vput(vp); 1579ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 1589ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1599ec7b004SRick Macklem *tl++ = txdr_unsigned(supported); 1609ec7b004SRick Macklem } else 1619ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1629ec7b004SRick Macklem *tl = txdr_unsigned(nfsmode); 163a9285ae5SZack Kirsch 164a9285ae5SZack Kirsch out: 165a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 1669ec7b004SRick Macklem return (0); 1679ec7b004SRick Macklem nfsmout: 1689ec7b004SRick Macklem vput(vp); 169a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1709ec7b004SRick Macklem return (error); 1719ec7b004SRick Macklem } 1729ec7b004SRick Macklem 1739ec7b004SRick Macklem /* 1749ec7b004SRick Macklem * nfs getattr service 1759ec7b004SRick Macklem */ 1769ec7b004SRick Macklem APPLESTATIC int 1779ec7b004SRick Macklem nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram, 1789ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 1799ec7b004SRick Macklem { 1809ec7b004SRick Macklem struct nfsvattr nva; 1819ec7b004SRick Macklem fhandle_t fh; 182a09001a8SRick Macklem int at_root = 0, error = 0, supports_nfsv4acls; 1839ec7b004SRick Macklem struct nfsreferral *refp; 18453f476caSRick Macklem nfsattrbit_t attrbits, tmpbits; 18507c0c166SRick Macklem struct mount *mp; 18607c0c166SRick Macklem struct vnode *tvp = NULL; 18707c0c166SRick Macklem struct vattr va; 18807c0c166SRick Macklem uint64_t mounted_on_fileno = 0; 18953f476caSRick Macklem accmode_t accmode; 1909ec7b004SRick Macklem 1919ec7b004SRick Macklem if (nd->nd_repstat) 192a9285ae5SZack Kirsch goto out; 1939ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 1949ec7b004SRick Macklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 1959ec7b004SRick Macklem if (error) { 1969ec7b004SRick Macklem vput(vp); 197a9285ae5SZack Kirsch goto out; 1989ec7b004SRick Macklem } 1999ec7b004SRick Macklem 2009ec7b004SRick Macklem /* 2019ec7b004SRick Macklem * Check for a referral. 2029ec7b004SRick Macklem */ 2039ec7b004SRick Macklem refp = nfsv4root_getreferral(vp, NULL, 0); 2049ec7b004SRick Macklem if (refp != NULL) { 2059ec7b004SRick Macklem (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1, 2069ec7b004SRick Macklem &nd->nd_repstat); 2079ec7b004SRick Macklem vput(vp); 208a9285ae5SZack Kirsch goto out; 2099ec7b004SRick Macklem } 21053f476caSRick Macklem if (nd->nd_repstat == 0) { 21153f476caSRick Macklem accmode = 0; 21253f476caSRick Macklem NFSSET_ATTRBIT(&tmpbits, &attrbits); 21353f476caSRick Macklem if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) { 21453f476caSRick Macklem NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL); 21553f476caSRick Macklem accmode |= VREAD_ACL; 21653f476caSRick Macklem } 21753f476caSRick Macklem if (NFSNONZERO_ATTRBIT(&tmpbits)) 21853f476caSRick Macklem accmode |= VREAD_ATTRIBUTES; 21953f476caSRick Macklem if (accmode != 0) 22053f476caSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, accmode, 2218da45f2cSRick Macklem nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, 2228da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 2239ec7b004SRick Macklem } 22453f476caSRick Macklem } 2259ec7b004SRick Macklem if (!nd->nd_repstat) 2260cf42b62SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 2279ec7b004SRick Macklem if (!nd->nd_repstat) { 2289ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 2299ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE)) 2309ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 2319ec7b004SRick Macklem if (!nd->nd_repstat) 2329ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkgetattr(nd, vp, 2339ec7b004SRick Macklem &nva, &attrbits, nd->nd_cred, p); 23407c0c166SRick Macklem if (nd->nd_repstat == 0) { 235a09001a8SRick Macklem supports_nfsv4acls = nfs_supportsnfsv4acls(vp); 23607c0c166SRick Macklem mp = vp->v_mount; 23707c0c166SRick Macklem if (nfsrv_enable_crossmntpt != 0 && 23807c0c166SRick Macklem vp->v_type == VDIR && 23907c0c166SRick Macklem (vp->v_vflag & VV_ROOT) != 0 && 24007c0c166SRick Macklem vp != rootvnode) { 24107c0c166SRick Macklem tvp = mp->mnt_vnodecovered; 24207c0c166SRick Macklem VREF(tvp); 24307c0c166SRick Macklem at_root = 1; 24407c0c166SRick Macklem } else 24507c0c166SRick Macklem at_root = 0; 24607c0c166SRick Macklem vfs_ref(mp); 247a9989634SZack Kirsch NFSVOPUNLOCK(vp, 0); 24807c0c166SRick Macklem if (at_root != 0) { 24907c0c166SRick Macklem if ((nd->nd_repstat = 25098f234f3SZack Kirsch NFSVOPLOCK(tvp, LK_SHARED)) == 0) { 25107c0c166SRick Macklem nd->nd_repstat = VOP_GETATTR( 25207c0c166SRick Macklem tvp, &va, nd->nd_cred); 25307c0c166SRick Macklem vput(tvp); 25407c0c166SRick Macklem } else 25507c0c166SRick Macklem vrele(tvp); 25607c0c166SRick Macklem if (nd->nd_repstat == 0) 25707c0c166SRick Macklem mounted_on_fileno = (uint64_t) 25807c0c166SRick Macklem va.va_fileid; 25907c0c166SRick Macklem else 26007c0c166SRick Macklem at_root = 0; 26107c0c166SRick Macklem } 26207c0c166SRick Macklem if (nd->nd_repstat == 0) 26307c0c166SRick Macklem nd->nd_repstat = vfs_busy(mp, 0); 26407c0c166SRick Macklem vfs_rel(mp); 26507c0c166SRick Macklem if (nd->nd_repstat == 0) { 26607c0c166SRick Macklem (void)nfsvno_fillattr(nd, mp, vp, &nva, 26707c0c166SRick Macklem &fh, 0, &attrbits, nd->nd_cred, p, 268a09001a8SRick Macklem isdgram, 1, supports_nfsv4acls, 269a09001a8SRick Macklem at_root, mounted_on_fileno); 27007c0c166SRick Macklem vfs_unbusy(mp); 27107c0c166SRick Macklem } 2729ec7b004SRick Macklem vrele(vp); 27307c0c166SRick Macklem } else 27407c0c166SRick Macklem vput(vp); 2759ec7b004SRick Macklem } else { 2769ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 2779ec7b004SRick Macklem vput(vp); 2789ec7b004SRick Macklem } 2799ec7b004SRick Macklem } else { 2809ec7b004SRick Macklem vput(vp); 2819ec7b004SRick Macklem } 282a9285ae5SZack Kirsch 283a9285ae5SZack Kirsch out: 284a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 285a9285ae5SZack Kirsch return (error); 2869ec7b004SRick Macklem } 2879ec7b004SRick Macklem 2889ec7b004SRick Macklem /* 2899ec7b004SRick Macklem * nfs setattr service 2909ec7b004SRick Macklem */ 2919ec7b004SRick Macklem APPLESTATIC int 2929ec7b004SRick Macklem nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram, 2939ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2949ec7b004SRick Macklem { 2959ec7b004SRick Macklem struct nfsvattr nva, nva2; 2969ec7b004SRick Macklem u_int32_t *tl; 2979ec7b004SRick Macklem int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0; 2989ec7b004SRick Macklem struct timespec guard = { 0, 0 }; 2999ec7b004SRick Macklem nfsattrbit_t attrbits, retbits; 3009ec7b004SRick Macklem nfsv4stateid_t stateid; 3019ec7b004SRick Macklem NFSACL_T *aclp = NULL; 3029ec7b004SRick Macklem 3039ec7b004SRick Macklem if (nd->nd_repstat) { 3049ec7b004SRick Macklem nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 305a9285ae5SZack Kirsch goto out; 3069ec7b004SRick Macklem } 3079ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 308c3e22f83SRick Macklem aclp = acl_alloc(M_WAITOK); 3099ec7b004SRick Macklem aclp->acl_cnt = 0; 3109ec7b004SRick Macklem #endif 3119ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 3129ec7b004SRick Macklem NFSZERO_ATTRBIT(&retbits); 3139ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 3149ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3159ec7b004SRick Macklem stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3169ec7b004SRick Macklem NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 3179ec7b004SRick Macklem } 3189ec7b004SRick Macklem error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p); 3199ec7b004SRick Macklem if (error) 3209ec7b004SRick Macklem goto nfsmout; 3210cf42b62SRick Macklem preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1); 3229ec7b004SRick Macklem if (!nd->nd_repstat) 3239ec7b004SRick Macklem nd->nd_repstat = preat_ret; 3249ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 3259ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3269ec7b004SRick Macklem gcheck = fxdr_unsigned(int, *tl); 3279ec7b004SRick Macklem if (gcheck) { 3289ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3299ec7b004SRick Macklem fxdr_nfsv3time(tl, &guard); 3309ec7b004SRick Macklem } 3319ec7b004SRick Macklem if (!nd->nd_repstat && gcheck && 3329ec7b004SRick Macklem (nva2.na_ctime.tv_sec != guard.tv_sec || 3339ec7b004SRick Macklem nva2.na_ctime.tv_nsec != guard.tv_nsec)) 3349ec7b004SRick Macklem nd->nd_repstat = NFSERR_NOT_SYNC; 3359ec7b004SRick Macklem if (nd->nd_repstat) { 3369ec7b004SRick Macklem vput(vp); 3379ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 3389ec7b004SRick Macklem acl_free(aclp); 3399ec7b004SRick Macklem #endif 3409ec7b004SRick Macklem nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 341a9285ae5SZack Kirsch goto out; 3429ec7b004SRick Macklem } 3439ec7b004SRick Macklem } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) 3449ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 3459ec7b004SRick Macklem 3469ec7b004SRick Macklem /* 3479ec7b004SRick Macklem * Now that we have all the fields, lets do it. 3489ec7b004SRick Macklem * If the size is being changed write access is required, otherwise 3499ec7b004SRick Macklem * just check for a read only file system. 3509ec7b004SRick Macklem */ 3519ec7b004SRick Macklem if (!nd->nd_repstat) { 3529ec7b004SRick Macklem if (NFSVNO_NOTSETSIZE(&nva)) { 3539ec7b004SRick Macklem if (NFSVNO_EXRDONLY(exp) || 3549ec7b004SRick Macklem (vfs_flags(vnode_mount(vp)) & MNT_RDONLY)) 3559ec7b004SRick Macklem nd->nd_repstat = EROFS; 3569ec7b004SRick Macklem } else { 3579ec7b004SRick Macklem if (vnode_vtype(vp) != VREG) 3589ec7b004SRick Macklem nd->nd_repstat = EINVAL; 3599ec7b004SRick Macklem else if (nva2.na_uid != nd->nd_cred->cr_uid || 3609ec7b004SRick Macklem NFSVNO_EXSTRICTACCESS(exp)) 3619ec7b004SRick Macklem nd->nd_repstat = nfsvno_accchk(vp, 3628da45f2cSRick Macklem VWRITE, nd->nd_cred, exp, p, 3638da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, 3648da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 3659ec7b004SRick Macklem } 3669ec7b004SRick Macklem } 3679ec7b004SRick Macklem if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) 3689ec7b004SRick Macklem nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid, 3699ec7b004SRick Macklem &nva, &attrbits, exp, p); 3709ec7b004SRick Macklem 3719ec7b004SRick Macklem if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 3729ec7b004SRick Macklem /* 3739ec7b004SRick Macklem * For V4, try setting the attrbutes in sets, so that the 3749ec7b004SRick Macklem * reply bitmap will be correct for an error case. 3759ec7b004SRick Macklem */ 3769ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) || 3779ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) { 3789ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 3799ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid); 3809ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid); 3819ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 3829ec7b004SRick Macklem exp); 3839ec7b004SRick Macklem if (!nd->nd_repstat) { 3849ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER)) 3859ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER); 3869ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) 3879ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP); 3889ec7b004SRick Macklem } 3899ec7b004SRick Macklem } 3909ec7b004SRick Macklem if (!nd->nd_repstat && 3919ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) { 3929ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 3939ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, size, nva.na_size); 3949ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 3959ec7b004SRick Macklem exp); 3969ec7b004SRick Macklem if (!nd->nd_repstat) 3979ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE); 3989ec7b004SRick Macklem } 3999ec7b004SRick Macklem if (!nd->nd_repstat && 4009ec7b004SRick Macklem (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) || 4019ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) { 4029ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 4039ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime); 4049ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime); 4059ec7b004SRick Macklem if (nva.na_vaflags & VA_UTIMES_NULL) { 4069ec7b004SRick Macklem nva2.na_vaflags |= VA_UTIMES_NULL; 4079ec7b004SRick Macklem NFSVNO_SETACTIVE(&nva2, vaflags); 4089ec7b004SRick Macklem } 4099ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 4109ec7b004SRick Macklem exp); 4119ec7b004SRick Macklem if (!nd->nd_repstat) { 4129ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET)) 4139ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET); 4149ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET)) 4159ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET); 4169ec7b004SRick Macklem } 4179ec7b004SRick Macklem } 4189ec7b004SRick Macklem if (!nd->nd_repstat && 4199ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) { 4209ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 4219ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode); 4229ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 4239ec7b004SRick Macklem exp); 4249ec7b004SRick Macklem if (!nd->nd_repstat) 4259ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE); 4269ec7b004SRick Macklem } 4279ec7b004SRick Macklem 4289ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 4299ec7b004SRick Macklem if (!nd->nd_repstat && aclp->acl_cnt > 0 && 4309ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) { 4319ec7b004SRick Macklem nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p); 4329ec7b004SRick Macklem if (!nd->nd_repstat) 4339ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL); 4349ec7b004SRick Macklem } 4359ec7b004SRick Macklem #endif 4369ec7b004SRick Macklem } else if (!nd->nd_repstat) { 4379ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p, 4389ec7b004SRick Macklem exp); 4399ec7b004SRick Macklem } 4409ec7b004SRick Macklem if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) { 4410cf42b62SRick Macklem postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 4429ec7b004SRick Macklem if (!nd->nd_repstat) 4439ec7b004SRick Macklem nd->nd_repstat = postat_ret; 4449ec7b004SRick Macklem } 4459ec7b004SRick Macklem vput(vp); 4469ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 4479ec7b004SRick Macklem acl_free(aclp); 4489ec7b004SRick Macklem #endif 4499ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 4509ec7b004SRick Macklem nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 4519ec7b004SRick Macklem else if (nd->nd_flag & ND_NFSV4) 4529ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &retbits); 4539ec7b004SRick Macklem else if (!nd->nd_repstat) 4549ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 455a9285ae5SZack Kirsch 456a9285ae5SZack Kirsch out: 457a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 4589ec7b004SRick Macklem return (0); 4599ec7b004SRick Macklem nfsmout: 4609ec7b004SRick Macklem vput(vp); 4619ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 4629ec7b004SRick Macklem acl_free(aclp); 4639ec7b004SRick Macklem #endif 4649ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 4659ec7b004SRick Macklem /* 4669ec7b004SRick Macklem * For all nd_repstat, the V4 reply includes a bitmap, 4679ec7b004SRick Macklem * even NFSERR_BADXDR, which is what this will end up 4689ec7b004SRick Macklem * returning. 4699ec7b004SRick Macklem */ 4709ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &retbits); 4719ec7b004SRick Macklem } 472a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 4739ec7b004SRick Macklem return (error); 4749ec7b004SRick Macklem } 4759ec7b004SRick Macklem 4769ec7b004SRick Macklem /* 4779ec7b004SRick Macklem * nfs lookup rpc 4789ec7b004SRick Macklem * (Also performs lookup parent for v4) 4799ec7b004SRick Macklem */ 4809ec7b004SRick Macklem APPLESTATIC int 4819ec7b004SRick Macklem nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram, 4829ec7b004SRick Macklem vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 48337b88c2dSRick Macklem struct nfsexstuff *exp) 4849ec7b004SRick Macklem { 4859ec7b004SRick Macklem struct nameidata named; 4869ec7b004SRick Macklem vnode_t vp, dirp = NULL; 487a9285ae5SZack Kirsch int error = 0, dattr_ret = 1; 4889ec7b004SRick Macklem struct nfsvattr nva, dattr; 4899ec7b004SRick Macklem char *bufp; 4909ec7b004SRick Macklem u_long *hashp; 4919ec7b004SRick Macklem 4929ec7b004SRick Macklem if (nd->nd_repstat) { 4939ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 494a9285ae5SZack Kirsch goto out; 4959ec7b004SRick Macklem } 4969ec7b004SRick Macklem 4979ec7b004SRick Macklem /* 4989ec7b004SRick Macklem * For some reason, if dp is a symlink, the error 4999ec7b004SRick Macklem * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR. 5009ec7b004SRick Macklem */ 5019ec7b004SRick Macklem if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) { 5029ec7b004SRick Macklem nd->nd_repstat = NFSERR_SYMLINK; 5039ec7b004SRick Macklem vrele(dp); 504a9285ae5SZack Kirsch goto out; 5059ec7b004SRick Macklem } 5069ec7b004SRick Macklem 5079ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 5089ec7b004SRick Macklem LOCKLEAF | SAVESTART); 5099ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 5109ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 5119ec7b004SRick Macklem if (error) { 5129ec7b004SRick Macklem vrele(dp); 5139ec7b004SRick Macklem nfsvno_relpathbuf(&named); 514a9285ae5SZack Kirsch goto out; 5159ec7b004SRick Macklem } 5169ec7b004SRick Macklem if (!nd->nd_repstat) { 5179ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 5189ec7b004SRick Macklem } else { 5199ec7b004SRick Macklem vrele(dp); 5209ec7b004SRick Macklem nfsvno_relpathbuf(&named); 5219ec7b004SRick Macklem } 5229ec7b004SRick Macklem if (nd->nd_repstat) { 5239ec7b004SRick Macklem if (dirp) { 5249ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 5259ec7b004SRick Macklem dattr_ret = nfsvno_getattr(dirp, &dattr, 5260cf42b62SRick Macklem nd->nd_cred, p, 0); 5279ec7b004SRick Macklem vrele(dirp); 5289ec7b004SRick Macklem } 5299ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 5309ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 531a9285ae5SZack Kirsch goto out; 5329ec7b004SRick Macklem } 5339ec7b004SRick Macklem if (named.ni_startdir) 5349ec7b004SRick Macklem vrele(named.ni_startdir); 5359ec7b004SRick Macklem nfsvno_relpathbuf(&named); 5369ec7b004SRick Macklem vp = named.ni_vp; 53737b88c2dSRick Macklem if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) && 53837b88c2dSRick Macklem vp->v_type != VDIR && vp->v_type != VLNK) 53937b88c2dSRick Macklem /* 54037b88c2dSRick Macklem * Only allow lookup of VDIR and VLNK for traversal of 54137b88c2dSRick Macklem * non-exported volumes during NFSv4 mounting. 54237b88c2dSRick Macklem */ 54337b88c2dSRick Macklem nd->nd_repstat = ENOENT; 54437b88c2dSRick Macklem if (nd->nd_repstat == 0) 5459ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 5469ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 5470cf42b62SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 54881f78d99SRick Macklem if (vpp != NULL && nd->nd_repstat == 0) 5499ec7b004SRick Macklem *vpp = vp; 55081f78d99SRick Macklem else 5519ec7b004SRick Macklem vput(vp); 5529ec7b004SRick Macklem if (dirp) { 5539ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 5549ec7b004SRick Macklem dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred, 5550cf42b62SRick Macklem p, 0); 5569ec7b004SRick Macklem vrele(dirp); 5579ec7b004SRick Macklem } 5589ec7b004SRick Macklem if (nd->nd_repstat) { 5599ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 5609ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 561a9285ae5SZack Kirsch goto out; 5629ec7b004SRick Macklem } 5639ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 5649ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 5659ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 5669ec7b004SRick Macklem } else if (nd->nd_flag & ND_NFSV3) { 5679ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 5689ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 5699ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 5709ec7b004SRick Macklem } 571a9285ae5SZack Kirsch 572a9285ae5SZack Kirsch out: 573a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 574a9285ae5SZack Kirsch return (error); 5759ec7b004SRick Macklem } 5769ec7b004SRick Macklem 5779ec7b004SRick Macklem /* 5789ec7b004SRick Macklem * nfs readlink service 5799ec7b004SRick Macklem */ 5809ec7b004SRick Macklem APPLESTATIC int 5819ec7b004SRick Macklem nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram, 5829ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 5839ec7b004SRick Macklem { 5849ec7b004SRick Macklem u_int32_t *tl; 5859ec7b004SRick Macklem mbuf_t mp = NULL, mpend = NULL; 5869ec7b004SRick Macklem int getret = 1, len; 5879ec7b004SRick Macklem struct nfsvattr nva; 5889ec7b004SRick Macklem 5899ec7b004SRick Macklem if (nd->nd_repstat) { 5909ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 591a9285ae5SZack Kirsch goto out; 5929ec7b004SRick Macklem } 5939ec7b004SRick Macklem if (vnode_vtype(vp) != VLNK) { 5949ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) 5959ec7b004SRick Macklem nd->nd_repstat = ENXIO; 5969ec7b004SRick Macklem else 5979ec7b004SRick Macklem nd->nd_repstat = EINVAL; 5989ec7b004SRick Macklem } 5999ec7b004SRick Macklem if (!nd->nd_repstat) 6009ec7b004SRick Macklem nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p, 6019ec7b004SRick Macklem &mp, &mpend, &len); 6029ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 6030cf42b62SRick Macklem getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 6049ec7b004SRick Macklem vput(vp); 6059ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 6069ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 6079ec7b004SRick Macklem if (nd->nd_repstat) 608a9285ae5SZack Kirsch goto out; 6099ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 6109ec7b004SRick Macklem *tl = txdr_unsigned(len); 6119ec7b004SRick Macklem mbuf_setnext(nd->nd_mb, mp); 6129ec7b004SRick Macklem nd->nd_mb = mpend; 6139ec7b004SRick Macklem nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend); 614a9285ae5SZack Kirsch 615a9285ae5SZack Kirsch out: 616a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 6179ec7b004SRick Macklem return (0); 6189ec7b004SRick Macklem } 6199ec7b004SRick Macklem 6209ec7b004SRick Macklem /* 6219ec7b004SRick Macklem * nfs read service 6229ec7b004SRick Macklem */ 6239ec7b004SRick Macklem APPLESTATIC int 6249ec7b004SRick Macklem nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram, 6259ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 6269ec7b004SRick Macklem { 6279ec7b004SRick Macklem u_int32_t *tl; 62806521fbbSZack Kirsch int error = 0, cnt, getret = 1, reqlen, eof = 0; 6299ec7b004SRick Macklem mbuf_t m2, m3; 6309ec7b004SRick Macklem struct nfsvattr nva; 6319ec7b004SRick Macklem off_t off = 0x0; 6329ec7b004SRick Macklem struct nfsstate st, *stp = &st; 6339ec7b004SRick Macklem struct nfslock lo, *lop = &lo; 6349ec7b004SRick Macklem nfsv4stateid_t stateid; 6359ec7b004SRick Macklem nfsquad_t clientid; 6369ec7b004SRick Macklem 6379ec7b004SRick Macklem if (nd->nd_repstat) { 6389ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 639a9285ae5SZack Kirsch goto out; 6409ec7b004SRick Macklem } 6419ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 6429ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 6439ec7b004SRick Macklem off = (off_t)fxdr_unsigned(u_int32_t, *tl++); 6449ec7b004SRick Macklem reqlen = fxdr_unsigned(int, *tl); 6459ec7b004SRick Macklem } else if (nd->nd_flag & ND_NFSV3) { 6469ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 6479ec7b004SRick Macklem off = fxdr_hyper(tl); 6489ec7b004SRick Macklem tl += 2; 6499ec7b004SRick Macklem reqlen = fxdr_unsigned(int, *tl); 6509ec7b004SRick Macklem } else { 6519ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED); 6529ec7b004SRick Macklem reqlen = fxdr_unsigned(int, *(tl + 6)); 6539ec7b004SRick Macklem } 6549ec7b004SRick Macklem if (reqlen > NFS_SRVMAXDATA(nd)) { 6559ec7b004SRick Macklem reqlen = NFS_SRVMAXDATA(nd); 6569ec7b004SRick Macklem } else if (reqlen < 0) { 6579ec7b004SRick Macklem error = EBADRPC; 6589ec7b004SRick Macklem goto nfsmout; 6599ec7b004SRick Macklem } 6609ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 6619ec7b004SRick Macklem stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS); 6629ec7b004SRick Macklem lop->lo_flags = NFSLCK_READ; 6639ec7b004SRick Macklem stp->ls_ownerlen = 0; 6649ec7b004SRick Macklem stp->ls_op = NULL; 6659ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 6669ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 6679ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 6689ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 669*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 670*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 671*c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 672*c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 673*c59e4cc3SRick Macklem printf("EEK1 multiple clids\n"); 6749ec7b004SRick Macklem } else { 675*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 676*c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 6779ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 6789ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 6799ec7b004SRick Macklem } 6809ec7b004SRick Macklem stp->ls_stateid.other[2] = *tl++; 6819ec7b004SRick Macklem off = fxdr_hyper(tl); 6829ec7b004SRick Macklem lop->lo_first = off; 6839ec7b004SRick Macklem tl += 2; 6849ec7b004SRick Macklem lop->lo_end = off + reqlen; 6859ec7b004SRick Macklem /* 6869ec7b004SRick Macklem * Paranoia, just in case it wraps around. 6879ec7b004SRick Macklem */ 6889ec7b004SRick Macklem if (lop->lo_end < off) 6899ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 6909ec7b004SRick Macklem } 6919ec7b004SRick Macklem if (vnode_vtype(vp) != VREG) { 6929ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 6939ec7b004SRick Macklem nd->nd_repstat = EINVAL; 6949ec7b004SRick Macklem else 6959ec7b004SRick Macklem nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR : 6969ec7b004SRick Macklem EINVAL; 6979ec7b004SRick Macklem } 6980cf42b62SRick Macklem getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 6999ec7b004SRick Macklem if (!nd->nd_repstat) 7009ec7b004SRick Macklem nd->nd_repstat = getret; 7019ec7b004SRick Macklem if (!nd->nd_repstat && 7029ec7b004SRick Macklem (nva.na_uid != nd->nd_cred->cr_uid || 7039ec7b004SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) { 7048da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, 7059ec7b004SRick Macklem nd->nd_cred, exp, p, 7068da45f2cSRick Macklem NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 7079ec7b004SRick Macklem if (nd->nd_repstat) 7088da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 7098da45f2cSRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 7108da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 7119ec7b004SRick Macklem } 7129ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 7139ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 7149ec7b004SRick Macklem &stateid, exp, nd, p); 7159ec7b004SRick Macklem if (nd->nd_repstat) { 7169ec7b004SRick Macklem vput(vp); 7179ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 7189ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 719a9285ae5SZack Kirsch goto out; 7209ec7b004SRick Macklem } 7219ec7b004SRick Macklem if (off >= nva.na_size) { 7229ec7b004SRick Macklem cnt = 0; 7239ec7b004SRick Macklem eof = 1; 7249ec7b004SRick Macklem } else if (reqlen == 0) 7259ec7b004SRick Macklem cnt = 0; 72606521fbbSZack Kirsch else if ((off + reqlen) >= nva.na_size) { 7279ec7b004SRick Macklem cnt = nva.na_size - off; 72806521fbbSZack Kirsch eof = 1; 72906521fbbSZack Kirsch } else 7309ec7b004SRick Macklem cnt = reqlen; 7319ec7b004SRick Macklem m3 = NULL; 7329ec7b004SRick Macklem if (cnt > 0) { 7339ec7b004SRick Macklem nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p, 7349ec7b004SRick Macklem &m3, &m2); 7359ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV4)) { 7360cf42b62SRick Macklem getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 7379ec7b004SRick Macklem if (!nd->nd_repstat) 7389ec7b004SRick Macklem nd->nd_repstat = getret; 7399ec7b004SRick Macklem } 7409ec7b004SRick Macklem if (nd->nd_repstat) { 7419ec7b004SRick Macklem vput(vp); 7429ec7b004SRick Macklem if (m3) 7439ec7b004SRick Macklem mbuf_freem(m3); 7449ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 7459ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 746a9285ae5SZack Kirsch goto out; 7479ec7b004SRick Macklem } 7489ec7b004SRick Macklem } 7499ec7b004SRick Macklem vput(vp); 7509ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 7519ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 7529ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 7539ec7b004SRick Macklem } else { 7549ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 7559ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 7569ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 7579ec7b004SRick Macklem *tl++ = txdr_unsigned(cnt); 7589ec7b004SRick Macklem } else 7599ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 76006521fbbSZack Kirsch if (eof) 7619ec7b004SRick Macklem *tl++ = newnfs_true; 7629ec7b004SRick Macklem else 7639ec7b004SRick Macklem *tl++ = newnfs_false; 7649ec7b004SRick Macklem } 7659ec7b004SRick Macklem *tl = txdr_unsigned(cnt); 7669ec7b004SRick Macklem if (m3) { 7679ec7b004SRick Macklem mbuf_setnext(nd->nd_mb, m3); 7689ec7b004SRick Macklem nd->nd_mb = m2; 7699ec7b004SRick Macklem nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2); 7709ec7b004SRick Macklem } 771a9285ae5SZack Kirsch 772a9285ae5SZack Kirsch out: 773a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 7749ec7b004SRick Macklem return (0); 7759ec7b004SRick Macklem nfsmout: 7769ec7b004SRick Macklem vput(vp); 777a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 7789ec7b004SRick Macklem return (error); 7799ec7b004SRick Macklem } 7809ec7b004SRick Macklem 7819ec7b004SRick Macklem /* 7829ec7b004SRick Macklem * nfs write service 7839ec7b004SRick Macklem */ 7849ec7b004SRick Macklem APPLESTATIC int 7859ec7b004SRick Macklem nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram, 7869ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 7879ec7b004SRick Macklem { 7889ec7b004SRick Macklem int i, cnt; 7899ec7b004SRick Macklem u_int32_t *tl; 7909ec7b004SRick Macklem mbuf_t mp; 7919ec7b004SRick Macklem struct nfsvattr nva, forat; 7929ec7b004SRick Macklem int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1; 7939ec7b004SRick Macklem int stable = NFSWRITE_FILESYNC; 7949ec7b004SRick Macklem off_t off; 7959ec7b004SRick Macklem struct nfsstate st, *stp = &st; 7969ec7b004SRick Macklem struct nfslock lo, *lop = &lo; 7979ec7b004SRick Macklem nfsv4stateid_t stateid; 7989ec7b004SRick Macklem nfsquad_t clientid; 7999ec7b004SRick Macklem 8009ec7b004SRick Macklem if (nd->nd_repstat) { 8019ec7b004SRick Macklem nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 802a9285ae5SZack Kirsch goto out; 8039ec7b004SRick Macklem } 8049ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 8059ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 8069ec7b004SRick Macklem off = (off_t)fxdr_unsigned(u_int32_t, *++tl); 8079ec7b004SRick Macklem tl += 2; 8089ec7b004SRick Macklem retlen = len = fxdr_unsigned(int32_t, *tl); 8099ec7b004SRick Macklem } else if (nd->nd_flag & ND_NFSV3) { 8109ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 8119ec7b004SRick Macklem off = fxdr_hyper(tl); 8129ec7b004SRick Macklem tl += 3; 8139ec7b004SRick Macklem stable = fxdr_unsigned(int, *tl++); 8149ec7b004SRick Macklem retlen = len = fxdr_unsigned(int32_t, *tl); 8159ec7b004SRick Macklem } else { 8169ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED); 8179ec7b004SRick Macklem stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 8189ec7b004SRick Macklem lop->lo_flags = NFSLCK_WRITE; 8199ec7b004SRick Macklem stp->ls_ownerlen = 0; 8209ec7b004SRick Macklem stp->ls_op = NULL; 8219ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 8229ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 8239ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 8249ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 825*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 826*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 827*c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 828*c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 829*c59e4cc3SRick Macklem printf("EEK2 multiple clids\n"); 8309ec7b004SRick Macklem } else { 831*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 832*c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 8339ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 8349ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 8359ec7b004SRick Macklem } 8369ec7b004SRick Macklem stp->ls_stateid.other[2] = *tl++; 8379ec7b004SRick Macklem off = fxdr_hyper(tl); 8389ec7b004SRick Macklem lop->lo_first = off; 8399ec7b004SRick Macklem tl += 2; 8409ec7b004SRick Macklem stable = fxdr_unsigned(int, *tl++); 8419ec7b004SRick Macklem retlen = len = fxdr_unsigned(int32_t, *tl); 8429ec7b004SRick Macklem lop->lo_end = off + len; 8439ec7b004SRick Macklem /* 8449ec7b004SRick Macklem * Paranoia, just in case it wraps around, which shouldn't 8459ec7b004SRick Macklem * ever happen anyhow. 8469ec7b004SRick Macklem */ 8479ec7b004SRick Macklem if (lop->lo_end < lop->lo_first) 8489ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 8499ec7b004SRick Macklem } 8509ec7b004SRick Macklem 8519ec7b004SRick Macklem /* 8529ec7b004SRick Macklem * Loop through the mbuf chain, counting how many mbufs are a 8539ec7b004SRick Macklem * part of this write operation, so the iovec size is known. 8549ec7b004SRick Macklem */ 8559ec7b004SRick Macklem cnt = 0; 8569ec7b004SRick Macklem mp = nd->nd_md; 8579ec7b004SRick Macklem i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos; 8589ec7b004SRick Macklem while (len > 0) { 8599ec7b004SRick Macklem if (i > 0) { 8609ec7b004SRick Macklem len -= i; 8619ec7b004SRick Macklem cnt++; 8629ec7b004SRick Macklem } 8639ec7b004SRick Macklem mp = mbuf_next(mp); 8649ec7b004SRick Macklem if (!mp) { 8659ec7b004SRick Macklem if (len > 0) { 8669ec7b004SRick Macklem error = EBADRPC; 8679ec7b004SRick Macklem goto nfsmout; 8689ec7b004SRick Macklem } 8699ec7b004SRick Macklem } else 8709ec7b004SRick Macklem i = mbuf_len(mp); 8719ec7b004SRick Macklem } 8729ec7b004SRick Macklem 8739ec7b004SRick Macklem if (retlen > NFS_MAXDATA || retlen < 0) 8749ec7b004SRick Macklem nd->nd_repstat = EIO; 8759ec7b004SRick Macklem if (vnode_vtype(vp) != VREG && !nd->nd_repstat) { 8769ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 8779ec7b004SRick Macklem nd->nd_repstat = EINVAL; 8789ec7b004SRick Macklem else 8799ec7b004SRick Macklem nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR : 8809ec7b004SRick Macklem EINVAL; 8819ec7b004SRick Macklem } 8820cf42b62SRick Macklem forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1); 8839ec7b004SRick Macklem if (!nd->nd_repstat) 8849ec7b004SRick Macklem nd->nd_repstat = forat_ret; 8859ec7b004SRick Macklem if (!nd->nd_repstat && 8869ec7b004SRick Macklem (forat.na_uid != nd->nd_cred->cr_uid || 8879ec7b004SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) 8888da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 8899ec7b004SRick Macklem nd->nd_cred, exp, p, 8908da45f2cSRick Macklem NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 8919ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 8929ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 8939ec7b004SRick Macklem &stateid, exp, nd, p); 8949ec7b004SRick Macklem } 8959ec7b004SRick Macklem if (nd->nd_repstat) { 8969ec7b004SRick Macklem vput(vp); 8979ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 8989ec7b004SRick Macklem nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 899a9285ae5SZack Kirsch goto out; 9009ec7b004SRick Macklem } 9019ec7b004SRick Macklem 9029ec7b004SRick Macklem /* 9039ec7b004SRick Macklem * For NFS Version 2, it is not obvious what a write of zero length 9049ec7b004SRick Macklem * should do, but I might as well be consistent with Version 3, 9059ec7b004SRick Macklem * which is to return ok so long as there are no permission problems. 9069ec7b004SRick Macklem */ 9079ec7b004SRick Macklem if (retlen > 0) { 9089ec7b004SRick Macklem nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable, 9099ec7b004SRick Macklem nd->nd_md, nd->nd_dpos, nd->nd_cred, p); 9109ec7b004SRick Macklem error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1); 9119ec7b004SRick Macklem if (error) 9129ec7b004SRick Macklem panic("nfsrv_write mbuf"); 9139ec7b004SRick Macklem } 9149ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) 9159ec7b004SRick Macklem aftat_ret = 0; 9169ec7b004SRick Macklem else 9170cf42b62SRick Macklem aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 9189ec7b004SRick Macklem vput(vp); 9199ec7b004SRick Macklem if (!nd->nd_repstat) 9209ec7b004SRick Macklem nd->nd_repstat = aftat_ret; 9219ec7b004SRick Macklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 9229ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 9239ec7b004SRick Macklem nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 9249ec7b004SRick Macklem if (nd->nd_repstat) 925a9285ae5SZack Kirsch goto out; 9269ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 9279ec7b004SRick Macklem *tl++ = txdr_unsigned(retlen); 928e4558aacSXin LI /* 929e4558aacSXin LI * If nfs_async is set, then pretend the write was FILESYNC. 930e4558aacSXin LI * Warning: Doing this violates RFC1813 and runs a risk 931e4558aacSXin LI * of data written by a client being lost when the server 932e4558aacSXin LI * crashes/reboots. 933e4558aacSXin LI */ 934e4558aacSXin LI if (stable == NFSWRITE_UNSTABLE && nfs_async == 0) 9359ec7b004SRick Macklem *tl++ = txdr_unsigned(stable); 9369ec7b004SRick Macklem else 9379ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSWRITE_FILESYNC); 9389ec7b004SRick Macklem /* 9399ec7b004SRick Macklem * Actually, there is no need to txdr these fields, 9409ec7b004SRick Macklem * but it may make the values more human readable, 9419ec7b004SRick Macklem * for debugging purposes. 9429ec7b004SRick Macklem */ 9439ec7b004SRick Macklem *tl++ = txdr_unsigned(nfsboottime.tv_sec); 9449ec7b004SRick Macklem *tl = txdr_unsigned(nfsboottime.tv_usec); 9459ec7b004SRick Macklem } else if (!nd->nd_repstat) 9469ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 947a9285ae5SZack Kirsch 948a9285ae5SZack Kirsch out: 949a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 9509ec7b004SRick Macklem return (0); 9519ec7b004SRick Macklem nfsmout: 9529ec7b004SRick Macklem vput(vp); 953a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 9549ec7b004SRick Macklem return (error); 9559ec7b004SRick Macklem } 9569ec7b004SRick Macklem 9579ec7b004SRick Macklem /* 9589ec7b004SRick Macklem * nfs create service (creates regular files for V2 and V3. Spec. files for V2.) 9599ec7b004SRick Macklem * now does a truncate to 0 length via. setattr if it already exists 9609ec7b004SRick Macklem * The core creation routine has been extracted out into nfsrv_creatsub(), 9619ec7b004SRick Macklem * so it can also be used by nfsrv_open() for V4. 9629ec7b004SRick Macklem */ 9639ec7b004SRick Macklem APPLESTATIC int 9649ec7b004SRick Macklem nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram, 9659ec7b004SRick Macklem vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 9669ec7b004SRick Macklem { 9679ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 9689ec7b004SRick Macklem struct nfsv2_sattr *sp; 9699ec7b004SRick Macklem struct nameidata named; 9709ec7b004SRick Macklem u_int32_t *tl; 9719ec7b004SRick Macklem int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1; 9729ec7b004SRick Macklem int how = NFSCREATE_UNCHECKED, exclusive_flag = 0; 9739ec7b004SRick Macklem NFSDEV_T rdev = 0; 9749ec7b004SRick Macklem vnode_t vp = NULL, dirp = NULL; 9759ec7b004SRick Macklem fhandle_t fh; 9769ec7b004SRick Macklem char *bufp; 9779ec7b004SRick Macklem u_long *hashp; 9789ec7b004SRick Macklem enum vtype vtyp; 979086f6e0cSRick Macklem int32_t cverf[2], tverf[2] = { 0, 0 }; 9809ec7b004SRick Macklem 9819ec7b004SRick Macklem if (nd->nd_repstat) { 9829ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 983a9285ae5SZack Kirsch goto out; 9849ec7b004SRick Macklem } 9859ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 9869ec7b004SRick Macklem LOCKPARENT | LOCKLEAF | SAVESTART); 9879ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 9889ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 989a9285ae5SZack Kirsch if (error) 990a9285ae5SZack Kirsch goto nfsmout; 9919ec7b004SRick Macklem if (!nd->nd_repstat) { 9929ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 9939ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 9949ec7b004SRick Macklem NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 9959ec7b004SRick Macklem vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode)); 9969ec7b004SRick Macklem if (vtyp == VNON) 9979ec7b004SRick Macklem vtyp = VREG; 9989ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, type, vtyp); 9999ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, mode, 10009ec7b004SRick Macklem nfstov_mode(sp->sa_mode)); 10019ec7b004SRick Macklem switch (nva.na_type) { 10029ec7b004SRick Macklem case VREG: 10039ec7b004SRick Macklem tsize = fxdr_unsigned(int32_t, sp->sa_size); 10049ec7b004SRick Macklem if (tsize != -1) 10059ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, size, 10069ec7b004SRick Macklem (u_quad_t)tsize); 10079ec7b004SRick Macklem break; 10089ec7b004SRick Macklem case VCHR: 10099ec7b004SRick Macklem case VBLK: 10109ec7b004SRick Macklem case VFIFO: 10119ec7b004SRick Macklem rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size); 10129ec7b004SRick Macklem break; 10139ec7b004SRick Macklem default: 10149ec7b004SRick Macklem break; 10159ec7b004SRick Macklem }; 10169ec7b004SRick Macklem } else { 10179ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 10189ec7b004SRick Macklem how = fxdr_unsigned(int, *tl); 10199ec7b004SRick Macklem switch (how) { 10209ec7b004SRick Macklem case NFSCREATE_GUARDED: 10219ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 10229ec7b004SRick Macklem error = nfsrv_sattr(nd, &nva, NULL, NULL, p); 10239ec7b004SRick Macklem if (error) 10249ec7b004SRick Macklem goto nfsmout; 10259ec7b004SRick Macklem break; 10269ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 1027086f6e0cSRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 1028086f6e0cSRick Macklem cverf[0] = *tl++; 1029086f6e0cSRick Macklem cverf[1] = *tl; 10309ec7b004SRick Macklem exclusive_flag = 1; 10319ec7b004SRick Macklem break; 10329ec7b004SRick Macklem }; 10339ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, type, VREG); 10349ec7b004SRick Macklem } 10359ec7b004SRick Macklem } 10369ec7b004SRick Macklem if (nd->nd_repstat) { 10379ec7b004SRick Macklem nfsvno_relpathbuf(&named); 10389ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 10399ec7b004SRick Macklem dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, 10400cf42b62SRick Macklem p, 1); 10419ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 10429ec7b004SRick Macklem &diraft); 10439ec7b004SRick Macklem } 10449ec7b004SRick Macklem vput(dp); 1045a9285ae5SZack Kirsch goto out; 10469ec7b004SRick Macklem } 10479ec7b004SRick Macklem 10489ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 10499ec7b004SRick Macklem if (dirp) { 10509ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 10519ec7b004SRick Macklem vrele(dirp); 10529ec7b004SRick Macklem dirp = NULL; 10539ec7b004SRick Macklem } else { 10549ec7b004SRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 10550cf42b62SRick Macklem p, 0); 10569ec7b004SRick Macklem } 10579ec7b004SRick Macklem } 10589ec7b004SRick Macklem if (nd->nd_repstat) { 10599ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 10609ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 10619ec7b004SRick Macklem &diraft); 10629ec7b004SRick Macklem if (dirp) 10639ec7b004SRick Macklem vrele(dirp); 1064a9285ae5SZack Kirsch goto out; 10659ec7b004SRick Macklem } 10669ec7b004SRick Macklem 10679ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) { 10689ec7b004SRick Macklem switch (how) { 10699ec7b004SRick Macklem case NFSCREATE_GUARDED: 10709ec7b004SRick Macklem if (named.ni_vp) 10719ec7b004SRick Macklem nd->nd_repstat = EEXIST; 10729ec7b004SRick Macklem break; 10739ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 10749ec7b004SRick Macklem break; 10759ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 10769ec7b004SRick Macklem if (named.ni_vp == NULL) 10779ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, mode, 0); 10789ec7b004SRick Macklem break; 10799ec7b004SRick Macklem }; 10809ec7b004SRick Macklem } 10819ec7b004SRick Macklem 10829ec7b004SRick Macklem /* 10839ec7b004SRick Macklem * Iff doesn't exist, create it 10849ec7b004SRick Macklem * otherwise just truncate to 0 length 10859ec7b004SRick Macklem * should I set the mode too ? 10869ec7b004SRick Macklem */ 10879ec7b004SRick Macklem nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva, 10889ec7b004SRick Macklem &exclusive_flag, cverf, rdev, p, exp); 10899ec7b004SRick Macklem 10909ec7b004SRick Macklem if (!nd->nd_repstat) { 10919ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 10929ec7b004SRick Macklem if (!nd->nd_repstat) 10939ec7b004SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, 10940cf42b62SRick Macklem p, 1); 10959ec7b004SRick Macklem vput(vp); 1096086f6e0cSRick Macklem if (!nd->nd_repstat) { 1097086f6e0cSRick Macklem tverf[0] = nva.na_atime.tv_sec; 1098086f6e0cSRick Macklem tverf[1] = nva.na_atime.tv_nsec; 1099086f6e0cSRick Macklem } 11009ec7b004SRick Macklem } 11019ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 11029ec7b004SRick Macklem if (!nd->nd_repstat) { 11039ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 11049ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 11059ec7b004SRick Macklem } 11069ec7b004SRick Macklem } else { 1107086f6e0cSRick Macklem if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0] 1108086f6e0cSRick Macklem || cverf[1] != tverf[1])) 11099ec7b004SRick Macklem nd->nd_repstat = EEXIST; 11100cf42b62SRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0); 11119ec7b004SRick Macklem vrele(dirp); 11129ec7b004SRick Macklem if (!nd->nd_repstat) { 11139ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1); 11149ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 11159ec7b004SRick Macklem } 11169ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 11179ec7b004SRick Macklem } 1118a9285ae5SZack Kirsch 1119a9285ae5SZack Kirsch out: 1120a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 11219ec7b004SRick Macklem return (0); 11229ec7b004SRick Macklem nfsmout: 11239ec7b004SRick Macklem vput(dp); 11249ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1125a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 11269ec7b004SRick Macklem return (error); 11279ec7b004SRick Macklem } 11289ec7b004SRick Macklem 11299ec7b004SRick Macklem /* 11309ec7b004SRick Macklem * nfs v3 mknod service (and v4 create) 11319ec7b004SRick Macklem */ 11329ec7b004SRick Macklem APPLESTATIC int 11339ec7b004SRick Macklem nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram, 11349ec7b004SRick Macklem vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 11359ec7b004SRick Macklem struct nfsexstuff *exp) 11369ec7b004SRick Macklem { 11379ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 11389ec7b004SRick Macklem u_int32_t *tl; 11399ec7b004SRick Macklem struct nameidata named; 11409ec7b004SRick Macklem int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 11419ec7b004SRick Macklem u_int32_t major, minor; 11429ec7b004SRick Macklem enum vtype vtyp = VNON; 11439ec7b004SRick Macklem nfstype nfs4type = NFNON; 11449ec7b004SRick Macklem vnode_t vp, dirp = NULL; 11459ec7b004SRick Macklem nfsattrbit_t attrbits; 11469ec7b004SRick Macklem char *bufp = NULL, *pathcp = NULL; 11479ec7b004SRick Macklem u_long *hashp, cnflags; 11489ec7b004SRick Macklem NFSACL_T *aclp = NULL; 11499ec7b004SRick Macklem 11509ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 11519ec7b004SRick Macklem cnflags = (LOCKPARENT | SAVESTART); 11529ec7b004SRick Macklem if (nd->nd_repstat) { 11539ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1154a9285ae5SZack Kirsch goto out; 11559ec7b004SRick Macklem } 11569ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 1157c3e22f83SRick Macklem aclp = acl_alloc(M_WAITOK); 11589ec7b004SRick Macklem aclp->acl_cnt = 0; 11599ec7b004SRick Macklem #endif 11609ec7b004SRick Macklem 11619ec7b004SRick Macklem /* 11629ec7b004SRick Macklem * For V4, the creation stuff is here, Yuck! 11639ec7b004SRick Macklem */ 11649ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 11659ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 11669ec7b004SRick Macklem vtyp = nfsv34tov_type(*tl); 11679ec7b004SRick Macklem nfs4type = fxdr_unsigned(nfstype, *tl); 11689ec7b004SRick Macklem switch (nfs4type) { 11699ec7b004SRick Macklem case NFLNK: 11709ec7b004SRick Macklem error = nfsvno_getsymlink(nd, &nva, p, &pathcp, 11719ec7b004SRick Macklem &pathlen); 1172a9285ae5SZack Kirsch if (error) 1173a9285ae5SZack Kirsch goto nfsmout; 11749ec7b004SRick Macklem break; 11759ec7b004SRick Macklem case NFCHR: 11769ec7b004SRick Macklem case NFBLK: 11779ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 11789ec7b004SRick Macklem major = fxdr_unsigned(u_int32_t, *tl++); 11799ec7b004SRick Macklem minor = fxdr_unsigned(u_int32_t, *tl); 11809ec7b004SRick Macklem nva.na_rdev = NFSMAKEDEV(major, minor); 11819ec7b004SRick Macklem break; 11829ec7b004SRick Macklem case NFSOCK: 11839ec7b004SRick Macklem case NFFIFO: 11849ec7b004SRick Macklem break; 11859ec7b004SRick Macklem case NFDIR: 1186f61786cbSRick Macklem cnflags = (LOCKPARENT | SAVENAME); 11879ec7b004SRick Macklem break; 11889ec7b004SRick Macklem default: 11899ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADTYPE; 11909ec7b004SRick Macklem vrele(dp); 11919ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 11929ec7b004SRick Macklem acl_free(aclp); 11939ec7b004SRick Macklem #endif 1194a9285ae5SZack Kirsch goto out; 1195a9285ae5SZack Kirsch } 11969ec7b004SRick Macklem } 11979ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags); 11989ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 11999ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1200a9285ae5SZack Kirsch if (error) 1201a9285ae5SZack Kirsch goto nfsmout; 12029ec7b004SRick Macklem if (!nd->nd_repstat) { 12039ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 12049ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 12059ec7b004SRick Macklem vtyp = nfsv34tov_type(*tl); 12069ec7b004SRick Macklem } 12079ec7b004SRick Macklem error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p); 1208a9285ae5SZack Kirsch if (error) 1209a9285ae5SZack Kirsch goto nfsmout; 12109ec7b004SRick Macklem nva.na_type = vtyp; 12119ec7b004SRick Macklem if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) && 12129ec7b004SRick Macklem (vtyp == VCHR || vtyp == VBLK)) { 12139ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 12149ec7b004SRick Macklem major = fxdr_unsigned(u_int32_t, *tl++); 12159ec7b004SRick Macklem minor = fxdr_unsigned(u_int32_t, *tl); 12169ec7b004SRick Macklem nva.na_rdev = NFSMAKEDEV(major, minor); 12179ec7b004SRick Macklem } 12189ec7b004SRick Macklem } 12199ec7b004SRick Macklem 12200cf42b62SRick Macklem dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0); 12219ec7b004SRick Macklem if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 12229ec7b004SRick Macklem if (!dirfor_ret && NFSVNO_ISSETGID(&nva) && 12239ec7b004SRick Macklem dirfor.na_gid == nva.na_gid) 12249ec7b004SRick Macklem NFSVNO_UNSET(&nva, gid); 12259ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 12269ec7b004SRick Macklem } 12279ec7b004SRick Macklem if (nd->nd_repstat) { 12289ec7b004SRick Macklem vrele(dp); 12299ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 12309ec7b004SRick Macklem acl_free(aclp); 12319ec7b004SRick Macklem #endif 12329ec7b004SRick Macklem nfsvno_relpathbuf(&named); 12339ec7b004SRick Macklem if (pathcp) 12349ec7b004SRick Macklem FREE(pathcp, M_TEMP); 12359ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 12369ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 12379ec7b004SRick Macklem &diraft); 1238a9285ae5SZack Kirsch goto out; 12399ec7b004SRick Macklem } 12409ec7b004SRick Macklem 12419ec7b004SRick Macklem /* 12429ec7b004SRick Macklem * Yuck! For V4, mkdir and link are here and some V4 clients don't fill 12439ec7b004SRick Macklem * in va_mode, so we'll have to set a default here. 12449ec7b004SRick Macklem */ 12459ec7b004SRick Macklem if (NFSVNO_NOTSETMODE(&nva)) { 12469ec7b004SRick Macklem if (vtyp == VLNK) 12479ec7b004SRick Macklem nva.na_mode = 0755; 12489ec7b004SRick Macklem else 12499ec7b004SRick Macklem nva.na_mode = 0400; 12509ec7b004SRick Macklem } 12519ec7b004SRick Macklem 12529ec7b004SRick Macklem if (vtyp == VDIR) 12539ec7b004SRick Macklem named.ni_cnd.cn_flags |= WILLBEDIR; 12549ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 12559ec7b004SRick Macklem if (nd->nd_repstat) { 12569ec7b004SRick Macklem if (dirp) { 12579ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 12589ec7b004SRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, 12590cf42b62SRick Macklem nd->nd_cred, p, 0); 12609ec7b004SRick Macklem vrele(dirp); 12619ec7b004SRick Macklem } 12629ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 12639ec7b004SRick Macklem acl_free(aclp); 12649ec7b004SRick Macklem #endif 12659ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 12669ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 12679ec7b004SRick Macklem &diraft); 1268a9285ae5SZack Kirsch goto out; 12699ec7b004SRick Macklem } 12709ec7b004SRick Macklem if (dirp) 12710cf42b62SRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0); 12729ec7b004SRick Macklem 12739ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) { 12749ec7b004SRick Macklem if (vtyp == VDIR) { 12759ec7b004SRick Macklem nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, 12769ec7b004SRick Macklem &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p, 12779ec7b004SRick Macklem exp); 12789ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 12799ec7b004SRick Macklem acl_free(aclp); 12809ec7b004SRick Macklem #endif 1281a9285ae5SZack Kirsch goto out; 12829ec7b004SRick Macklem } else if (vtyp == VLNK) { 12839ec7b004SRick Macklem nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 12849ec7b004SRick Macklem &dirfor, &diraft, &diraft_ret, &attrbits, 12859ec7b004SRick Macklem aclp, p, exp, pathcp, pathlen); 12869ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 12879ec7b004SRick Macklem acl_free(aclp); 12889ec7b004SRick Macklem #endif 12899ec7b004SRick Macklem FREE(pathcp, M_TEMP); 1290a9285ae5SZack Kirsch goto out; 12919ec7b004SRick Macklem } 12929ec7b004SRick Macklem } 12939ec7b004SRick Macklem 12949ec7b004SRick Macklem nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p); 12959ec7b004SRick Macklem if (!nd->nd_repstat) { 12969ec7b004SRick Macklem vp = named.ni_vp; 12979ec7b004SRick Macklem nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp); 12989ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 12999ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat) 13009ec7b004SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, 13010cf42b62SRick Macklem p, 1); 130281f78d99SRick Macklem if (vpp != NULL && nd->nd_repstat == 0) { 1303a9989634SZack Kirsch NFSVOPUNLOCK(vp, 0); 13049ec7b004SRick Macklem *vpp = vp; 130581f78d99SRick Macklem } else 13069ec7b004SRick Macklem vput(vp); 13079ec7b004SRick Macklem } 13089ec7b004SRick Macklem 13090cf42b62SRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0); 13109ec7b004SRick Macklem vrele(dirp); 13119ec7b004SRick Macklem if (!nd->nd_repstat) { 13129ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 13139ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 13149ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 13159ec7b004SRick Macklem } else { 13169ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 13179ec7b004SRick Macklem *tl++ = newnfs_false; 13189ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 13199ec7b004SRick Macklem tl += 2; 13209ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 13219ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &attrbits); 13229ec7b004SRick Macklem } 13239ec7b004SRick Macklem } 13249ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 13259ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 13269ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 13279ec7b004SRick Macklem acl_free(aclp); 13289ec7b004SRick Macklem #endif 1329a9285ae5SZack Kirsch 1330a9285ae5SZack Kirsch out: 1331a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 13329ec7b004SRick Macklem return (0); 13339ec7b004SRick Macklem nfsmout: 13349ec7b004SRick Macklem vrele(dp); 13359ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 13369ec7b004SRick Macklem acl_free(aclp); 13379ec7b004SRick Macklem #endif 13389ec7b004SRick Macklem if (bufp) 13399ec7b004SRick Macklem nfsvno_relpathbuf(&named); 13409ec7b004SRick Macklem if (pathcp) 13419ec7b004SRick Macklem FREE(pathcp, M_TEMP); 1342a9285ae5SZack Kirsch 1343a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 13449ec7b004SRick Macklem return (error); 13459ec7b004SRick Macklem } 13469ec7b004SRick Macklem 13479ec7b004SRick Macklem /* 13489ec7b004SRick Macklem * nfs remove service 13499ec7b004SRick Macklem */ 13509ec7b004SRick Macklem APPLESTATIC int 13519ec7b004SRick Macklem nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram, 13529ec7b004SRick Macklem vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 13539ec7b004SRick Macklem { 13549ec7b004SRick Macklem struct nameidata named; 13559ec7b004SRick Macklem u_int32_t *tl; 1356a9285ae5SZack Kirsch int error = 0, dirfor_ret = 1, diraft_ret = 1; 13579ec7b004SRick Macklem vnode_t dirp = NULL; 13589ec7b004SRick Macklem struct nfsvattr dirfor, diraft; 13599ec7b004SRick Macklem char *bufp; 13609ec7b004SRick Macklem u_long *hashp; 13619ec7b004SRick Macklem 13629ec7b004SRick Macklem if (nd->nd_repstat) { 13639ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1364a9285ae5SZack Kirsch goto out; 13659ec7b004SRick Macklem } 13669ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE, 13679ec7b004SRick Macklem LOCKPARENT | LOCKLEAF); 13689ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 13699ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 13709ec7b004SRick Macklem if (error) { 13719ec7b004SRick Macklem vput(dp); 13729ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1373a9285ae5SZack Kirsch goto out; 13749ec7b004SRick Macklem } 13759ec7b004SRick Macklem if (!nd->nd_repstat) { 13769ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 13779ec7b004SRick Macklem } else { 13789ec7b004SRick Macklem vput(dp); 13799ec7b004SRick Macklem nfsvno_relpathbuf(&named); 13809ec7b004SRick Macklem } 13819ec7b004SRick Macklem if (dirp) { 13829ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) { 13839ec7b004SRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, 13840cf42b62SRick Macklem nd->nd_cred, p, 0); 13859ec7b004SRick Macklem } else { 13869ec7b004SRick Macklem vrele(dirp); 13879ec7b004SRick Macklem dirp = NULL; 13889ec7b004SRick Macklem } 13899ec7b004SRick Macklem } 13909ec7b004SRick Macklem if (!nd->nd_repstat) { 13919ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 13929ec7b004SRick Macklem if (vnode_vtype(named.ni_vp) == VDIR) 13939ec7b004SRick Macklem nd->nd_repstat = nfsvno_rmdirsub(&named, 1, 13949ec7b004SRick Macklem nd->nd_cred, p, exp); 13959ec7b004SRick Macklem else 13969ec7b004SRick Macklem nd->nd_repstat = nfsvno_removesub(&named, 1, 13979ec7b004SRick Macklem nd->nd_cred, p, exp); 13989ec7b004SRick Macklem } else if (nd->nd_procnum == NFSPROC_RMDIR) { 13999ec7b004SRick Macklem nd->nd_repstat = nfsvno_rmdirsub(&named, 0, 14009ec7b004SRick Macklem nd->nd_cred, p, exp); 14019ec7b004SRick Macklem } else { 14029ec7b004SRick Macklem nd->nd_repstat = nfsvno_removesub(&named, 0, 14039ec7b004SRick Macklem nd->nd_cred, p, exp); 14049ec7b004SRick Macklem } 14059ec7b004SRick Macklem } 14069ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) { 14079ec7b004SRick Macklem if (dirp) { 14089ec7b004SRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, 14090cf42b62SRick Macklem p, 0); 14109ec7b004SRick Macklem vrele(dirp); 14119ec7b004SRick Macklem } 14129ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 14139ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 14149ec7b004SRick Macklem &diraft); 14159ec7b004SRick Macklem } else if (!nd->nd_repstat) { 14169ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 14179ec7b004SRick Macklem *tl++ = newnfs_false; 14189ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 14199ec7b004SRick Macklem tl += 2; 14209ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 14219ec7b004SRick Macklem } 14229ec7b004SRick Macklem } 1423a9285ae5SZack Kirsch 1424a9285ae5SZack Kirsch out: 1425a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1426a9285ae5SZack Kirsch return (error); 14279ec7b004SRick Macklem } 14289ec7b004SRick Macklem 14299ec7b004SRick Macklem /* 14309ec7b004SRick Macklem * nfs rename service 14319ec7b004SRick Macklem */ 14329ec7b004SRick Macklem APPLESTATIC int 14339ec7b004SRick Macklem nfsrvd_rename(struct nfsrv_descript *nd, int isdgram, 14349ec7b004SRick Macklem vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp, 14359ec7b004SRick Macklem struct nfsexstuff *toexp) 14369ec7b004SRick Macklem { 14379ec7b004SRick Macklem u_int32_t *tl; 1438a9285ae5SZack Kirsch int error = 0, fdirfor_ret = 1, fdiraft_ret = 1; 14399ec7b004SRick Macklem int tdirfor_ret = 1, tdiraft_ret = 1; 14409ec7b004SRick Macklem struct nameidata fromnd, tond; 14419ec7b004SRick Macklem vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL; 14429ec7b004SRick Macklem struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft; 14439ec7b004SRick Macklem struct nfsexstuff tnes; 14449ec7b004SRick Macklem struct nfsrvfh tfh; 14459ec7b004SRick Macklem char *bufp, *tbufp = NULL; 14469ec7b004SRick Macklem u_long *hashp; 14476b3dfc6aSRick Macklem fhandle_t fh; 14489ec7b004SRick Macklem 14499ec7b004SRick Macklem if (nd->nd_repstat) { 14509ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 14519ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 1452a9285ae5SZack Kirsch goto out; 14539ec7b004SRick Macklem } 14549ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) 14550cf42b62SRick Macklem fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1); 14569ec7b004SRick Macklem tond.ni_cnd.cn_nameiop = 0; 14579ec7b004SRick Macklem tond.ni_startdir = NULL; 14589ec7b004SRick Macklem NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART); 14599ec7b004SRick Macklem nfsvno_setpathbuf(&fromnd, &bufp, &hashp); 14609ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen); 14619ec7b004SRick Macklem if (error) { 14629ec7b004SRick Macklem vput(dp); 14639ec7b004SRick Macklem if (todp) 14649ec7b004SRick Macklem vrele(todp); 14659ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 1466a9285ae5SZack Kirsch goto out; 14679ec7b004SRick Macklem } 146825bfde79SXin LI /* 146925bfde79SXin LI * Unlock dp in this code section, so it is unlocked before 147025bfde79SXin LI * tdp gets locked. This avoids a potential LOR if tdp is the 147125bfde79SXin LI * parent directory of dp. 147225bfde79SXin LI */ 14739ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 14749ec7b004SRick Macklem tdp = todp; 14759ec7b004SRick Macklem tnes = *toexp; 147625bfde79SXin LI if (dp != tdp) { 147725bfde79SXin LI NFSVOPUNLOCK(dp, 0); 147825bfde79SXin LI tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, 147925bfde79SXin LI p, 0); /* Might lock tdp. */ 148025bfde79SXin LI } else { 148125bfde79SXin LI tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, 148225bfde79SXin LI p, 1); 148325bfde79SXin LI NFSVOPUNLOCK(dp, 0); 148425bfde79SXin LI } 14859ec7b004SRick Macklem } else { 14866b3dfc6aSRick Macklem tfh.nfsrvfh_len = 0; 14879ec7b004SRick Macklem error = nfsrv_mtofh(nd, &tfh); 14886b3dfc6aSRick Macklem if (error == 0) 14896b3dfc6aSRick Macklem error = nfsvno_getfh(dp, &fh, p); 14909ec7b004SRick Macklem if (error) { 14919ec7b004SRick Macklem vput(dp); 14929ec7b004SRick Macklem /* todp is always NULL except NFSv4 */ 14939ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 1494a9285ae5SZack Kirsch goto out; 14959ec7b004SRick Macklem } 14966b3dfc6aSRick Macklem 14976b3dfc6aSRick Macklem /* If this is the same file handle, just VREF() the vnode. */ 14986b3dfc6aSRick Macklem if (tfh.nfsrvfh_len == NFSX_MYFH && 14996b3dfc6aSRick Macklem !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) { 15006b3dfc6aSRick Macklem VREF(dp); 15016b3dfc6aSRick Macklem tdp = dp; 15026b3dfc6aSRick Macklem tnes = *exp; 15039ec7b004SRick Macklem tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, 15040cf42b62SRick Macklem p, 1); 150525bfde79SXin LI NFSVOPUNLOCK(dp, 0); 15066b3dfc6aSRick Macklem } else { 150725bfde79SXin LI NFSVOPUNLOCK(dp, 0); 15086b3dfc6aSRick Macklem nd->nd_cred->cr_uid = nd->nd_saveduid; 15096b3dfc6aSRick Macklem nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL, 151025bfde79SXin LI 0, p); /* Locks tdp. */ 15116b3dfc6aSRick Macklem if (tdp) { 15126b3dfc6aSRick Macklem tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, 15136b3dfc6aSRick Macklem nd->nd_cred, p, 1); 1514c383087cSZack Kirsch NFSVOPUNLOCK(tdp, 0); 15159ec7b004SRick Macklem } 15169ec7b004SRick Macklem } 15176b3dfc6aSRick Macklem } 15189ec7b004SRick Macklem NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART); 15199ec7b004SRick Macklem nfsvno_setpathbuf(&tond, &tbufp, &hashp); 15209ec7b004SRick Macklem if (!nd->nd_repstat) { 15219ec7b004SRick Macklem error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen); 15229ec7b004SRick Macklem if (error) { 15238974bc2fSRick Macklem if (tdp) 15249ec7b004SRick Macklem vrele(tdp); 152525bfde79SXin LI vrele(dp); 15269ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 15279ec7b004SRick Macklem nfsvno_relpathbuf(&tond); 1528a9285ae5SZack Kirsch goto out; 15299ec7b004SRick Macklem } 15309ec7b004SRick Macklem } 15319ec7b004SRick Macklem if (nd->nd_repstat) { 15329ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 15339ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 15349ec7b004SRick Macklem &fdiraft); 15359ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 15369ec7b004SRick Macklem &tdiraft); 15379ec7b004SRick Macklem } 15388974bc2fSRick Macklem if (tdp) 15399ec7b004SRick Macklem vrele(tdp); 154025bfde79SXin LI vrele(dp); 15419ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 15429ec7b004SRick Macklem nfsvno_relpathbuf(&tond); 1543a9285ae5SZack Kirsch goto out; 15449ec7b004SRick Macklem } 15459ec7b004SRick Macklem 15469ec7b004SRick Macklem /* 15479ec7b004SRick Macklem * Done parsing, now down to business. 15489ec7b004SRick Macklem */ 154925bfde79SXin LI nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp); 15509ec7b004SRick Macklem if (nd->nd_repstat) { 15519ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 15529ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 15539ec7b004SRick Macklem &fdiraft); 15549ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 15559ec7b004SRick Macklem &tdiraft); 15569ec7b004SRick Macklem } 15579ec7b004SRick Macklem if (fdirp) 15589ec7b004SRick Macklem vrele(fdirp); 15598974bc2fSRick Macklem if (tdp) 15609ec7b004SRick Macklem vrele(tdp); 15619ec7b004SRick Macklem nfsvno_relpathbuf(&tond); 1562a9285ae5SZack Kirsch goto out; 15639ec7b004SRick Macklem } 15649ec7b004SRick Macklem if (vnode_vtype(fromnd.ni_vp) == VDIR) 15659ec7b004SRick Macklem tond.ni_cnd.cn_flags |= WILLBEDIR; 15669ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp); 15679ec7b004SRick Macklem nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat, 15689ec7b004SRick Macklem nd->nd_flag, nd->nd_cred, p); 15699ec7b004SRick Macklem if (fdirp) 15700cf42b62SRick Macklem fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p, 15710cf42b62SRick Macklem 0); 15729ec7b004SRick Macklem if (tdirp) 15730cf42b62SRick Macklem tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p, 15740cf42b62SRick Macklem 0); 15759ec7b004SRick Macklem if (fdirp) 15769ec7b004SRick Macklem vrele(fdirp); 15779ec7b004SRick Macklem if (tdirp) 15789ec7b004SRick Macklem vrele(tdirp); 15799ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 15809ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 15819ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 15829ec7b004SRick Macklem } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 15839ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED); 15849ec7b004SRick Macklem *tl++ = newnfs_false; 15859ec7b004SRick Macklem txdr_hyper(fdirfor.na_filerev, tl); 15869ec7b004SRick Macklem tl += 2; 15879ec7b004SRick Macklem txdr_hyper(fdiraft.na_filerev, tl); 15889ec7b004SRick Macklem tl += 2; 15899ec7b004SRick Macklem *tl++ = newnfs_false; 15909ec7b004SRick Macklem txdr_hyper(tdirfor.na_filerev, tl); 15919ec7b004SRick Macklem tl += 2; 15929ec7b004SRick Macklem txdr_hyper(tdiraft.na_filerev, tl); 15939ec7b004SRick Macklem } 1594a9285ae5SZack Kirsch 1595a9285ae5SZack Kirsch out: 1596a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1597a9285ae5SZack Kirsch return (error); 15989ec7b004SRick Macklem } 15999ec7b004SRick Macklem 16009ec7b004SRick Macklem /* 16019ec7b004SRick Macklem * nfs link service 16029ec7b004SRick Macklem */ 16039ec7b004SRick Macklem APPLESTATIC int 16049ec7b004SRick Macklem nfsrvd_link(struct nfsrv_descript *nd, int isdgram, 16059ec7b004SRick Macklem vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp, 16069ec7b004SRick Macklem struct nfsexstuff *toexp) 16079ec7b004SRick Macklem { 16089ec7b004SRick Macklem struct nameidata named; 16099ec7b004SRick Macklem u_int32_t *tl; 16109ec7b004SRick Macklem int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1; 16119ec7b004SRick Macklem vnode_t dirp = NULL, dp = NULL; 16129ec7b004SRick Macklem struct nfsvattr dirfor, diraft, at; 16139ec7b004SRick Macklem struct nfsexstuff tnes; 16149ec7b004SRick Macklem struct nfsrvfh dfh; 16159ec7b004SRick Macklem char *bufp; 16169ec7b004SRick Macklem u_long *hashp; 16179ec7b004SRick Macklem 16189ec7b004SRick Macklem if (nd->nd_repstat) { 16199ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 16209ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1621a9285ae5SZack Kirsch goto out; 16229ec7b004SRick Macklem } 1623c383087cSZack Kirsch NFSVOPUNLOCK(vp, 0); 16249ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) { 16259ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) 16269ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 16279ec7b004SRick Macklem else 16289ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 16299ec7b004SRick Macklem if (tovp) 16309ec7b004SRick Macklem vrele(tovp); 16319ec7b004SRick Macklem } 16329ec7b004SRick Macklem if (!nd->nd_repstat) { 16339ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 16349ec7b004SRick Macklem dp = tovp; 16359ec7b004SRick Macklem tnes = *toexp; 16369ec7b004SRick Macklem } else { 16379ec7b004SRick Macklem error = nfsrv_mtofh(nd, &dfh); 16389ec7b004SRick Macklem if (error) { 16399ec7b004SRick Macklem vrele(vp); 16409ec7b004SRick Macklem /* tovp is always NULL unless NFSv4 */ 1641a9285ae5SZack Kirsch goto out; 16429ec7b004SRick Macklem } 16438974bc2fSRick Macklem nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0, 164417891d00SRick Macklem p); 16459ec7b004SRick Macklem if (dp) 1646c383087cSZack Kirsch NFSVOPUNLOCK(dp, 0); 16479ec7b004SRick Macklem } 16489ec7b004SRick Macklem } 1649f61786cbSRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1650f61786cbSRick Macklem LOCKPARENT | SAVENAME); 16519ec7b004SRick Macklem if (!nd->nd_repstat) { 16529ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 16539ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 16549ec7b004SRick Macklem if (error) { 16559ec7b004SRick Macklem vrele(vp); 16568974bc2fSRick Macklem if (dp) 16579ec7b004SRick Macklem vrele(dp); 16589ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1659a9285ae5SZack Kirsch goto out; 16609ec7b004SRick Macklem } 16619ec7b004SRick Macklem if (!nd->nd_repstat) { 16629ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes, 16639ec7b004SRick Macklem p, &dirp); 16649ec7b004SRick Macklem } else { 16659ec7b004SRick Macklem if (dp) 16669ec7b004SRick Macklem vrele(dp); 16679ec7b004SRick Macklem nfsvno_relpathbuf(&named); 16689ec7b004SRick Macklem } 16699ec7b004SRick Macklem } 16709ec7b004SRick Macklem if (dirp) { 16719ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 16729ec7b004SRick Macklem vrele(dirp); 16739ec7b004SRick Macklem dirp = NULL; 16749ec7b004SRick Macklem } else { 16759ec7b004SRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, 16760cf42b62SRick Macklem nd->nd_cred, p, 0); 16779ec7b004SRick Macklem } 16789ec7b004SRick Macklem } 16799ec7b004SRick Macklem if (!nd->nd_repstat) 16809ec7b004SRick Macklem nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp); 16819ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 16820cf42b62SRick Macklem getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0); 16839ec7b004SRick Macklem if (dirp) { 16840cf42b62SRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0); 16859ec7b004SRick Macklem vrele(dirp); 16869ec7b004SRick Macklem } 16879ec7b004SRick Macklem vrele(vp); 16889ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 16899ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 16909ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 16919ec7b004SRick Macklem } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 16929ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 16939ec7b004SRick Macklem *tl++ = newnfs_false; 16949ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 16959ec7b004SRick Macklem tl += 2; 16969ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 16979ec7b004SRick Macklem } 1698a9285ae5SZack Kirsch 1699a9285ae5SZack Kirsch out: 1700a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1701a9285ae5SZack Kirsch return (error); 17029ec7b004SRick Macklem } 17039ec7b004SRick Macklem 17049ec7b004SRick Macklem /* 17059ec7b004SRick Macklem * nfs symbolic link service 17069ec7b004SRick Macklem */ 17079ec7b004SRick Macklem APPLESTATIC int 17089ec7b004SRick Macklem nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram, 17099ec7b004SRick Macklem vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 17109ec7b004SRick Macklem struct nfsexstuff *exp) 17119ec7b004SRick Macklem { 17129ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 17139ec7b004SRick Macklem struct nameidata named; 1714a9285ae5SZack Kirsch int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 17159ec7b004SRick Macklem vnode_t dirp = NULL; 17169ec7b004SRick Macklem char *bufp, *pathcp = NULL; 17179ec7b004SRick Macklem u_long *hashp; 17189ec7b004SRick Macklem 17199ec7b004SRick Macklem if (nd->nd_repstat) { 17209ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1721a9285ae5SZack Kirsch goto out; 17229ec7b004SRick Macklem } 17239ec7b004SRick Macklem if (vpp) 17249ec7b004SRick Macklem *vpp = NULL; 17259ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 17269ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 17279ec7b004SRick Macklem LOCKPARENT | SAVESTART); 17289ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 17299ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 17309ec7b004SRick Macklem if (!error && !nd->nd_repstat) 17319ec7b004SRick Macklem error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen); 17329ec7b004SRick Macklem if (error) { 17339ec7b004SRick Macklem vrele(dp); 17349ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1735a9285ae5SZack Kirsch goto out; 17369ec7b004SRick Macklem } 17379ec7b004SRick Macklem if (!nd->nd_repstat) { 17389ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 17399ec7b004SRick Macklem } else { 17409ec7b004SRick Macklem vrele(dp); 17419ec7b004SRick Macklem nfsvno_relpathbuf(&named); 17429ec7b004SRick Macklem } 17439ec7b004SRick Macklem if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 17449ec7b004SRick Macklem vrele(dirp); 17459ec7b004SRick Macklem dirp = NULL; 17469ec7b004SRick Macklem } 17479ec7b004SRick Macklem 17489ec7b004SRick Macklem /* 17499ec7b004SRick Macklem * And call nfsrvd_symlinksub() to do the common code. It will 17509ec7b004SRick Macklem * return EBADRPC upon a parsing error, 0 otherwise. 17519ec7b004SRick Macklem */ 17529ec7b004SRick Macklem if (!nd->nd_repstat) { 17539ec7b004SRick Macklem if (dirp != NULL) 17549ec7b004SRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 17550cf42b62SRick Macklem p, 0); 17569ec7b004SRick Macklem nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 17579ec7b004SRick Macklem &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp, 17589ec7b004SRick Macklem pathcp, pathlen); 17599ec7b004SRick Macklem } else if (dirp != NULL) { 17600cf42b62SRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0); 17619ec7b004SRick Macklem vrele(dirp); 17629ec7b004SRick Macklem } 17639ec7b004SRick Macklem if (pathcp) 17649ec7b004SRick Macklem FREE(pathcp, M_TEMP); 17659ec7b004SRick Macklem 17669ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 17679ec7b004SRick Macklem if (!nd->nd_repstat) { 17689ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 17699ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 17709ec7b004SRick Macklem } 17719ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 17729ec7b004SRick Macklem } 1773a9285ae5SZack Kirsch 1774a9285ae5SZack Kirsch out: 1775a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1776a9285ae5SZack Kirsch return (error); 17779ec7b004SRick Macklem } 17789ec7b004SRick Macklem 17799ec7b004SRick Macklem /* 17809ec7b004SRick Macklem * Common code for creating a symbolic link. 17819ec7b004SRick Macklem */ 17829ec7b004SRick Macklem static void 17839ec7b004SRick Macklem nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 17849ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 17859ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 17869ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, 17879ec7b004SRick Macklem NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 17889ec7b004SRick Macklem int pathlen) 17899ec7b004SRick Macklem { 17909ec7b004SRick Macklem u_int32_t *tl; 17919ec7b004SRick Macklem 17929ec7b004SRick Macklem nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen, 17939ec7b004SRick Macklem !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp); 17949ec7b004SRick Macklem if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) { 17959ec7b004SRick Macklem nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp); 17969ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 17979ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p); 17989ec7b004SRick Macklem if (!nd->nd_repstat) 17999ec7b004SRick Macklem nd->nd_repstat = nfsvno_getattr(ndp->ni_vp, 18000cf42b62SRick Macklem nvap, nd->nd_cred, p, 1); 18019ec7b004SRick Macklem } 180281f78d99SRick Macklem if (vpp != NULL && nd->nd_repstat == 0) { 1803a9989634SZack Kirsch NFSVOPUNLOCK(ndp->ni_vp, 0); 18049ec7b004SRick Macklem *vpp = ndp->ni_vp; 180581f78d99SRick Macklem } else 18069ec7b004SRick Macklem vput(ndp->ni_vp); 18079ec7b004SRick Macklem } 18089ec7b004SRick Macklem if (dirp) { 18090cf42b62SRick Macklem *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0); 18109ec7b004SRick Macklem vrele(dirp); 18119ec7b004SRick Macklem } 18129ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 18139ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 18149ec7b004SRick Macklem *tl++ = newnfs_false; 18159ec7b004SRick Macklem txdr_hyper(dirforp->na_filerev, tl); 18169ec7b004SRick Macklem tl += 2; 18179ec7b004SRick Macklem txdr_hyper(diraftp->na_filerev, tl); 18189ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, attrbitp); 18199ec7b004SRick Macklem } 1820a9285ae5SZack Kirsch 1821a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 18229ec7b004SRick Macklem } 18239ec7b004SRick Macklem 18249ec7b004SRick Macklem /* 18259ec7b004SRick Macklem * nfs mkdir service 18269ec7b004SRick Macklem */ 18279ec7b004SRick Macklem APPLESTATIC int 18289ec7b004SRick Macklem nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram, 18299ec7b004SRick Macklem vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 18309ec7b004SRick Macklem struct nfsexstuff *exp) 18319ec7b004SRick Macklem { 18329ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 18339ec7b004SRick Macklem struct nameidata named; 18349ec7b004SRick Macklem u_int32_t *tl; 1835a9285ae5SZack Kirsch int error = 0, dirfor_ret = 1, diraft_ret = 1; 18369ec7b004SRick Macklem vnode_t dirp = NULL; 18379ec7b004SRick Macklem char *bufp; 18389ec7b004SRick Macklem u_long *hashp; 18399ec7b004SRick Macklem 18409ec7b004SRick Macklem if (nd->nd_repstat) { 18419ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1842a9285ae5SZack Kirsch goto out; 18439ec7b004SRick Macklem } 1844f61786cbSRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1845f61786cbSRick Macklem LOCKPARENT | SAVENAME); 18469ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 18479ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1848a9285ae5SZack Kirsch if (error) 1849a9285ae5SZack Kirsch goto nfsmout; 18509ec7b004SRick Macklem if (!nd->nd_repstat) { 18519ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 18529ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 18539ec7b004SRick Macklem error = nfsrv_sattr(nd, &nva, NULL, NULL, p); 1854a9285ae5SZack Kirsch if (error) 1855a9285ae5SZack Kirsch goto nfsmout; 18569ec7b004SRick Macklem } else { 18579ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 18589ec7b004SRick Macklem nva.na_mode = nfstov_mode(*tl++); 18599ec7b004SRick Macklem } 18609ec7b004SRick Macklem } 18619ec7b004SRick Macklem if (!nd->nd_repstat) { 18629ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 18639ec7b004SRick Macklem } else { 18649ec7b004SRick Macklem vrele(dp); 18659ec7b004SRick Macklem nfsvno_relpathbuf(&named); 18669ec7b004SRick Macklem } 18679ec7b004SRick Macklem if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 18689ec7b004SRick Macklem vrele(dirp); 18699ec7b004SRick Macklem dirp = NULL; 18709ec7b004SRick Macklem } 18719ec7b004SRick Macklem if (nd->nd_repstat) { 18729ec7b004SRick Macklem if (dirp != NULL) { 18739ec7b004SRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 18740cf42b62SRick Macklem p, 0); 18759ec7b004SRick Macklem vrele(dirp); 18769ec7b004SRick Macklem } 18779ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 18789ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 18799ec7b004SRick Macklem &diraft); 1880a9285ae5SZack Kirsch goto out; 18819ec7b004SRick Macklem } 18829ec7b004SRick Macklem if (dirp != NULL) 18830cf42b62SRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0); 18849ec7b004SRick Macklem 18859ec7b004SRick Macklem /* 18869ec7b004SRick Macklem * Call nfsrvd_mkdirsub() for the code common to V4 as well. 18879ec7b004SRick Macklem */ 18889ec7b004SRick Macklem nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft, 18899ec7b004SRick Macklem &diraft_ret, NULL, NULL, p, exp); 18909ec7b004SRick Macklem 18919ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 18929ec7b004SRick Macklem if (!nd->nd_repstat) { 18939ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 18949ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 18959ec7b004SRick Macklem } 18969ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 18979ec7b004SRick Macklem } else if (!nd->nd_repstat) { 18989ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 18999ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 19009ec7b004SRick Macklem } 1901a9285ae5SZack Kirsch 1902a9285ae5SZack Kirsch out: 1903a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 19049ec7b004SRick Macklem return (0); 19059ec7b004SRick Macklem nfsmout: 19069ec7b004SRick Macklem vrele(dp); 19079ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1908a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 19099ec7b004SRick Macklem return (error); 19109ec7b004SRick Macklem } 19119ec7b004SRick Macklem 19129ec7b004SRick Macklem /* 19139ec7b004SRick Macklem * Code common to mkdir for V2,3 and 4. 19149ec7b004SRick Macklem */ 19159ec7b004SRick Macklem static void 19169ec7b004SRick Macklem nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 19179ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 19189ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 19199ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 19209ec7b004SRick Macklem NFSPROC_T *p, struct nfsexstuff *exp) 19219ec7b004SRick Macklem { 19229ec7b004SRick Macklem vnode_t vp; 19239ec7b004SRick Macklem u_int32_t *tl; 19249ec7b004SRick Macklem 19259ec7b004SRick Macklem NFSVNO_SETATTRVAL(nvap, type, VDIR); 19269ec7b004SRick Macklem nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid, 19279ec7b004SRick Macklem nd->nd_cred, p, exp); 19289ec7b004SRick Macklem if (!nd->nd_repstat) { 19299ec7b004SRick Macklem vp = ndp->ni_vp; 19309ec7b004SRick Macklem nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp); 19319ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 19329ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 19339ec7b004SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred, 19340cf42b62SRick Macklem p, 1); 19359ec7b004SRick Macklem if (vpp && !nd->nd_repstat) { 1936c383087cSZack Kirsch NFSVOPUNLOCK(vp, 0); 19379ec7b004SRick Macklem *vpp = vp; 19389ec7b004SRick Macklem } else { 19399ec7b004SRick Macklem vput(vp); 19409ec7b004SRick Macklem } 19419ec7b004SRick Macklem } 19429ec7b004SRick Macklem if (dirp) { 19430cf42b62SRick Macklem *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0); 19449ec7b004SRick Macklem vrele(dirp); 19459ec7b004SRick Macklem } 19469ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 19479ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 19489ec7b004SRick Macklem *tl++ = newnfs_false; 19499ec7b004SRick Macklem txdr_hyper(dirforp->na_filerev, tl); 19509ec7b004SRick Macklem tl += 2; 19519ec7b004SRick Macklem txdr_hyper(diraftp->na_filerev, tl); 19529ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, attrbitp); 19539ec7b004SRick Macklem } 1954a9285ae5SZack Kirsch 1955a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 19569ec7b004SRick Macklem } 19579ec7b004SRick Macklem 19589ec7b004SRick Macklem /* 19599ec7b004SRick Macklem * nfs commit service 19609ec7b004SRick Macklem */ 19619ec7b004SRick Macklem APPLESTATIC int 19629ec7b004SRick Macklem nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram, 19639ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 19649ec7b004SRick Macklem { 19659ec7b004SRick Macklem struct nfsvattr bfor, aft; 19669ec7b004SRick Macklem u_int32_t *tl; 19679ec7b004SRick Macklem int error = 0, for_ret = 1, aft_ret = 1, cnt; 19689ec7b004SRick Macklem u_int64_t off; 19699ec7b004SRick Macklem 19709ec7b004SRick Macklem if (nd->nd_repstat) { 19719ec7b004SRick Macklem nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 1972a9285ae5SZack Kirsch goto out; 19739ec7b004SRick Macklem } 19749ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 19759ec7b004SRick Macklem /* 19769ec7b004SRick Macklem * XXX At this time VOP_FSYNC() does not accept offset and byte 19779ec7b004SRick Macklem * count parameters, so these arguments are useless (someday maybe). 19789ec7b004SRick Macklem */ 19799ec7b004SRick Macklem off = fxdr_hyper(tl); 19809ec7b004SRick Macklem tl += 2; 19819ec7b004SRick Macklem cnt = fxdr_unsigned(int, *tl); 19829ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 19830cf42b62SRick Macklem for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1); 19849ec7b004SRick Macklem nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p); 19859ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 19860cf42b62SRick Macklem aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1); 19879ec7b004SRick Macklem nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 19889ec7b004SRick Macklem } 19899ec7b004SRick Macklem vput(vp); 19909ec7b004SRick Macklem if (!nd->nd_repstat) { 19919ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 19929ec7b004SRick Macklem *tl++ = txdr_unsigned(nfsboottime.tv_sec); 19939ec7b004SRick Macklem *tl = txdr_unsigned(nfsboottime.tv_usec); 19949ec7b004SRick Macklem } 1995a9285ae5SZack Kirsch 1996a9285ae5SZack Kirsch out: 1997a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 19989ec7b004SRick Macklem return (0); 19999ec7b004SRick Macklem nfsmout: 20009ec7b004SRick Macklem vput(vp); 2001a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 20029ec7b004SRick Macklem return (error); 20039ec7b004SRick Macklem } 20049ec7b004SRick Macklem 20059ec7b004SRick Macklem /* 20069ec7b004SRick Macklem * nfs statfs service 20079ec7b004SRick Macklem */ 20089ec7b004SRick Macklem APPLESTATIC int 20099ec7b004SRick Macklem nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram, 20109ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 20119ec7b004SRick Macklem { 20129ec7b004SRick Macklem struct statfs *sf; 20139ec7b004SRick Macklem u_int32_t *tl; 20149ec7b004SRick Macklem int getret = 1; 20159ec7b004SRick Macklem struct nfsvattr at; 20169ec7b004SRick Macklem struct statfs sfs; 20179ec7b004SRick Macklem u_quad_t tval; 20189ec7b004SRick Macklem 20199ec7b004SRick Macklem if (nd->nd_repstat) { 20209ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 2021a9285ae5SZack Kirsch goto out; 20229ec7b004SRick Macklem } 20239ec7b004SRick Macklem sf = &sfs; 2024dfd233edSAttilio Rao nd->nd_repstat = nfsvno_statfs(vp, sf); 20250cf42b62SRick Macklem getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 20269ec7b004SRick Macklem vput(vp); 20279ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 20289ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 20299ec7b004SRick Macklem if (nd->nd_repstat) 2030a9285ae5SZack Kirsch goto out; 20319ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 20329ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS); 20339ec7b004SRick Macklem *tl++ = txdr_unsigned(NFS_V2MAXDATA); 20349ec7b004SRick Macklem *tl++ = txdr_unsigned(sf->f_bsize); 20359ec7b004SRick Macklem *tl++ = txdr_unsigned(sf->f_blocks); 20369ec7b004SRick Macklem *tl++ = txdr_unsigned(sf->f_bfree); 20379ec7b004SRick Macklem *tl = txdr_unsigned(sf->f_bavail); 20389ec7b004SRick Macklem } else { 20399ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS); 20409ec7b004SRick Macklem tval = (u_quad_t)sf->f_blocks; 20419ec7b004SRick Macklem tval *= (u_quad_t)sf->f_bsize; 20429ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 20439ec7b004SRick Macklem tval = (u_quad_t)sf->f_bfree; 20449ec7b004SRick Macklem tval *= (u_quad_t)sf->f_bsize; 20459ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 20469ec7b004SRick Macklem tval = (u_quad_t)sf->f_bavail; 20479ec7b004SRick Macklem tval *= (u_quad_t)sf->f_bsize; 20489ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 20499ec7b004SRick Macklem tval = (u_quad_t)sf->f_files; 20509ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 20519ec7b004SRick Macklem tval = (u_quad_t)sf->f_ffree; 20529ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 20539ec7b004SRick Macklem tval = (u_quad_t)sf->f_ffree; 20549ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 20559ec7b004SRick Macklem *tl = 0; 20569ec7b004SRick Macklem } 2057a9285ae5SZack Kirsch 2058a9285ae5SZack Kirsch out: 2059a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 20609ec7b004SRick Macklem return (0); 20619ec7b004SRick Macklem } 20629ec7b004SRick Macklem 20639ec7b004SRick Macklem /* 20649ec7b004SRick Macklem * nfs fsinfo service 20659ec7b004SRick Macklem */ 20669ec7b004SRick Macklem APPLESTATIC int 20679ec7b004SRick Macklem nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram, 20689ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 20699ec7b004SRick Macklem { 20709ec7b004SRick Macklem u_int32_t *tl; 20719ec7b004SRick Macklem struct nfsfsinfo fs; 20729ec7b004SRick Macklem int getret = 1; 20739ec7b004SRick Macklem struct nfsvattr at; 20749ec7b004SRick Macklem 20759ec7b004SRick Macklem if (nd->nd_repstat) { 20769ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 2077a9285ae5SZack Kirsch goto out; 20789ec7b004SRick Macklem } 20790cf42b62SRick Macklem getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 20809ec7b004SRick Macklem nfsvno_getfs(&fs, isdgram); 20819ec7b004SRick Macklem vput(vp); 20829ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 20839ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO); 20849ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_rtmax); 20859ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_rtpref); 20869ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_rtmult); 20879ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_wtmax); 20889ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_wtpref); 20899ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_wtmult); 20909ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_dtpref); 20919ec7b004SRick Macklem txdr_hyper(fs.fs_maxfilesize, tl); 20929ec7b004SRick Macklem tl += 2; 20939ec7b004SRick Macklem txdr_nfsv3time(&fs.fs_timedelta, tl); 20949ec7b004SRick Macklem tl += 2; 20959ec7b004SRick Macklem *tl = txdr_unsigned(fs.fs_properties); 2096a9285ae5SZack Kirsch 2097a9285ae5SZack Kirsch out: 2098a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 20999ec7b004SRick Macklem return (0); 21009ec7b004SRick Macklem } 21019ec7b004SRick Macklem 21029ec7b004SRick Macklem /* 21039ec7b004SRick Macklem * nfs pathconf service 21049ec7b004SRick Macklem */ 21059ec7b004SRick Macklem APPLESTATIC int 21069ec7b004SRick Macklem nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram, 21079ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 21089ec7b004SRick Macklem { 21099ec7b004SRick Macklem struct nfsv3_pathconf *pc; 21109ec7b004SRick Macklem int getret = 1; 21119ec7b004SRick Macklem register_t linkmax, namemax, chownres, notrunc; 21129ec7b004SRick Macklem struct nfsvattr at; 21139ec7b004SRick Macklem 21149ec7b004SRick Macklem if (nd->nd_repstat) { 21159ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 2116a9285ae5SZack Kirsch goto out; 21179ec7b004SRick Macklem } 21189ec7b004SRick Macklem nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax, 21199ec7b004SRick Macklem nd->nd_cred, p); 21209ec7b004SRick Macklem if (!nd->nd_repstat) 21219ec7b004SRick Macklem nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax, 21229ec7b004SRick Macklem nd->nd_cred, p); 21239ec7b004SRick Macklem if (!nd->nd_repstat) 21249ec7b004SRick Macklem nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED, 21259ec7b004SRick Macklem &chownres, nd->nd_cred, p); 21269ec7b004SRick Macklem if (!nd->nd_repstat) 21279ec7b004SRick Macklem nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc, 21289ec7b004SRick Macklem nd->nd_cred, p); 21290cf42b62SRick Macklem getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 21309ec7b004SRick Macklem vput(vp); 21319ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 21329ec7b004SRick Macklem if (!nd->nd_repstat) { 21339ec7b004SRick Macklem NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); 21349ec7b004SRick Macklem pc->pc_linkmax = txdr_unsigned(linkmax); 21359ec7b004SRick Macklem pc->pc_namemax = txdr_unsigned(namemax); 21369ec7b004SRick Macklem pc->pc_notrunc = txdr_unsigned(notrunc); 21379ec7b004SRick Macklem pc->pc_chownrestricted = txdr_unsigned(chownres); 21389ec7b004SRick Macklem 21399ec7b004SRick Macklem /* 21409ec7b004SRick Macklem * These should probably be supported by VOP_PATHCONF(), but 21419ec7b004SRick Macklem * until msdosfs is exportable (why would you want to?), the 21429ec7b004SRick Macklem * Unix defaults should be ok. 21439ec7b004SRick Macklem */ 21449ec7b004SRick Macklem pc->pc_caseinsensitive = newnfs_false; 21459ec7b004SRick Macklem pc->pc_casepreserving = newnfs_true; 21469ec7b004SRick Macklem } 2147a9285ae5SZack Kirsch 2148a9285ae5SZack Kirsch out: 2149a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 21509ec7b004SRick Macklem return (0); 21519ec7b004SRick Macklem } 21529ec7b004SRick Macklem 21539ec7b004SRick Macklem /* 21549ec7b004SRick Macklem * nfsv4 lock service 21559ec7b004SRick Macklem */ 21569ec7b004SRick Macklem APPLESTATIC int 21579ec7b004SRick Macklem nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram, 21589ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 21599ec7b004SRick Macklem { 21609ec7b004SRick Macklem u_int32_t *tl; 21619ec7b004SRick Macklem int i; 21629ec7b004SRick Macklem struct nfsstate *stp = NULL; 21639ec7b004SRick Macklem struct nfslock *lop; 21649ec7b004SRick Macklem struct nfslockconflict cf; 21659ec7b004SRick Macklem int error = 0; 21669ec7b004SRick Macklem u_short flags = NFSLCK_LOCK, lflags; 21679ec7b004SRick Macklem u_int64_t offset, len; 21689ec7b004SRick Macklem nfsv4stateid_t stateid; 21699ec7b004SRick Macklem nfsquad_t clientid; 21709ec7b004SRick Macklem 21719ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 21729ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 21739ec7b004SRick Macklem switch (i) { 21749ec7b004SRick Macklem case NFSV4LOCKT_READW: 21759ec7b004SRick Macklem flags |= NFSLCK_BLOCKING; 21769ec7b004SRick Macklem case NFSV4LOCKT_READ: 21779ec7b004SRick Macklem lflags = NFSLCK_READ; 21789ec7b004SRick Macklem break; 21799ec7b004SRick Macklem case NFSV4LOCKT_WRITEW: 21809ec7b004SRick Macklem flags |= NFSLCK_BLOCKING; 21819ec7b004SRick Macklem case NFSV4LOCKT_WRITE: 21829ec7b004SRick Macklem lflags = NFSLCK_WRITE; 21839ec7b004SRick Macklem break; 21849ec7b004SRick Macklem default: 21859ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 21869ec7b004SRick Macklem goto nfsmout; 21879ec7b004SRick Macklem }; 21889ec7b004SRick Macklem if (*tl++ == newnfs_true) 21899ec7b004SRick Macklem flags |= NFSLCK_RECLAIM; 21909ec7b004SRick Macklem offset = fxdr_hyper(tl); 21919ec7b004SRick Macklem tl += 2; 21929ec7b004SRick Macklem len = fxdr_hyper(tl); 21939ec7b004SRick Macklem tl += 2; 21949ec7b004SRick Macklem if (*tl == newnfs_true) 21959ec7b004SRick Macklem flags |= NFSLCK_OPENTOLOCK; 21969ec7b004SRick Macklem if (flags & NFSLCK_OPENTOLOCK) { 21979ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID); 21989ec7b004SRick Macklem i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED))); 21992a45247cSRick Macklem if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 22002a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 22012a45247cSRick Macklem goto nfsmout; 22022a45247cSRick Macklem } 22039ec7b004SRick Macklem MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 22049ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 22059ec7b004SRick Macklem stp->ls_ownerlen = i; 22069ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 22079ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(int, *tl++); 22089ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 22099ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 22109ec7b004SRick Macklem NFSX_STATEIDOTHER); 22119ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 22129ec7b004SRick Macklem stp->ls_opentolockseq = fxdr_unsigned(int, *tl++); 22139ec7b004SRick Macklem clientid.lval[0] = *tl++; 22149ec7b004SRick Macklem clientid.lval[1] = *tl++; 2215*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2216*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2217*c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2218*c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2219*c59e4cc3SRick Macklem printf("EEK3 multiple clids\n"); 22209ec7b004SRick Macklem } else { 2221*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2222*c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 22239ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 22249ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 22259ec7b004SRick Macklem } 22269ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 22279ec7b004SRick Macklem if (error) 22289ec7b004SRick Macklem goto nfsmout; 22299ec7b004SRick Macklem } else { 22309ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 22319ec7b004SRick Macklem MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate), 22329ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 22339ec7b004SRick Macklem stp->ls_ownerlen = 0; 22349ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 22359ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 22369ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 22379ec7b004SRick Macklem NFSX_STATEIDOTHER); 22389ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 22399ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(int, *tl); 22409ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 22419ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 2242*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2243*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2244*c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2245*c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2246*c59e4cc3SRick Macklem printf("EEK4 multiple clids\n"); 22479ec7b004SRick Macklem } else { 2248*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2249*c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 22509ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 22519ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 22529ec7b004SRick Macklem } 22539ec7b004SRick Macklem } 22549ec7b004SRick Macklem MALLOC(lop, struct nfslock *, sizeof (struct nfslock), 22559ec7b004SRick Macklem M_NFSDLOCK, M_WAITOK); 22569ec7b004SRick Macklem lop->lo_first = offset; 22579ec7b004SRick Macklem if (len == NFS64BITSSET) { 22589ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 22599ec7b004SRick Macklem } else { 22609ec7b004SRick Macklem lop->lo_end = offset + len; 22619ec7b004SRick Macklem if (lop->lo_end <= lop->lo_first) 22629ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 22639ec7b004SRick Macklem } 22649ec7b004SRick Macklem lop->lo_flags = lflags; 22659ec7b004SRick Macklem stp->ls_flags = flags; 22669ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 22679ec7b004SRick Macklem 22689ec7b004SRick Macklem /* 22699ec7b004SRick Macklem * Do basic access checking. 22709ec7b004SRick Macklem */ 22719ec7b004SRick Macklem if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 22729ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 22739ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 22749ec7b004SRick Macklem else 22759ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 22769ec7b004SRick Macklem } 22779ec7b004SRick Macklem if (!nd->nd_repstat) { 22789ec7b004SRick Macklem if (lflags & NFSLCK_WRITE) { 22798da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 22809ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 22818da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 22829ec7b004SRick Macklem } else { 22838da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, 22849ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 22858da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 22869ec7b004SRick Macklem if (nd->nd_repstat) 22878da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 22889ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 22898da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 22909ec7b004SRick Macklem } 22919ec7b004SRick Macklem } 22929ec7b004SRick Macklem 22939ec7b004SRick Macklem /* 22949ec7b004SRick Macklem * We call nfsrv_lockctrl() even if nd_repstat set, so that the 22959ec7b004SRick Macklem * seqid# gets updated. nfsrv_lockctrl() will return the value 22969ec7b004SRick Macklem * of nd_repstat, if it gets that far. 22979ec7b004SRick Macklem */ 22989ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 22999ec7b004SRick Macklem &stateid, exp, nd, p); 23009ec7b004SRick Macklem if (lop) 23019ec7b004SRick Macklem FREE((caddr_t)lop, M_NFSDLOCK); 23029ec7b004SRick Macklem if (stp) 23039ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 23049ec7b004SRick Macklem if (!nd->nd_repstat) { 23059ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 23069ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 23079ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 23089ec7b004SRick Macklem } else if (nd->nd_repstat == NFSERR_DENIED) { 23099ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 23109ec7b004SRick Macklem txdr_hyper(cf.cl_first, tl); 23119ec7b004SRick Macklem tl += 2; 23129ec7b004SRick Macklem if (cf.cl_end == NFS64BITSSET) 23139ec7b004SRick Macklem len = NFS64BITSSET; 23149ec7b004SRick Macklem else 23159ec7b004SRick Macklem len = cf.cl_end - cf.cl_first; 23169ec7b004SRick Macklem txdr_hyper(len, tl); 23179ec7b004SRick Macklem tl += 2; 23189ec7b004SRick Macklem if (cf.cl_flags == NFSLCK_WRITE) 23199ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 23209ec7b004SRick Macklem else 23219ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 23229ec7b004SRick Macklem *tl++ = stateid.other[0]; 23239ec7b004SRick Macklem *tl = stateid.other[1]; 23249ec7b004SRick Macklem (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 23259ec7b004SRick Macklem } 23269ec7b004SRick Macklem vput(vp); 2327a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 23289ec7b004SRick Macklem return (0); 23299ec7b004SRick Macklem nfsmout: 23309ec7b004SRick Macklem vput(vp); 23319ec7b004SRick Macklem if (stp) 23329ec7b004SRick Macklem free((caddr_t)stp, M_NFSDSTATE); 2333a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 23349ec7b004SRick Macklem return (error); 23359ec7b004SRick Macklem } 23369ec7b004SRick Macklem 23379ec7b004SRick Macklem /* 23389ec7b004SRick Macklem * nfsv4 lock test service 23399ec7b004SRick Macklem */ 23409ec7b004SRick Macklem APPLESTATIC int 23419ec7b004SRick Macklem nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram, 23429ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 23439ec7b004SRick Macklem { 23449ec7b004SRick Macklem u_int32_t *tl; 23459ec7b004SRick Macklem int i; 23469ec7b004SRick Macklem struct nfsstate *stp = NULL; 23479ec7b004SRick Macklem struct nfslock lo, *lop = &lo; 23489ec7b004SRick Macklem struct nfslockconflict cf; 23499ec7b004SRick Macklem int error = 0; 23509ec7b004SRick Macklem nfsv4stateid_t stateid; 23519ec7b004SRick Macklem nfsquad_t clientid; 23529ec7b004SRick Macklem u_int64_t len; 23539ec7b004SRick Macklem 23549ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 23559ec7b004SRick Macklem i = fxdr_unsigned(int, *(tl + 7)); 23562a45247cSRick Macklem if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 23572a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 23582a45247cSRick Macklem goto nfsmout; 23592a45247cSRick Macklem } 23609ec7b004SRick Macklem MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 23619ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 23629ec7b004SRick Macklem stp->ls_ownerlen = i; 23639ec7b004SRick Macklem stp->ls_op = NULL; 23649ec7b004SRick Macklem stp->ls_flags = NFSLCK_TEST; 23659ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 23669ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 23679ec7b004SRick Macklem switch (i) { 23689ec7b004SRick Macklem case NFSV4LOCKT_READW: 23699ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 23709ec7b004SRick Macklem case NFSV4LOCKT_READ: 23719ec7b004SRick Macklem lo.lo_flags = NFSLCK_READ; 23729ec7b004SRick Macklem break; 23739ec7b004SRick Macklem case NFSV4LOCKT_WRITEW: 23749ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 23759ec7b004SRick Macklem case NFSV4LOCKT_WRITE: 23769ec7b004SRick Macklem lo.lo_flags = NFSLCK_WRITE; 23779ec7b004SRick Macklem break; 23789ec7b004SRick Macklem default: 23799ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 23809ec7b004SRick Macklem goto nfsmout; 23819ec7b004SRick Macklem }; 23829ec7b004SRick Macklem lo.lo_first = fxdr_hyper(tl); 23839ec7b004SRick Macklem tl += 2; 23849ec7b004SRick Macklem len = fxdr_hyper(tl); 23859ec7b004SRick Macklem if (len == NFS64BITSSET) { 23869ec7b004SRick Macklem lo.lo_end = NFS64BITSSET; 23879ec7b004SRick Macklem } else { 23889ec7b004SRick Macklem lo.lo_end = lo.lo_first + len; 23899ec7b004SRick Macklem if (lo.lo_end <= lo.lo_first) 23909ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 23919ec7b004SRick Macklem } 23929ec7b004SRick Macklem tl += 2; 23939ec7b004SRick Macklem clientid.lval[0] = *tl++; 23949ec7b004SRick Macklem clientid.lval[1] = *tl; 2395*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2396*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2397*c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2398*c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2399*c59e4cc3SRick Macklem printf("EEK5 multiple clids\n"); 24009ec7b004SRick Macklem } else { 2401*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2402*c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 24039ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 24049ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 24059ec7b004SRick Macklem } 24069ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 24079ec7b004SRick Macklem if (error) 24089ec7b004SRick Macklem goto nfsmout; 24099ec7b004SRick Macklem if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 24109ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 24119ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 24129ec7b004SRick Macklem else 24139ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 24149ec7b004SRick Macklem } 24159ec7b004SRick Macklem if (!nd->nd_repstat) 24169ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 24179ec7b004SRick Macklem &stateid, exp, nd, p); 24189ec7b004SRick Macklem if (stp) 24199ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 24209ec7b004SRick Macklem if (nd->nd_repstat) { 24219ec7b004SRick Macklem if (nd->nd_repstat == NFSERR_DENIED) { 24229ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 24239ec7b004SRick Macklem txdr_hyper(cf.cl_first, tl); 24249ec7b004SRick Macklem tl += 2; 24259ec7b004SRick Macklem if (cf.cl_end == NFS64BITSSET) 24269ec7b004SRick Macklem len = NFS64BITSSET; 24279ec7b004SRick Macklem else 24289ec7b004SRick Macklem len = cf.cl_end - cf.cl_first; 24299ec7b004SRick Macklem txdr_hyper(len, tl); 24309ec7b004SRick Macklem tl += 2; 24319ec7b004SRick Macklem if (cf.cl_flags == NFSLCK_WRITE) 24329ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 24339ec7b004SRick Macklem else 24349ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 24359ec7b004SRick Macklem *tl++ = stp->ls_stateid.other[0]; 24369ec7b004SRick Macklem *tl = stp->ls_stateid.other[1]; 24379ec7b004SRick Macklem (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 24389ec7b004SRick Macklem } 24399ec7b004SRick Macklem } 24409ec7b004SRick Macklem vput(vp); 2441a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 24429ec7b004SRick Macklem return (0); 24439ec7b004SRick Macklem nfsmout: 24449ec7b004SRick Macklem vput(vp); 24459ec7b004SRick Macklem if (stp) 24469ec7b004SRick Macklem free((caddr_t)stp, M_NFSDSTATE); 2447a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 24489ec7b004SRick Macklem return (error); 24499ec7b004SRick Macklem } 24509ec7b004SRick Macklem 24519ec7b004SRick Macklem /* 24529ec7b004SRick Macklem * nfsv4 unlock service 24539ec7b004SRick Macklem */ 24549ec7b004SRick Macklem APPLESTATIC int 24559ec7b004SRick Macklem nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram, 24569ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 24579ec7b004SRick Macklem { 24589ec7b004SRick Macklem u_int32_t *tl; 24599ec7b004SRick Macklem int i; 24609ec7b004SRick Macklem struct nfsstate *stp; 24619ec7b004SRick Macklem struct nfslock *lop; 24629ec7b004SRick Macklem int error = 0; 24639ec7b004SRick Macklem nfsv4stateid_t stateid; 24649ec7b004SRick Macklem nfsquad_t clientid; 24659ec7b004SRick Macklem u_int64_t len; 24669ec7b004SRick Macklem 24679ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID); 24689ec7b004SRick Macklem MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate), 24699ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 24709ec7b004SRick Macklem MALLOC(lop, struct nfslock *, sizeof (struct nfslock), 24719ec7b004SRick Macklem M_NFSDLOCK, M_WAITOK); 24729ec7b004SRick Macklem stp->ls_flags = NFSLCK_UNLOCK; 24739ec7b004SRick Macklem lop->lo_flags = NFSLCK_UNLOCK; 24749ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 24759ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 24769ec7b004SRick Macklem switch (i) { 24779ec7b004SRick Macklem case NFSV4LOCKT_READW: 24789ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 24799ec7b004SRick Macklem case NFSV4LOCKT_READ: 24809ec7b004SRick Macklem break; 24819ec7b004SRick Macklem case NFSV4LOCKT_WRITEW: 24829ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 24839ec7b004SRick Macklem case NFSV4LOCKT_WRITE: 24849ec7b004SRick Macklem break; 24859ec7b004SRick Macklem default: 24869ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 24872a45247cSRick Macklem free(stp, M_NFSDSTATE); 24882a45247cSRick Macklem free(lop, M_NFSDLOCK); 24899ec7b004SRick Macklem goto nfsmout; 24909ec7b004SRick Macklem }; 24919ec7b004SRick Macklem stp->ls_ownerlen = 0; 24929ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 24939ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(int, *tl++); 24949ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 24959ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 24969ec7b004SRick Macklem NFSX_STATEIDOTHER); 24979ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 24989ec7b004SRick Macklem lop->lo_first = fxdr_hyper(tl); 24999ec7b004SRick Macklem tl += 2; 25009ec7b004SRick Macklem len = fxdr_hyper(tl); 25019ec7b004SRick Macklem if (len == NFS64BITSSET) { 25029ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 25039ec7b004SRick Macklem } else { 25049ec7b004SRick Macklem lop->lo_end = lop->lo_first + len; 25059ec7b004SRick Macklem if (lop->lo_end <= lop->lo_first) 25069ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 25079ec7b004SRick Macklem } 25089ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 25099ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 2510*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2511*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2512*c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2513*c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2514*c59e4cc3SRick Macklem printf("EEK6 multiple clids\n"); 25159ec7b004SRick Macklem } else { 2516*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2517*c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 25189ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 25199ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 25209ec7b004SRick Macklem } 25219ec7b004SRick Macklem if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 25229ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 25239ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 25249ec7b004SRick Macklem else 25259ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 25269ec7b004SRick Macklem } 25279ec7b004SRick Macklem /* 25289ec7b004SRick Macklem * Call nfsrv_lockctrl() even if nd_repstat is set, so that the 25299ec7b004SRick Macklem * seqid# gets incremented. nfsrv_lockctrl() will return the 25309ec7b004SRick Macklem * value of nd_repstat, if it gets that far. 25319ec7b004SRick Macklem */ 25329ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 25339ec7b004SRick Macklem &stateid, exp, nd, p); 25349ec7b004SRick Macklem if (stp) 25359ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 25369ec7b004SRick Macklem if (lop) 25379ec7b004SRick Macklem free((caddr_t)lop, M_NFSDLOCK); 25389ec7b004SRick Macklem if (!nd->nd_repstat) { 25399ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 25409ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 25419ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 25429ec7b004SRick Macklem } 25439ec7b004SRick Macklem nfsmout: 25449ec7b004SRick Macklem vput(vp); 2545a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 25469ec7b004SRick Macklem return (error); 25479ec7b004SRick Macklem } 25489ec7b004SRick Macklem 25499ec7b004SRick Macklem /* 25509ec7b004SRick Macklem * nfsv4 open service 25519ec7b004SRick Macklem */ 25529ec7b004SRick Macklem APPLESTATIC int 25539ec7b004SRick Macklem nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram, 25549ec7b004SRick Macklem vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p, 25559ec7b004SRick Macklem struct nfsexstuff *exp) 25569ec7b004SRick Macklem { 25579ec7b004SRick Macklem u_int32_t *tl; 2558*c59e4cc3SRick Macklem int i, retext; 25599ec7b004SRick Macklem struct nfsstate *stp = NULL; 25609ec7b004SRick Macklem int error = 0, create, claim, exclusive_flag = 0; 25619ec7b004SRick Macklem u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask; 25629ec7b004SRick Macklem int how = NFSCREATE_UNCHECKED; 2563086f6e0cSRick Macklem int32_t cverf[2], tverf[2] = { 0, 0 }; 25649ec7b004SRick Macklem vnode_t vp = NULL, dirp = NULL; 25659ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 25669ec7b004SRick Macklem struct nameidata named; 25679ec7b004SRick Macklem nfsv4stateid_t stateid, delegstateid; 25689ec7b004SRick Macklem nfsattrbit_t attrbits; 25699ec7b004SRick Macklem nfsquad_t clientid; 25709ec7b004SRick Macklem char *bufp = NULL; 25719ec7b004SRick Macklem u_long *hashp; 25729ec7b004SRick Macklem NFSACL_T *aclp = NULL; 25739ec7b004SRick Macklem 25749ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 2575c3e22f83SRick Macklem aclp = acl_alloc(M_WAITOK); 25769ec7b004SRick Macklem aclp->acl_cnt = 0; 25779ec7b004SRick Macklem #endif 25789ec7b004SRick Macklem NFSZERO_ATTRBIT(&attrbits); 25799ec7b004SRick Macklem named.ni_startdir = NULL; 25809ec7b004SRick Macklem named.ni_cnd.cn_nameiop = 0; 25819ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 25829ec7b004SRick Macklem i = fxdr_unsigned(int, *(tl + 5)); 25832a45247cSRick Macklem if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 25842a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 2585a9285ae5SZack Kirsch goto nfsmout; 25862a45247cSRick Macklem } 25879ec7b004SRick Macklem MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 25889ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 25899ec7b004SRick Macklem stp->ls_ownerlen = i; 25909ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 25919ec7b004SRick Macklem stp->ls_flags = NFSLCK_OPEN; 25929ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 25939ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 25949ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 2595*c59e4cc3SRick Macklem retext = 0; 2596*c59e4cc3SRick Macklem if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG | 2597*c59e4cc3SRick Macklem NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) { 2598*c59e4cc3SRick Macklem retext = 1; 2599*c59e4cc3SRick Macklem /* For now, ignore these. */ 2600*c59e4cc3SRick Macklem i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG); 2601*c59e4cc3SRick Macklem switch (i & NFSV4OPEN_WANTDELEGMASK) { 2602*c59e4cc3SRick Macklem case NFSV4OPEN_WANTANYDELEG: 2603*c59e4cc3SRick Macklem stp->ls_flags |= (NFSLCK_WANTRDELEG | 2604*c59e4cc3SRick Macklem NFSLCK_WANTWDELEG); 2605*c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2606*c59e4cc3SRick Macklem break; 2607*c59e4cc3SRick Macklem case NFSV4OPEN_WANTREADDELEG: 2608*c59e4cc3SRick Macklem stp->ls_flags |= NFSLCK_WANTRDELEG; 2609*c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2610*c59e4cc3SRick Macklem break; 2611*c59e4cc3SRick Macklem case NFSV4OPEN_WANTWRITEDELEG: 2612*c59e4cc3SRick Macklem stp->ls_flags |= NFSLCK_WANTWDELEG; 2613*c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2614*c59e4cc3SRick Macklem break; 2615*c59e4cc3SRick Macklem case NFSV4OPEN_WANTNODELEG: 2616*c59e4cc3SRick Macklem stp->ls_flags |= NFSLCK_WANTNODELEG; 2617*c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2618*c59e4cc3SRick Macklem break; 2619*c59e4cc3SRick Macklem case NFSV4OPEN_WANTCANCEL: 2620*c59e4cc3SRick Macklem printf("NFSv4: ignore Open WantCancel\n"); 2621*c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2622*c59e4cc3SRick Macklem break; 2623*c59e4cc3SRick Macklem default: 2624*c59e4cc3SRick Macklem /* nd_repstat will be set to NFSERR_INVAL below. */ 2625*c59e4cc3SRick Macklem break; 2626*c59e4cc3SRick Macklem }; 2627*c59e4cc3SRick Macklem } 26289ec7b004SRick Macklem switch (i) { 26299ec7b004SRick Macklem case NFSV4OPEN_ACCESSREAD: 26309ec7b004SRick Macklem stp->ls_flags |= NFSLCK_READACCESS; 26319ec7b004SRick Macklem break; 26329ec7b004SRick Macklem case NFSV4OPEN_ACCESSWRITE: 26339ec7b004SRick Macklem stp->ls_flags |= NFSLCK_WRITEACCESS; 26349ec7b004SRick Macklem break; 26359ec7b004SRick Macklem case NFSV4OPEN_ACCESSBOTH: 26369ec7b004SRick Macklem stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 26379ec7b004SRick Macklem break; 26389ec7b004SRick Macklem default: 26399ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 26409ec7b004SRick Macklem }; 26419ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 26429ec7b004SRick Macklem switch (i) { 26439ec7b004SRick Macklem case NFSV4OPEN_DENYNONE: 26449ec7b004SRick Macklem break; 26459ec7b004SRick Macklem case NFSV4OPEN_DENYREAD: 26469ec7b004SRick Macklem stp->ls_flags |= NFSLCK_READDENY; 26479ec7b004SRick Macklem break; 26489ec7b004SRick Macklem case NFSV4OPEN_DENYWRITE: 26499ec7b004SRick Macklem stp->ls_flags |= NFSLCK_WRITEDENY; 26509ec7b004SRick Macklem break; 26519ec7b004SRick Macklem case NFSV4OPEN_DENYBOTH: 26529ec7b004SRick Macklem stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 26539ec7b004SRick Macklem break; 26549ec7b004SRick Macklem default: 26559ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 26569ec7b004SRick Macklem }; 26579ec7b004SRick Macklem clientid.lval[0] = *tl++; 26589ec7b004SRick Macklem clientid.lval[1] = *tl; 2659*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2660*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2661*c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2662*c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2663*c59e4cc3SRick Macklem printf("EEK7 multiple clids\n"); 26649ec7b004SRick Macklem } else { 2665*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2666*c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 26679ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 26689ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 26699ec7b004SRick Macklem } 26709ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2671a9285ae5SZack Kirsch if (error) 2672a9285ae5SZack Kirsch goto nfsmout; 26739ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 26749ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 26759ec7b004SRick Macklem create = fxdr_unsigned(int, *tl); 26769ec7b004SRick Macklem if (!nd->nd_repstat) 26770cf42b62SRick Macklem nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0); 26789ec7b004SRick Macklem if (create == NFSV4OPEN_CREATE) { 26799ec7b004SRick Macklem nva.na_type = VREG; 26809ec7b004SRick Macklem nva.na_mode = 0; 26819ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 26829ec7b004SRick Macklem how = fxdr_unsigned(int, *tl); 26839ec7b004SRick Macklem switch (how) { 26849ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 26859ec7b004SRick Macklem case NFSCREATE_GUARDED: 26869ec7b004SRick Macklem error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p); 2687a9285ae5SZack Kirsch if (error) 2688a9285ae5SZack Kirsch goto nfsmout; 26899ec7b004SRick Macklem /* 26909ec7b004SRick Macklem * If the na_gid being set is the same as that of 26919ec7b004SRick Macklem * the directory it is going in, clear it, since 26929ec7b004SRick Macklem * that is what will be set by default. This allows 26939ec7b004SRick Macklem * a user that isn't in that group to do the create. 26949ec7b004SRick Macklem */ 26959ec7b004SRick Macklem if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) && 26969ec7b004SRick Macklem nva.na_gid == dirfor.na_gid) 26979ec7b004SRick Macklem NFSVNO_UNSET(&nva, gid); 26989ec7b004SRick Macklem if (!nd->nd_repstat) 26999ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 27009ec7b004SRick Macklem break; 27019ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 27029ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2703086f6e0cSRick Macklem cverf[0] = *tl++; 2704086f6e0cSRick Macklem cverf[1] = *tl; 27059ec7b004SRick Macklem break; 2706*c59e4cc3SRick Macklem case NFSCREATE_EXCLUSIVE41: 2707*c59e4cc3SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2708*c59e4cc3SRick Macklem cverf[0] = *tl++; 2709*c59e4cc3SRick Macklem cverf[1] = *tl; 2710*c59e4cc3SRick Macklem error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p); 2711*c59e4cc3SRick Macklem if (error != 0) 2712*c59e4cc3SRick Macklem goto nfsmout; 2713*c59e4cc3SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, 2714*c59e4cc3SRick Macklem NFSATTRBIT_TIMEACCESSSET)) 2715*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_INVAL; 2716*c59e4cc3SRick Macklem /* 2717*c59e4cc3SRick Macklem * If the na_gid being set is the same as that of 2718*c59e4cc3SRick Macklem * the directory it is going in, clear it, since 2719*c59e4cc3SRick Macklem * that is what will be set by default. This allows 2720*c59e4cc3SRick Macklem * a user that isn't in that group to do the create. 2721*c59e4cc3SRick Macklem */ 2722*c59e4cc3SRick Macklem if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) && 2723*c59e4cc3SRick Macklem nva.na_gid == dirfor.na_gid) 2724*c59e4cc3SRick Macklem NFSVNO_UNSET(&nva, gid); 2725*c59e4cc3SRick Macklem if (nd->nd_repstat == 0) 2726*c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2727*c59e4cc3SRick Macklem break; 27289ec7b004SRick Macklem default: 27299ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 2730a9285ae5SZack Kirsch goto nfsmout; 27319ec7b004SRick Macklem }; 27329ec7b004SRick Macklem } else if (create != NFSV4OPEN_NOCREATE) { 27339ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 2734a9285ae5SZack Kirsch goto nfsmout; 27359ec7b004SRick Macklem } 27369ec7b004SRick Macklem 27379ec7b004SRick Macklem /* 27389ec7b004SRick Macklem * Now, handle the claim, which usually includes looking up a 27399ec7b004SRick Macklem * name in the directory referenced by dp. The exception is 27409ec7b004SRick Macklem * NFSV4OPEN_CLAIMPREVIOUS. 27419ec7b004SRick Macklem */ 27429ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 27439ec7b004SRick Macklem claim = fxdr_unsigned(int, *tl); 27449ec7b004SRick Macklem if (claim == NFSV4OPEN_CLAIMDELEGATECUR) { 27459ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 27469ec7b004SRick Macklem stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 27479ec7b004SRick Macklem NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 27489ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGCUR; 27499ec7b004SRick Macklem } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 27509ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGPREV; 27519ec7b004SRick Macklem } 27529ec7b004SRick Macklem if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR 27539ec7b004SRick Macklem || claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 27549ec7b004SRick Macklem if (!nd->nd_repstat && create == NFSV4OPEN_CREATE && 27559ec7b004SRick Macklem claim != NFSV4OPEN_CLAIMNULL) 27569ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 27579ec7b004SRick Macklem if (nd->nd_repstat) { 27589ec7b004SRick Macklem nd->nd_repstat = nfsrv_opencheck(clientid, 27599ec7b004SRick Macklem &stateid, stp, NULL, nd, p, nd->nd_repstat); 2760a9285ae5SZack Kirsch goto nfsmout; 27619ec7b004SRick Macklem } 27629ec7b004SRick Macklem if (create == NFSV4OPEN_CREATE) 27639ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 27649ec7b004SRick Macklem LOCKPARENT | LOCKLEAF | SAVESTART); 27659ec7b004SRick Macklem else 27669ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 27679ec7b004SRick Macklem LOCKLEAF | SAVESTART); 27689ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 27699ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 27709ec7b004SRick Macklem if (error) { 27719ec7b004SRick Macklem vrele(dp); 27729ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 27739ec7b004SRick Macklem acl_free(aclp); 27749ec7b004SRick Macklem #endif 27759ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 27769ec7b004SRick Macklem nfsvno_relpathbuf(&named); 2777a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 27789ec7b004SRick Macklem return (error); 27799ec7b004SRick Macklem } 27809ec7b004SRick Macklem if (!nd->nd_repstat) { 27819ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, 27829ec7b004SRick Macklem p, &dirp); 27839ec7b004SRick Macklem } else { 27849ec7b004SRick Macklem vrele(dp); 27859ec7b004SRick Macklem nfsvno_relpathbuf(&named); 27869ec7b004SRick Macklem } 27879ec7b004SRick Macklem if (create == NFSV4OPEN_CREATE) { 27889ec7b004SRick Macklem switch (how) { 27899ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 27909ec7b004SRick Macklem if (named.ni_vp) { 27919ec7b004SRick Macklem /* 27929ec7b004SRick Macklem * Clear the setable attribute bits, except 27939ec7b004SRick Macklem * for Size, if it is being truncated. 27949ec7b004SRick Macklem */ 27959ec7b004SRick Macklem NFSZERO_ATTRBIT(&attrbits); 27969ec7b004SRick Macklem if (NFSVNO_ISSETSIZE(&nva)) 27979ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, 27989ec7b004SRick Macklem NFSATTRBIT_SIZE); 27999ec7b004SRick Macklem } 28009ec7b004SRick Macklem break; 28019ec7b004SRick Macklem case NFSCREATE_GUARDED: 28029ec7b004SRick Macklem if (named.ni_vp && !nd->nd_repstat) 28039ec7b004SRick Macklem nd->nd_repstat = EEXIST; 28049ec7b004SRick Macklem break; 28059ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 28069ec7b004SRick Macklem exclusive_flag = 1; 28079ec7b004SRick Macklem if (!named.ni_vp) 28089ec7b004SRick Macklem nva.na_mode = 0; 2809*c59e4cc3SRick Macklem break; 2810*c59e4cc3SRick Macklem case NFSCREATE_EXCLUSIVE41: 2811*c59e4cc3SRick Macklem exclusive_flag = 1; 2812*c59e4cc3SRick Macklem break; 28139ec7b004SRick Macklem }; 28149ec7b004SRick Macklem } 28159ec7b004SRick Macklem nfsvno_open(nd, &named, clientid, &stateid, stp, 28169ec7b004SRick Macklem &exclusive_flag, &nva, cverf, create, aclp, &attrbits, 28179ec7b004SRick Macklem nd->nd_cred, p, exp, &vp); 2818*c59e4cc3SRick Macklem } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim == 2819*c59e4cc3SRick Macklem NFSV4OPEN_CLAIMFH) { 2820*c59e4cc3SRick Macklem if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 28219ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 28229ec7b004SRick Macklem i = fxdr_unsigned(int, *tl); 28239ec7b004SRick Macklem switch (i) { 28249ec7b004SRick Macklem case NFSV4OPEN_DELEGATEREAD: 28259ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGREAD; 28269ec7b004SRick Macklem break; 28279ec7b004SRick Macklem case NFSV4OPEN_DELEGATEWRITE: 28289ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGWRITE; 28299ec7b004SRick Macklem case NFSV4OPEN_DELEGATENONE: 28309ec7b004SRick Macklem break; 28319ec7b004SRick Macklem default: 28329ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 2833a9285ae5SZack Kirsch goto nfsmout; 28349ec7b004SRick Macklem }; 28359ec7b004SRick Macklem stp->ls_flags |= NFSLCK_RECLAIM; 2836*c59e4cc3SRick Macklem } else { 2837*c59e4cc3SRick Macklem /* CLAIM_NULL_FH */ 2838*c59e4cc3SRick Macklem if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE) 2839*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_INVAL; 2840*c59e4cc3SRick Macklem } 28419ec7b004SRick Macklem vp = dp; 284298f234f3SZack Kirsch NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 2843629fa50eSRick Macklem if ((vp->v_iflag & VI_DOOMED) == 0) 2844629fa50eSRick Macklem nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, 2845629fa50eSRick Macklem stp, vp, nd, p, nd->nd_repstat); 2846629fa50eSRick Macklem else 2847629fa50eSRick Macklem nd->nd_repstat = NFSERR_PERM; 28489ec7b004SRick Macklem } else { 28499ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 2850a9285ae5SZack Kirsch goto nfsmout; 28519ec7b004SRick Macklem } 28529ec7b004SRick Macklem 28539ec7b004SRick Macklem /* 28549ec7b004SRick Macklem * Do basic access checking. 28559ec7b004SRick Macklem */ 28569ec7b004SRick Macklem if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2857de67b496SRick Macklem /* 2858de67b496SRick Macklem * The IETF working group decided that this is the correct 2859de67b496SRick Macklem * error return for all non-regular files. 2860de67b496SRick Macklem */ 28619ec7b004SRick Macklem nd->nd_repstat = NFSERR_SYMLINK; 28629ec7b004SRick Macklem } 28639ec7b004SRick Macklem if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS)) 28648da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, 28658da45f2cSRick Macklem exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 28669ec7b004SRick Macklem if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) { 28678da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, 28688da45f2cSRick Macklem exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 28699ec7b004SRick Macklem if (nd->nd_repstat) 28708da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 28719ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 28728da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 28739ec7b004SRick Macklem } 28749ec7b004SRick Macklem 2875086f6e0cSRick Macklem if (!nd->nd_repstat) { 28760cf42b62SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 2877086f6e0cSRick Macklem if (!nd->nd_repstat) { 2878086f6e0cSRick Macklem tverf[0] = nva.na_atime.tv_sec; 2879086f6e0cSRick Macklem tverf[1] = nva.na_atime.tv_nsec; 2880086f6e0cSRick Macklem } 2881086f6e0cSRick Macklem } 2882086f6e0cSRick Macklem if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] || 2883086f6e0cSRick Macklem cverf[1] != tverf[1])) 28849ec7b004SRick Macklem nd->nd_repstat = EEXIST; 28859ec7b004SRick Macklem /* 28869ec7b004SRick Macklem * Do the open locking/delegation stuff. 28879ec7b004SRick Macklem */ 28889ec7b004SRick Macklem if (!nd->nd_repstat) 28899ec7b004SRick Macklem nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid, 28909ec7b004SRick Macklem &delegstateid, &rflags, exp, p, nva.na_filerev); 28919ec7b004SRick Macklem 28929ec7b004SRick Macklem /* 28939ec7b004SRick Macklem * vp must be unlocked before the call to nfsvno_getattr(dirp,...) 28949ec7b004SRick Macklem * below, to avoid a deadlock with the lookup in nfsvno_namei() above. 28959ec7b004SRick Macklem * (ie: Leave the NFSVOPUNLOCK() about here.) 28969ec7b004SRick Macklem */ 28979ec7b004SRick Macklem if (vp) 2898c383087cSZack Kirsch NFSVOPUNLOCK(vp, 0); 28999ec7b004SRick Macklem if (stp) 29009ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 29019ec7b004SRick Macklem if (!nd->nd_repstat && dirp) 29020cf42b62SRick Macklem nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 29030cf42b62SRick Macklem 0); 29049ec7b004SRick Macklem if (!nd->nd_repstat) { 29059ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 29069ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 29079ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 29089ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 29099ec7b004SRick Macklem if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 29109ec7b004SRick Macklem *tl++ = newnfs_true; 29119ec7b004SRick Macklem *tl++ = 0; 29129ec7b004SRick Macklem *tl++ = 0; 29139ec7b004SRick Macklem *tl++ = 0; 29149ec7b004SRick Macklem *tl++ = 0; 29159ec7b004SRick Macklem } else { 29169ec7b004SRick Macklem *tl++ = newnfs_false; /* Since dirp is not locked */ 29179ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 29189ec7b004SRick Macklem tl += 2; 29199ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 29209ec7b004SRick Macklem tl += 2; 29219ec7b004SRick Macklem } 29229ec7b004SRick Macklem *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS); 29239ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &attrbits); 29249ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 29259ec7b004SRick Macklem if (rflags & NFSV4OPEN_READDELEGATE) 29269ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD); 29279ec7b004SRick Macklem else if (rflags & NFSV4OPEN_WRITEDELEGATE) 29289ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE); 2929*c59e4cc3SRick Macklem else if (retext != 0) { 2930*c59e4cc3SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT); 2931*c59e4cc3SRick Macklem if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) { 2932*c59e4cc3SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2933*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION); 2934*c59e4cc3SRick Macklem *tl = newnfs_false; 2935*c59e4cc3SRick Macklem } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) { 2936*c59e4cc3SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2937*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE); 2938*c59e4cc3SRick Macklem *tl = newnfs_false; 2939*c59e4cc3SRick Macklem } else { 2940*c59e4cc3SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2941*c59e4cc3SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 2942*c59e4cc3SRick Macklem } 2943*c59e4cc3SRick Macklem } else 29449ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE); 29459ec7b004SRick Macklem if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) { 29469ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED); 29479ec7b004SRick Macklem *tl++ = txdr_unsigned(delegstateid.seqid); 29489ec7b004SRick Macklem NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl, 29499ec7b004SRick Macklem NFSX_STATEIDOTHER); 29509ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 29519ec7b004SRick Macklem if (rflags & NFSV4OPEN_RECALL) 29529ec7b004SRick Macklem *tl = newnfs_true; 29539ec7b004SRick Macklem else 29549ec7b004SRick Macklem *tl = newnfs_false; 29559ec7b004SRick Macklem if (rflags & NFSV4OPEN_WRITEDELEGATE) { 29569ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 29579ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE); 29589ec7b004SRick Macklem txdr_hyper(nva.na_size, tl); 29599ec7b004SRick Macklem } 29609ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 29619ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE); 29629ec7b004SRick Macklem *tl++ = txdr_unsigned(0x0); 29639ec7b004SRick Macklem acemask = NFSV4ACE_ALLFILESMASK; 29649ec7b004SRick Macklem if (nva.na_mode & S_IRUSR) 29659ec7b004SRick Macklem acemask |= NFSV4ACE_READMASK; 29669ec7b004SRick Macklem if (nva.na_mode & S_IWUSR) 29679ec7b004SRick Macklem acemask |= NFSV4ACE_WRITEMASK; 29689ec7b004SRick Macklem if (nva.na_mode & S_IXUSR) 29699ec7b004SRick Macklem acemask |= NFSV4ACE_EXECUTEMASK; 29709ec7b004SRick Macklem *tl = txdr_unsigned(acemask); 29719ec7b004SRick Macklem (void) nfsm_strtom(nd, "OWNER@", 6); 29729ec7b004SRick Macklem } 29739ec7b004SRick Macklem *vpp = vp; 29749ec7b004SRick Macklem } else if (vp) { 29759ec7b004SRick Macklem vrele(vp); 29769ec7b004SRick Macklem } 29779ec7b004SRick Macklem if (dirp) 29789ec7b004SRick Macklem vrele(dirp); 29799ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 29809ec7b004SRick Macklem acl_free(aclp); 29819ec7b004SRick Macklem #endif 2982a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 29839ec7b004SRick Macklem return (0); 29849ec7b004SRick Macklem nfsmout: 29859ec7b004SRick Macklem vrele(dp); 29869ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 29879ec7b004SRick Macklem acl_free(aclp); 29889ec7b004SRick Macklem #endif 29899ec7b004SRick Macklem if (stp) 29909ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 2991a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 29929ec7b004SRick Macklem return (error); 29939ec7b004SRick Macklem } 29949ec7b004SRick Macklem 29959ec7b004SRick Macklem /* 29969ec7b004SRick Macklem * nfsv4 close service 29979ec7b004SRick Macklem */ 29989ec7b004SRick Macklem APPLESTATIC int 29999ec7b004SRick Macklem nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram, 30009ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 30019ec7b004SRick Macklem { 30029ec7b004SRick Macklem u_int32_t *tl; 30039ec7b004SRick Macklem struct nfsstate st, *stp = &st; 30049ec7b004SRick Macklem int error = 0; 30059ec7b004SRick Macklem nfsv4stateid_t stateid; 30069ec7b004SRick Macklem nfsquad_t clientid; 30079ec7b004SRick Macklem 30089ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 30099ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 30109ec7b004SRick Macklem stp->ls_ownerlen = 0; 30119ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 30129ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 30139ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 30149ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 30159ec7b004SRick Macklem NFSX_STATEIDOTHER); 30169ec7b004SRick Macklem stp->ls_flags = NFSLCK_CLOSE; 30179ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 30189ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 3019*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3020*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3021*c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3022*c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3023*c59e4cc3SRick Macklem printf("EEK8 multiple clids\n"); 30249ec7b004SRick Macklem } else { 3025*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3026*c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 30279ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 30289ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 30299ec7b004SRick Macklem } 30309ec7b004SRick Macklem nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p); 30319ec7b004SRick Macklem vput(vp); 30329ec7b004SRick Macklem if (!nd->nd_repstat) { 30339ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 30349ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 30359ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 30369ec7b004SRick Macklem } 3037a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 30389ec7b004SRick Macklem return (0); 30399ec7b004SRick Macklem nfsmout: 30409ec7b004SRick Macklem vput(vp); 3041a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 30429ec7b004SRick Macklem return (error); 30439ec7b004SRick Macklem } 30449ec7b004SRick Macklem 30459ec7b004SRick Macklem /* 30469ec7b004SRick Macklem * nfsv4 delegpurge service 30479ec7b004SRick Macklem */ 30489ec7b004SRick Macklem APPLESTATIC int 30499ec7b004SRick Macklem nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram, 30509ec7b004SRick Macklem __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 30519ec7b004SRick Macklem { 30529ec7b004SRick Macklem u_int32_t *tl; 30539ec7b004SRick Macklem int error = 0; 30549ec7b004SRick Macklem nfsquad_t clientid; 30559ec7b004SRick Macklem 3056c9aad40fSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3057b1cfc0d9SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3058a9285ae5SZack Kirsch goto nfsmout; 3059b1cfc0d9SRick Macklem } 30609ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 30619ec7b004SRick Macklem clientid.lval[0] = *tl++; 30629ec7b004SRick Macklem clientid.lval[1] = *tl; 3063*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3064*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3065*c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3066*c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3067*c59e4cc3SRick Macklem printf("EEK9 multiple clids\n"); 30689ec7b004SRick Macklem } else { 3069*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3070*c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 30719ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 30729ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 30739ec7b004SRick Macklem } 3074*c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL, 30759ec7b004SRick Macklem NFSV4OP_DELEGPURGE, nd->nd_cred, p); 30769ec7b004SRick Macklem nfsmout: 3077a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 30789ec7b004SRick Macklem return (error); 30799ec7b004SRick Macklem } 30809ec7b004SRick Macklem 30819ec7b004SRick Macklem /* 30829ec7b004SRick Macklem * nfsv4 delegreturn service 30839ec7b004SRick Macklem */ 30849ec7b004SRick Macklem APPLESTATIC int 30859ec7b004SRick Macklem nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram, 30869ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 30879ec7b004SRick Macklem { 30889ec7b004SRick Macklem u_int32_t *tl; 30899ec7b004SRick Macklem int error = 0; 30909ec7b004SRick Macklem nfsv4stateid_t stateid; 30919ec7b004SRick Macklem nfsquad_t clientid; 30929ec7b004SRick Macklem 30939ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 30949ec7b004SRick Macklem stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 30959ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER); 30969ec7b004SRick Macklem clientid.lval[0] = stateid.other[0]; 30979ec7b004SRick Macklem clientid.lval[1] = stateid.other[1]; 3098*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3099*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3100*c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3101*c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3102*c59e4cc3SRick Macklem printf("EEK10 multiple clids\n"); 31039ec7b004SRick Macklem } else { 3104*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3105*c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 31069ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 31079ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 31089ec7b004SRick Macklem } 3109*c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp, 31109ec7b004SRick Macklem NFSV4OP_DELEGRETURN, nd->nd_cred, p); 31119ec7b004SRick Macklem nfsmout: 31129ec7b004SRick Macklem vput(vp); 3113a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 31149ec7b004SRick Macklem return (error); 31159ec7b004SRick Macklem } 31169ec7b004SRick Macklem 31179ec7b004SRick Macklem /* 31189ec7b004SRick Macklem * nfsv4 get file handle service 31199ec7b004SRick Macklem */ 31209ec7b004SRick Macklem APPLESTATIC int 31219ec7b004SRick Macklem nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram, 31229ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 31239ec7b004SRick Macklem { 31249ec7b004SRick Macklem fhandle_t fh; 31259ec7b004SRick Macklem 31269ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 31279ec7b004SRick Macklem vput(vp); 31289ec7b004SRick Macklem if (!nd->nd_repstat) 31299ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 3130a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 31319ec7b004SRick Macklem return (0); 31329ec7b004SRick Macklem } 31339ec7b004SRick Macklem 31349ec7b004SRick Macklem /* 31359ec7b004SRick Macklem * nfsv4 open confirm service 31369ec7b004SRick Macklem */ 31379ec7b004SRick Macklem APPLESTATIC int 31389ec7b004SRick Macklem nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram, 31399ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 31409ec7b004SRick Macklem { 31419ec7b004SRick Macklem u_int32_t *tl; 31429ec7b004SRick Macklem struct nfsstate st, *stp = &st; 31439ec7b004SRick Macklem int error = 0; 31449ec7b004SRick Macklem nfsv4stateid_t stateid; 31459ec7b004SRick Macklem nfsquad_t clientid; 31469ec7b004SRick Macklem 3147*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3148*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3149*c59e4cc3SRick Macklem goto nfsmout; 3150*c59e4cc3SRick Macklem } 31519ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 31529ec7b004SRick Macklem stp->ls_ownerlen = 0; 31539ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 31549ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 31559ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 31569ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 31579ec7b004SRick Macklem NFSX_STATEIDOTHER); 31589ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 31599ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl); 31609ec7b004SRick Macklem stp->ls_flags = NFSLCK_CONFIRM; 31619ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 31629ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 3163*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3164*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3165*c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3166*c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3167*c59e4cc3SRick Macklem printf("EEK11 multiple clids\n"); 31689ec7b004SRick Macklem } else { 3169*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3170*c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 31719ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 31729ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 31739ec7b004SRick Macklem } 31749ec7b004SRick Macklem nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p); 31759ec7b004SRick Macklem if (!nd->nd_repstat) { 31769ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 31779ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 31789ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 31799ec7b004SRick Macklem } 31809ec7b004SRick Macklem nfsmout: 31819ec7b004SRick Macklem vput(vp); 3182a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 31839ec7b004SRick Macklem return (error); 31849ec7b004SRick Macklem } 31859ec7b004SRick Macklem 31869ec7b004SRick Macklem /* 31879ec7b004SRick Macklem * nfsv4 open downgrade service 31889ec7b004SRick Macklem */ 31899ec7b004SRick Macklem APPLESTATIC int 31909ec7b004SRick Macklem nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram, 31919ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 31929ec7b004SRick Macklem { 31939ec7b004SRick Macklem u_int32_t *tl; 31949ec7b004SRick Macklem int i; 31959ec7b004SRick Macklem struct nfsstate st, *stp = &st; 31969ec7b004SRick Macklem int error = 0; 31979ec7b004SRick Macklem nfsv4stateid_t stateid; 31989ec7b004SRick Macklem nfsquad_t clientid; 31999ec7b004SRick Macklem 32009ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 32019ec7b004SRick Macklem stp->ls_ownerlen = 0; 32029ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 32039ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 32049ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 32059ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 32069ec7b004SRick Macklem NFSX_STATEIDOTHER); 32079ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 32089ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 32099ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 32109ec7b004SRick Macklem switch (i) { 32119ec7b004SRick Macklem case NFSV4OPEN_ACCESSREAD: 32129ec7b004SRick Macklem stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE); 32139ec7b004SRick Macklem break; 32149ec7b004SRick Macklem case NFSV4OPEN_ACCESSWRITE: 32159ec7b004SRick Macklem stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); 32169ec7b004SRick Macklem break; 32179ec7b004SRick Macklem case NFSV4OPEN_ACCESSBOTH: 32189ec7b004SRick Macklem stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS | 32199ec7b004SRick Macklem NFSLCK_DOWNGRADE); 32209ec7b004SRick Macklem break; 32219ec7b004SRick Macklem default: 32229ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 32239ec7b004SRick Macklem }; 32249ec7b004SRick Macklem i = fxdr_unsigned(int, *tl); 32259ec7b004SRick Macklem switch (i) { 32269ec7b004SRick Macklem case NFSV4OPEN_DENYNONE: 32279ec7b004SRick Macklem break; 32289ec7b004SRick Macklem case NFSV4OPEN_DENYREAD: 32299ec7b004SRick Macklem stp->ls_flags |= NFSLCK_READDENY; 32309ec7b004SRick Macklem break; 32319ec7b004SRick Macklem case NFSV4OPEN_DENYWRITE: 32329ec7b004SRick Macklem stp->ls_flags |= NFSLCK_WRITEDENY; 32339ec7b004SRick Macklem break; 32349ec7b004SRick Macklem case NFSV4OPEN_DENYBOTH: 32359ec7b004SRick Macklem stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 32369ec7b004SRick Macklem break; 32379ec7b004SRick Macklem default: 32389ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 32399ec7b004SRick Macklem }; 32409ec7b004SRick Macklem 32419ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 32429ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 3243*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3244*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3245*c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3246*c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3247*c59e4cc3SRick Macklem printf("EEK12 multiple clids\n"); 32489ec7b004SRick Macklem } else { 3249*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3250*c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 32519ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 32529ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 32539ec7b004SRick Macklem } 32549ec7b004SRick Macklem if (!nd->nd_repstat) 32559ec7b004SRick Macklem nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, 32569ec7b004SRick Macklem nd, p); 32579ec7b004SRick Macklem if (!nd->nd_repstat) { 32589ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 32599ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 32609ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 32619ec7b004SRick Macklem } 32629ec7b004SRick Macklem nfsmout: 32639ec7b004SRick Macklem vput(vp); 3264a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 32659ec7b004SRick Macklem return (error); 32669ec7b004SRick Macklem } 32679ec7b004SRick Macklem 32689ec7b004SRick Macklem /* 32699ec7b004SRick Macklem * nfsv4 renew lease service 32709ec7b004SRick Macklem */ 32719ec7b004SRick Macklem APPLESTATIC int 32729ec7b004SRick Macklem nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram, 32739ec7b004SRick Macklem __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 32749ec7b004SRick Macklem { 32759ec7b004SRick Macklem u_int32_t *tl; 32769ec7b004SRick Macklem int error = 0; 32779ec7b004SRick Macklem nfsquad_t clientid; 32789ec7b004SRick Macklem 3279*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3280*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3281*c59e4cc3SRick Macklem goto nfsmout; 3282*c59e4cc3SRick Macklem } 3283c9aad40fSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3284b1cfc0d9SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3285a9285ae5SZack Kirsch goto nfsmout; 3286b1cfc0d9SRick Macklem } 32879ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 32889ec7b004SRick Macklem clientid.lval[0] = *tl++; 32899ec7b004SRick Macklem clientid.lval[1] = *tl; 3290*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3291*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3292*c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3293*c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3294*c59e4cc3SRick Macklem printf("EEK13 multiple clids\n"); 32959ec7b004SRick Macklem } else { 3296*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3297*c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 32989ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 32999ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 33009ec7b004SRick Macklem } 33019ec7b004SRick Macklem nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW), 3302*c59e4cc3SRick Macklem NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p); 33039ec7b004SRick Macklem nfsmout: 3304a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 33059ec7b004SRick Macklem return (error); 33069ec7b004SRick Macklem } 33079ec7b004SRick Macklem 33089ec7b004SRick Macklem /* 33099ec7b004SRick Macklem * nfsv4 security info service 33109ec7b004SRick Macklem */ 33119ec7b004SRick Macklem APPLESTATIC int 33129ec7b004SRick Macklem nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram, 33139ec7b004SRick Macklem vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 33149ec7b004SRick Macklem { 33159ec7b004SRick Macklem u_int32_t *tl; 33169ec7b004SRick Macklem int len; 33179ec7b004SRick Macklem struct nameidata named; 33189ec7b004SRick Macklem vnode_t dirp = NULL, vp; 33199ec7b004SRick Macklem struct nfsrvfh fh; 33209ec7b004SRick Macklem struct nfsexstuff retnes; 33219ec7b004SRick Macklem u_int32_t *sizp; 3322a9285ae5SZack Kirsch int error = 0, savflag, i; 33239ec7b004SRick Macklem char *bufp; 33249ec7b004SRick Macklem u_long *hashp; 33259ec7b004SRick Macklem 33269ec7b004SRick Macklem /* 33279ec7b004SRick Macklem * All this just to get the export flags for the name. 33289ec7b004SRick Macklem */ 33299ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 33309ec7b004SRick Macklem LOCKLEAF | SAVESTART); 33319ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 33329ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 33339ec7b004SRick Macklem if (error) { 33349ec7b004SRick Macklem vput(dp); 33359ec7b004SRick Macklem nfsvno_relpathbuf(&named); 3336a9285ae5SZack Kirsch goto out; 33379ec7b004SRick Macklem } 33389ec7b004SRick Macklem if (!nd->nd_repstat) { 33399ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 33409ec7b004SRick Macklem } else { 33419ec7b004SRick Macklem vput(dp); 33429ec7b004SRick Macklem nfsvno_relpathbuf(&named); 33439ec7b004SRick Macklem } 33449ec7b004SRick Macklem if (dirp) 33459ec7b004SRick Macklem vrele(dirp); 33469ec7b004SRick Macklem if (nd->nd_repstat) 3347a9285ae5SZack Kirsch goto out; 33489ec7b004SRick Macklem vrele(named.ni_startdir); 33499ec7b004SRick Macklem nfsvno_relpathbuf(&named); 33509ec7b004SRick Macklem fh.nfsrvfh_len = NFSX_MYFH; 33519ec7b004SRick Macklem vp = named.ni_vp; 33529ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 33539ec7b004SRick Macklem vput(vp); 33549ec7b004SRick Macklem savflag = nd->nd_flag; 33559ec7b004SRick Macklem if (!nd->nd_repstat) { 33568974bc2fSRick Macklem nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p); 33579ec7b004SRick Macklem if (vp) 33589ec7b004SRick Macklem vput(vp); 33599ec7b004SRick Macklem } 33609ec7b004SRick Macklem nd->nd_flag = savflag; 33619ec7b004SRick Macklem if (nd->nd_repstat) 3362a9285ae5SZack Kirsch goto out; 33639ec7b004SRick Macklem 33649ec7b004SRick Macklem /* 33659ec7b004SRick Macklem * Finally have the export flags for name, so we can create 33669ec7b004SRick Macklem * the security info. 33679ec7b004SRick Macklem */ 33689ec7b004SRick Macklem len = 0; 33699ec7b004SRick Macklem NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED); 337098ad4453SRick Macklem for (i = 0; i < retnes.nes_numsecflavor; i++) { 337198ad4453SRick Macklem if (retnes.nes_secflavors[i] == AUTH_SYS) { 33729ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 33739ec7b004SRick Macklem *tl = txdr_unsigned(RPCAUTH_UNIX); 33749ec7b004SRick Macklem len++; 337598ad4453SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 33769ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 33779ec7b004SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_GSS); 33789ec7b004SRick Macklem (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 33799ec7b004SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 33809ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 33819ec7b004SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 338298ad4453SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 33839ec7b004SRick Macklem len++; 338498ad4453SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 338598ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 338698ad4453SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_GSS); 338798ad4453SRick Macklem (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 338898ad4453SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 338998ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 339098ad4453SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 339198ad4453SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 339298ad4453SRick Macklem len++; 339398ad4453SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 339498ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 339598ad4453SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_GSS); 339698ad4453SRick Macklem (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 339798ad4453SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 339898ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 339998ad4453SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 340098ad4453SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 340198ad4453SRick Macklem len++; 340298ad4453SRick Macklem } 34039ec7b004SRick Macklem } 34049ec7b004SRick Macklem *sizp = txdr_unsigned(len); 3405a9285ae5SZack Kirsch 3406a9285ae5SZack Kirsch out: 3407a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 3408a9285ae5SZack Kirsch return (error); 34099ec7b004SRick Macklem } 34109ec7b004SRick Macklem 34119ec7b004SRick Macklem /* 34129ec7b004SRick Macklem * nfsv4 set client id service 34139ec7b004SRick Macklem */ 34149ec7b004SRick Macklem APPLESTATIC int 34159ec7b004SRick Macklem nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, 34169ec7b004SRick Macklem __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 34179ec7b004SRick Macklem { 34189ec7b004SRick Macklem u_int32_t *tl; 34199ec7b004SRick Macklem int i; 34209ec7b004SRick Macklem int error = 0, idlen; 34219ec7b004SRick Macklem struct nfsclient *clp = NULL; 34229ec7b004SRick Macklem struct sockaddr_in *rad; 34239ec7b004SRick Macklem u_char *verf, *ucp, *ucp2, addrbuf[24]; 34249ec7b004SRick Macklem nfsquad_t clientid, confirm; 34259ec7b004SRick Macklem 3426*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3427*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3428*c59e4cc3SRick Macklem goto nfsmout; 3429*c59e4cc3SRick Macklem } 3430c9aad40fSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 34319ec7b004SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3432a9285ae5SZack Kirsch goto out; 34339ec7b004SRick Macklem } 34349ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 34359ec7b004SRick Macklem verf = (u_char *)tl; 34369ec7b004SRick Macklem tl += (NFSX_VERF / NFSX_UNSIGNED); 34379ec7b004SRick Macklem i = fxdr_unsigned(int, *tl); 34389ec7b004SRick Macklem if (i > NFSV4_OPAQUELIMIT || i <= 0) { 34399ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 3440a9285ae5SZack Kirsch goto nfsmout; 34419ec7b004SRick Macklem } 34429ec7b004SRick Macklem idlen = i; 34439ec7b004SRick Macklem if (nd->nd_flag & ND_GSS) 34449ec7b004SRick Macklem i += nd->nd_princlen; 34459ec7b004SRick Macklem MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i, 34469ec7b004SRick Macklem M_NFSDCLIENT, M_WAITOK); 34479ec7b004SRick Macklem NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i); 34489ec7b004SRick Macklem NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 34499ec7b004SRick Macklem NFSSOCKADDRALLOC(clp->lc_req.nr_nam); 34509ec7b004SRick Macklem NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in)); 34519ec7b004SRick Macklem clp->lc_req.nr_cred = NULL; 34529ec7b004SRick Macklem NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 34539ec7b004SRick Macklem clp->lc_idlen = idlen; 34549ec7b004SRick Macklem error = nfsrv_mtostr(nd, clp->lc_id, idlen); 34559ec7b004SRick Macklem if (error) 34569ec7b004SRick Macklem goto nfsmout; 34579ec7b004SRick Macklem if (nd->nd_flag & ND_GSS) { 34589ec7b004SRick Macklem clp->lc_flags = LCL_GSS; 34599ec7b004SRick Macklem if (nd->nd_flag & ND_GSSINTEGRITY) 34609ec7b004SRick Macklem clp->lc_flags |= LCL_GSSINTEGRITY; 34619ec7b004SRick Macklem else if (nd->nd_flag & ND_GSSPRIVACY) 34629ec7b004SRick Macklem clp->lc_flags |= LCL_GSSPRIVACY; 34639ec7b004SRick Macklem } else { 34649ec7b004SRick Macklem clp->lc_flags = 0; 34659ec7b004SRick Macklem } 34669ec7b004SRick Macklem if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) { 34679ec7b004SRick Macklem clp->lc_flags |= LCL_NAME; 34689ec7b004SRick Macklem clp->lc_namelen = nd->nd_princlen; 34699ec7b004SRick Macklem clp->lc_name = &clp->lc_id[idlen]; 34709ec7b004SRick Macklem NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 34719ec7b004SRick Macklem } else { 34729ec7b004SRick Macklem clp->lc_uid = nd->nd_cred->cr_uid; 34739ec7b004SRick Macklem clp->lc_gid = nd->nd_cred->cr_gid; 34749ec7b004SRick Macklem } 34759ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 34769ec7b004SRick Macklem clp->lc_program = fxdr_unsigned(u_int32_t, *tl); 34779ec7b004SRick Macklem error = nfsrv_getclientipaddr(nd, clp); 34789ec7b004SRick Macklem if (error) 34799ec7b004SRick Macklem goto nfsmout; 34809ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 34819ec7b004SRick Macklem clp->lc_callback = fxdr_unsigned(u_int32_t, *tl); 34829ec7b004SRick Macklem 34839ec7b004SRick Macklem /* 34849ec7b004SRick Macklem * nfsrv_setclient() does the actual work of adding it to the 34859ec7b004SRick Macklem * client list. If there is no error, the structure has been 34869ec7b004SRick Macklem * linked into the client list and clp should no longer be used 34879ec7b004SRick Macklem * here. When an error is returned, it has not been linked in, 34889ec7b004SRick Macklem * so it should be free'd. 34899ec7b004SRick Macklem */ 34909ec7b004SRick Macklem nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 34919ec7b004SRick Macklem if (nd->nd_repstat == NFSERR_CLIDINUSE) { 34929ec7b004SRick Macklem if (clp->lc_flags & LCL_TCPCALLBACK) 34939ec7b004SRick Macklem (void) nfsm_strtom(nd, "tcp", 3); 34949ec7b004SRick Macklem else 34959ec7b004SRick Macklem (void) nfsm_strtom(nd, "udp", 3); 34969ec7b004SRick Macklem rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *); 34979ec7b004SRick Macklem ucp = (u_char *)&rad->sin_addr.s_addr; 34989ec7b004SRick Macklem ucp2 = (u_char *)&rad->sin_port; 34999ec7b004SRick Macklem sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff, 35009ec7b004SRick Macklem ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff, 35019ec7b004SRick Macklem ucp2[0] & 0xff, ucp2[1] & 0xff); 35029ec7b004SRick Macklem (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf)); 35039ec7b004SRick Macklem } 35049ec7b004SRick Macklem if (clp) { 35059ec7b004SRick Macklem NFSSOCKADDRFREE(clp->lc_req.nr_nam); 35069ec7b004SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 35079ec7b004SRick Macklem free((caddr_t)clp, M_NFSDCLIENT); 35089ec7b004SRick Macklem } 35099ec7b004SRick Macklem if (!nd->nd_repstat) { 35109ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); 35119ec7b004SRick Macklem *tl++ = clientid.lval[0]; 35129ec7b004SRick Macklem *tl++ = clientid.lval[1]; 35139ec7b004SRick Macklem *tl++ = confirm.lval[0]; 35149ec7b004SRick Macklem *tl = confirm.lval[1]; 35159ec7b004SRick Macklem } 3516a9285ae5SZack Kirsch 3517a9285ae5SZack Kirsch out: 3518a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 35199ec7b004SRick Macklem return (0); 35209ec7b004SRick Macklem nfsmout: 35219ec7b004SRick Macklem if (clp) { 35229ec7b004SRick Macklem NFSSOCKADDRFREE(clp->lc_req.nr_nam); 35239ec7b004SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 35249ec7b004SRick Macklem free((caddr_t)clp, M_NFSDCLIENT); 35259ec7b004SRick Macklem } 3526a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 35279ec7b004SRick Macklem return (error); 35289ec7b004SRick Macklem } 35299ec7b004SRick Macklem 35309ec7b004SRick Macklem /* 35319ec7b004SRick Macklem * nfsv4 set client id confirm service 35329ec7b004SRick Macklem */ 35339ec7b004SRick Macklem APPLESTATIC int 35349ec7b004SRick Macklem nfsrvd_setclientidcfrm(struct nfsrv_descript *nd, 35359ec7b004SRick Macklem __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p, 35369ec7b004SRick Macklem __unused struct nfsexstuff *exp) 35379ec7b004SRick Macklem { 35389ec7b004SRick Macklem u_int32_t *tl; 35399ec7b004SRick Macklem int error = 0; 35409ec7b004SRick Macklem nfsquad_t clientid, confirm; 35419ec7b004SRick Macklem 3542*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3543*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3544*c59e4cc3SRick Macklem goto nfsmout; 3545*c59e4cc3SRick Macklem } 3546c9aad40fSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 35479ec7b004SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3548a9285ae5SZack Kirsch goto nfsmout; 35499ec7b004SRick Macklem } 35509ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER); 35519ec7b004SRick Macklem clientid.lval[0] = *tl++; 35529ec7b004SRick Macklem clientid.lval[1] = *tl++; 35539ec7b004SRick Macklem confirm.lval[0] = *tl++; 35549ec7b004SRick Macklem confirm.lval[1] = *tl; 35559ec7b004SRick Macklem 35569ec7b004SRick Macklem /* 35579ec7b004SRick Macklem * nfsrv_getclient() searches the client list for a match and 35589ec7b004SRick Macklem * returns the appropriate NFSERR status. 35599ec7b004SRick Macklem */ 35609ec7b004SRick Macklem nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW), 3561*c59e4cc3SRick Macklem NULL, NULL, confirm, 0, nd, p); 35629ec7b004SRick Macklem nfsmout: 3563a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 35649ec7b004SRick Macklem return (error); 35659ec7b004SRick Macklem } 35669ec7b004SRick Macklem 35679ec7b004SRick Macklem /* 35689ec7b004SRick Macklem * nfsv4 verify service 35699ec7b004SRick Macklem */ 35709ec7b004SRick Macklem APPLESTATIC int 35719ec7b004SRick Macklem nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, 35729ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 35739ec7b004SRick Macklem { 35749ec7b004SRick Macklem int error = 0, ret, fhsize = NFSX_MYFH; 35759ec7b004SRick Macklem struct nfsvattr nva; 35769ec7b004SRick Macklem struct statfs sf; 35779ec7b004SRick Macklem struct nfsfsinfo fs; 35789ec7b004SRick Macklem fhandle_t fh; 35799ec7b004SRick Macklem 35800cf42b62SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 35819ec7b004SRick Macklem if (!nd->nd_repstat) 3582dfd233edSAttilio Rao nd->nd_repstat = nfsvno_statfs(vp, &sf); 35839ec7b004SRick Macklem if (!nd->nd_repstat) 35849ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 35859ec7b004SRick Macklem if (!nd->nd_repstat) { 35869ec7b004SRick Macklem nfsvno_getfs(&fs, isdgram); 35879ec7b004SRick Macklem error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL, 35889ec7b004SRick Macklem &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred); 35899ec7b004SRick Macklem if (!error) { 35909ec7b004SRick Macklem if (nd->nd_procnum == NFSV4OP_NVERIFY) { 35919ec7b004SRick Macklem if (ret == 0) 35929ec7b004SRick Macklem nd->nd_repstat = NFSERR_SAME; 35939ec7b004SRick Macklem else if (ret != NFSERR_NOTSAME) 35949ec7b004SRick Macklem nd->nd_repstat = ret; 35959ec7b004SRick Macklem } else if (ret) 35969ec7b004SRick Macklem nd->nd_repstat = ret; 35979ec7b004SRick Macklem } 35989ec7b004SRick Macklem } 35999ec7b004SRick Macklem vput(vp); 3600a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 36019ec7b004SRick Macklem return (error); 36029ec7b004SRick Macklem } 36039ec7b004SRick Macklem 36049ec7b004SRick Macklem /* 36059ec7b004SRick Macklem * nfs openattr rpc 36069ec7b004SRick Macklem */ 36079ec7b004SRick Macklem APPLESTATIC int 36089ec7b004SRick Macklem nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram, 36099ec7b004SRick Macklem vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp, 36109ec7b004SRick Macklem __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 36119ec7b004SRick Macklem { 36129ec7b004SRick Macklem u_int32_t *tl; 36139ec7b004SRick Macklem int error = 0, createdir; 36149ec7b004SRick Macklem 36159ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 36169ec7b004SRick Macklem createdir = fxdr_unsigned(int, *tl); 36179ec7b004SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 36189ec7b004SRick Macklem nfsmout: 36199ec7b004SRick Macklem vrele(dp); 3620a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 36219ec7b004SRick Macklem return (error); 36229ec7b004SRick Macklem } 36239ec7b004SRick Macklem 36249ec7b004SRick Macklem /* 36259ec7b004SRick Macklem * nfsv4 release lock owner service 36269ec7b004SRick Macklem */ 36279ec7b004SRick Macklem APPLESTATIC int 36289ec7b004SRick Macklem nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram, 36299ec7b004SRick Macklem __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 36309ec7b004SRick Macklem { 36319ec7b004SRick Macklem u_int32_t *tl; 36329ec7b004SRick Macklem struct nfsstate *stp = NULL; 36339ec7b004SRick Macklem int error = 0, len; 36349ec7b004SRick Macklem nfsquad_t clientid; 36359ec7b004SRick Macklem 3636*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3637*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3638*c59e4cc3SRick Macklem goto nfsmout; 3639*c59e4cc3SRick Macklem } 3640c9aad40fSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3641b1cfc0d9SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3642a9285ae5SZack Kirsch goto nfsmout; 3643b1cfc0d9SRick Macklem } 36449ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 36459ec7b004SRick Macklem len = fxdr_unsigned(int, *(tl + 2)); 36462a45247cSRick Macklem if (len <= 0 || len > NFSV4_OPAQUELIMIT) { 36472a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 3648a9285ae5SZack Kirsch goto nfsmout; 36492a45247cSRick Macklem } 36509ec7b004SRick Macklem MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len, 36519ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 36529ec7b004SRick Macklem stp->ls_ownerlen = len; 36539ec7b004SRick Macklem stp->ls_op = NULL; 36549ec7b004SRick Macklem stp->ls_flags = NFSLCK_RELEASE; 36559ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 36569ec7b004SRick Macklem clientid.lval[0] = *tl++; 36579ec7b004SRick Macklem clientid.lval[1] = *tl; 3658*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3659*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3660*c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3661*c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3662*c59e4cc3SRick Macklem printf("EEK14 multiple clids\n"); 36639ec7b004SRick Macklem } else { 3664*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3665*c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 36669ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 36679ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 36689ec7b004SRick Macklem } 36699ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, len); 36709ec7b004SRick Macklem if (error) 36719ec7b004SRick Macklem goto nfsmout; 36729ec7b004SRick Macklem nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p); 36739ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 3674a9285ae5SZack Kirsch 3675a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 36769ec7b004SRick Macklem return (0); 36779ec7b004SRick Macklem nfsmout: 36789ec7b004SRick Macklem if (stp) 36799ec7b004SRick Macklem free((caddr_t)stp, M_NFSDSTATE); 3680a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 36819ec7b004SRick Macklem return (error); 36829ec7b004SRick Macklem } 3683*c59e4cc3SRick Macklem 3684*c59e4cc3SRick Macklem /* 3685*c59e4cc3SRick Macklem * nfsv4 exchange_id service 3686*c59e4cc3SRick Macklem */ 3687*c59e4cc3SRick Macklem APPLESTATIC int 3688*c59e4cc3SRick Macklem nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram, 3689*c59e4cc3SRick Macklem __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3690*c59e4cc3SRick Macklem { 3691*c59e4cc3SRick Macklem uint32_t *tl; 3692*c59e4cc3SRick Macklem int error = 0, i, idlen; 3693*c59e4cc3SRick Macklem struct nfsclient *clp = NULL; 3694*c59e4cc3SRick Macklem nfsquad_t clientid, confirm; 3695*c59e4cc3SRick Macklem uint8_t *verf; 3696*c59e4cc3SRick Macklem uint32_t sp4type, v41flags; 3697*c59e4cc3SRick Macklem uint64_t owner_minor; 3698*c59e4cc3SRick Macklem struct timespec verstime; 3699*c59e4cc3SRick Macklem 3700*c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3701*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3702*c59e4cc3SRick Macklem goto nfsmout; 3703*c59e4cc3SRick Macklem } 3704*c59e4cc3SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 3705*c59e4cc3SRick Macklem verf = (uint8_t *)tl; 3706*c59e4cc3SRick Macklem tl += (NFSX_VERF / NFSX_UNSIGNED); 3707*c59e4cc3SRick Macklem i = fxdr_unsigned(int, *tl); 3708*c59e4cc3SRick Macklem if (i > NFSV4_OPAQUELIMIT || i <= 0) { 3709*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 3710*c59e4cc3SRick Macklem goto nfsmout; 3711*c59e4cc3SRick Macklem } 3712*c59e4cc3SRick Macklem idlen = i; 3713*c59e4cc3SRick Macklem if (nd->nd_flag & ND_GSS) 3714*c59e4cc3SRick Macklem i += nd->nd_princlen; 3715*c59e4cc3SRick Macklem clp = (struct nfsclient *)malloc(sizeof(struct nfsclient) + i, 3716*c59e4cc3SRick Macklem M_NFSDCLIENT, M_WAITOK | M_ZERO); 3717*c59e4cc3SRick Macklem NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3718*c59e4cc3SRick Macklem NFSSOCKADDRALLOC(clp->lc_req.nr_nam); 3719*c59e4cc3SRick Macklem NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in)); 3720*c59e4cc3SRick Macklem clp->lc_req.nr_cred = NULL; 3721*c59e4cc3SRick Macklem NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 3722*c59e4cc3SRick Macklem clp->lc_idlen = idlen; 3723*c59e4cc3SRick Macklem error = nfsrv_mtostr(nd, clp->lc_id, idlen); 3724*c59e4cc3SRick Macklem if (error != 0) 3725*c59e4cc3SRick Macklem goto nfsmout; 3726*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_GSS) != 0) { 3727*c59e4cc3SRick Macklem clp->lc_flags = LCL_GSS | LCL_NFSV41; 3728*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_GSSINTEGRITY) != 0) 3729*c59e4cc3SRick Macklem clp->lc_flags |= LCL_GSSINTEGRITY; 3730*c59e4cc3SRick Macklem else if ((nd->nd_flag & ND_GSSPRIVACY) != 0) 3731*c59e4cc3SRick Macklem clp->lc_flags |= LCL_GSSPRIVACY; 3732*c59e4cc3SRick Macklem } else 3733*c59e4cc3SRick Macklem clp->lc_flags = LCL_NFSV41; 3734*c59e4cc3SRick Macklem if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) { 3735*c59e4cc3SRick Macklem clp->lc_flags |= LCL_NAME; 3736*c59e4cc3SRick Macklem clp->lc_namelen = nd->nd_princlen; 3737*c59e4cc3SRick Macklem clp->lc_name = &clp->lc_id[idlen]; 3738*c59e4cc3SRick Macklem NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 3739*c59e4cc3SRick Macklem } else { 3740*c59e4cc3SRick Macklem clp->lc_uid = nd->nd_cred->cr_uid; 3741*c59e4cc3SRick Macklem clp->lc_gid = nd->nd_cred->cr_gid; 3742*c59e4cc3SRick Macklem } 3743*c59e4cc3SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3744*c59e4cc3SRick Macklem v41flags = fxdr_unsigned(uint32_t, *tl++); 3745*c59e4cc3SRick Macklem if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR | 3746*c59e4cc3SRick Macklem NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS | 3747*c59e4cc3SRick Macklem NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) { 3748*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_INVAL; 3749*c59e4cc3SRick Macklem goto nfsmout; 3750*c59e4cc3SRick Macklem } 3751*c59e4cc3SRick Macklem if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0) 3752*c59e4cc3SRick Macklem confirm.lval[1] = 1; 3753*c59e4cc3SRick Macklem else 3754*c59e4cc3SRick Macklem confirm.lval[1] = 0; 3755*c59e4cc3SRick Macklem v41flags = NFSV4EXCH_USENONPNFS; 3756*c59e4cc3SRick Macklem sp4type = fxdr_unsigned(uint32_t, *tl); 3757*c59e4cc3SRick Macklem if (sp4type != NFSV4EXCH_SP4NONE) { 3758*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3759*c59e4cc3SRick Macklem goto nfsmout; 3760*c59e4cc3SRick Macklem } 3761*c59e4cc3SRick Macklem 3762*c59e4cc3SRick Macklem /* 3763*c59e4cc3SRick Macklem * nfsrv_setclient() does the actual work of adding it to the 3764*c59e4cc3SRick Macklem * client list. If there is no error, the structure has been 3765*c59e4cc3SRick Macklem * linked into the client list and clp should no longer be used 3766*c59e4cc3SRick Macklem * here. When an error is returned, it has not been linked in, 3767*c59e4cc3SRick Macklem * so it should be free'd. 3768*c59e4cc3SRick Macklem */ 3769*c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 3770*c59e4cc3SRick Macklem if (clp != NULL) { 3771*c59e4cc3SRick Macklem NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3772*c59e4cc3SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3773*c59e4cc3SRick Macklem free(clp, M_NFSDCLIENT); 3774*c59e4cc3SRick Macklem } 3775*c59e4cc3SRick Macklem if (nd->nd_repstat == 0) { 3776*c59e4cc3SRick Macklem if (confirm.lval[1] != 0) 3777*c59e4cc3SRick Macklem v41flags |= NFSV4EXCH_CONFIRMEDR; 3778*c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED); 3779*c59e4cc3SRick Macklem *tl++ = clientid.lval[0]; /* ClientID */ 3780*c59e4cc3SRick Macklem *tl++ = clientid.lval[1]; 3781*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */ 3782*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(v41flags); /* Exch flags */ 3783*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */ 3784*c59e4cc3SRick Macklem owner_minor = 0; /* Owner */ 3785*c59e4cc3SRick Macklem txdr_hyper(owner_minor, tl); /* Minor */ 3786*c59e4cc3SRick Macklem (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid, 3787*c59e4cc3SRick Macklem strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */ 3788*c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 3789*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(NFSX_UNSIGNED); 3790*c59e4cc3SRick Macklem *tl++ = time_uptime; /* Make scope a unique value. */ 3791*c59e4cc3SRick Macklem *tl = txdr_unsigned(1); 3792*c59e4cc3SRick Macklem (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 3793*c59e4cc3SRick Macklem (void)nfsm_strtom(nd, version, strlen(version)); 3794*c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 3795*c59e4cc3SRick Macklem verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 3796*c59e4cc3SRick Macklem verstime.tv_nsec = 0; 3797*c59e4cc3SRick Macklem txdr_nfsv4time(&verstime, tl); 3798*c59e4cc3SRick Macklem } 3799*c59e4cc3SRick Macklem NFSEXITCODE2(0, nd); 3800*c59e4cc3SRick Macklem return (0); 3801*c59e4cc3SRick Macklem nfsmout: 3802*c59e4cc3SRick Macklem if (clp != NULL) { 3803*c59e4cc3SRick Macklem NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3804*c59e4cc3SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3805*c59e4cc3SRick Macklem free(clp, M_NFSDCLIENT); 3806*c59e4cc3SRick Macklem } 3807*c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 3808*c59e4cc3SRick Macklem return (error); 3809*c59e4cc3SRick Macklem } 3810*c59e4cc3SRick Macklem 3811*c59e4cc3SRick Macklem /* 3812*c59e4cc3SRick Macklem * nfsv4 create session service 3813*c59e4cc3SRick Macklem */ 3814*c59e4cc3SRick Macklem APPLESTATIC int 3815*c59e4cc3SRick Macklem nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram, 3816*c59e4cc3SRick Macklem __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3817*c59e4cc3SRick Macklem { 3818*c59e4cc3SRick Macklem uint32_t *tl; 3819*c59e4cc3SRick Macklem int error = 0; 3820*c59e4cc3SRick Macklem nfsquad_t clientid, confirm; 3821*c59e4cc3SRick Macklem struct nfsdsession *sep = NULL; 3822*c59e4cc3SRick Macklem uint32_t rdmacnt; 3823*c59e4cc3SRick Macklem 3824*c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3825*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3826*c59e4cc3SRick Macklem goto nfsmout; 3827*c59e4cc3SRick Macklem } 3828*c59e4cc3SRick Macklem sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession), 3829*c59e4cc3SRick Macklem M_NFSDSESSION, M_WAITOK | M_ZERO); 3830*c59e4cc3SRick Macklem sep->sess_refcnt = 1; 3831*c59e4cc3SRick Macklem mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF); 3832*c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 3833*c59e4cc3SRick Macklem clientid.lval[0] = *tl++; 3834*c59e4cc3SRick Macklem clientid.lval[1] = *tl++; 3835*c59e4cc3SRick Macklem confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++); 3836*c59e4cc3SRick Macklem sep->sess_crflags = fxdr_unsigned(uint32_t, *tl); 3837*c59e4cc3SRick Macklem /* Persistent sessions and RDMA are not supported. */ 3838*c59e4cc3SRick Macklem sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN; 3839*c59e4cc3SRick Macklem 3840*c59e4cc3SRick Macklem /* Fore channel attributes. */ 3841*c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 3842*c59e4cc3SRick Macklem tl++; /* Header pad always 0. */ 3843*c59e4cc3SRick Macklem sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++); 3844*c59e4cc3SRick Macklem sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++); 3845*c59e4cc3SRick Macklem sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++); 3846*c59e4cc3SRick Macklem sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++); 3847*c59e4cc3SRick Macklem sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++); 3848*c59e4cc3SRick Macklem if (sep->sess_maxslots > NFSV4_SLOTS) 3849*c59e4cc3SRick Macklem sep->sess_maxslots = NFSV4_SLOTS; 3850*c59e4cc3SRick Macklem rdmacnt = fxdr_unsigned(uint32_t, *tl); 3851*c59e4cc3SRick Macklem if (rdmacnt > 1) { 3852*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 3853*c59e4cc3SRick Macklem goto nfsmout; 3854*c59e4cc3SRick Macklem } else if (rdmacnt == 1) 3855*c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3856*c59e4cc3SRick Macklem 3857*c59e4cc3SRick Macklem /* Back channel attributes. */ 3858*c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 3859*c59e4cc3SRick Macklem tl++; /* Header pad always 0. */ 3860*c59e4cc3SRick Macklem sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++); 3861*c59e4cc3SRick Macklem sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++); 3862*c59e4cc3SRick Macklem sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++); 3863*c59e4cc3SRick Macklem sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++); 3864*c59e4cc3SRick Macklem sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++); 3865*c59e4cc3SRick Macklem rdmacnt = fxdr_unsigned(uint32_t, *tl); 3866*c59e4cc3SRick Macklem if (rdmacnt > 1) { 3867*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 3868*c59e4cc3SRick Macklem goto nfsmout; 3869*c59e4cc3SRick Macklem } else if (rdmacnt == 1) 3870*c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3871*c59e4cc3SRick Macklem 3872*c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3873*c59e4cc3SRick Macklem sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl); 3874*c59e4cc3SRick Macklem 3875*c59e4cc3SRick Macklem /* 3876*c59e4cc3SRick Macklem * nfsrv_getclient() searches the client list for a match and 3877*c59e4cc3SRick Macklem * returns the appropriate NFSERR status. 3878*c59e4cc3SRick Macklem */ 3879*c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW, 3880*c59e4cc3SRick Macklem NULL, sep, confirm, sep->sess_cbprogram, nd, p); 3881*c59e4cc3SRick Macklem if (nd->nd_repstat == 0) { 3882*c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 3883*c59e4cc3SRick Macklem NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID); 3884*c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED); 3885*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */ 3886*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_crflags); 3887*c59e4cc3SRick Macklem 3888*c59e4cc3SRick Macklem /* Fore channel attributes. */ 3889*c59e4cc3SRick Macklem *tl++ = 0; 3890*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxreq); 3891*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxresp); 3892*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxrespcached); 3893*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxops); 3894*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxslots); 3895*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(1); 3896*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(0); /* No RDMA. */ 3897*c59e4cc3SRick Macklem 3898*c59e4cc3SRick Macklem /* Back channel attributes. */ 3899*c59e4cc3SRick Macklem *tl++ = 0; 3900*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbmaxreq); 3901*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbmaxresp); 3902*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached); 3903*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbmaxops); 3904*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots); 3905*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(1); 3906*c59e4cc3SRick Macklem *tl = txdr_unsigned(0); /* No RDMA. */ 3907*c59e4cc3SRick Macklem } 3908*c59e4cc3SRick Macklem nfsmout: 3909*c59e4cc3SRick Macklem if (nd->nd_repstat != 0 && sep != NULL) 3910*c59e4cc3SRick Macklem free(sep, M_NFSDSESSION); 3911*c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 3912*c59e4cc3SRick Macklem return (error); 3913*c59e4cc3SRick Macklem } 3914*c59e4cc3SRick Macklem 3915*c59e4cc3SRick Macklem /* 3916*c59e4cc3SRick Macklem * nfsv4 sequence service 3917*c59e4cc3SRick Macklem */ 3918*c59e4cc3SRick Macklem APPLESTATIC int 3919*c59e4cc3SRick Macklem nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram, 3920*c59e4cc3SRick Macklem __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3921*c59e4cc3SRick Macklem { 3922*c59e4cc3SRick Macklem uint32_t *tl; 3923*c59e4cc3SRick Macklem uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid; 3924*c59e4cc3SRick Macklem int cache_this, error = 0; 3925*c59e4cc3SRick Macklem 3926*c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3927*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3928*c59e4cc3SRick Macklem goto nfsmout; 3929*c59e4cc3SRick Macklem } 3930*c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID); 3931*c59e4cc3SRick Macklem NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID); 3932*c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 3933*c59e4cc3SRick Macklem sequenceid = fxdr_unsigned(uint32_t, *tl++); 3934*c59e4cc3SRick Macklem nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++); 3935*c59e4cc3SRick Macklem highest_slotid = fxdr_unsigned(uint32_t, *tl++); 3936*c59e4cc3SRick Macklem if (*tl == newnfs_true) 3937*c59e4cc3SRick Macklem cache_this = 1; 3938*c59e4cc3SRick Macklem else 3939*c59e4cc3SRick Macklem cache_this = 0; 3940*c59e4cc3SRick Macklem nd->nd_flag |= ND_HASSEQUENCE; 3941*c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid, 3942*c59e4cc3SRick Macklem &target_highest_slotid, cache_this, &sflags, p); 3943*c59e4cc3SRick Macklem if (nd->nd_repstat == 0) { 3944*c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 3945*c59e4cc3SRick Macklem NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID); 3946*c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 3947*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sequenceid); 3948*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(nd->nd_slotid); 3949*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(highest_slotid); 3950*c59e4cc3SRick Macklem *tl++ = txdr_unsigned(target_highest_slotid); 3951*c59e4cc3SRick Macklem *tl = txdr_unsigned(sflags); 3952*c59e4cc3SRick Macklem } 3953*c59e4cc3SRick Macklem nfsmout: 3954*c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 3955*c59e4cc3SRick Macklem return (error); 3956*c59e4cc3SRick Macklem } 3957*c59e4cc3SRick Macklem 3958*c59e4cc3SRick Macklem /* 3959*c59e4cc3SRick Macklem * nfsv4 reclaim complete service 3960*c59e4cc3SRick Macklem */ 3961*c59e4cc3SRick Macklem APPLESTATIC int 3962*c59e4cc3SRick Macklem nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram, 3963*c59e4cc3SRick Macklem __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3964*c59e4cc3SRick Macklem { 3965*c59e4cc3SRick Macklem uint32_t *tl; 3966*c59e4cc3SRick Macklem int error = 0; 3967*c59e4cc3SRick Macklem 3968*c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3969*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3970*c59e4cc3SRick Macklem goto nfsmout; 3971*c59e4cc3SRick Macklem } 3972*c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3973*c59e4cc3SRick Macklem if (*tl == newnfs_true) 3974*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3975*c59e4cc3SRick Macklem else 3976*c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_checkreclaimcomplete(nd); 3977*c59e4cc3SRick Macklem nfsmout: 3978*c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 3979*c59e4cc3SRick Macklem return (error); 3980*c59e4cc3SRick Macklem } 3981*c59e4cc3SRick Macklem 3982*c59e4cc3SRick Macklem /* 3983*c59e4cc3SRick Macklem * nfsv4 destroy clientid service 3984*c59e4cc3SRick Macklem */ 3985*c59e4cc3SRick Macklem APPLESTATIC int 3986*c59e4cc3SRick Macklem nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram, 3987*c59e4cc3SRick Macklem __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3988*c59e4cc3SRick Macklem { 3989*c59e4cc3SRick Macklem uint32_t *tl; 3990*c59e4cc3SRick Macklem nfsquad_t clientid; 3991*c59e4cc3SRick Macklem int error = 0; 3992*c59e4cc3SRick Macklem 3993*c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3994*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3995*c59e4cc3SRick Macklem goto nfsmout; 3996*c59e4cc3SRick Macklem } 3997*c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3998*c59e4cc3SRick Macklem clientid.lval[0] = *tl++; 3999*c59e4cc3SRick Macklem clientid.lval[1] = *tl; 4000*c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_destroyclient(clientid, p); 4001*c59e4cc3SRick Macklem nfsmout: 4002*c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4003*c59e4cc3SRick Macklem return (error); 4004*c59e4cc3SRick Macklem } 4005*c59e4cc3SRick Macklem 4006*c59e4cc3SRick Macklem /* 4007*c59e4cc3SRick Macklem * nfsv4 destroy session service 4008*c59e4cc3SRick Macklem */ 4009*c59e4cc3SRick Macklem APPLESTATIC int 4010*c59e4cc3SRick Macklem nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram, 4011*c59e4cc3SRick Macklem __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 4012*c59e4cc3SRick Macklem { 4013*c59e4cc3SRick Macklem uint8_t *cp, sessid[NFSX_V4SESSIONID]; 4014*c59e4cc3SRick Macklem int error = 0; 4015*c59e4cc3SRick Macklem 4016*c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4017*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 4018*c59e4cc3SRick Macklem goto nfsmout; 4019*c59e4cc3SRick Macklem } 4020*c59e4cc3SRick Macklem NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID); 4021*c59e4cc3SRick Macklem NFSBCOPY(cp, sessid, NFSX_V4SESSIONID); 4022*c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_destroysession(nd, sessid); 4023*c59e4cc3SRick Macklem nfsmout: 4024*c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4025*c59e4cc3SRick Macklem return (error); 4026*c59e4cc3SRick Macklem } 4027*c59e4cc3SRick Macklem 4028*c59e4cc3SRick Macklem /* 4029*c59e4cc3SRick Macklem * nfsv4 free stateid service 4030*c59e4cc3SRick Macklem */ 4031*c59e4cc3SRick Macklem APPLESTATIC int 4032*c59e4cc3SRick Macklem nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram, 4033*c59e4cc3SRick Macklem __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 4034*c59e4cc3SRick Macklem { 4035*c59e4cc3SRick Macklem uint32_t *tl; 4036*c59e4cc3SRick Macklem nfsv4stateid_t stateid; 4037*c59e4cc3SRick Macklem int error = 0; 4038*c59e4cc3SRick Macklem 4039*c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4040*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 4041*c59e4cc3SRick Macklem goto nfsmout; 4042*c59e4cc3SRick Macklem } 4043*c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 4044*c59e4cc3SRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4045*c59e4cc3SRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4046*c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p); 4047*c59e4cc3SRick Macklem nfsmout: 4048*c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4049*c59e4cc3SRick Macklem return (error); 4050*c59e4cc3SRick Macklem } 4051*c59e4cc3SRick Macklem 4052*c59e4cc3SRick Macklem /* 4053*c59e4cc3SRick Macklem * nfsv4 service not supported 4054*c59e4cc3SRick Macklem */ 4055*c59e4cc3SRick Macklem APPLESTATIC int 4056*c59e4cc3SRick Macklem nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram, 4057*c59e4cc3SRick Macklem __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 4058*c59e4cc3SRick Macklem { 4059*c59e4cc3SRick Macklem 4060*c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 4061*c59e4cc3SRick Macklem NFSEXITCODE2(0, nd); 4062*c59e4cc3SRick Macklem return (0); 4063*c59e4cc3SRick Macklem } 4064*c59e4cc3SRick Macklem 4065