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 589ec7b004SRick Macklem /* 599ec7b004SRick Macklem * This list defines the GSS mechanisms supported. 609ec7b004SRick Macklem * (Don't ask me how you get these strings from the RFC stuff like 619ec7b004SRick Macklem * iso(1), org(3)... but someone did it, so I don't need to know.) 629ec7b004SRick Macklem */ 639ec7b004SRick Macklem static struct nfsgss_mechlist nfsgss_mechlist[] = { 649ec7b004SRick Macklem { 9, "\052\206\110\206\367\022\001\002\002", 11 }, 659ec7b004SRick Macklem { 0, "", 0 }, 669ec7b004SRick Macklem }; 679ec7b004SRick Macklem 689ec7b004SRick Macklem /* local functions */ 699ec7b004SRick Macklem static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 709ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 719ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 729ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, 739ec7b004SRick Macklem NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 749ec7b004SRick Macklem int pathlen); 759ec7b004SRick Macklem static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 769ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 779ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 789ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 799ec7b004SRick Macklem NFSPROC_T *p, struct nfsexstuff *exp); 809ec7b004SRick Macklem 819ec7b004SRick Macklem /* 829ec7b004SRick Macklem * nfs access service (not a part of NFS V2) 839ec7b004SRick Macklem */ 849ec7b004SRick Macklem APPLESTATIC int 859ec7b004SRick Macklem nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram, 869ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 879ec7b004SRick Macklem { 889ec7b004SRick Macklem u_int32_t *tl; 899ec7b004SRick Macklem int getret, error = 0; 909ec7b004SRick Macklem struct nfsvattr nva; 919ec7b004SRick Macklem u_int32_t testmode, nfsmode, supported = 0; 928da45f2cSRick Macklem accmode_t deletebit; 939ec7b004SRick Macklem 949ec7b004SRick Macklem if (nd->nd_repstat) { 959ec7b004SRick Macklem nfsrv_postopattr(nd, 1, &nva); 969ec7b004SRick Macklem return (0); 979ec7b004SRick Macklem } 989ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 999ec7b004SRick Macklem nfsmode = fxdr_unsigned(u_int32_t, *tl); 1009ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && 1019ec7b004SRick Macklem (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP | 1029ec7b004SRick Macklem NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE | 1039ec7b004SRick Macklem NFSACCESS_EXECUTE))) { 1049ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 1059ec7b004SRick Macklem vput(vp); 1069ec7b004SRick Macklem return (0); 1079ec7b004SRick Macklem } 1089ec7b004SRick Macklem if (nfsmode & NFSACCESS_READ) { 1099ec7b004SRick Macklem supported |= NFSACCESS_READ; 1108da45f2cSRick Macklem if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, 1118da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1129ec7b004SRick Macklem nfsmode &= ~NFSACCESS_READ; 1139ec7b004SRick Macklem } 1149ec7b004SRick Macklem if (nfsmode & NFSACCESS_MODIFY) { 1159ec7b004SRick Macklem supported |= NFSACCESS_MODIFY; 1168da45f2cSRick Macklem if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, 1178da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1189ec7b004SRick Macklem nfsmode &= ~NFSACCESS_MODIFY; 1199ec7b004SRick Macklem } 1209ec7b004SRick Macklem if (nfsmode & NFSACCESS_EXTEND) { 1219ec7b004SRick Macklem supported |= NFSACCESS_EXTEND; 1228da45f2cSRick Macklem if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p, 1238da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1249ec7b004SRick Macklem nfsmode &= ~NFSACCESS_EXTEND; 1259ec7b004SRick Macklem } 1269ec7b004SRick Macklem if (nfsmode & NFSACCESS_DELETE) { 1279ec7b004SRick Macklem supported |= NFSACCESS_DELETE; 1288da45f2cSRick Macklem if (vp->v_type == VDIR) 1298da45f2cSRick Macklem deletebit = VDELETE_CHILD; 1308da45f2cSRick Macklem else 1318da45f2cSRick Macklem deletebit = VDELETE; 1328da45f2cSRick Macklem if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p, 1338da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1349ec7b004SRick Macklem nfsmode &= ~NFSACCESS_DELETE; 1359ec7b004SRick Macklem } 1369ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 1379ec7b004SRick Macklem testmode = NFSACCESS_LOOKUP; 1389ec7b004SRick Macklem else 1399ec7b004SRick Macklem testmode = NFSACCESS_EXECUTE; 1409ec7b004SRick Macklem if (nfsmode & testmode) { 1419ec7b004SRick Macklem supported |= (nfsmode & testmode); 1428da45f2cSRick Macklem if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p, 1438da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1449ec7b004SRick Macklem nfsmode &= ~testmode; 1459ec7b004SRick Macklem } 1469ec7b004SRick Macklem nfsmode &= supported; 1479ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 1480cf42b62SRick Macklem getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 1499ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 1509ec7b004SRick Macklem } 1519ec7b004SRick Macklem vput(vp); 1529ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 1539ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1549ec7b004SRick Macklem *tl++ = txdr_unsigned(supported); 1559ec7b004SRick Macklem } else 1569ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1579ec7b004SRick Macklem *tl = txdr_unsigned(nfsmode); 1589ec7b004SRick Macklem return (0); 1599ec7b004SRick Macklem nfsmout: 1609ec7b004SRick Macklem vput(vp); 1619ec7b004SRick Macklem return (error); 1629ec7b004SRick Macklem } 1639ec7b004SRick Macklem 1649ec7b004SRick Macklem /* 1659ec7b004SRick Macklem * nfs getattr service 1669ec7b004SRick Macklem */ 1679ec7b004SRick Macklem APPLESTATIC int 1689ec7b004SRick Macklem nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram, 1699ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 1709ec7b004SRick Macklem { 1719ec7b004SRick Macklem struct nfsvattr nva; 1729ec7b004SRick Macklem fhandle_t fh; 173a09001a8SRick Macklem int at_root = 0, error = 0, supports_nfsv4acls; 1749ec7b004SRick Macklem struct nfsreferral *refp; 175*53f476caSRick Macklem nfsattrbit_t attrbits, tmpbits; 17607c0c166SRick Macklem struct mount *mp; 17707c0c166SRick Macklem struct vnode *tvp = NULL; 17807c0c166SRick Macklem struct vattr va; 17907c0c166SRick Macklem uint64_t mounted_on_fileno = 0; 180*53f476caSRick Macklem accmode_t accmode; 1819ec7b004SRick Macklem 1829ec7b004SRick Macklem if (nd->nd_repstat) 1839ec7b004SRick Macklem return (0); 1849ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 1859ec7b004SRick Macklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 1869ec7b004SRick Macklem if (error) { 1879ec7b004SRick Macklem vput(vp); 1889ec7b004SRick Macklem return (error); 1899ec7b004SRick Macklem } 1909ec7b004SRick Macklem 1919ec7b004SRick Macklem /* 1929ec7b004SRick Macklem * Check for a referral. 1939ec7b004SRick Macklem */ 1949ec7b004SRick Macklem refp = nfsv4root_getreferral(vp, NULL, 0); 1959ec7b004SRick Macklem if (refp != NULL) { 1969ec7b004SRick Macklem (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1, 1979ec7b004SRick Macklem &nd->nd_repstat); 1989ec7b004SRick Macklem vput(vp); 1999ec7b004SRick Macklem return (0); 2009ec7b004SRick Macklem } 201*53f476caSRick Macklem if (nd->nd_repstat == 0) { 202*53f476caSRick Macklem accmode = 0; 203*53f476caSRick Macklem NFSSET_ATTRBIT(&tmpbits, &attrbits); 204*53f476caSRick Macklem if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) { 205*53f476caSRick Macklem NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL); 206*53f476caSRick Macklem accmode |= VREAD_ACL; 207*53f476caSRick Macklem } 208*53f476caSRick Macklem if (NFSNONZERO_ATTRBIT(&tmpbits)) 209*53f476caSRick Macklem accmode |= VREAD_ATTRIBUTES; 210*53f476caSRick Macklem if (accmode != 0) 211*53f476caSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, accmode, 2128da45f2cSRick Macklem nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, 2138da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 2149ec7b004SRick Macklem } 215*53f476caSRick Macklem } 2169ec7b004SRick Macklem if (!nd->nd_repstat) 2170cf42b62SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 2189ec7b004SRick Macklem if (!nd->nd_repstat) { 2199ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 2209ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE)) 2219ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 2229ec7b004SRick Macklem if (!nd->nd_repstat) 2239ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkgetattr(nd, vp, 2249ec7b004SRick Macklem &nva, &attrbits, nd->nd_cred, p); 22507c0c166SRick Macklem if (nd->nd_repstat == 0) { 226a09001a8SRick Macklem supports_nfsv4acls = nfs_supportsnfsv4acls(vp); 22707c0c166SRick Macklem mp = vp->v_mount; 22807c0c166SRick Macklem if (nfsrv_enable_crossmntpt != 0 && 22907c0c166SRick Macklem vp->v_type == VDIR && 23007c0c166SRick Macklem (vp->v_vflag & VV_ROOT) != 0 && 23107c0c166SRick Macklem vp != rootvnode) { 23207c0c166SRick Macklem tvp = mp->mnt_vnodecovered; 23307c0c166SRick Macklem VREF(tvp); 23407c0c166SRick Macklem at_root = 1; 23507c0c166SRick Macklem } else 23607c0c166SRick Macklem at_root = 0; 23707c0c166SRick Macklem vfs_ref(mp); 23807c0c166SRick Macklem VOP_UNLOCK(vp, 0); 23907c0c166SRick Macklem if (at_root != 0) { 24007c0c166SRick Macklem if ((nd->nd_repstat = 24107c0c166SRick Macklem vn_lock(tvp, LK_SHARED)) == 0) { 24207c0c166SRick Macklem nd->nd_repstat = VOP_GETATTR( 24307c0c166SRick Macklem tvp, &va, nd->nd_cred); 24407c0c166SRick Macklem vput(tvp); 24507c0c166SRick Macklem } else 24607c0c166SRick Macklem vrele(tvp); 24707c0c166SRick Macklem if (nd->nd_repstat == 0) 24807c0c166SRick Macklem mounted_on_fileno = (uint64_t) 24907c0c166SRick Macklem va.va_fileid; 25007c0c166SRick Macklem else 25107c0c166SRick Macklem at_root = 0; 25207c0c166SRick Macklem } 25307c0c166SRick Macklem if (nd->nd_repstat == 0) 25407c0c166SRick Macklem nd->nd_repstat = vfs_busy(mp, 0); 25507c0c166SRick Macklem vfs_rel(mp); 25607c0c166SRick Macklem if (nd->nd_repstat == 0) { 25707c0c166SRick Macklem (void)nfsvno_fillattr(nd, mp, vp, &nva, 25807c0c166SRick Macklem &fh, 0, &attrbits, nd->nd_cred, p, 259a09001a8SRick Macklem isdgram, 1, supports_nfsv4acls, 260a09001a8SRick Macklem at_root, mounted_on_fileno); 26107c0c166SRick Macklem vfs_unbusy(mp); 26207c0c166SRick Macklem } 2639ec7b004SRick Macklem vrele(vp); 26407c0c166SRick Macklem } else 26507c0c166SRick Macklem vput(vp); 2669ec7b004SRick Macklem } else { 2679ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 2689ec7b004SRick Macklem vput(vp); 2699ec7b004SRick Macklem } 2709ec7b004SRick Macklem } else { 2719ec7b004SRick Macklem vput(vp); 2729ec7b004SRick Macklem } 2739ec7b004SRick Macklem return (0); 2749ec7b004SRick Macklem } 2759ec7b004SRick Macklem 2769ec7b004SRick Macklem /* 2779ec7b004SRick Macklem * nfs setattr service 2789ec7b004SRick Macklem */ 2799ec7b004SRick Macklem APPLESTATIC int 2809ec7b004SRick Macklem nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram, 2819ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2829ec7b004SRick Macklem { 2839ec7b004SRick Macklem struct nfsvattr nva, nva2; 2849ec7b004SRick Macklem u_int32_t *tl; 2859ec7b004SRick Macklem int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0; 2869ec7b004SRick Macklem struct timespec guard = { 0, 0 }; 2879ec7b004SRick Macklem nfsattrbit_t attrbits, retbits; 2889ec7b004SRick Macklem nfsv4stateid_t stateid; 2899ec7b004SRick Macklem NFSACL_T *aclp = NULL; 2909ec7b004SRick Macklem 2919ec7b004SRick Macklem if (nd->nd_repstat) { 2929ec7b004SRick Macklem nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 2939ec7b004SRick Macklem return (0); 2949ec7b004SRick Macklem } 2959ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 296c3e22f83SRick Macklem aclp = acl_alloc(M_WAITOK); 2979ec7b004SRick Macklem aclp->acl_cnt = 0; 2989ec7b004SRick Macklem #endif 2999ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 3009ec7b004SRick Macklem NFSZERO_ATTRBIT(&retbits); 3019ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 3029ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3039ec7b004SRick Macklem stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3049ec7b004SRick Macklem NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 3059ec7b004SRick Macklem } 3069ec7b004SRick Macklem error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p); 3079ec7b004SRick Macklem if (error) 3089ec7b004SRick Macklem goto nfsmout; 3090cf42b62SRick Macklem preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1); 3109ec7b004SRick Macklem if (!nd->nd_repstat) 3119ec7b004SRick Macklem nd->nd_repstat = preat_ret; 3129ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 3139ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3149ec7b004SRick Macklem gcheck = fxdr_unsigned(int, *tl); 3159ec7b004SRick Macklem if (gcheck) { 3169ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3179ec7b004SRick Macklem fxdr_nfsv3time(tl, &guard); 3189ec7b004SRick Macklem } 3199ec7b004SRick Macklem if (!nd->nd_repstat && gcheck && 3209ec7b004SRick Macklem (nva2.na_ctime.tv_sec != guard.tv_sec || 3219ec7b004SRick Macklem nva2.na_ctime.tv_nsec != guard.tv_nsec)) 3229ec7b004SRick Macklem nd->nd_repstat = NFSERR_NOT_SYNC; 3239ec7b004SRick Macklem if (nd->nd_repstat) { 3249ec7b004SRick Macklem vput(vp); 3259ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 3269ec7b004SRick Macklem acl_free(aclp); 3279ec7b004SRick Macklem #endif 3289ec7b004SRick Macklem nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 3299ec7b004SRick Macklem return (0); 3309ec7b004SRick Macklem } 3319ec7b004SRick Macklem } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) 3329ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 3339ec7b004SRick Macklem 3349ec7b004SRick Macklem /* 3359ec7b004SRick Macklem * Now that we have all the fields, lets do it. 3369ec7b004SRick Macklem * If the size is being changed write access is required, otherwise 3379ec7b004SRick Macklem * just check for a read only file system. 3389ec7b004SRick Macklem */ 3399ec7b004SRick Macklem if (!nd->nd_repstat) { 3409ec7b004SRick Macklem if (NFSVNO_NOTSETSIZE(&nva)) { 3419ec7b004SRick Macklem if (NFSVNO_EXRDONLY(exp) || 3429ec7b004SRick Macklem (vfs_flags(vnode_mount(vp)) & MNT_RDONLY)) 3439ec7b004SRick Macklem nd->nd_repstat = EROFS; 3449ec7b004SRick Macklem } else { 3459ec7b004SRick Macklem if (vnode_vtype(vp) != VREG) 3469ec7b004SRick Macklem nd->nd_repstat = EINVAL; 3479ec7b004SRick Macklem else if (nva2.na_uid != nd->nd_cred->cr_uid || 3489ec7b004SRick Macklem NFSVNO_EXSTRICTACCESS(exp)) 3499ec7b004SRick Macklem nd->nd_repstat = nfsvno_accchk(vp, 3508da45f2cSRick Macklem VWRITE, nd->nd_cred, exp, p, 3518da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, 3528da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 3539ec7b004SRick Macklem } 3549ec7b004SRick Macklem } 3559ec7b004SRick Macklem if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) 3569ec7b004SRick Macklem nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid, 3579ec7b004SRick Macklem &nva, &attrbits, exp, p); 3589ec7b004SRick Macklem 3599ec7b004SRick Macklem if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 3609ec7b004SRick Macklem /* 3619ec7b004SRick Macklem * For V4, try setting the attrbutes in sets, so that the 3629ec7b004SRick Macklem * reply bitmap will be correct for an error case. 3639ec7b004SRick Macklem */ 3649ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) || 3659ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) { 3669ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 3679ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid); 3689ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid); 3699ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 3709ec7b004SRick Macklem exp); 3719ec7b004SRick Macklem if (!nd->nd_repstat) { 3729ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER)) 3739ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER); 3749ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) 3759ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP); 3769ec7b004SRick Macklem } 3779ec7b004SRick Macklem } 3789ec7b004SRick Macklem if (!nd->nd_repstat && 3799ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) { 3809ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 3819ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, size, nva.na_size); 3829ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 3839ec7b004SRick Macklem exp); 3849ec7b004SRick Macklem if (!nd->nd_repstat) 3859ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE); 3869ec7b004SRick Macklem } 3879ec7b004SRick Macklem if (!nd->nd_repstat && 3889ec7b004SRick Macklem (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) || 3899ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) { 3909ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 3919ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime); 3929ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime); 3939ec7b004SRick Macklem if (nva.na_vaflags & VA_UTIMES_NULL) { 3949ec7b004SRick Macklem nva2.na_vaflags |= VA_UTIMES_NULL; 3959ec7b004SRick Macklem NFSVNO_SETACTIVE(&nva2, vaflags); 3969ec7b004SRick Macklem } 3979ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 3989ec7b004SRick Macklem exp); 3999ec7b004SRick Macklem if (!nd->nd_repstat) { 4009ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET)) 4019ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET); 4029ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET)) 4039ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET); 4049ec7b004SRick Macklem } 4059ec7b004SRick Macklem } 4069ec7b004SRick Macklem if (!nd->nd_repstat && 4079ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) { 4089ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 4099ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode); 4109ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 4119ec7b004SRick Macklem exp); 4129ec7b004SRick Macklem if (!nd->nd_repstat) 4139ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE); 4149ec7b004SRick Macklem } 4159ec7b004SRick Macklem 4169ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 4179ec7b004SRick Macklem if (!nd->nd_repstat && aclp->acl_cnt > 0 && 4189ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) { 4199ec7b004SRick Macklem nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p); 4209ec7b004SRick Macklem if (!nd->nd_repstat) 4219ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL); 4229ec7b004SRick Macklem } 4239ec7b004SRick Macklem #endif 4249ec7b004SRick Macklem } else if (!nd->nd_repstat) { 4259ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p, 4269ec7b004SRick Macklem exp); 4279ec7b004SRick Macklem } 4289ec7b004SRick Macklem if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) { 4290cf42b62SRick Macklem postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 4309ec7b004SRick Macklem if (!nd->nd_repstat) 4319ec7b004SRick Macklem nd->nd_repstat = postat_ret; 4329ec7b004SRick Macklem } 4339ec7b004SRick Macklem vput(vp); 4349ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 4359ec7b004SRick Macklem acl_free(aclp); 4369ec7b004SRick Macklem #endif 4379ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 4389ec7b004SRick Macklem nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 4399ec7b004SRick Macklem else if (nd->nd_flag & ND_NFSV4) 4409ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &retbits); 4419ec7b004SRick Macklem else if (!nd->nd_repstat) 4429ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 4439ec7b004SRick Macklem return (0); 4449ec7b004SRick Macklem nfsmout: 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_NFSV4) { 4509ec7b004SRick Macklem /* 4519ec7b004SRick Macklem * For all nd_repstat, the V4 reply includes a bitmap, 4529ec7b004SRick Macklem * even NFSERR_BADXDR, which is what this will end up 4539ec7b004SRick Macklem * returning. 4549ec7b004SRick Macklem */ 4559ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &retbits); 4569ec7b004SRick Macklem } 4579ec7b004SRick Macklem return (error); 4589ec7b004SRick Macklem } 4599ec7b004SRick Macklem 4609ec7b004SRick Macklem /* 4619ec7b004SRick Macklem * nfs lookup rpc 4629ec7b004SRick Macklem * (Also performs lookup parent for v4) 4639ec7b004SRick Macklem */ 4649ec7b004SRick Macklem APPLESTATIC int 4659ec7b004SRick Macklem nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram, 4669ec7b004SRick Macklem vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 46737b88c2dSRick Macklem struct nfsexstuff *exp) 4689ec7b004SRick Macklem { 4699ec7b004SRick Macklem struct nameidata named; 4709ec7b004SRick Macklem vnode_t vp, dirp = NULL; 4719ec7b004SRick Macklem int error, dattr_ret = 1; 4729ec7b004SRick Macklem struct nfsvattr nva, dattr; 4739ec7b004SRick Macklem char *bufp; 4749ec7b004SRick Macklem u_long *hashp; 4759ec7b004SRick Macklem 4769ec7b004SRick Macklem if (nd->nd_repstat) { 4779ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 4789ec7b004SRick Macklem return (0); 4799ec7b004SRick Macklem } 4809ec7b004SRick Macklem 4819ec7b004SRick Macklem /* 4829ec7b004SRick Macklem * For some reason, if dp is a symlink, the error 4839ec7b004SRick Macklem * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR. 4849ec7b004SRick Macklem */ 4859ec7b004SRick Macklem if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) { 4869ec7b004SRick Macklem nd->nd_repstat = NFSERR_SYMLINK; 4879ec7b004SRick Macklem vrele(dp); 4889ec7b004SRick Macklem return (0); 4899ec7b004SRick Macklem } 4909ec7b004SRick Macklem 4919ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 4929ec7b004SRick Macklem LOCKLEAF | SAVESTART); 4939ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 4949ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 4959ec7b004SRick Macklem if (error) { 4969ec7b004SRick Macklem vrele(dp); 4979ec7b004SRick Macklem nfsvno_relpathbuf(&named); 4989ec7b004SRick Macklem return (error); 4999ec7b004SRick Macklem } 5009ec7b004SRick Macklem if (!nd->nd_repstat) { 5019ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 5029ec7b004SRick Macklem } else { 5039ec7b004SRick Macklem vrele(dp); 5049ec7b004SRick Macklem nfsvno_relpathbuf(&named); 5059ec7b004SRick Macklem } 5069ec7b004SRick Macklem if (nd->nd_repstat) { 5079ec7b004SRick Macklem if (dirp) { 5089ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 5099ec7b004SRick Macklem dattr_ret = nfsvno_getattr(dirp, &dattr, 5100cf42b62SRick Macklem nd->nd_cred, p, 0); 5119ec7b004SRick Macklem vrele(dirp); 5129ec7b004SRick Macklem } 5139ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 5149ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 5159ec7b004SRick Macklem return (0); 5169ec7b004SRick Macklem } 5179ec7b004SRick Macklem if (named.ni_startdir) 5189ec7b004SRick Macklem vrele(named.ni_startdir); 5199ec7b004SRick Macklem nfsvno_relpathbuf(&named); 5209ec7b004SRick Macklem vp = named.ni_vp; 52137b88c2dSRick Macklem if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) && 52237b88c2dSRick Macklem vp->v_type != VDIR && vp->v_type != VLNK) 52337b88c2dSRick Macklem /* 52437b88c2dSRick Macklem * Only allow lookup of VDIR and VLNK for traversal of 52537b88c2dSRick Macklem * non-exported volumes during NFSv4 mounting. 52637b88c2dSRick Macklem */ 52737b88c2dSRick Macklem nd->nd_repstat = ENOENT; 52837b88c2dSRick Macklem if (nd->nd_repstat == 0) 5299ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 5309ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 5310cf42b62SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 53281f78d99SRick Macklem if (vpp != NULL && nd->nd_repstat == 0) 5339ec7b004SRick Macklem *vpp = vp; 53481f78d99SRick Macklem else 5359ec7b004SRick Macklem vput(vp); 5369ec7b004SRick Macklem if (dirp) { 5379ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 5389ec7b004SRick Macklem dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred, 5390cf42b62SRick Macklem p, 0); 5409ec7b004SRick Macklem vrele(dirp); 5419ec7b004SRick Macklem } 5429ec7b004SRick Macklem if (nd->nd_repstat) { 5439ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 5449ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 5459ec7b004SRick Macklem return (0); 5469ec7b004SRick Macklem } 5479ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 5489ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 5499ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 5509ec7b004SRick Macklem } else if (nd->nd_flag & ND_NFSV3) { 5519ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 5529ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 5539ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 5549ec7b004SRick Macklem } 5559ec7b004SRick Macklem return (0); 5569ec7b004SRick Macklem } 5579ec7b004SRick Macklem 5589ec7b004SRick Macklem /* 5599ec7b004SRick Macklem * nfs readlink service 5609ec7b004SRick Macklem */ 5619ec7b004SRick Macklem APPLESTATIC int 5629ec7b004SRick Macklem nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram, 5639ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 5649ec7b004SRick Macklem { 5659ec7b004SRick Macklem u_int32_t *tl; 5669ec7b004SRick Macklem mbuf_t mp = NULL, mpend = NULL; 5679ec7b004SRick Macklem int getret = 1, len; 5689ec7b004SRick Macklem struct nfsvattr nva; 5699ec7b004SRick Macklem 5709ec7b004SRick Macklem if (nd->nd_repstat) { 5719ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 5729ec7b004SRick Macklem return (0); 5739ec7b004SRick Macklem } 5749ec7b004SRick Macklem if (vnode_vtype(vp) != VLNK) { 5759ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) 5769ec7b004SRick Macklem nd->nd_repstat = ENXIO; 5779ec7b004SRick Macklem else 5789ec7b004SRick Macklem nd->nd_repstat = EINVAL; 5799ec7b004SRick Macklem } 5809ec7b004SRick Macklem if (!nd->nd_repstat) 5819ec7b004SRick Macklem nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p, 5829ec7b004SRick Macklem &mp, &mpend, &len); 5839ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 5840cf42b62SRick Macklem getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 5859ec7b004SRick Macklem vput(vp); 5869ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 5879ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 5889ec7b004SRick Macklem if (nd->nd_repstat) 5899ec7b004SRick Macklem return (0); 5909ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 5919ec7b004SRick Macklem *tl = txdr_unsigned(len); 5929ec7b004SRick Macklem mbuf_setnext(nd->nd_mb, mp); 5939ec7b004SRick Macklem nd->nd_mb = mpend; 5949ec7b004SRick Macklem nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend); 5959ec7b004SRick Macklem return (0); 5969ec7b004SRick Macklem } 5979ec7b004SRick Macklem 5989ec7b004SRick Macklem /* 5999ec7b004SRick Macklem * nfs read service 6009ec7b004SRick Macklem */ 6019ec7b004SRick Macklem APPLESTATIC int 6029ec7b004SRick Macklem nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram, 6039ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 6049ec7b004SRick Macklem { 6059ec7b004SRick Macklem u_int32_t *tl; 6069ec7b004SRick Macklem int error = 0, cnt, len, getret = 1, reqlen, eof = 0; 6079ec7b004SRick Macklem mbuf_t m2, m3; 6089ec7b004SRick Macklem struct nfsvattr nva; 6099ec7b004SRick Macklem off_t off = 0x0; 6109ec7b004SRick Macklem struct nfsstate st, *stp = &st; 6119ec7b004SRick Macklem struct nfslock lo, *lop = &lo; 6129ec7b004SRick Macklem nfsv4stateid_t stateid; 6139ec7b004SRick Macklem nfsquad_t clientid; 6149ec7b004SRick Macklem 6159ec7b004SRick Macklem if (nd->nd_repstat) { 6169ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 6179ec7b004SRick Macklem return (0); 6189ec7b004SRick Macklem } 6199ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 6209ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 6219ec7b004SRick Macklem off = (off_t)fxdr_unsigned(u_int32_t, *tl++); 6229ec7b004SRick Macklem reqlen = fxdr_unsigned(int, *tl); 6239ec7b004SRick Macklem } else if (nd->nd_flag & ND_NFSV3) { 6249ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 6259ec7b004SRick Macklem off = fxdr_hyper(tl); 6269ec7b004SRick Macklem tl += 2; 6279ec7b004SRick Macklem reqlen = fxdr_unsigned(int, *tl); 6289ec7b004SRick Macklem } else { 6299ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED); 6309ec7b004SRick Macklem reqlen = fxdr_unsigned(int, *(tl + 6)); 6319ec7b004SRick Macklem } 6329ec7b004SRick Macklem if (reqlen > NFS_SRVMAXDATA(nd)) { 6339ec7b004SRick Macklem reqlen = NFS_SRVMAXDATA(nd); 6349ec7b004SRick Macklem } else if (reqlen < 0) { 6359ec7b004SRick Macklem error = EBADRPC; 6369ec7b004SRick Macklem goto nfsmout; 6379ec7b004SRick Macklem } 6389ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 6399ec7b004SRick Macklem stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS); 6409ec7b004SRick Macklem lop->lo_flags = NFSLCK_READ; 6419ec7b004SRick Macklem stp->ls_ownerlen = 0; 6429ec7b004SRick Macklem stp->ls_op = NULL; 6439ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 6449ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 6459ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 6469ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 6479ec7b004SRick Macklem if (nd->nd_flag & ND_IMPLIEDCLID) { 6489ec7b004SRick Macklem if (nd->nd_clientid.qval != clientid.qval) 6499ec7b004SRick Macklem printf("EEK! multiple clids\n"); 6509ec7b004SRick Macklem } else { 6519ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 6529ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 6539ec7b004SRick Macklem } 6549ec7b004SRick Macklem stp->ls_stateid.other[2] = *tl++; 6559ec7b004SRick Macklem off = fxdr_hyper(tl); 6569ec7b004SRick Macklem lop->lo_first = off; 6579ec7b004SRick Macklem tl += 2; 6589ec7b004SRick Macklem lop->lo_end = off + reqlen; 6599ec7b004SRick Macklem /* 6609ec7b004SRick Macklem * Paranoia, just in case it wraps around. 6619ec7b004SRick Macklem */ 6629ec7b004SRick Macklem if (lop->lo_end < off) 6639ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 6649ec7b004SRick Macklem } 6659ec7b004SRick Macklem if (vnode_vtype(vp) != VREG) { 6669ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 6679ec7b004SRick Macklem nd->nd_repstat = EINVAL; 6689ec7b004SRick Macklem else 6699ec7b004SRick Macklem nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR : 6709ec7b004SRick Macklem EINVAL; 6719ec7b004SRick Macklem } 6720cf42b62SRick Macklem getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 6739ec7b004SRick Macklem if (!nd->nd_repstat) 6749ec7b004SRick Macklem nd->nd_repstat = getret; 6759ec7b004SRick Macklem if (!nd->nd_repstat && 6769ec7b004SRick Macklem (nva.na_uid != nd->nd_cred->cr_uid || 6779ec7b004SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) { 6788da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, 6799ec7b004SRick Macklem nd->nd_cred, exp, p, 6808da45f2cSRick Macklem NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 6819ec7b004SRick Macklem if (nd->nd_repstat) 6828da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 6838da45f2cSRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 6848da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 6859ec7b004SRick Macklem } 6869ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 6879ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 6889ec7b004SRick Macklem &stateid, exp, nd, p); 6899ec7b004SRick Macklem if (nd->nd_repstat) { 6909ec7b004SRick Macklem vput(vp); 6919ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 6929ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 6939ec7b004SRick Macklem return (0); 6949ec7b004SRick Macklem } 6959ec7b004SRick Macklem if (off >= nva.na_size) { 6969ec7b004SRick Macklem cnt = 0; 6979ec7b004SRick Macklem eof = 1; 6989ec7b004SRick Macklem } else if (reqlen == 0) 6999ec7b004SRick Macklem cnt = 0; 7009ec7b004SRick Macklem else if ((off + reqlen) > nva.na_size) 7019ec7b004SRick Macklem cnt = nva.na_size - off; 7029ec7b004SRick Macklem else 7039ec7b004SRick Macklem cnt = reqlen; 7049ec7b004SRick Macklem len = NFSM_RNDUP(cnt); 7059ec7b004SRick Macklem m3 = NULL; 7069ec7b004SRick Macklem if (cnt > 0) { 7079ec7b004SRick Macklem nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p, 7089ec7b004SRick Macklem &m3, &m2); 7099ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV4)) { 7100cf42b62SRick Macklem getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 7119ec7b004SRick Macklem if (!nd->nd_repstat) 7129ec7b004SRick Macklem nd->nd_repstat = getret; 7139ec7b004SRick Macklem } 7149ec7b004SRick Macklem if (nd->nd_repstat) { 7159ec7b004SRick Macklem vput(vp); 7169ec7b004SRick Macklem if (m3) 7179ec7b004SRick Macklem mbuf_freem(m3); 7189ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 7199ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 7209ec7b004SRick Macklem return (0); 7219ec7b004SRick Macklem } 7229ec7b004SRick Macklem } 7239ec7b004SRick Macklem vput(vp); 7249ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 7259ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 7269ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 7279ec7b004SRick Macklem } else { 7289ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 7299ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 7309ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 7319ec7b004SRick Macklem *tl++ = txdr_unsigned(cnt); 7329ec7b004SRick Macklem } else 7339ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 7349ec7b004SRick Macklem if (len < reqlen || eof) 7359ec7b004SRick Macklem *tl++ = newnfs_true; 7369ec7b004SRick Macklem else 7379ec7b004SRick Macklem *tl++ = newnfs_false; 7389ec7b004SRick Macklem } 7399ec7b004SRick Macklem *tl = txdr_unsigned(cnt); 7409ec7b004SRick Macklem if (m3) { 7419ec7b004SRick Macklem mbuf_setnext(nd->nd_mb, m3); 7429ec7b004SRick Macklem nd->nd_mb = m2; 7439ec7b004SRick Macklem nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2); 7449ec7b004SRick Macklem } 7459ec7b004SRick Macklem return (0); 7469ec7b004SRick Macklem nfsmout: 7479ec7b004SRick Macklem vput(vp); 7489ec7b004SRick Macklem return (error); 7499ec7b004SRick Macklem } 7509ec7b004SRick Macklem 7519ec7b004SRick Macklem /* 7529ec7b004SRick Macklem * nfs write service 7539ec7b004SRick Macklem */ 7549ec7b004SRick Macklem APPLESTATIC int 7559ec7b004SRick Macklem nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram, 7569ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 7579ec7b004SRick Macklem { 7589ec7b004SRick Macklem int i, cnt; 7599ec7b004SRick Macklem u_int32_t *tl; 7609ec7b004SRick Macklem mbuf_t mp; 7619ec7b004SRick Macklem struct nfsvattr nva, forat; 7629ec7b004SRick Macklem int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1; 7639ec7b004SRick Macklem int stable = NFSWRITE_FILESYNC; 7649ec7b004SRick Macklem off_t off; 7659ec7b004SRick Macklem struct nfsstate st, *stp = &st; 7669ec7b004SRick Macklem struct nfslock lo, *lop = &lo; 7679ec7b004SRick Macklem nfsv4stateid_t stateid; 7689ec7b004SRick Macklem nfsquad_t clientid; 7699ec7b004SRick Macklem 7709ec7b004SRick Macklem if (nd->nd_repstat) { 7719ec7b004SRick Macklem nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 7729ec7b004SRick Macklem return (0); 7739ec7b004SRick Macklem } 7749ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 7759ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 7769ec7b004SRick Macklem off = (off_t)fxdr_unsigned(u_int32_t, *++tl); 7779ec7b004SRick Macklem tl += 2; 7789ec7b004SRick Macklem retlen = len = fxdr_unsigned(int32_t, *tl); 7799ec7b004SRick Macklem } else if (nd->nd_flag & ND_NFSV3) { 7809ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 7819ec7b004SRick Macklem off = fxdr_hyper(tl); 7829ec7b004SRick Macklem tl += 3; 7839ec7b004SRick Macklem stable = fxdr_unsigned(int, *tl++); 7849ec7b004SRick Macklem retlen = len = fxdr_unsigned(int32_t, *tl); 7859ec7b004SRick Macklem } else { 7869ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED); 7879ec7b004SRick Macklem stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 7889ec7b004SRick Macklem lop->lo_flags = NFSLCK_WRITE; 7899ec7b004SRick Macklem stp->ls_ownerlen = 0; 7909ec7b004SRick Macklem stp->ls_op = NULL; 7919ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 7929ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 7939ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 7949ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 7959ec7b004SRick Macklem if (nd->nd_flag & ND_IMPLIEDCLID) { 7969ec7b004SRick Macklem if (nd->nd_clientid.qval != clientid.qval) 7979ec7b004SRick Macklem printf("EEK! multiple clids\n"); 7989ec7b004SRick Macklem } else { 7999ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 8009ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 8019ec7b004SRick Macklem } 8029ec7b004SRick Macklem stp->ls_stateid.other[2] = *tl++; 8039ec7b004SRick Macklem off = fxdr_hyper(tl); 8049ec7b004SRick Macklem lop->lo_first = off; 8059ec7b004SRick Macklem tl += 2; 8069ec7b004SRick Macklem stable = fxdr_unsigned(int, *tl++); 8079ec7b004SRick Macklem retlen = len = fxdr_unsigned(int32_t, *tl); 8089ec7b004SRick Macklem lop->lo_end = off + len; 8099ec7b004SRick Macklem /* 8109ec7b004SRick Macklem * Paranoia, just in case it wraps around, which shouldn't 8119ec7b004SRick Macklem * ever happen anyhow. 8129ec7b004SRick Macklem */ 8139ec7b004SRick Macklem if (lop->lo_end < lop->lo_first) 8149ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 8159ec7b004SRick Macklem } 8169ec7b004SRick Macklem 8179ec7b004SRick Macklem /* 8189ec7b004SRick Macklem * Loop through the mbuf chain, counting how many mbufs are a 8199ec7b004SRick Macklem * part of this write operation, so the iovec size is known. 8209ec7b004SRick Macklem */ 8219ec7b004SRick Macklem cnt = 0; 8229ec7b004SRick Macklem mp = nd->nd_md; 8239ec7b004SRick Macklem i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos; 8249ec7b004SRick Macklem while (len > 0) { 8259ec7b004SRick Macklem if (i > 0) { 8269ec7b004SRick Macklem len -= i; 8279ec7b004SRick Macklem cnt++; 8289ec7b004SRick Macklem } 8299ec7b004SRick Macklem mp = mbuf_next(mp); 8309ec7b004SRick Macklem if (!mp) { 8319ec7b004SRick Macklem if (len > 0) { 8329ec7b004SRick Macklem error = EBADRPC; 8339ec7b004SRick Macklem goto nfsmout; 8349ec7b004SRick Macklem } 8359ec7b004SRick Macklem } else 8369ec7b004SRick Macklem i = mbuf_len(mp); 8379ec7b004SRick Macklem } 8389ec7b004SRick Macklem 8399ec7b004SRick Macklem if (retlen > NFS_MAXDATA || retlen < 0) 8409ec7b004SRick Macklem nd->nd_repstat = EIO; 8419ec7b004SRick Macklem if (vnode_vtype(vp) != VREG && !nd->nd_repstat) { 8429ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 8439ec7b004SRick Macklem nd->nd_repstat = EINVAL; 8449ec7b004SRick Macklem else 8459ec7b004SRick Macklem nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR : 8469ec7b004SRick Macklem EINVAL; 8479ec7b004SRick Macklem } 8480cf42b62SRick Macklem forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1); 8499ec7b004SRick Macklem if (!nd->nd_repstat) 8509ec7b004SRick Macklem nd->nd_repstat = forat_ret; 8519ec7b004SRick Macklem if (!nd->nd_repstat && 8529ec7b004SRick Macklem (forat.na_uid != nd->nd_cred->cr_uid || 8539ec7b004SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) 8548da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 8559ec7b004SRick Macklem nd->nd_cred, exp, p, 8568da45f2cSRick Macklem NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 8579ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 8589ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 8599ec7b004SRick Macklem &stateid, exp, nd, p); 8609ec7b004SRick Macklem } 8619ec7b004SRick Macklem if (nd->nd_repstat) { 8629ec7b004SRick Macklem vput(vp); 8639ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 8649ec7b004SRick Macklem nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 8659ec7b004SRick Macklem return (0); 8669ec7b004SRick Macklem } 8679ec7b004SRick Macklem 8689ec7b004SRick Macklem /* 8699ec7b004SRick Macklem * For NFS Version 2, it is not obvious what a write of zero length 8709ec7b004SRick Macklem * should do, but I might as well be consistent with Version 3, 8719ec7b004SRick Macklem * which is to return ok so long as there are no permission problems. 8729ec7b004SRick Macklem */ 8739ec7b004SRick Macklem if (retlen > 0) { 8749ec7b004SRick Macklem nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable, 8759ec7b004SRick Macklem nd->nd_md, nd->nd_dpos, nd->nd_cred, p); 8769ec7b004SRick Macklem error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1); 8779ec7b004SRick Macklem if (error) 8789ec7b004SRick Macklem panic("nfsrv_write mbuf"); 8799ec7b004SRick Macklem } 8809ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) 8819ec7b004SRick Macklem aftat_ret = 0; 8829ec7b004SRick Macklem else 8830cf42b62SRick Macklem aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 8849ec7b004SRick Macklem vput(vp); 8859ec7b004SRick Macklem if (!nd->nd_repstat) 8869ec7b004SRick Macklem nd->nd_repstat = aftat_ret; 8879ec7b004SRick Macklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 8889ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 8899ec7b004SRick Macklem nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 8909ec7b004SRick Macklem if (nd->nd_repstat) 8919ec7b004SRick Macklem return (0); 8929ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 8939ec7b004SRick Macklem *tl++ = txdr_unsigned(retlen); 8949ec7b004SRick Macklem if (stable == NFSWRITE_UNSTABLE) 8959ec7b004SRick Macklem *tl++ = txdr_unsigned(stable); 8969ec7b004SRick Macklem else 8979ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSWRITE_FILESYNC); 8989ec7b004SRick Macklem /* 8999ec7b004SRick Macklem * Actually, there is no need to txdr these fields, 9009ec7b004SRick Macklem * but it may make the values more human readable, 9019ec7b004SRick Macklem * for debugging purposes. 9029ec7b004SRick Macklem */ 9039ec7b004SRick Macklem *tl++ = txdr_unsigned(nfsboottime.tv_sec); 9049ec7b004SRick Macklem *tl = txdr_unsigned(nfsboottime.tv_usec); 9059ec7b004SRick Macklem } else if (!nd->nd_repstat) 9069ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 9079ec7b004SRick Macklem return (0); 9089ec7b004SRick Macklem nfsmout: 9099ec7b004SRick Macklem vput(vp); 9109ec7b004SRick Macklem return (error); 9119ec7b004SRick Macklem } 9129ec7b004SRick Macklem 9139ec7b004SRick Macklem /* 9149ec7b004SRick Macklem * nfs create service (creates regular files for V2 and V3. Spec. files for V2.) 9159ec7b004SRick Macklem * now does a truncate to 0 length via. setattr if it already exists 9169ec7b004SRick Macklem * The core creation routine has been extracted out into nfsrv_creatsub(), 9179ec7b004SRick Macklem * so it can also be used by nfsrv_open() for V4. 9189ec7b004SRick Macklem */ 9199ec7b004SRick Macklem APPLESTATIC int 9209ec7b004SRick Macklem nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram, 9219ec7b004SRick Macklem vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 9229ec7b004SRick Macklem { 9239ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 9249ec7b004SRick Macklem struct nfsv2_sattr *sp; 9259ec7b004SRick Macklem struct nameidata named; 9269ec7b004SRick Macklem u_int32_t *tl; 9279ec7b004SRick Macklem int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1; 9289ec7b004SRick Macklem int how = NFSCREATE_UNCHECKED, exclusive_flag = 0; 9299ec7b004SRick Macklem NFSDEV_T rdev = 0; 9309ec7b004SRick Macklem vnode_t vp = NULL, dirp = NULL; 9319ec7b004SRick Macklem fhandle_t fh; 9329ec7b004SRick Macklem char *bufp; 9339ec7b004SRick Macklem u_long *hashp; 9349ec7b004SRick Macklem enum vtype vtyp; 935086f6e0cSRick Macklem int32_t cverf[2], tverf[2] = { 0, 0 }; 9369ec7b004SRick Macklem 9379ec7b004SRick Macklem if (nd->nd_repstat) { 9389ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 9399ec7b004SRick Macklem return (0); 9409ec7b004SRick Macklem } 9419ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 9429ec7b004SRick Macklem LOCKPARENT | LOCKLEAF | SAVESTART); 9439ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 9449ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 9459ec7b004SRick Macklem if (error) { 9469ec7b004SRick Macklem vput(dp); 9479ec7b004SRick Macklem nfsvno_relpathbuf(&named); 9489ec7b004SRick Macklem return (error); 9499ec7b004SRick Macklem } 9509ec7b004SRick Macklem if (!nd->nd_repstat) { 9519ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 9529ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 9539ec7b004SRick Macklem NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 9549ec7b004SRick Macklem vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode)); 9559ec7b004SRick Macklem if (vtyp == VNON) 9569ec7b004SRick Macklem vtyp = VREG; 9579ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, type, vtyp); 9589ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, mode, 9599ec7b004SRick Macklem nfstov_mode(sp->sa_mode)); 9609ec7b004SRick Macklem switch (nva.na_type) { 9619ec7b004SRick Macklem case VREG: 9629ec7b004SRick Macklem tsize = fxdr_unsigned(int32_t, sp->sa_size); 9639ec7b004SRick Macklem if (tsize != -1) 9649ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, size, 9659ec7b004SRick Macklem (u_quad_t)tsize); 9669ec7b004SRick Macklem break; 9679ec7b004SRick Macklem case VCHR: 9689ec7b004SRick Macklem case VBLK: 9699ec7b004SRick Macklem case VFIFO: 9709ec7b004SRick Macklem rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size); 9719ec7b004SRick Macklem break; 9729ec7b004SRick Macklem default: 9739ec7b004SRick Macklem break; 9749ec7b004SRick Macklem }; 9759ec7b004SRick Macklem } else { 9769ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 9779ec7b004SRick Macklem how = fxdr_unsigned(int, *tl); 9789ec7b004SRick Macklem switch (how) { 9799ec7b004SRick Macklem case NFSCREATE_GUARDED: 9809ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 9819ec7b004SRick Macklem error = nfsrv_sattr(nd, &nva, NULL, NULL, p); 9829ec7b004SRick Macklem if (error) 9839ec7b004SRick Macklem goto nfsmout; 9849ec7b004SRick Macklem break; 9859ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 986086f6e0cSRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 987086f6e0cSRick Macklem cverf[0] = *tl++; 988086f6e0cSRick Macklem cverf[1] = *tl; 9899ec7b004SRick Macklem exclusive_flag = 1; 9909ec7b004SRick Macklem break; 9919ec7b004SRick Macklem }; 9929ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, type, VREG); 9939ec7b004SRick Macklem } 9949ec7b004SRick Macklem } 9959ec7b004SRick Macklem if (nd->nd_repstat) { 9969ec7b004SRick Macklem nfsvno_relpathbuf(&named); 9979ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 9989ec7b004SRick Macklem dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, 9990cf42b62SRick Macklem p, 1); 10009ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 10019ec7b004SRick Macklem &diraft); 10029ec7b004SRick Macklem } 10039ec7b004SRick Macklem vput(dp); 10049ec7b004SRick Macklem return (0); 10059ec7b004SRick Macklem } 10069ec7b004SRick Macklem 10079ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 10089ec7b004SRick Macklem if (dirp) { 10099ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 10109ec7b004SRick Macklem vrele(dirp); 10119ec7b004SRick Macklem dirp = NULL; 10129ec7b004SRick Macklem } else { 10139ec7b004SRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 10140cf42b62SRick Macklem p, 0); 10159ec7b004SRick Macklem } 10169ec7b004SRick Macklem } 10179ec7b004SRick Macklem if (nd->nd_repstat) { 10189ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 10199ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 10209ec7b004SRick Macklem &diraft); 10219ec7b004SRick Macklem if (dirp) 10229ec7b004SRick Macklem vrele(dirp); 10239ec7b004SRick Macklem return (0); 10249ec7b004SRick Macklem } 10259ec7b004SRick Macklem 10269ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) { 10279ec7b004SRick Macklem switch (how) { 10289ec7b004SRick Macklem case NFSCREATE_GUARDED: 10299ec7b004SRick Macklem if (named.ni_vp) 10309ec7b004SRick Macklem nd->nd_repstat = EEXIST; 10319ec7b004SRick Macklem break; 10329ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 10339ec7b004SRick Macklem break; 10349ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 10359ec7b004SRick Macklem if (named.ni_vp == NULL) 10369ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, mode, 0); 10379ec7b004SRick Macklem break; 10389ec7b004SRick Macklem }; 10399ec7b004SRick Macklem } 10409ec7b004SRick Macklem 10419ec7b004SRick Macklem /* 10429ec7b004SRick Macklem * Iff doesn't exist, create it 10439ec7b004SRick Macklem * otherwise just truncate to 0 length 10449ec7b004SRick Macklem * should I set the mode too ? 10459ec7b004SRick Macklem */ 10469ec7b004SRick Macklem nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva, 10479ec7b004SRick Macklem &exclusive_flag, cverf, rdev, p, exp); 10489ec7b004SRick Macklem 10499ec7b004SRick Macklem if (!nd->nd_repstat) { 10509ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 10519ec7b004SRick Macklem if (!nd->nd_repstat) 10529ec7b004SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, 10530cf42b62SRick Macklem p, 1); 10549ec7b004SRick Macklem vput(vp); 1055086f6e0cSRick Macklem if (!nd->nd_repstat) { 1056086f6e0cSRick Macklem tverf[0] = nva.na_atime.tv_sec; 1057086f6e0cSRick Macklem tverf[1] = nva.na_atime.tv_nsec; 1058086f6e0cSRick Macklem } 10599ec7b004SRick Macklem } 10609ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 10619ec7b004SRick Macklem if (!nd->nd_repstat) { 10629ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 10639ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 10649ec7b004SRick Macklem } 10659ec7b004SRick Macklem } else { 1066086f6e0cSRick Macklem if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0] 1067086f6e0cSRick Macklem || cverf[1] != tverf[1])) 10689ec7b004SRick Macklem nd->nd_repstat = EEXIST; 10690cf42b62SRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0); 10709ec7b004SRick Macklem vrele(dirp); 10719ec7b004SRick Macklem if (!nd->nd_repstat) { 10729ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1); 10739ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 10749ec7b004SRick Macklem } 10759ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 10769ec7b004SRick Macklem } 10779ec7b004SRick Macklem return (0); 10789ec7b004SRick Macklem nfsmout: 10799ec7b004SRick Macklem vput(dp); 10809ec7b004SRick Macklem nfsvno_relpathbuf(&named); 10819ec7b004SRick Macklem return (error); 10829ec7b004SRick Macklem } 10839ec7b004SRick Macklem 10849ec7b004SRick Macklem /* 10859ec7b004SRick Macklem * nfs v3 mknod service (and v4 create) 10869ec7b004SRick Macklem */ 10879ec7b004SRick Macklem APPLESTATIC int 10889ec7b004SRick Macklem nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram, 10899ec7b004SRick Macklem vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 10909ec7b004SRick Macklem struct nfsexstuff *exp) 10919ec7b004SRick Macklem { 10929ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 10939ec7b004SRick Macklem u_int32_t *tl; 10949ec7b004SRick Macklem struct nameidata named; 10959ec7b004SRick Macklem int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 10969ec7b004SRick Macklem u_int32_t major, minor; 10979ec7b004SRick Macklem enum vtype vtyp = VNON; 10989ec7b004SRick Macklem nfstype nfs4type = NFNON; 10999ec7b004SRick Macklem vnode_t vp, dirp = NULL; 11009ec7b004SRick Macklem nfsattrbit_t attrbits; 11019ec7b004SRick Macklem char *bufp = NULL, *pathcp = NULL; 11029ec7b004SRick Macklem u_long *hashp, cnflags; 11039ec7b004SRick Macklem NFSACL_T *aclp = NULL; 11049ec7b004SRick Macklem 11059ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 11069ec7b004SRick Macklem cnflags = (LOCKPARENT | SAVESTART); 11079ec7b004SRick Macklem if (nd->nd_repstat) { 11089ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 11099ec7b004SRick Macklem return (0); 11109ec7b004SRick Macklem } 11119ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 1112c3e22f83SRick Macklem aclp = acl_alloc(M_WAITOK); 11139ec7b004SRick Macklem aclp->acl_cnt = 0; 11149ec7b004SRick Macklem #endif 11159ec7b004SRick Macklem 11169ec7b004SRick Macklem /* 11179ec7b004SRick Macklem * For V4, the creation stuff is here, Yuck! 11189ec7b004SRick Macklem */ 11199ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 11209ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 11219ec7b004SRick Macklem vtyp = nfsv34tov_type(*tl); 11229ec7b004SRick Macklem nfs4type = fxdr_unsigned(nfstype, *tl); 11239ec7b004SRick Macklem switch (nfs4type) { 11249ec7b004SRick Macklem case NFLNK: 11259ec7b004SRick Macklem error = nfsvno_getsymlink(nd, &nva, p, &pathcp, 11269ec7b004SRick Macklem &pathlen); 11279ec7b004SRick Macklem if (error) { 11289ec7b004SRick Macklem vrele(dp); 11299ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 11309ec7b004SRick Macklem acl_free(aclp); 11319ec7b004SRick Macklem #endif 11329ec7b004SRick Macklem return (error); 11339ec7b004SRick Macklem } 11349ec7b004SRick Macklem break; 11359ec7b004SRick Macklem case NFCHR: 11369ec7b004SRick Macklem case NFBLK: 11379ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 11389ec7b004SRick Macklem major = fxdr_unsigned(u_int32_t, *tl++); 11399ec7b004SRick Macklem minor = fxdr_unsigned(u_int32_t, *tl); 11409ec7b004SRick Macklem nva.na_rdev = NFSMAKEDEV(major, minor); 11419ec7b004SRick Macklem break; 11429ec7b004SRick Macklem case NFSOCK: 11439ec7b004SRick Macklem case NFFIFO: 11449ec7b004SRick Macklem break; 11459ec7b004SRick Macklem case NFDIR: 1146f61786cbSRick Macklem cnflags = (LOCKPARENT | SAVENAME); 11479ec7b004SRick Macklem break; 11489ec7b004SRick Macklem default: 11499ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADTYPE; 11509ec7b004SRick Macklem vrele(dp); 11519ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 11529ec7b004SRick Macklem acl_free(aclp); 11539ec7b004SRick Macklem #endif 11549ec7b004SRick Macklem return (0); 11559ec7b004SRick Macklem }; 11569ec7b004SRick Macklem } 11579ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags); 11589ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 11599ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 11609ec7b004SRick Macklem if (error) { 11619ec7b004SRick Macklem vrele(dp); 11629ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 11639ec7b004SRick Macklem acl_free(aclp); 11649ec7b004SRick Macklem #endif 11659ec7b004SRick Macklem nfsvno_relpathbuf(&named); 11669ec7b004SRick Macklem if (pathcp) 11679ec7b004SRick Macklem FREE(pathcp, M_TEMP); 11689ec7b004SRick Macklem return (error); 11699ec7b004SRick Macklem } 11709ec7b004SRick Macklem if (!nd->nd_repstat) { 11719ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 11729ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 11739ec7b004SRick Macklem vtyp = nfsv34tov_type(*tl); 11749ec7b004SRick Macklem } 11759ec7b004SRick Macklem error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p); 11769ec7b004SRick Macklem if (error) { 11779ec7b004SRick Macklem vrele(dp); 11789ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 11799ec7b004SRick Macklem acl_free(aclp); 11809ec7b004SRick Macklem #endif 11819ec7b004SRick Macklem nfsvno_relpathbuf(&named); 11829ec7b004SRick Macklem if (pathcp) 11839ec7b004SRick Macklem FREE(pathcp, M_TEMP); 11849ec7b004SRick Macklem return (error); 11859ec7b004SRick Macklem } 11869ec7b004SRick Macklem nva.na_type = vtyp; 11879ec7b004SRick Macklem if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) && 11889ec7b004SRick Macklem (vtyp == VCHR || vtyp == VBLK)) { 11899ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 11909ec7b004SRick Macklem major = fxdr_unsigned(u_int32_t, *tl++); 11919ec7b004SRick Macklem minor = fxdr_unsigned(u_int32_t, *tl); 11929ec7b004SRick Macklem nva.na_rdev = NFSMAKEDEV(major, minor); 11939ec7b004SRick Macklem } 11949ec7b004SRick Macklem } 11959ec7b004SRick Macklem 11960cf42b62SRick Macklem dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0); 11979ec7b004SRick Macklem if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 11989ec7b004SRick Macklem if (!dirfor_ret && NFSVNO_ISSETGID(&nva) && 11999ec7b004SRick Macklem dirfor.na_gid == nva.na_gid) 12009ec7b004SRick Macklem NFSVNO_UNSET(&nva, gid); 12019ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 12029ec7b004SRick Macklem } 12039ec7b004SRick Macklem if (nd->nd_repstat) { 12049ec7b004SRick Macklem vrele(dp); 12059ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 12069ec7b004SRick Macklem acl_free(aclp); 12079ec7b004SRick Macklem #endif 12089ec7b004SRick Macklem nfsvno_relpathbuf(&named); 12099ec7b004SRick Macklem if (pathcp) 12109ec7b004SRick Macklem FREE(pathcp, M_TEMP); 12119ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 12129ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 12139ec7b004SRick Macklem &diraft); 12149ec7b004SRick Macklem return (0); 12159ec7b004SRick Macklem } 12169ec7b004SRick Macklem 12179ec7b004SRick Macklem /* 12189ec7b004SRick Macklem * Yuck! For V4, mkdir and link are here and some V4 clients don't fill 12199ec7b004SRick Macklem * in va_mode, so we'll have to set a default here. 12209ec7b004SRick Macklem */ 12219ec7b004SRick Macklem if (NFSVNO_NOTSETMODE(&nva)) { 12229ec7b004SRick Macklem if (vtyp == VLNK) 12239ec7b004SRick Macklem nva.na_mode = 0755; 12249ec7b004SRick Macklem else 12259ec7b004SRick Macklem nva.na_mode = 0400; 12269ec7b004SRick Macklem } 12279ec7b004SRick Macklem 12289ec7b004SRick Macklem if (vtyp == VDIR) 12299ec7b004SRick Macklem named.ni_cnd.cn_flags |= WILLBEDIR; 12309ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 12319ec7b004SRick Macklem if (nd->nd_repstat) { 12329ec7b004SRick Macklem if (dirp) { 12339ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 12349ec7b004SRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, 12350cf42b62SRick Macklem nd->nd_cred, p, 0); 12369ec7b004SRick Macklem vrele(dirp); 12379ec7b004SRick Macklem } 12389ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 12399ec7b004SRick Macklem acl_free(aclp); 12409ec7b004SRick Macklem #endif 12419ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 12429ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 12439ec7b004SRick Macklem &diraft); 12449ec7b004SRick Macklem return (0); 12459ec7b004SRick Macklem } 12469ec7b004SRick Macklem if (dirp) 12470cf42b62SRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0); 12489ec7b004SRick Macklem 12499ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) { 12509ec7b004SRick Macklem if (vtyp == VDIR) { 12519ec7b004SRick Macklem nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, 12529ec7b004SRick Macklem &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p, 12539ec7b004SRick Macklem exp); 12549ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 12559ec7b004SRick Macklem acl_free(aclp); 12569ec7b004SRick Macklem #endif 12579ec7b004SRick Macklem return (0); 12589ec7b004SRick Macklem } else if (vtyp == VLNK) { 12599ec7b004SRick Macklem nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 12609ec7b004SRick Macklem &dirfor, &diraft, &diraft_ret, &attrbits, 12619ec7b004SRick Macklem aclp, p, exp, pathcp, pathlen); 12629ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 12639ec7b004SRick Macklem acl_free(aclp); 12649ec7b004SRick Macklem #endif 12659ec7b004SRick Macklem FREE(pathcp, M_TEMP); 12669ec7b004SRick Macklem return (0); 12679ec7b004SRick Macklem } 12689ec7b004SRick Macklem } 12699ec7b004SRick Macklem 12709ec7b004SRick Macklem nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p); 12719ec7b004SRick Macklem if (!nd->nd_repstat) { 12729ec7b004SRick Macklem vp = named.ni_vp; 12739ec7b004SRick Macklem nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp); 12749ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 12759ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat) 12769ec7b004SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, 12770cf42b62SRick Macklem p, 1); 127881f78d99SRick Macklem if (vpp != NULL && nd->nd_repstat == 0) { 127981f78d99SRick Macklem VOP_UNLOCK(vp, 0); 12809ec7b004SRick Macklem *vpp = vp; 128181f78d99SRick Macklem } else 12829ec7b004SRick Macklem vput(vp); 12839ec7b004SRick Macklem } 12849ec7b004SRick Macklem 12850cf42b62SRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0); 12869ec7b004SRick Macklem vrele(dirp); 12879ec7b004SRick Macklem if (!nd->nd_repstat) { 12889ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 12899ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 12909ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 12919ec7b004SRick Macklem } else { 12929ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 12939ec7b004SRick Macklem *tl++ = newnfs_false; 12949ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 12959ec7b004SRick Macklem tl += 2; 12969ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 12979ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &attrbits); 12989ec7b004SRick Macklem } 12999ec7b004SRick Macklem } 13009ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 13019ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 13029ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 13039ec7b004SRick Macklem acl_free(aclp); 13049ec7b004SRick Macklem #endif 13059ec7b004SRick Macklem return (0); 13069ec7b004SRick Macklem nfsmout: 13079ec7b004SRick Macklem vrele(dp); 13089ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 13099ec7b004SRick Macklem acl_free(aclp); 13109ec7b004SRick Macklem #endif 13119ec7b004SRick Macklem if (bufp) 13129ec7b004SRick Macklem nfsvno_relpathbuf(&named); 13139ec7b004SRick Macklem if (pathcp) 13149ec7b004SRick Macklem FREE(pathcp, M_TEMP); 13159ec7b004SRick Macklem return (error); 13169ec7b004SRick Macklem } 13179ec7b004SRick Macklem 13189ec7b004SRick Macklem /* 13199ec7b004SRick Macklem * nfs remove service 13209ec7b004SRick Macklem */ 13219ec7b004SRick Macklem APPLESTATIC int 13229ec7b004SRick Macklem nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram, 13239ec7b004SRick Macklem vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 13249ec7b004SRick Macklem { 13259ec7b004SRick Macklem struct nameidata named; 13269ec7b004SRick Macklem u_int32_t *tl; 13279ec7b004SRick Macklem int error, dirfor_ret = 1, diraft_ret = 1; 13289ec7b004SRick Macklem vnode_t dirp = NULL; 13299ec7b004SRick Macklem struct nfsvattr dirfor, diraft; 13309ec7b004SRick Macklem char *bufp; 13319ec7b004SRick Macklem u_long *hashp; 13329ec7b004SRick Macklem 13339ec7b004SRick Macklem if (nd->nd_repstat) { 13349ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 13359ec7b004SRick Macklem return (0); 13369ec7b004SRick Macklem } 13379ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE, 13389ec7b004SRick Macklem LOCKPARENT | LOCKLEAF); 13399ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 13409ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 13419ec7b004SRick Macklem if (error) { 13429ec7b004SRick Macklem vput(dp); 13439ec7b004SRick Macklem nfsvno_relpathbuf(&named); 13449ec7b004SRick Macklem return (error); 13459ec7b004SRick Macklem } 13469ec7b004SRick Macklem if (!nd->nd_repstat) { 13479ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 13489ec7b004SRick Macklem } else { 13499ec7b004SRick Macklem vput(dp); 13509ec7b004SRick Macklem nfsvno_relpathbuf(&named); 13519ec7b004SRick Macklem } 13529ec7b004SRick Macklem if (dirp) { 13539ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) { 13549ec7b004SRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, 13550cf42b62SRick Macklem nd->nd_cred, p, 0); 13569ec7b004SRick Macklem } else { 13579ec7b004SRick Macklem vrele(dirp); 13589ec7b004SRick Macklem dirp = NULL; 13599ec7b004SRick Macklem } 13609ec7b004SRick Macklem } 13619ec7b004SRick Macklem if (!nd->nd_repstat) { 13629ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 13639ec7b004SRick Macklem if (vnode_vtype(named.ni_vp) == VDIR) 13649ec7b004SRick Macklem nd->nd_repstat = nfsvno_rmdirsub(&named, 1, 13659ec7b004SRick Macklem nd->nd_cred, p, exp); 13669ec7b004SRick Macklem else 13679ec7b004SRick Macklem nd->nd_repstat = nfsvno_removesub(&named, 1, 13689ec7b004SRick Macklem nd->nd_cred, p, exp); 13699ec7b004SRick Macklem } else if (nd->nd_procnum == NFSPROC_RMDIR) { 13709ec7b004SRick Macklem nd->nd_repstat = nfsvno_rmdirsub(&named, 0, 13719ec7b004SRick Macklem nd->nd_cred, p, exp); 13729ec7b004SRick Macklem } else { 13739ec7b004SRick Macklem nd->nd_repstat = nfsvno_removesub(&named, 0, 13749ec7b004SRick Macklem nd->nd_cred, p, exp); 13759ec7b004SRick Macklem } 13769ec7b004SRick Macklem } 13779ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) { 13789ec7b004SRick Macklem if (dirp) { 13799ec7b004SRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, 13800cf42b62SRick Macklem p, 0); 13819ec7b004SRick Macklem vrele(dirp); 13829ec7b004SRick Macklem } 13839ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 13849ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 13859ec7b004SRick Macklem &diraft); 13869ec7b004SRick Macklem } else if (!nd->nd_repstat) { 13879ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 13889ec7b004SRick Macklem *tl++ = newnfs_false; 13899ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 13909ec7b004SRick Macklem tl += 2; 13919ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 13929ec7b004SRick Macklem } 13939ec7b004SRick Macklem } 13949ec7b004SRick Macklem return (0); 13959ec7b004SRick Macklem } 13969ec7b004SRick Macklem 13979ec7b004SRick Macklem /* 13989ec7b004SRick Macklem * nfs rename service 13999ec7b004SRick Macklem */ 14009ec7b004SRick Macklem APPLESTATIC int 14019ec7b004SRick Macklem nfsrvd_rename(struct nfsrv_descript *nd, int isdgram, 14029ec7b004SRick Macklem vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp, 14039ec7b004SRick Macklem struct nfsexstuff *toexp) 14049ec7b004SRick Macklem { 14059ec7b004SRick Macklem u_int32_t *tl; 14069ec7b004SRick Macklem int error, fdirfor_ret = 1, fdiraft_ret = 1; 14079ec7b004SRick Macklem int tdirfor_ret = 1, tdiraft_ret = 1; 14089ec7b004SRick Macklem struct nameidata fromnd, tond; 14099ec7b004SRick Macklem vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL; 14109ec7b004SRick Macklem struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft; 14119ec7b004SRick Macklem struct nfsexstuff tnes; 14129ec7b004SRick Macklem struct nfsrvfh tfh; 14139ec7b004SRick Macklem char *bufp, *tbufp = NULL; 14149ec7b004SRick Macklem u_long *hashp; 14159ec7b004SRick Macklem 14169ec7b004SRick Macklem if (nd->nd_repstat) { 14179ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 14189ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 14199ec7b004SRick Macklem return (0); 14209ec7b004SRick Macklem } 14219ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) 14220cf42b62SRick Macklem fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1); 14239ec7b004SRick Macklem tond.ni_cnd.cn_nameiop = 0; 14249ec7b004SRick Macklem tond.ni_startdir = NULL; 14259ec7b004SRick Macklem NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART); 14269ec7b004SRick Macklem nfsvno_setpathbuf(&fromnd, &bufp, &hashp); 14279ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen); 14289ec7b004SRick Macklem if (error) { 14299ec7b004SRick Macklem vput(dp); 14309ec7b004SRick Macklem if (todp) 14319ec7b004SRick Macklem vrele(todp); 14329ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 14339ec7b004SRick Macklem return (error); 14349ec7b004SRick Macklem } 14359ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 14369ec7b004SRick Macklem tdp = todp; 14379ec7b004SRick Macklem tnes = *toexp; 14380cf42b62SRick Macklem tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, p, 0); 14399ec7b004SRick Macklem } else { 14409ec7b004SRick Macklem error = nfsrv_mtofh(nd, &tfh); 14419ec7b004SRick Macklem if (error) { 14429ec7b004SRick Macklem vput(dp); 14439ec7b004SRick Macklem /* todp is always NULL except NFSv4 */ 14449ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 14459ec7b004SRick Macklem return (error); 14469ec7b004SRick Macklem } 14479ec7b004SRick Macklem nd->nd_cred->cr_uid = nd->nd_saveduid; 14488974bc2fSRick Macklem nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL, 0, p); 14499ec7b004SRick Macklem if (tdp) { 14509ec7b004SRick Macklem tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, 14510cf42b62SRick Macklem p, 1); 14529ec7b004SRick Macklem NFSVOPUNLOCK(tdp, 0, p); 14539ec7b004SRick Macklem } 14549ec7b004SRick Macklem } 14559ec7b004SRick Macklem NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART); 14569ec7b004SRick Macklem nfsvno_setpathbuf(&tond, &tbufp, &hashp); 14579ec7b004SRick Macklem if (!nd->nd_repstat) { 14589ec7b004SRick Macklem error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen); 14599ec7b004SRick Macklem if (error) { 14608974bc2fSRick Macklem if (tdp) 14619ec7b004SRick Macklem vrele(tdp); 14629ec7b004SRick Macklem vput(dp); 14639ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 14649ec7b004SRick Macklem nfsvno_relpathbuf(&tond); 14659ec7b004SRick Macklem return (error); 14669ec7b004SRick Macklem } 14679ec7b004SRick Macklem } 14689ec7b004SRick Macklem if (nd->nd_repstat) { 14699ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 14709ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 14719ec7b004SRick Macklem &fdiraft); 14729ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 14739ec7b004SRick Macklem &tdiraft); 14749ec7b004SRick Macklem } 14758974bc2fSRick Macklem if (tdp) 14769ec7b004SRick Macklem vrele(tdp); 14779ec7b004SRick Macklem vput(dp); 14789ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 14799ec7b004SRick Macklem nfsvno_relpathbuf(&tond); 14809ec7b004SRick Macklem return (0); 14819ec7b004SRick Macklem } 14829ec7b004SRick Macklem 14839ec7b004SRick Macklem /* 14849ec7b004SRick Macklem * Done parsing, now down to business. 14859ec7b004SRick Macklem */ 14869ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 1, exp, p, &fdirp); 14879ec7b004SRick Macklem if (nd->nd_repstat) { 14889ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 14899ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 14909ec7b004SRick Macklem &fdiraft); 14919ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 14929ec7b004SRick Macklem &tdiraft); 14939ec7b004SRick Macklem } 14949ec7b004SRick Macklem if (fdirp) 14959ec7b004SRick Macklem vrele(fdirp); 14968974bc2fSRick Macklem if (tdp) 14979ec7b004SRick Macklem vrele(tdp); 14989ec7b004SRick Macklem nfsvno_relpathbuf(&tond); 14999ec7b004SRick Macklem return (0); 15009ec7b004SRick Macklem } 15019ec7b004SRick Macklem if (vnode_vtype(fromnd.ni_vp) == VDIR) 15029ec7b004SRick Macklem tond.ni_cnd.cn_flags |= WILLBEDIR; 15039ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp); 15049ec7b004SRick Macklem nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat, 15059ec7b004SRick Macklem nd->nd_flag, nd->nd_cred, p); 15069ec7b004SRick Macklem if (fdirp) 15070cf42b62SRick Macklem fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p, 15080cf42b62SRick Macklem 0); 15099ec7b004SRick Macklem if (tdirp) 15100cf42b62SRick Macklem tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p, 15110cf42b62SRick Macklem 0); 15129ec7b004SRick Macklem if (fdirp) 15139ec7b004SRick Macklem vrele(fdirp); 15149ec7b004SRick Macklem if (tdirp) 15159ec7b004SRick Macklem vrele(tdirp); 15169ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 15179ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 15189ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 15199ec7b004SRick Macklem } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 15209ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED); 15219ec7b004SRick Macklem *tl++ = newnfs_false; 15229ec7b004SRick Macklem txdr_hyper(fdirfor.na_filerev, tl); 15239ec7b004SRick Macklem tl += 2; 15249ec7b004SRick Macklem txdr_hyper(fdiraft.na_filerev, tl); 15259ec7b004SRick Macklem tl += 2; 15269ec7b004SRick Macklem *tl++ = newnfs_false; 15279ec7b004SRick Macklem txdr_hyper(tdirfor.na_filerev, tl); 15289ec7b004SRick Macklem tl += 2; 15299ec7b004SRick Macklem txdr_hyper(tdiraft.na_filerev, tl); 15309ec7b004SRick Macklem } 15319ec7b004SRick Macklem return (0); 15329ec7b004SRick Macklem } 15339ec7b004SRick Macklem 15349ec7b004SRick Macklem /* 15359ec7b004SRick Macklem * nfs link service 15369ec7b004SRick Macklem */ 15379ec7b004SRick Macklem APPLESTATIC int 15389ec7b004SRick Macklem nfsrvd_link(struct nfsrv_descript *nd, int isdgram, 15399ec7b004SRick Macklem vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp, 15409ec7b004SRick Macklem struct nfsexstuff *toexp) 15419ec7b004SRick Macklem { 15429ec7b004SRick Macklem struct nameidata named; 15439ec7b004SRick Macklem u_int32_t *tl; 15449ec7b004SRick Macklem int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1; 15459ec7b004SRick Macklem vnode_t dirp = NULL, dp = NULL; 15469ec7b004SRick Macklem struct nfsvattr dirfor, diraft, at; 15479ec7b004SRick Macklem struct nfsexstuff tnes; 15489ec7b004SRick Macklem struct nfsrvfh dfh; 15499ec7b004SRick Macklem char *bufp; 15509ec7b004SRick Macklem u_long *hashp; 15519ec7b004SRick Macklem 15529ec7b004SRick Macklem if (nd->nd_repstat) { 15539ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 15549ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 15559ec7b004SRick Macklem return (0); 15569ec7b004SRick Macklem } 15579ec7b004SRick Macklem NFSVOPUNLOCK(vp, 0, p); 15589ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) { 15599ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) 15609ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 15619ec7b004SRick Macklem else 15629ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 15639ec7b004SRick Macklem if (tovp) 15649ec7b004SRick Macklem vrele(tovp); 15659ec7b004SRick Macklem } else if (vnode_vtype(vp) == VLNK) { 15669ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) 15679ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 15689ec7b004SRick Macklem else 15699ec7b004SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 15709ec7b004SRick Macklem if (tovp) 15719ec7b004SRick Macklem vrele(tovp); 15729ec7b004SRick Macklem } 15739ec7b004SRick Macklem if (!nd->nd_repstat) { 15749ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 15759ec7b004SRick Macklem dp = tovp; 15769ec7b004SRick Macklem tnes = *toexp; 15779ec7b004SRick Macklem } else { 15789ec7b004SRick Macklem error = nfsrv_mtofh(nd, &dfh); 15799ec7b004SRick Macklem if (error) { 15809ec7b004SRick Macklem vrele(vp); 15819ec7b004SRick Macklem /* tovp is always NULL unless NFSv4 */ 15829ec7b004SRick Macklem return (error); 15839ec7b004SRick Macklem } 15848974bc2fSRick Macklem nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0, 158517891d00SRick Macklem p); 15869ec7b004SRick Macklem if (dp) 15879ec7b004SRick Macklem NFSVOPUNLOCK(dp, 0, p); 15889ec7b004SRick Macklem } 15899ec7b004SRick Macklem } 1590f61786cbSRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1591f61786cbSRick Macklem LOCKPARENT | SAVENAME); 15929ec7b004SRick Macklem if (!nd->nd_repstat) { 15939ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 15949ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 15959ec7b004SRick Macklem if (error) { 15969ec7b004SRick Macklem vrele(vp); 15978974bc2fSRick Macklem if (dp) 15989ec7b004SRick Macklem vrele(dp); 15999ec7b004SRick Macklem nfsvno_relpathbuf(&named); 16009ec7b004SRick Macklem return (error); 16019ec7b004SRick Macklem } 16029ec7b004SRick Macklem if (!nd->nd_repstat) { 16039ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes, 16049ec7b004SRick Macklem p, &dirp); 16059ec7b004SRick Macklem } else { 16069ec7b004SRick Macklem if (dp) 16079ec7b004SRick Macklem vrele(dp); 16089ec7b004SRick Macklem nfsvno_relpathbuf(&named); 16099ec7b004SRick Macklem } 16109ec7b004SRick Macklem } 16119ec7b004SRick Macklem if (dirp) { 16129ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 16139ec7b004SRick Macklem vrele(dirp); 16149ec7b004SRick Macklem dirp = NULL; 16159ec7b004SRick Macklem } else { 16169ec7b004SRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, 16170cf42b62SRick Macklem nd->nd_cred, p, 0); 16189ec7b004SRick Macklem } 16199ec7b004SRick Macklem } 16209ec7b004SRick Macklem if (!nd->nd_repstat) 16219ec7b004SRick Macklem nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp); 16229ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 16230cf42b62SRick Macklem getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0); 16249ec7b004SRick Macklem if (dirp) { 16250cf42b62SRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0); 16269ec7b004SRick Macklem vrele(dirp); 16279ec7b004SRick Macklem } 16289ec7b004SRick Macklem vrele(vp); 16299ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 16309ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 16319ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 16329ec7b004SRick Macklem } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 16339ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 16349ec7b004SRick Macklem *tl++ = newnfs_false; 16359ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 16369ec7b004SRick Macklem tl += 2; 16379ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 16389ec7b004SRick Macklem } 16399ec7b004SRick Macklem return (0); 16409ec7b004SRick Macklem } 16419ec7b004SRick Macklem 16429ec7b004SRick Macklem /* 16439ec7b004SRick Macklem * nfs symbolic link service 16449ec7b004SRick Macklem */ 16459ec7b004SRick Macklem APPLESTATIC int 16469ec7b004SRick Macklem nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram, 16479ec7b004SRick Macklem vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 16489ec7b004SRick Macklem struct nfsexstuff *exp) 16499ec7b004SRick Macklem { 16509ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 16519ec7b004SRick Macklem struct nameidata named; 16529ec7b004SRick Macklem int error, dirfor_ret = 1, diraft_ret = 1, pathlen; 16539ec7b004SRick Macklem vnode_t dirp = NULL; 16549ec7b004SRick Macklem char *bufp, *pathcp = NULL; 16559ec7b004SRick Macklem u_long *hashp; 16569ec7b004SRick Macklem 16579ec7b004SRick Macklem if (nd->nd_repstat) { 16589ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 16599ec7b004SRick Macklem return (0); 16609ec7b004SRick Macklem } 16619ec7b004SRick Macklem if (vpp) 16629ec7b004SRick Macklem *vpp = NULL; 16639ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 16649ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 16659ec7b004SRick Macklem LOCKPARENT | SAVESTART); 16669ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 16679ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 16689ec7b004SRick Macklem if (!error && !nd->nd_repstat) 16699ec7b004SRick Macklem error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen); 16709ec7b004SRick Macklem if (error) { 16719ec7b004SRick Macklem vrele(dp); 16729ec7b004SRick Macklem nfsvno_relpathbuf(&named); 16739ec7b004SRick Macklem return (error); 16749ec7b004SRick Macklem } 16759ec7b004SRick Macklem if (!nd->nd_repstat) { 16769ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 16779ec7b004SRick Macklem } else { 16789ec7b004SRick Macklem vrele(dp); 16799ec7b004SRick Macklem nfsvno_relpathbuf(&named); 16809ec7b004SRick Macklem } 16819ec7b004SRick Macklem if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 16829ec7b004SRick Macklem vrele(dirp); 16839ec7b004SRick Macklem dirp = NULL; 16849ec7b004SRick Macklem } 16859ec7b004SRick Macklem 16869ec7b004SRick Macklem /* 16879ec7b004SRick Macklem * And call nfsrvd_symlinksub() to do the common code. It will 16889ec7b004SRick Macklem * return EBADRPC upon a parsing error, 0 otherwise. 16899ec7b004SRick Macklem */ 16909ec7b004SRick Macklem if (!nd->nd_repstat) { 16919ec7b004SRick Macklem if (dirp != NULL) 16929ec7b004SRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 16930cf42b62SRick Macklem p, 0); 16949ec7b004SRick Macklem nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 16959ec7b004SRick Macklem &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp, 16969ec7b004SRick Macklem pathcp, pathlen); 16979ec7b004SRick Macklem } else if (dirp != NULL) { 16980cf42b62SRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0); 16999ec7b004SRick Macklem vrele(dirp); 17009ec7b004SRick Macklem } 17019ec7b004SRick Macklem if (pathcp) 17029ec7b004SRick Macklem FREE(pathcp, M_TEMP); 17039ec7b004SRick Macklem 17049ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 17059ec7b004SRick Macklem if (!nd->nd_repstat) { 17069ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 17079ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 17089ec7b004SRick Macklem } 17099ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 17109ec7b004SRick Macklem } 17119ec7b004SRick Macklem return (0); 17129ec7b004SRick Macklem } 17139ec7b004SRick Macklem 17149ec7b004SRick Macklem /* 17159ec7b004SRick Macklem * Common code for creating a symbolic link. 17169ec7b004SRick Macklem */ 17179ec7b004SRick Macklem static void 17189ec7b004SRick Macklem nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 17199ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 17209ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 17219ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, 17229ec7b004SRick Macklem NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 17239ec7b004SRick Macklem int pathlen) 17249ec7b004SRick Macklem { 17259ec7b004SRick Macklem u_int32_t *tl; 17269ec7b004SRick Macklem 17279ec7b004SRick Macklem nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen, 17289ec7b004SRick Macklem !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp); 17299ec7b004SRick Macklem if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) { 17309ec7b004SRick Macklem nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp); 17319ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 17329ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p); 17339ec7b004SRick Macklem if (!nd->nd_repstat) 17349ec7b004SRick Macklem nd->nd_repstat = nfsvno_getattr(ndp->ni_vp, 17350cf42b62SRick Macklem nvap, nd->nd_cred, p, 1); 17369ec7b004SRick Macklem } 173781f78d99SRick Macklem if (vpp != NULL && nd->nd_repstat == 0) { 173881f78d99SRick Macklem VOP_UNLOCK(ndp->ni_vp, 0); 17399ec7b004SRick Macklem *vpp = ndp->ni_vp; 174081f78d99SRick Macklem } else 17419ec7b004SRick Macklem vput(ndp->ni_vp); 17429ec7b004SRick Macklem } 17439ec7b004SRick Macklem if (dirp) { 17440cf42b62SRick Macklem *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0); 17459ec7b004SRick Macklem vrele(dirp); 17469ec7b004SRick Macklem } 17479ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 17489ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 17499ec7b004SRick Macklem *tl++ = newnfs_false; 17509ec7b004SRick Macklem txdr_hyper(dirforp->na_filerev, tl); 17519ec7b004SRick Macklem tl += 2; 17529ec7b004SRick Macklem txdr_hyper(diraftp->na_filerev, tl); 17539ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, attrbitp); 17549ec7b004SRick Macklem } 17559ec7b004SRick Macklem } 17569ec7b004SRick Macklem 17579ec7b004SRick Macklem /* 17589ec7b004SRick Macklem * nfs mkdir service 17599ec7b004SRick Macklem */ 17609ec7b004SRick Macklem APPLESTATIC int 17619ec7b004SRick Macklem nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram, 17629ec7b004SRick Macklem vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 17639ec7b004SRick Macklem struct nfsexstuff *exp) 17649ec7b004SRick Macklem { 17659ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 17669ec7b004SRick Macklem struct nameidata named; 17679ec7b004SRick Macklem u_int32_t *tl; 17689ec7b004SRick Macklem int error, dirfor_ret = 1, diraft_ret = 1; 17699ec7b004SRick Macklem vnode_t dirp = NULL; 17709ec7b004SRick Macklem char *bufp; 17719ec7b004SRick Macklem u_long *hashp; 17729ec7b004SRick Macklem 17739ec7b004SRick Macklem if (nd->nd_repstat) { 17749ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 17759ec7b004SRick Macklem return (0); 17769ec7b004SRick Macklem } 1777f61786cbSRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1778f61786cbSRick Macklem LOCKPARENT | SAVENAME); 17799ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 17809ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 17819ec7b004SRick Macklem if (error) { 17829ec7b004SRick Macklem vrele(dp); 17839ec7b004SRick Macklem nfsvno_relpathbuf(&named); 17849ec7b004SRick Macklem return (error); 17859ec7b004SRick Macklem } 17869ec7b004SRick Macklem if (!nd->nd_repstat) { 17879ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 17889ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 17899ec7b004SRick Macklem error = nfsrv_sattr(nd, &nva, NULL, NULL, p); 17909ec7b004SRick Macklem if (error) { 17919ec7b004SRick Macklem vrele(dp); 17929ec7b004SRick Macklem nfsvno_relpathbuf(&named); 17939ec7b004SRick Macklem return (error); 17949ec7b004SRick Macklem } 17959ec7b004SRick Macklem } else { 17969ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 17979ec7b004SRick Macklem nva.na_mode = nfstov_mode(*tl++); 17989ec7b004SRick Macklem } 17999ec7b004SRick Macklem } 18009ec7b004SRick Macklem if (!nd->nd_repstat) { 18019ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 18029ec7b004SRick Macklem } else { 18039ec7b004SRick Macklem vrele(dp); 18049ec7b004SRick Macklem nfsvno_relpathbuf(&named); 18059ec7b004SRick Macklem } 18069ec7b004SRick Macklem if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 18079ec7b004SRick Macklem vrele(dirp); 18089ec7b004SRick Macklem dirp = NULL; 18099ec7b004SRick Macklem } 18109ec7b004SRick Macklem if (nd->nd_repstat) { 18119ec7b004SRick Macklem if (dirp != NULL) { 18129ec7b004SRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 18130cf42b62SRick Macklem p, 0); 18149ec7b004SRick Macklem vrele(dirp); 18159ec7b004SRick Macklem } 18169ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 18179ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 18189ec7b004SRick Macklem &diraft); 18199ec7b004SRick Macklem return (0); 18209ec7b004SRick Macklem } 18219ec7b004SRick Macklem if (dirp != NULL) 18220cf42b62SRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0); 18239ec7b004SRick Macklem 18249ec7b004SRick Macklem /* 18259ec7b004SRick Macklem * Call nfsrvd_mkdirsub() for the code common to V4 as well. 18269ec7b004SRick Macklem */ 18279ec7b004SRick Macklem nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft, 18289ec7b004SRick Macklem &diraft_ret, NULL, NULL, p, exp); 18299ec7b004SRick Macklem 18309ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 18319ec7b004SRick Macklem if (!nd->nd_repstat) { 18329ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 18339ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 18349ec7b004SRick Macklem } 18359ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 18369ec7b004SRick Macklem } else if (!nd->nd_repstat) { 18379ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 18389ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 18399ec7b004SRick Macklem } 18409ec7b004SRick Macklem return (0); 18419ec7b004SRick Macklem nfsmout: 18429ec7b004SRick Macklem vrele(dp); 18439ec7b004SRick Macklem nfsvno_relpathbuf(&named); 18449ec7b004SRick Macklem return (error); 18459ec7b004SRick Macklem } 18469ec7b004SRick Macklem 18479ec7b004SRick Macklem /* 18489ec7b004SRick Macklem * Code common to mkdir for V2,3 and 4. 18499ec7b004SRick Macklem */ 18509ec7b004SRick Macklem static void 18519ec7b004SRick Macklem nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 18529ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 18539ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 18549ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 18559ec7b004SRick Macklem NFSPROC_T *p, struct nfsexstuff *exp) 18569ec7b004SRick Macklem { 18579ec7b004SRick Macklem vnode_t vp; 18589ec7b004SRick Macklem u_int32_t *tl; 18599ec7b004SRick Macklem 18609ec7b004SRick Macklem NFSVNO_SETATTRVAL(nvap, type, VDIR); 18619ec7b004SRick Macklem nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid, 18629ec7b004SRick Macklem nd->nd_cred, p, exp); 18639ec7b004SRick Macklem if (!nd->nd_repstat) { 18649ec7b004SRick Macklem vp = ndp->ni_vp; 18659ec7b004SRick Macklem nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp); 18669ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 18679ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 18689ec7b004SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred, 18690cf42b62SRick Macklem p, 1); 18709ec7b004SRick Macklem if (vpp && !nd->nd_repstat) { 18719ec7b004SRick Macklem NFSVOPUNLOCK(vp, 0, p); 18729ec7b004SRick Macklem *vpp = vp; 18739ec7b004SRick Macklem } else { 18749ec7b004SRick Macklem vput(vp); 18759ec7b004SRick Macklem } 18769ec7b004SRick Macklem } 18779ec7b004SRick Macklem if (dirp) { 18780cf42b62SRick Macklem *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0); 18799ec7b004SRick Macklem vrele(dirp); 18809ec7b004SRick Macklem } 18819ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 18829ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 18839ec7b004SRick Macklem *tl++ = newnfs_false; 18849ec7b004SRick Macklem txdr_hyper(dirforp->na_filerev, tl); 18859ec7b004SRick Macklem tl += 2; 18869ec7b004SRick Macklem txdr_hyper(diraftp->na_filerev, tl); 18879ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, attrbitp); 18889ec7b004SRick Macklem } 18899ec7b004SRick Macklem } 18909ec7b004SRick Macklem 18919ec7b004SRick Macklem /* 18929ec7b004SRick Macklem * nfs commit service 18939ec7b004SRick Macklem */ 18949ec7b004SRick Macklem APPLESTATIC int 18959ec7b004SRick Macklem nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram, 18969ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 18979ec7b004SRick Macklem { 18989ec7b004SRick Macklem struct nfsvattr bfor, aft; 18999ec7b004SRick Macklem u_int32_t *tl; 19009ec7b004SRick Macklem int error = 0, for_ret = 1, aft_ret = 1, cnt; 19019ec7b004SRick Macklem u_int64_t off; 19029ec7b004SRick Macklem 19039ec7b004SRick Macklem if (nd->nd_repstat) { 19049ec7b004SRick Macklem nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 19059ec7b004SRick Macklem return (0); 19069ec7b004SRick Macklem } 19079ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 19089ec7b004SRick Macklem /* 19099ec7b004SRick Macklem * XXX At this time VOP_FSYNC() does not accept offset and byte 19109ec7b004SRick Macklem * count parameters, so these arguments are useless (someday maybe). 19119ec7b004SRick Macklem */ 19129ec7b004SRick Macklem off = fxdr_hyper(tl); 19139ec7b004SRick Macklem tl += 2; 19149ec7b004SRick Macklem cnt = fxdr_unsigned(int, *tl); 19159ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 19160cf42b62SRick Macklem for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1); 19179ec7b004SRick Macklem nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p); 19189ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 19190cf42b62SRick Macklem aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1); 19209ec7b004SRick Macklem nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 19219ec7b004SRick Macklem } 19229ec7b004SRick Macklem vput(vp); 19239ec7b004SRick Macklem if (!nd->nd_repstat) { 19249ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 19259ec7b004SRick Macklem *tl++ = txdr_unsigned(nfsboottime.tv_sec); 19269ec7b004SRick Macklem *tl = txdr_unsigned(nfsboottime.tv_usec); 19279ec7b004SRick Macklem } 19289ec7b004SRick Macklem return (0); 19299ec7b004SRick Macklem nfsmout: 19309ec7b004SRick Macklem vput(vp); 19319ec7b004SRick Macklem return (error); 19329ec7b004SRick Macklem } 19339ec7b004SRick Macklem 19349ec7b004SRick Macklem /* 19359ec7b004SRick Macklem * nfs statfs service 19369ec7b004SRick Macklem */ 19379ec7b004SRick Macklem APPLESTATIC int 19389ec7b004SRick Macklem nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram, 19399ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 19409ec7b004SRick Macklem { 19419ec7b004SRick Macklem struct statfs *sf; 19429ec7b004SRick Macklem u_int32_t *tl; 19439ec7b004SRick Macklem int getret = 1; 19449ec7b004SRick Macklem struct nfsvattr at; 19459ec7b004SRick Macklem struct statfs sfs; 19469ec7b004SRick Macklem u_quad_t tval; 19479ec7b004SRick Macklem 19489ec7b004SRick Macklem if (nd->nd_repstat) { 19499ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 19509ec7b004SRick Macklem return (0); 19519ec7b004SRick Macklem } 19529ec7b004SRick Macklem sf = &sfs; 1953dfd233edSAttilio Rao nd->nd_repstat = nfsvno_statfs(vp, sf); 19540cf42b62SRick Macklem getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 19559ec7b004SRick Macklem vput(vp); 19569ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 19579ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 19589ec7b004SRick Macklem if (nd->nd_repstat) 19599ec7b004SRick Macklem return (0); 19609ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 19619ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS); 19629ec7b004SRick Macklem *tl++ = txdr_unsigned(NFS_V2MAXDATA); 19639ec7b004SRick Macklem *tl++ = txdr_unsigned(sf->f_bsize); 19649ec7b004SRick Macklem *tl++ = txdr_unsigned(sf->f_blocks); 19659ec7b004SRick Macklem *tl++ = txdr_unsigned(sf->f_bfree); 19669ec7b004SRick Macklem *tl = txdr_unsigned(sf->f_bavail); 19679ec7b004SRick Macklem } else { 19689ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS); 19699ec7b004SRick Macklem tval = (u_quad_t)sf->f_blocks; 19709ec7b004SRick Macklem tval *= (u_quad_t)sf->f_bsize; 19719ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 19729ec7b004SRick Macklem tval = (u_quad_t)sf->f_bfree; 19739ec7b004SRick Macklem tval *= (u_quad_t)sf->f_bsize; 19749ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 19759ec7b004SRick Macklem tval = (u_quad_t)sf->f_bavail; 19769ec7b004SRick Macklem tval *= (u_quad_t)sf->f_bsize; 19779ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 19789ec7b004SRick Macklem tval = (u_quad_t)sf->f_files; 19799ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 19809ec7b004SRick Macklem tval = (u_quad_t)sf->f_ffree; 19819ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 19829ec7b004SRick Macklem tval = (u_quad_t)sf->f_ffree; 19839ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 19849ec7b004SRick Macklem *tl = 0; 19859ec7b004SRick Macklem } 19869ec7b004SRick Macklem return (0); 19879ec7b004SRick Macklem } 19889ec7b004SRick Macklem 19899ec7b004SRick Macklem /* 19909ec7b004SRick Macklem * nfs fsinfo service 19919ec7b004SRick Macklem */ 19929ec7b004SRick Macklem APPLESTATIC int 19939ec7b004SRick Macklem nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram, 19949ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 19959ec7b004SRick Macklem { 19969ec7b004SRick Macklem u_int32_t *tl; 19979ec7b004SRick Macklem struct nfsfsinfo fs; 19989ec7b004SRick Macklem int getret = 1; 19999ec7b004SRick Macklem struct nfsvattr at; 20009ec7b004SRick Macklem 20019ec7b004SRick Macklem if (nd->nd_repstat) { 20029ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 20039ec7b004SRick Macklem return (0); 20049ec7b004SRick Macklem } 20050cf42b62SRick Macklem getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 20069ec7b004SRick Macklem nfsvno_getfs(&fs, isdgram); 20079ec7b004SRick Macklem vput(vp); 20089ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 20099ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO); 20109ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_rtmax); 20119ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_rtpref); 20129ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_rtmult); 20139ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_wtmax); 20149ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_wtpref); 20159ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_wtmult); 20169ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_dtpref); 20179ec7b004SRick Macklem txdr_hyper(fs.fs_maxfilesize, tl); 20189ec7b004SRick Macklem tl += 2; 20199ec7b004SRick Macklem txdr_nfsv3time(&fs.fs_timedelta, tl); 20209ec7b004SRick Macklem tl += 2; 20219ec7b004SRick Macklem *tl = txdr_unsigned(fs.fs_properties); 20229ec7b004SRick Macklem return (0); 20239ec7b004SRick Macklem } 20249ec7b004SRick Macklem 20259ec7b004SRick Macklem /* 20269ec7b004SRick Macklem * nfs pathconf service 20279ec7b004SRick Macklem */ 20289ec7b004SRick Macklem APPLESTATIC int 20299ec7b004SRick Macklem nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram, 20309ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 20319ec7b004SRick Macklem { 20329ec7b004SRick Macklem struct nfsv3_pathconf *pc; 20339ec7b004SRick Macklem int getret = 1; 20349ec7b004SRick Macklem register_t linkmax, namemax, chownres, notrunc; 20359ec7b004SRick Macklem struct nfsvattr at; 20369ec7b004SRick Macklem 20379ec7b004SRick Macklem if (nd->nd_repstat) { 20389ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 20399ec7b004SRick Macklem return (0); 20409ec7b004SRick Macklem } 20419ec7b004SRick Macklem nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax, 20429ec7b004SRick Macklem nd->nd_cred, p); 20439ec7b004SRick Macklem if (!nd->nd_repstat) 20449ec7b004SRick Macklem nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax, 20459ec7b004SRick Macklem nd->nd_cred, p); 20469ec7b004SRick Macklem if (!nd->nd_repstat) 20479ec7b004SRick Macklem nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED, 20489ec7b004SRick Macklem &chownres, nd->nd_cred, p); 20499ec7b004SRick Macklem if (!nd->nd_repstat) 20509ec7b004SRick Macklem nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc, 20519ec7b004SRick Macklem nd->nd_cred, p); 20520cf42b62SRick Macklem getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 20539ec7b004SRick Macklem vput(vp); 20549ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 20559ec7b004SRick Macklem if (!nd->nd_repstat) { 20569ec7b004SRick Macklem NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); 20579ec7b004SRick Macklem pc->pc_linkmax = txdr_unsigned(linkmax); 20589ec7b004SRick Macklem pc->pc_namemax = txdr_unsigned(namemax); 20599ec7b004SRick Macklem pc->pc_notrunc = txdr_unsigned(notrunc); 20609ec7b004SRick Macklem pc->pc_chownrestricted = txdr_unsigned(chownres); 20619ec7b004SRick Macklem 20629ec7b004SRick Macklem /* 20639ec7b004SRick Macklem * These should probably be supported by VOP_PATHCONF(), but 20649ec7b004SRick Macklem * until msdosfs is exportable (why would you want to?), the 20659ec7b004SRick Macklem * Unix defaults should be ok. 20669ec7b004SRick Macklem */ 20679ec7b004SRick Macklem pc->pc_caseinsensitive = newnfs_false; 20689ec7b004SRick Macklem pc->pc_casepreserving = newnfs_true; 20699ec7b004SRick Macklem } 20709ec7b004SRick Macklem return (0); 20719ec7b004SRick Macklem } 20729ec7b004SRick Macklem 20739ec7b004SRick Macklem /* 20749ec7b004SRick Macklem * nfsv4 lock service 20759ec7b004SRick Macklem */ 20769ec7b004SRick Macklem APPLESTATIC int 20779ec7b004SRick Macklem nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram, 20789ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 20799ec7b004SRick Macklem { 20809ec7b004SRick Macklem u_int32_t *tl; 20819ec7b004SRick Macklem int i; 20829ec7b004SRick Macklem struct nfsstate *stp = NULL; 20839ec7b004SRick Macklem struct nfslock *lop; 20849ec7b004SRick Macklem struct nfslockconflict cf; 20859ec7b004SRick Macklem int error = 0; 20869ec7b004SRick Macklem u_short flags = NFSLCK_LOCK, lflags; 20879ec7b004SRick Macklem u_int64_t offset, len; 20889ec7b004SRick Macklem nfsv4stateid_t stateid; 20899ec7b004SRick Macklem nfsquad_t clientid; 20909ec7b004SRick Macklem 20919ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 20929ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 20939ec7b004SRick Macklem switch (i) { 20949ec7b004SRick Macklem case NFSV4LOCKT_READW: 20959ec7b004SRick Macklem flags |= NFSLCK_BLOCKING; 20969ec7b004SRick Macklem case NFSV4LOCKT_READ: 20979ec7b004SRick Macklem lflags = NFSLCK_READ; 20989ec7b004SRick Macklem break; 20999ec7b004SRick Macklem case NFSV4LOCKT_WRITEW: 21009ec7b004SRick Macklem flags |= NFSLCK_BLOCKING; 21019ec7b004SRick Macklem case NFSV4LOCKT_WRITE: 21029ec7b004SRick Macklem lflags = NFSLCK_WRITE; 21039ec7b004SRick Macklem break; 21049ec7b004SRick Macklem default: 21059ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 21069ec7b004SRick Macklem goto nfsmout; 21079ec7b004SRick Macklem }; 21089ec7b004SRick Macklem if (*tl++ == newnfs_true) 21099ec7b004SRick Macklem flags |= NFSLCK_RECLAIM; 21109ec7b004SRick Macklem offset = fxdr_hyper(tl); 21119ec7b004SRick Macklem tl += 2; 21129ec7b004SRick Macklem len = fxdr_hyper(tl); 21139ec7b004SRick Macklem tl += 2; 21149ec7b004SRick Macklem if (*tl == newnfs_true) 21159ec7b004SRick Macklem flags |= NFSLCK_OPENTOLOCK; 21169ec7b004SRick Macklem if (flags & NFSLCK_OPENTOLOCK) { 21179ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID); 21189ec7b004SRick Macklem i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED))); 21192a45247cSRick Macklem if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 21202a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 21212a45247cSRick Macklem goto nfsmout; 21222a45247cSRick Macklem } 21239ec7b004SRick Macklem MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 21249ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 21259ec7b004SRick Macklem stp->ls_ownerlen = i; 21269ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 21279ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(int, *tl++); 21289ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 21299ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 21309ec7b004SRick Macklem NFSX_STATEIDOTHER); 21319ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 21329ec7b004SRick Macklem stp->ls_opentolockseq = fxdr_unsigned(int, *tl++); 21339ec7b004SRick Macklem clientid.lval[0] = *tl++; 21349ec7b004SRick Macklem clientid.lval[1] = *tl++; 21359ec7b004SRick Macklem if (nd->nd_flag & ND_IMPLIEDCLID) { 21369ec7b004SRick Macklem if (nd->nd_clientid.qval != clientid.qval) 21379ec7b004SRick Macklem printf("EEK! multiple clids\n"); 21389ec7b004SRick Macklem } else { 21399ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 21409ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 21419ec7b004SRick Macklem } 21429ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 21439ec7b004SRick Macklem if (error) 21449ec7b004SRick Macklem goto nfsmout; 21459ec7b004SRick Macklem } else { 21469ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 21479ec7b004SRick Macklem MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate), 21489ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 21499ec7b004SRick Macklem stp->ls_ownerlen = 0; 21509ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 21519ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 21529ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 21539ec7b004SRick Macklem NFSX_STATEIDOTHER); 21549ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 21559ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(int, *tl); 21569ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 21579ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 21589ec7b004SRick Macklem if (nd->nd_flag & ND_IMPLIEDCLID) { 21599ec7b004SRick Macklem if (nd->nd_clientid.qval != clientid.qval) 21609ec7b004SRick Macklem printf("EEK! multiple clids\n"); 21619ec7b004SRick Macklem } else { 21629ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 21639ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 21649ec7b004SRick Macklem } 21659ec7b004SRick Macklem } 21669ec7b004SRick Macklem MALLOC(lop, struct nfslock *, sizeof (struct nfslock), 21679ec7b004SRick Macklem M_NFSDLOCK, M_WAITOK); 21689ec7b004SRick Macklem lop->lo_first = offset; 21699ec7b004SRick Macklem if (len == NFS64BITSSET) { 21709ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 21719ec7b004SRick Macklem } else { 21729ec7b004SRick Macklem lop->lo_end = offset + len; 21739ec7b004SRick Macklem if (lop->lo_end <= lop->lo_first) 21749ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 21759ec7b004SRick Macklem } 21769ec7b004SRick Macklem lop->lo_flags = lflags; 21779ec7b004SRick Macklem stp->ls_flags = flags; 21789ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 21799ec7b004SRick Macklem 21809ec7b004SRick Macklem /* 21819ec7b004SRick Macklem * Do basic access checking. 21829ec7b004SRick Macklem */ 21839ec7b004SRick Macklem if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 21849ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 21859ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 21869ec7b004SRick Macklem else 21879ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 21889ec7b004SRick Macklem } 21899ec7b004SRick Macklem if (!nd->nd_repstat) { 21909ec7b004SRick Macklem if (lflags & NFSLCK_WRITE) { 21918da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 21929ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 21938da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 21949ec7b004SRick Macklem } else { 21958da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, 21969ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 21978da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 21989ec7b004SRick Macklem if (nd->nd_repstat) 21998da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 22009ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 22018da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 22029ec7b004SRick Macklem } 22039ec7b004SRick Macklem } 22049ec7b004SRick Macklem 22059ec7b004SRick Macklem /* 22069ec7b004SRick Macklem * We call nfsrv_lockctrl() even if nd_repstat set, so that the 22079ec7b004SRick Macklem * seqid# gets updated. nfsrv_lockctrl() will return the value 22089ec7b004SRick Macklem * of nd_repstat, if it gets that far. 22099ec7b004SRick Macklem */ 22109ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 22119ec7b004SRick Macklem &stateid, exp, nd, p); 22129ec7b004SRick Macklem if (lop) 22139ec7b004SRick Macklem FREE((caddr_t)lop, M_NFSDLOCK); 22149ec7b004SRick Macklem if (stp) 22159ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 22169ec7b004SRick Macklem if (!nd->nd_repstat) { 22179ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 22189ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 22199ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 22209ec7b004SRick Macklem } else if (nd->nd_repstat == NFSERR_DENIED) { 22219ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 22229ec7b004SRick Macklem txdr_hyper(cf.cl_first, tl); 22239ec7b004SRick Macklem tl += 2; 22249ec7b004SRick Macklem if (cf.cl_end == NFS64BITSSET) 22259ec7b004SRick Macklem len = NFS64BITSSET; 22269ec7b004SRick Macklem else 22279ec7b004SRick Macklem len = cf.cl_end - cf.cl_first; 22289ec7b004SRick Macklem txdr_hyper(len, tl); 22299ec7b004SRick Macklem tl += 2; 22309ec7b004SRick Macklem if (cf.cl_flags == NFSLCK_WRITE) 22319ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 22329ec7b004SRick Macklem else 22339ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 22349ec7b004SRick Macklem *tl++ = stateid.other[0]; 22359ec7b004SRick Macklem *tl = stateid.other[1]; 22369ec7b004SRick Macklem (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 22379ec7b004SRick Macklem } 22389ec7b004SRick Macklem vput(vp); 22399ec7b004SRick Macklem return (0); 22409ec7b004SRick Macklem nfsmout: 22419ec7b004SRick Macklem vput(vp); 22429ec7b004SRick Macklem if (stp) 22439ec7b004SRick Macklem free((caddr_t)stp, M_NFSDSTATE); 22449ec7b004SRick Macklem return (error); 22459ec7b004SRick Macklem } 22469ec7b004SRick Macklem 22479ec7b004SRick Macklem /* 22489ec7b004SRick Macklem * nfsv4 lock test service 22499ec7b004SRick Macklem */ 22509ec7b004SRick Macklem APPLESTATIC int 22519ec7b004SRick Macklem nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram, 22529ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 22539ec7b004SRick Macklem { 22549ec7b004SRick Macklem u_int32_t *tl; 22559ec7b004SRick Macklem int i; 22569ec7b004SRick Macklem struct nfsstate *stp = NULL; 22579ec7b004SRick Macklem struct nfslock lo, *lop = &lo; 22589ec7b004SRick Macklem struct nfslockconflict cf; 22599ec7b004SRick Macklem int error = 0; 22609ec7b004SRick Macklem nfsv4stateid_t stateid; 22619ec7b004SRick Macklem nfsquad_t clientid; 22629ec7b004SRick Macklem u_int64_t len; 22639ec7b004SRick Macklem 22649ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 22659ec7b004SRick Macklem i = fxdr_unsigned(int, *(tl + 7)); 22662a45247cSRick Macklem if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 22672a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 22682a45247cSRick Macklem goto nfsmout; 22692a45247cSRick Macklem } 22709ec7b004SRick Macklem MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 22719ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 22729ec7b004SRick Macklem stp->ls_ownerlen = i; 22739ec7b004SRick Macklem stp->ls_op = NULL; 22749ec7b004SRick Macklem stp->ls_flags = NFSLCK_TEST; 22759ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 22769ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 22779ec7b004SRick Macklem switch (i) { 22789ec7b004SRick Macklem case NFSV4LOCKT_READW: 22799ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 22809ec7b004SRick Macklem case NFSV4LOCKT_READ: 22819ec7b004SRick Macklem lo.lo_flags = NFSLCK_READ; 22829ec7b004SRick Macklem break; 22839ec7b004SRick Macklem case NFSV4LOCKT_WRITEW: 22849ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 22859ec7b004SRick Macklem case NFSV4LOCKT_WRITE: 22869ec7b004SRick Macklem lo.lo_flags = NFSLCK_WRITE; 22879ec7b004SRick Macklem break; 22889ec7b004SRick Macklem default: 22899ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 22909ec7b004SRick Macklem goto nfsmout; 22919ec7b004SRick Macklem }; 22929ec7b004SRick Macklem lo.lo_first = fxdr_hyper(tl); 22939ec7b004SRick Macklem tl += 2; 22949ec7b004SRick Macklem len = fxdr_hyper(tl); 22959ec7b004SRick Macklem if (len == NFS64BITSSET) { 22969ec7b004SRick Macklem lo.lo_end = NFS64BITSSET; 22979ec7b004SRick Macklem } else { 22989ec7b004SRick Macklem lo.lo_end = lo.lo_first + len; 22999ec7b004SRick Macklem if (lo.lo_end <= lo.lo_first) 23009ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 23019ec7b004SRick Macklem } 23029ec7b004SRick Macklem tl += 2; 23039ec7b004SRick Macklem clientid.lval[0] = *tl++; 23049ec7b004SRick Macklem clientid.lval[1] = *tl; 23059ec7b004SRick Macklem if (nd->nd_flag & ND_IMPLIEDCLID) { 23069ec7b004SRick Macklem if (nd->nd_clientid.qval != clientid.qval) 23079ec7b004SRick Macklem printf("EEK! multiple clids\n"); 23089ec7b004SRick Macklem } else { 23099ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 23109ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 23119ec7b004SRick Macklem } 23129ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 23139ec7b004SRick Macklem if (error) 23149ec7b004SRick Macklem goto nfsmout; 23159ec7b004SRick Macklem if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 23169ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 23179ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 23189ec7b004SRick Macklem else 23199ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 23209ec7b004SRick Macklem } 23219ec7b004SRick Macklem if (!nd->nd_repstat) 23229ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 23239ec7b004SRick Macklem &stateid, exp, nd, p); 23249ec7b004SRick Macklem if (stp) 23259ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 23269ec7b004SRick Macklem if (nd->nd_repstat) { 23279ec7b004SRick Macklem if (nd->nd_repstat == NFSERR_DENIED) { 23289ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 23299ec7b004SRick Macklem txdr_hyper(cf.cl_first, tl); 23309ec7b004SRick Macklem tl += 2; 23319ec7b004SRick Macklem if (cf.cl_end == NFS64BITSSET) 23329ec7b004SRick Macklem len = NFS64BITSSET; 23339ec7b004SRick Macklem else 23349ec7b004SRick Macklem len = cf.cl_end - cf.cl_first; 23359ec7b004SRick Macklem txdr_hyper(len, tl); 23369ec7b004SRick Macklem tl += 2; 23379ec7b004SRick Macklem if (cf.cl_flags == NFSLCK_WRITE) 23389ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 23399ec7b004SRick Macklem else 23409ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 23419ec7b004SRick Macklem *tl++ = stp->ls_stateid.other[0]; 23429ec7b004SRick Macklem *tl = stp->ls_stateid.other[1]; 23439ec7b004SRick Macklem (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 23449ec7b004SRick Macklem } 23459ec7b004SRick Macklem } 23469ec7b004SRick Macklem vput(vp); 23479ec7b004SRick Macklem return (0); 23489ec7b004SRick Macklem nfsmout: 23499ec7b004SRick Macklem vput(vp); 23509ec7b004SRick Macklem if (stp) 23519ec7b004SRick Macklem free((caddr_t)stp, M_NFSDSTATE); 23529ec7b004SRick Macklem return (error); 23539ec7b004SRick Macklem } 23549ec7b004SRick Macklem 23559ec7b004SRick Macklem /* 23569ec7b004SRick Macklem * nfsv4 unlock service 23579ec7b004SRick Macklem */ 23589ec7b004SRick Macklem APPLESTATIC int 23599ec7b004SRick Macklem nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram, 23609ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 23619ec7b004SRick Macklem { 23629ec7b004SRick Macklem u_int32_t *tl; 23639ec7b004SRick Macklem int i; 23649ec7b004SRick Macklem struct nfsstate *stp; 23659ec7b004SRick Macklem struct nfslock *lop; 23669ec7b004SRick Macklem int error = 0; 23679ec7b004SRick Macklem nfsv4stateid_t stateid; 23689ec7b004SRick Macklem nfsquad_t clientid; 23699ec7b004SRick Macklem u_int64_t len; 23709ec7b004SRick Macklem 23719ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID); 23729ec7b004SRick Macklem MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate), 23739ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 23749ec7b004SRick Macklem MALLOC(lop, struct nfslock *, sizeof (struct nfslock), 23759ec7b004SRick Macklem M_NFSDLOCK, M_WAITOK); 23769ec7b004SRick Macklem stp->ls_flags = NFSLCK_UNLOCK; 23779ec7b004SRick Macklem lop->lo_flags = NFSLCK_UNLOCK; 23789ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 23799ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 23809ec7b004SRick Macklem switch (i) { 23819ec7b004SRick Macklem case NFSV4LOCKT_READW: 23829ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 23839ec7b004SRick Macklem case NFSV4LOCKT_READ: 23849ec7b004SRick Macklem break; 23859ec7b004SRick Macklem case NFSV4LOCKT_WRITEW: 23869ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 23879ec7b004SRick Macklem case NFSV4LOCKT_WRITE: 23889ec7b004SRick Macklem break; 23899ec7b004SRick Macklem default: 23909ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 23912a45247cSRick Macklem free(stp, M_NFSDSTATE); 23922a45247cSRick Macklem free(lop, M_NFSDLOCK); 23939ec7b004SRick Macklem goto nfsmout; 23949ec7b004SRick Macklem }; 23959ec7b004SRick Macklem stp->ls_ownerlen = 0; 23969ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 23979ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(int, *tl++); 23989ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 23999ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 24009ec7b004SRick Macklem NFSX_STATEIDOTHER); 24019ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 24029ec7b004SRick Macklem lop->lo_first = fxdr_hyper(tl); 24039ec7b004SRick Macklem tl += 2; 24049ec7b004SRick Macklem len = fxdr_hyper(tl); 24059ec7b004SRick Macklem if (len == NFS64BITSSET) { 24069ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 24079ec7b004SRick Macklem } else { 24089ec7b004SRick Macklem lop->lo_end = lop->lo_first + len; 24099ec7b004SRick Macklem if (lop->lo_end <= lop->lo_first) 24109ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 24119ec7b004SRick Macklem } 24129ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 24139ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 24149ec7b004SRick Macklem if (nd->nd_flag & ND_IMPLIEDCLID) { 24159ec7b004SRick Macklem if (nd->nd_clientid.qval != clientid.qval) 24169ec7b004SRick Macklem printf("EEK! multiple clids\n"); 24179ec7b004SRick Macklem } else { 24189ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 24199ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 24209ec7b004SRick Macklem } 24219ec7b004SRick Macklem if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 24229ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 24239ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 24249ec7b004SRick Macklem else 24259ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 24269ec7b004SRick Macklem } 24279ec7b004SRick Macklem /* 24289ec7b004SRick Macklem * Call nfsrv_lockctrl() even if nd_repstat is set, so that the 24299ec7b004SRick Macklem * seqid# gets incremented. nfsrv_lockctrl() will return the 24309ec7b004SRick Macklem * value of nd_repstat, if it gets that far. 24319ec7b004SRick Macklem */ 24329ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 24339ec7b004SRick Macklem &stateid, exp, nd, p); 24349ec7b004SRick Macklem if (stp) 24359ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 24369ec7b004SRick Macklem if (lop) 24379ec7b004SRick Macklem free((caddr_t)lop, M_NFSDLOCK); 24389ec7b004SRick Macklem if (!nd->nd_repstat) { 24399ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 24409ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 24419ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 24429ec7b004SRick Macklem } 24439ec7b004SRick Macklem nfsmout: 24449ec7b004SRick Macklem vput(vp); 24459ec7b004SRick Macklem return (error); 24469ec7b004SRick Macklem } 24479ec7b004SRick Macklem 24489ec7b004SRick Macklem /* 24499ec7b004SRick Macklem * nfsv4 open service 24509ec7b004SRick Macklem */ 24519ec7b004SRick Macklem APPLESTATIC int 24529ec7b004SRick Macklem nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram, 24539ec7b004SRick Macklem vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p, 24549ec7b004SRick Macklem struct nfsexstuff *exp) 24559ec7b004SRick Macklem { 24569ec7b004SRick Macklem u_int32_t *tl; 24579ec7b004SRick Macklem int i; 24589ec7b004SRick Macklem struct nfsstate *stp = NULL; 24599ec7b004SRick Macklem int error = 0, create, claim, exclusive_flag = 0; 24609ec7b004SRick Macklem u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask; 24619ec7b004SRick Macklem int how = NFSCREATE_UNCHECKED; 2462086f6e0cSRick Macklem int32_t cverf[2], tverf[2] = { 0, 0 }; 24639ec7b004SRick Macklem vnode_t vp = NULL, dirp = NULL; 24649ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 24659ec7b004SRick Macklem struct nameidata named; 24669ec7b004SRick Macklem nfsv4stateid_t stateid, delegstateid; 24679ec7b004SRick Macklem nfsattrbit_t attrbits; 24689ec7b004SRick Macklem nfsquad_t clientid; 24699ec7b004SRick Macklem char *bufp = NULL; 24709ec7b004SRick Macklem u_long *hashp; 24719ec7b004SRick Macklem NFSACL_T *aclp = NULL; 24729ec7b004SRick Macklem 24739ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 2474c3e22f83SRick Macklem aclp = acl_alloc(M_WAITOK); 24759ec7b004SRick Macklem aclp->acl_cnt = 0; 24769ec7b004SRick Macklem #endif 24779ec7b004SRick Macklem NFSZERO_ATTRBIT(&attrbits); 24789ec7b004SRick Macklem named.ni_startdir = NULL; 24799ec7b004SRick Macklem named.ni_cnd.cn_nameiop = 0; 24809ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 24819ec7b004SRick Macklem i = fxdr_unsigned(int, *(tl + 5)); 24822a45247cSRick Macklem if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 24832a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 24842a45247cSRick Macklem vrele(dp); 24852a45247cSRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 24862a45247cSRick Macklem acl_free(aclp); 24872a45247cSRick Macklem #endif 24882a45247cSRick Macklem return (0); 24892a45247cSRick Macklem } 24909ec7b004SRick Macklem MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 24919ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 24929ec7b004SRick Macklem stp->ls_ownerlen = i; 24939ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 24949ec7b004SRick Macklem stp->ls_flags = NFSLCK_OPEN; 24959ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 24969ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 24979ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 24989ec7b004SRick Macklem switch (i) { 24999ec7b004SRick Macklem case NFSV4OPEN_ACCESSREAD: 25009ec7b004SRick Macklem stp->ls_flags |= NFSLCK_READACCESS; 25019ec7b004SRick Macklem break; 25029ec7b004SRick Macklem case NFSV4OPEN_ACCESSWRITE: 25039ec7b004SRick Macklem stp->ls_flags |= NFSLCK_WRITEACCESS; 25049ec7b004SRick Macklem break; 25059ec7b004SRick Macklem case NFSV4OPEN_ACCESSBOTH: 25069ec7b004SRick Macklem stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 25079ec7b004SRick Macklem break; 25089ec7b004SRick Macklem default: 25099ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 25109ec7b004SRick Macklem }; 25119ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 25129ec7b004SRick Macklem switch (i) { 25139ec7b004SRick Macklem case NFSV4OPEN_DENYNONE: 25149ec7b004SRick Macklem break; 25159ec7b004SRick Macklem case NFSV4OPEN_DENYREAD: 25169ec7b004SRick Macklem stp->ls_flags |= NFSLCK_READDENY; 25179ec7b004SRick Macklem break; 25189ec7b004SRick Macklem case NFSV4OPEN_DENYWRITE: 25199ec7b004SRick Macklem stp->ls_flags |= NFSLCK_WRITEDENY; 25209ec7b004SRick Macklem break; 25219ec7b004SRick Macklem case NFSV4OPEN_DENYBOTH: 25229ec7b004SRick Macklem stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 25239ec7b004SRick Macklem break; 25249ec7b004SRick Macklem default: 25259ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 25269ec7b004SRick Macklem }; 25279ec7b004SRick Macklem clientid.lval[0] = *tl++; 25289ec7b004SRick Macklem clientid.lval[1] = *tl; 25299ec7b004SRick Macklem if (nd->nd_flag & ND_IMPLIEDCLID) { 25309ec7b004SRick Macklem if (nd->nd_clientid.qval != clientid.qval) 25319ec7b004SRick Macklem printf("EEK! multiple clids\n"); 25329ec7b004SRick Macklem } else { 25339ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 25349ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 25359ec7b004SRick Macklem } 25369ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 25379ec7b004SRick Macklem if (error) { 25389ec7b004SRick Macklem vrele(dp); 25399ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 25409ec7b004SRick Macklem acl_free(aclp); 25419ec7b004SRick Macklem #endif 25429ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 25439ec7b004SRick Macklem return (error); 25449ec7b004SRick Macklem } 25459ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 25469ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 25479ec7b004SRick Macklem create = fxdr_unsigned(int, *tl); 25489ec7b004SRick Macklem if (!nd->nd_repstat) 25490cf42b62SRick Macklem nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0); 25509ec7b004SRick Macklem if (create == NFSV4OPEN_CREATE) { 25519ec7b004SRick Macklem nva.na_type = VREG; 25529ec7b004SRick Macklem nva.na_mode = 0; 25539ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 25549ec7b004SRick Macklem how = fxdr_unsigned(int, *tl); 25559ec7b004SRick Macklem switch (how) { 25569ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 25579ec7b004SRick Macklem case NFSCREATE_GUARDED: 25589ec7b004SRick Macklem error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p); 25599ec7b004SRick Macklem if (error) { 25609ec7b004SRick Macklem vrele(dp); 25619ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 25629ec7b004SRick Macklem acl_free(aclp); 25639ec7b004SRick Macklem #endif 25649ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 25659ec7b004SRick Macklem return (error); 25669ec7b004SRick Macklem } 25679ec7b004SRick Macklem /* 25689ec7b004SRick Macklem * If the na_gid being set is the same as that of 25699ec7b004SRick Macklem * the directory it is going in, clear it, since 25709ec7b004SRick Macklem * that is what will be set by default. This allows 25719ec7b004SRick Macklem * a user that isn't in that group to do the create. 25729ec7b004SRick Macklem */ 25739ec7b004SRick Macklem if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) && 25749ec7b004SRick Macklem nva.na_gid == dirfor.na_gid) 25759ec7b004SRick Macklem NFSVNO_UNSET(&nva, gid); 25769ec7b004SRick Macklem if (!nd->nd_repstat) 25779ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 25789ec7b004SRick Macklem break; 25799ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 25809ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2581086f6e0cSRick Macklem cverf[0] = *tl++; 2582086f6e0cSRick Macklem cverf[1] = *tl; 25839ec7b004SRick Macklem break; 25849ec7b004SRick Macklem default: 25859ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 25869ec7b004SRick Macklem vrele(dp); 25879ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 25889ec7b004SRick Macklem acl_free(aclp); 25899ec7b004SRick Macklem #endif 25909ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 25919ec7b004SRick Macklem return (0); 25929ec7b004SRick Macklem }; 25939ec7b004SRick Macklem } else if (create != NFSV4OPEN_NOCREATE) { 25949ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 25959ec7b004SRick Macklem vrele(dp); 25969ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 25979ec7b004SRick Macklem acl_free(aclp); 25989ec7b004SRick Macklem #endif 25999ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 26009ec7b004SRick Macklem return (0); 26019ec7b004SRick Macklem } 26029ec7b004SRick Macklem 26039ec7b004SRick Macklem /* 26049ec7b004SRick Macklem * Now, handle the claim, which usually includes looking up a 26059ec7b004SRick Macklem * name in the directory referenced by dp. The exception is 26069ec7b004SRick Macklem * NFSV4OPEN_CLAIMPREVIOUS. 26079ec7b004SRick Macklem */ 26089ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 26099ec7b004SRick Macklem claim = fxdr_unsigned(int, *tl); 26109ec7b004SRick Macklem if (claim == NFSV4OPEN_CLAIMDELEGATECUR) { 26119ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 26129ec7b004SRick Macklem stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 26139ec7b004SRick Macklem NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 26149ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGCUR; 26159ec7b004SRick Macklem } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 26169ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGPREV; 26179ec7b004SRick Macklem } 26189ec7b004SRick Macklem if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR 26199ec7b004SRick Macklem || claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 26209ec7b004SRick Macklem if (!nd->nd_repstat && create == NFSV4OPEN_CREATE && 26219ec7b004SRick Macklem claim != NFSV4OPEN_CLAIMNULL) 26229ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 26239ec7b004SRick Macklem if (nd->nd_repstat) { 26249ec7b004SRick Macklem nd->nd_repstat = nfsrv_opencheck(clientid, 26259ec7b004SRick Macklem &stateid, stp, NULL, nd, p, nd->nd_repstat); 26269ec7b004SRick Macklem vrele(dp); 26279ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 26289ec7b004SRick Macklem acl_free(aclp); 26299ec7b004SRick Macklem #endif 26309ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 26319ec7b004SRick Macklem return (0); 26329ec7b004SRick Macklem } 26339ec7b004SRick Macklem if (create == NFSV4OPEN_CREATE) 26349ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 26359ec7b004SRick Macklem LOCKPARENT | LOCKLEAF | SAVESTART); 26369ec7b004SRick Macklem else 26379ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 26389ec7b004SRick Macklem LOCKLEAF | SAVESTART); 26399ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 26409ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 26419ec7b004SRick Macklem if (error) { 26429ec7b004SRick Macklem vrele(dp); 26439ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 26449ec7b004SRick Macklem acl_free(aclp); 26459ec7b004SRick Macklem #endif 26469ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 26479ec7b004SRick Macklem nfsvno_relpathbuf(&named); 26489ec7b004SRick Macklem return (error); 26499ec7b004SRick Macklem } 26509ec7b004SRick Macklem if (!nd->nd_repstat) { 26519ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, 26529ec7b004SRick Macklem p, &dirp); 26539ec7b004SRick Macklem } else { 26549ec7b004SRick Macklem vrele(dp); 26559ec7b004SRick Macklem nfsvno_relpathbuf(&named); 26569ec7b004SRick Macklem } 26579ec7b004SRick Macklem if (create == NFSV4OPEN_CREATE) { 26589ec7b004SRick Macklem switch (how) { 26599ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 26609ec7b004SRick Macklem if (named.ni_vp) { 26619ec7b004SRick Macklem /* 26629ec7b004SRick Macklem * Clear the setable attribute bits, except 26639ec7b004SRick Macklem * for Size, if it is being truncated. 26649ec7b004SRick Macklem */ 26659ec7b004SRick Macklem NFSZERO_ATTRBIT(&attrbits); 26669ec7b004SRick Macklem if (NFSVNO_ISSETSIZE(&nva)) 26679ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, 26689ec7b004SRick Macklem NFSATTRBIT_SIZE); 26699ec7b004SRick Macklem } 26709ec7b004SRick Macklem break; 26719ec7b004SRick Macklem case NFSCREATE_GUARDED: 26729ec7b004SRick Macklem if (named.ni_vp && !nd->nd_repstat) 26739ec7b004SRick Macklem nd->nd_repstat = EEXIST; 26749ec7b004SRick Macklem break; 26759ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 26769ec7b004SRick Macklem exclusive_flag = 1; 26779ec7b004SRick Macklem if (!named.ni_vp) 26789ec7b004SRick Macklem nva.na_mode = 0; 26799ec7b004SRick Macklem }; 26809ec7b004SRick Macklem } 26819ec7b004SRick Macklem nfsvno_open(nd, &named, clientid, &stateid, stp, 26829ec7b004SRick Macklem &exclusive_flag, &nva, cverf, create, aclp, &attrbits, 26839ec7b004SRick Macklem nd->nd_cred, p, exp, &vp); 26849ec7b004SRick Macklem } else if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 26859ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 26869ec7b004SRick Macklem i = fxdr_unsigned(int, *tl); 26879ec7b004SRick Macklem switch (i) { 26889ec7b004SRick Macklem case NFSV4OPEN_DELEGATEREAD: 26899ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGREAD; 26909ec7b004SRick Macklem break; 26919ec7b004SRick Macklem case NFSV4OPEN_DELEGATEWRITE: 26929ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGWRITE; 26939ec7b004SRick Macklem case NFSV4OPEN_DELEGATENONE: 26949ec7b004SRick Macklem break; 26959ec7b004SRick Macklem default: 26969ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 26979ec7b004SRick Macklem vrele(dp); 26989ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 26999ec7b004SRick Macklem acl_free(aclp); 27009ec7b004SRick Macklem #endif 27019ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 27029ec7b004SRick Macklem return (0); 27039ec7b004SRick Macklem }; 27049ec7b004SRick Macklem stp->ls_flags |= NFSLCK_RECLAIM; 27059ec7b004SRick Macklem vp = dp; 2706629fa50eSRick Macklem vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2707629fa50eSRick Macklem if ((vp->v_iflag & VI_DOOMED) == 0) 2708629fa50eSRick Macklem nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, 2709629fa50eSRick Macklem stp, vp, nd, p, nd->nd_repstat); 2710629fa50eSRick Macklem else 2711629fa50eSRick Macklem nd->nd_repstat = NFSERR_PERM; 27129ec7b004SRick Macklem } else { 27139ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 27149ec7b004SRick Macklem vrele(dp); 27159ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 27169ec7b004SRick Macklem acl_free(aclp); 27179ec7b004SRick Macklem #endif 27189ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 27199ec7b004SRick Macklem return (0); 27209ec7b004SRick Macklem } 27219ec7b004SRick Macklem 27229ec7b004SRick Macklem /* 27239ec7b004SRick Macklem * Do basic access checking. 27249ec7b004SRick Macklem */ 27259ec7b004SRick Macklem if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 27269ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 27279ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 27289ec7b004SRick Macklem else if (vnode_vtype(vp) == VLNK) 27299ec7b004SRick Macklem nd->nd_repstat = NFSERR_SYMLINK; 27309ec7b004SRick Macklem else 27319ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 27329ec7b004SRick Macklem } 27339ec7b004SRick Macklem if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS)) 27348da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, 27358da45f2cSRick Macklem exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 27369ec7b004SRick Macklem if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) { 27378da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, 27388da45f2cSRick Macklem exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 27399ec7b004SRick Macklem if (nd->nd_repstat) 27408da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 27419ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 27428da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 27439ec7b004SRick Macklem } 27449ec7b004SRick Macklem 2745086f6e0cSRick Macklem if (!nd->nd_repstat) { 27460cf42b62SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 2747086f6e0cSRick Macklem if (!nd->nd_repstat) { 2748086f6e0cSRick Macklem tverf[0] = nva.na_atime.tv_sec; 2749086f6e0cSRick Macklem tverf[1] = nva.na_atime.tv_nsec; 2750086f6e0cSRick Macklem } 2751086f6e0cSRick Macklem } 2752086f6e0cSRick Macklem if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] || 2753086f6e0cSRick Macklem cverf[1] != tverf[1])) 27549ec7b004SRick Macklem nd->nd_repstat = EEXIST; 27559ec7b004SRick Macklem /* 27569ec7b004SRick Macklem * Do the open locking/delegation stuff. 27579ec7b004SRick Macklem */ 27589ec7b004SRick Macklem if (!nd->nd_repstat) 27599ec7b004SRick Macklem nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid, 27609ec7b004SRick Macklem &delegstateid, &rflags, exp, p, nva.na_filerev); 27619ec7b004SRick Macklem 27629ec7b004SRick Macklem /* 27639ec7b004SRick Macklem * vp must be unlocked before the call to nfsvno_getattr(dirp,...) 27649ec7b004SRick Macklem * below, to avoid a deadlock with the lookup in nfsvno_namei() above. 27659ec7b004SRick Macklem * (ie: Leave the NFSVOPUNLOCK() about here.) 27669ec7b004SRick Macklem */ 27679ec7b004SRick Macklem if (vp) 27689ec7b004SRick Macklem NFSVOPUNLOCK(vp, 0, p); 27699ec7b004SRick Macklem if (stp) 27709ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 27719ec7b004SRick Macklem if (!nd->nd_repstat && dirp) 27720cf42b62SRick Macklem nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 27730cf42b62SRick Macklem 0); 27749ec7b004SRick Macklem if (!nd->nd_repstat) { 27759ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 27769ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 27779ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 27789ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 27799ec7b004SRick Macklem if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 27809ec7b004SRick Macklem *tl++ = newnfs_true; 27819ec7b004SRick Macklem *tl++ = 0; 27829ec7b004SRick Macklem *tl++ = 0; 27839ec7b004SRick Macklem *tl++ = 0; 27849ec7b004SRick Macklem *tl++ = 0; 27859ec7b004SRick Macklem } else { 27869ec7b004SRick Macklem *tl++ = newnfs_false; /* Since dirp is not locked */ 27879ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 27889ec7b004SRick Macklem tl += 2; 27899ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 27909ec7b004SRick Macklem tl += 2; 27919ec7b004SRick Macklem } 27929ec7b004SRick Macklem *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS); 27939ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &attrbits); 27949ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 27959ec7b004SRick Macklem if (rflags & NFSV4OPEN_READDELEGATE) 27969ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD); 27979ec7b004SRick Macklem else if (rflags & NFSV4OPEN_WRITEDELEGATE) 27989ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE); 27999ec7b004SRick Macklem else 28009ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE); 28019ec7b004SRick Macklem if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) { 28029ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED); 28039ec7b004SRick Macklem *tl++ = txdr_unsigned(delegstateid.seqid); 28049ec7b004SRick Macklem NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl, 28059ec7b004SRick Macklem NFSX_STATEIDOTHER); 28069ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 28079ec7b004SRick Macklem if (rflags & NFSV4OPEN_RECALL) 28089ec7b004SRick Macklem *tl = newnfs_true; 28099ec7b004SRick Macklem else 28109ec7b004SRick Macklem *tl = newnfs_false; 28119ec7b004SRick Macklem if (rflags & NFSV4OPEN_WRITEDELEGATE) { 28129ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 28139ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE); 28149ec7b004SRick Macklem txdr_hyper(nva.na_size, tl); 28159ec7b004SRick Macklem } 28169ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 28179ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE); 28189ec7b004SRick Macklem *tl++ = txdr_unsigned(0x0); 28199ec7b004SRick Macklem acemask = NFSV4ACE_ALLFILESMASK; 28209ec7b004SRick Macklem if (nva.na_mode & S_IRUSR) 28219ec7b004SRick Macklem acemask |= NFSV4ACE_READMASK; 28229ec7b004SRick Macklem if (nva.na_mode & S_IWUSR) 28239ec7b004SRick Macklem acemask |= NFSV4ACE_WRITEMASK; 28249ec7b004SRick Macklem if (nva.na_mode & S_IXUSR) 28259ec7b004SRick Macklem acemask |= NFSV4ACE_EXECUTEMASK; 28269ec7b004SRick Macklem *tl = txdr_unsigned(acemask); 28279ec7b004SRick Macklem (void) nfsm_strtom(nd, "OWNER@", 6); 28289ec7b004SRick Macklem } 28299ec7b004SRick Macklem *vpp = vp; 28309ec7b004SRick Macklem } else if (vp) { 28319ec7b004SRick Macklem vrele(vp); 28329ec7b004SRick Macklem } 28339ec7b004SRick Macklem if (dirp) 28349ec7b004SRick Macklem vrele(dirp); 28359ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 28369ec7b004SRick Macklem acl_free(aclp); 28379ec7b004SRick Macklem #endif 28389ec7b004SRick Macklem return (0); 28399ec7b004SRick Macklem nfsmout: 28409ec7b004SRick Macklem vrele(dp); 28419ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 28429ec7b004SRick Macklem acl_free(aclp); 28439ec7b004SRick Macklem #endif 28449ec7b004SRick Macklem if (stp) 28459ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 28469ec7b004SRick Macklem return (error); 28479ec7b004SRick Macklem } 28489ec7b004SRick Macklem 28499ec7b004SRick Macklem /* 28509ec7b004SRick Macklem * nfsv4 close service 28519ec7b004SRick Macklem */ 28529ec7b004SRick Macklem APPLESTATIC int 28539ec7b004SRick Macklem nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram, 28549ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 28559ec7b004SRick Macklem { 28569ec7b004SRick Macklem u_int32_t *tl; 28579ec7b004SRick Macklem struct nfsstate st, *stp = &st; 28589ec7b004SRick Macklem int error = 0; 28599ec7b004SRick Macklem nfsv4stateid_t stateid; 28609ec7b004SRick Macklem nfsquad_t clientid; 28619ec7b004SRick Macklem 28629ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 28639ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 28649ec7b004SRick Macklem stp->ls_ownerlen = 0; 28659ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 28669ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 28679ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 28689ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 28699ec7b004SRick Macklem NFSX_STATEIDOTHER); 28709ec7b004SRick Macklem stp->ls_flags = NFSLCK_CLOSE; 28719ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 28729ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 28739ec7b004SRick Macklem if (nd->nd_flag & ND_IMPLIEDCLID) { 28749ec7b004SRick Macklem if (nd->nd_clientid.qval != clientid.qval) 28759ec7b004SRick Macklem printf("EEK! multiple clids\n"); 28769ec7b004SRick Macklem } else { 28779ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 28789ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 28799ec7b004SRick Macklem } 28809ec7b004SRick Macklem nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p); 28819ec7b004SRick Macklem vput(vp); 28829ec7b004SRick Macklem if (!nd->nd_repstat) { 28839ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 28849ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 28859ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 28869ec7b004SRick Macklem } 28879ec7b004SRick Macklem return (0); 28889ec7b004SRick Macklem nfsmout: 28899ec7b004SRick Macklem vput(vp); 28909ec7b004SRick Macklem return (error); 28919ec7b004SRick Macklem } 28929ec7b004SRick Macklem 28939ec7b004SRick Macklem /* 28949ec7b004SRick Macklem * nfsv4 delegpurge service 28959ec7b004SRick Macklem */ 28969ec7b004SRick Macklem APPLESTATIC int 28979ec7b004SRick Macklem nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram, 28989ec7b004SRick Macklem __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 28999ec7b004SRick Macklem { 29009ec7b004SRick Macklem u_int32_t *tl; 29019ec7b004SRick Macklem int error = 0; 29029ec7b004SRick Macklem nfsquad_t clientid; 29039ec7b004SRick Macklem 2904c9aad40fSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 2905b1cfc0d9SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 2906b1cfc0d9SRick Macklem return (0); 2907b1cfc0d9SRick Macklem } 29089ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 29099ec7b004SRick Macklem clientid.lval[0] = *tl++; 29109ec7b004SRick Macklem clientid.lval[1] = *tl; 29119ec7b004SRick Macklem if (nd->nd_flag & ND_IMPLIEDCLID) { 29129ec7b004SRick Macklem if (nd->nd_clientid.qval != clientid.qval) 29139ec7b004SRick Macklem printf("EEK! multiple clids\n"); 29149ec7b004SRick Macklem } else { 29159ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 29169ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 29179ec7b004SRick Macklem } 29189ec7b004SRick Macklem nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL, 29199ec7b004SRick Macklem NFSV4OP_DELEGPURGE, nd->nd_cred, p); 29209ec7b004SRick Macklem nfsmout: 29219ec7b004SRick Macklem return (error); 29229ec7b004SRick Macklem } 29239ec7b004SRick Macklem 29249ec7b004SRick Macklem /* 29259ec7b004SRick Macklem * nfsv4 delegreturn service 29269ec7b004SRick Macklem */ 29279ec7b004SRick Macklem APPLESTATIC int 29289ec7b004SRick Macklem nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram, 29299ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 29309ec7b004SRick Macklem { 29319ec7b004SRick Macklem u_int32_t *tl; 29329ec7b004SRick Macklem int error = 0; 29339ec7b004SRick Macklem nfsv4stateid_t stateid; 29349ec7b004SRick Macklem nfsquad_t clientid; 29359ec7b004SRick Macklem 29369ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 29379ec7b004SRick Macklem stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 29389ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER); 29399ec7b004SRick Macklem clientid.lval[0] = stateid.other[0]; 29409ec7b004SRick Macklem clientid.lval[1] = stateid.other[1]; 29419ec7b004SRick Macklem if (nd->nd_flag & ND_IMPLIEDCLID) { 29429ec7b004SRick Macklem if (nd->nd_clientid.qval != clientid.qval) 29439ec7b004SRick Macklem printf("EEK! multiple clids\n"); 29449ec7b004SRick Macklem } else { 29459ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 29469ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 29479ec7b004SRick Macklem } 29489ec7b004SRick Macklem nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp, 29499ec7b004SRick Macklem NFSV4OP_DELEGRETURN, nd->nd_cred, p); 29509ec7b004SRick Macklem nfsmout: 29519ec7b004SRick Macklem vput(vp); 29529ec7b004SRick Macklem return (error); 29539ec7b004SRick Macklem } 29549ec7b004SRick Macklem 29559ec7b004SRick Macklem /* 29569ec7b004SRick Macklem * nfsv4 get file handle service 29579ec7b004SRick Macklem */ 29589ec7b004SRick Macklem APPLESTATIC int 29599ec7b004SRick Macklem nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram, 29609ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 29619ec7b004SRick Macklem { 29629ec7b004SRick Macklem fhandle_t fh; 29639ec7b004SRick Macklem 29649ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 29659ec7b004SRick Macklem vput(vp); 29669ec7b004SRick Macklem if (!nd->nd_repstat) 29679ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 29689ec7b004SRick Macklem return (0); 29699ec7b004SRick Macklem } 29709ec7b004SRick Macklem 29719ec7b004SRick Macklem /* 29729ec7b004SRick Macklem * nfsv4 open confirm service 29739ec7b004SRick Macklem */ 29749ec7b004SRick Macklem APPLESTATIC int 29759ec7b004SRick Macklem nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram, 29769ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 29779ec7b004SRick Macklem { 29789ec7b004SRick Macklem u_int32_t *tl; 29799ec7b004SRick Macklem struct nfsstate st, *stp = &st; 29809ec7b004SRick Macklem int error = 0; 29819ec7b004SRick Macklem nfsv4stateid_t stateid; 29829ec7b004SRick Macklem nfsquad_t clientid; 29839ec7b004SRick Macklem 29849ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 29859ec7b004SRick Macklem stp->ls_ownerlen = 0; 29869ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 29879ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 29889ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 29899ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 29909ec7b004SRick Macklem NFSX_STATEIDOTHER); 29919ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 29929ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl); 29939ec7b004SRick Macklem stp->ls_flags = NFSLCK_CONFIRM; 29949ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 29959ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 29969ec7b004SRick Macklem if (nd->nd_flag & ND_IMPLIEDCLID) { 29979ec7b004SRick Macklem if (nd->nd_clientid.qval != clientid.qval) 29989ec7b004SRick Macklem printf("EEK! multiple clids\n"); 29999ec7b004SRick Macklem } else { 30009ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 30019ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 30029ec7b004SRick Macklem } 30039ec7b004SRick Macklem nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p); 30049ec7b004SRick Macklem if (!nd->nd_repstat) { 30059ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 30069ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 30079ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 30089ec7b004SRick Macklem } 30099ec7b004SRick Macklem nfsmout: 30109ec7b004SRick Macklem vput(vp); 30119ec7b004SRick Macklem return (error); 30129ec7b004SRick Macklem } 30139ec7b004SRick Macklem 30149ec7b004SRick Macklem /* 30159ec7b004SRick Macklem * nfsv4 open downgrade service 30169ec7b004SRick Macklem */ 30179ec7b004SRick Macklem APPLESTATIC int 30189ec7b004SRick Macklem nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram, 30199ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 30209ec7b004SRick Macklem { 30219ec7b004SRick Macklem u_int32_t *tl; 30229ec7b004SRick Macklem int i; 30239ec7b004SRick Macklem struct nfsstate st, *stp = &st; 30249ec7b004SRick Macklem int error = 0; 30259ec7b004SRick Macklem nfsv4stateid_t stateid; 30269ec7b004SRick Macklem nfsquad_t clientid; 30279ec7b004SRick Macklem 30289ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 30299ec7b004SRick Macklem stp->ls_ownerlen = 0; 30309ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 30319ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 30329ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 30339ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 30349ec7b004SRick Macklem NFSX_STATEIDOTHER); 30359ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 30369ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 30379ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 30389ec7b004SRick Macklem switch (i) { 30399ec7b004SRick Macklem case NFSV4OPEN_ACCESSREAD: 30409ec7b004SRick Macklem stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE); 30419ec7b004SRick Macklem break; 30429ec7b004SRick Macklem case NFSV4OPEN_ACCESSWRITE: 30439ec7b004SRick Macklem stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); 30449ec7b004SRick Macklem break; 30459ec7b004SRick Macklem case NFSV4OPEN_ACCESSBOTH: 30469ec7b004SRick Macklem stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS | 30479ec7b004SRick Macklem NFSLCK_DOWNGRADE); 30489ec7b004SRick Macklem break; 30499ec7b004SRick Macklem default: 30509ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 30519ec7b004SRick Macklem }; 30529ec7b004SRick Macklem i = fxdr_unsigned(int, *tl); 30539ec7b004SRick Macklem switch (i) { 30549ec7b004SRick Macklem case NFSV4OPEN_DENYNONE: 30559ec7b004SRick Macklem break; 30569ec7b004SRick Macklem case NFSV4OPEN_DENYREAD: 30579ec7b004SRick Macklem stp->ls_flags |= NFSLCK_READDENY; 30589ec7b004SRick Macklem break; 30599ec7b004SRick Macklem case NFSV4OPEN_DENYWRITE: 30609ec7b004SRick Macklem stp->ls_flags |= NFSLCK_WRITEDENY; 30619ec7b004SRick Macklem break; 30629ec7b004SRick Macklem case NFSV4OPEN_DENYBOTH: 30639ec7b004SRick Macklem stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 30649ec7b004SRick Macklem break; 30659ec7b004SRick Macklem default: 30669ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 30679ec7b004SRick Macklem }; 30689ec7b004SRick Macklem 30699ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 30709ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 30719ec7b004SRick Macklem if (nd->nd_flag & ND_IMPLIEDCLID) { 30729ec7b004SRick Macklem if (nd->nd_clientid.qval != clientid.qval) 30739ec7b004SRick Macklem printf("EEK! multiple clids\n"); 30749ec7b004SRick Macklem } else { 30759ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 30769ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 30779ec7b004SRick Macklem } 30789ec7b004SRick Macklem if (!nd->nd_repstat) 30799ec7b004SRick Macklem nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, 30809ec7b004SRick Macklem nd, p); 30819ec7b004SRick Macklem if (!nd->nd_repstat) { 30829ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 30839ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 30849ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 30859ec7b004SRick Macklem } 30869ec7b004SRick Macklem nfsmout: 30879ec7b004SRick Macklem vput(vp); 30889ec7b004SRick Macklem return (error); 30899ec7b004SRick Macklem } 30909ec7b004SRick Macklem 30919ec7b004SRick Macklem /* 30929ec7b004SRick Macklem * nfsv4 renew lease service 30939ec7b004SRick Macklem */ 30949ec7b004SRick Macklem APPLESTATIC int 30959ec7b004SRick Macklem nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram, 30969ec7b004SRick Macklem __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 30979ec7b004SRick Macklem { 30989ec7b004SRick Macklem u_int32_t *tl; 30999ec7b004SRick Macklem int error = 0; 31009ec7b004SRick Macklem nfsquad_t clientid; 31019ec7b004SRick Macklem 3102c9aad40fSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3103b1cfc0d9SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3104b1cfc0d9SRick Macklem return (0); 3105b1cfc0d9SRick Macklem } 31069ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 31079ec7b004SRick Macklem clientid.lval[0] = *tl++; 31089ec7b004SRick Macklem clientid.lval[1] = *tl; 31099ec7b004SRick Macklem if (nd->nd_flag & ND_IMPLIEDCLID) { 31109ec7b004SRick Macklem if (nd->nd_clientid.qval != clientid.qval) 31119ec7b004SRick Macklem printf("EEK! multiple clids\n"); 31129ec7b004SRick Macklem } else { 31139ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 31149ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 31159ec7b004SRick Macklem } 31169ec7b004SRick Macklem nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW), 31179ec7b004SRick Macklem NULL, (nfsquad_t)((u_quad_t)0), nd, p); 31189ec7b004SRick Macklem nfsmout: 31199ec7b004SRick Macklem return (error); 31209ec7b004SRick Macklem } 31219ec7b004SRick Macklem 31229ec7b004SRick Macklem /* 31239ec7b004SRick Macklem * nfsv4 security info service 31249ec7b004SRick Macklem */ 31259ec7b004SRick Macklem APPLESTATIC int 31269ec7b004SRick Macklem nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram, 31279ec7b004SRick Macklem vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 31289ec7b004SRick Macklem { 31299ec7b004SRick Macklem u_int32_t *tl; 31309ec7b004SRick Macklem int len; 31319ec7b004SRick Macklem struct nameidata named; 31329ec7b004SRick Macklem vnode_t dirp = NULL, vp; 31339ec7b004SRick Macklem struct nfsrvfh fh; 31349ec7b004SRick Macklem struct nfsexstuff retnes; 31359ec7b004SRick Macklem u_int32_t *sizp; 31369ec7b004SRick Macklem int error, savflag, i; 31379ec7b004SRick Macklem char *bufp; 31389ec7b004SRick Macklem u_long *hashp; 31399ec7b004SRick Macklem 31409ec7b004SRick Macklem /* 31419ec7b004SRick Macklem * All this just to get the export flags for the name. 31429ec7b004SRick Macklem */ 31439ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 31449ec7b004SRick Macklem LOCKLEAF | SAVESTART); 31459ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 31469ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 31479ec7b004SRick Macklem if (error) { 31489ec7b004SRick Macklem vput(dp); 31499ec7b004SRick Macklem nfsvno_relpathbuf(&named); 31509ec7b004SRick Macklem return (error); 31519ec7b004SRick Macklem } 31529ec7b004SRick Macklem if (!nd->nd_repstat) { 31539ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 31549ec7b004SRick Macklem } else { 31559ec7b004SRick Macklem vput(dp); 31569ec7b004SRick Macklem nfsvno_relpathbuf(&named); 31579ec7b004SRick Macklem } 31589ec7b004SRick Macklem if (dirp) 31599ec7b004SRick Macklem vrele(dirp); 31609ec7b004SRick Macklem if (nd->nd_repstat) 31619ec7b004SRick Macklem return (0); 31629ec7b004SRick Macklem vrele(named.ni_startdir); 31639ec7b004SRick Macklem nfsvno_relpathbuf(&named); 31649ec7b004SRick Macklem fh.nfsrvfh_len = NFSX_MYFH; 31659ec7b004SRick Macklem vp = named.ni_vp; 31669ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 31679ec7b004SRick Macklem vput(vp); 31689ec7b004SRick Macklem savflag = nd->nd_flag; 31699ec7b004SRick Macklem if (!nd->nd_repstat) { 31708974bc2fSRick Macklem nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p); 31719ec7b004SRick Macklem if (vp) 31729ec7b004SRick Macklem vput(vp); 31739ec7b004SRick Macklem } 31749ec7b004SRick Macklem nd->nd_flag = savflag; 31759ec7b004SRick Macklem if (nd->nd_repstat) 31769ec7b004SRick Macklem return (0); 31779ec7b004SRick Macklem 31789ec7b004SRick Macklem /* 31799ec7b004SRick Macklem * Finally have the export flags for name, so we can create 31809ec7b004SRick Macklem * the security info. 31819ec7b004SRick Macklem */ 31829ec7b004SRick Macklem len = 0; 31839ec7b004SRick Macklem NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED); 318498ad4453SRick Macklem for (i = 0; i < retnes.nes_numsecflavor; i++) { 318598ad4453SRick Macklem if (retnes.nes_secflavors[i] == AUTH_SYS) { 31869ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 31879ec7b004SRick Macklem *tl = txdr_unsigned(RPCAUTH_UNIX); 31889ec7b004SRick Macklem len++; 318998ad4453SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 31909ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 31919ec7b004SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_GSS); 31929ec7b004SRick Macklem (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 31939ec7b004SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 31949ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 31959ec7b004SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 319698ad4453SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 31979ec7b004SRick Macklem len++; 319898ad4453SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 319998ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 320098ad4453SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_GSS); 320198ad4453SRick Macklem (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 320298ad4453SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 320398ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 320498ad4453SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 320598ad4453SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 320698ad4453SRick Macklem len++; 320798ad4453SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 320898ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 320998ad4453SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_GSS); 321098ad4453SRick Macklem (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 321198ad4453SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 321298ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 321398ad4453SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 321498ad4453SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 321598ad4453SRick Macklem len++; 321698ad4453SRick Macklem } 32179ec7b004SRick Macklem } 32189ec7b004SRick Macklem *sizp = txdr_unsigned(len); 32199ec7b004SRick Macklem return (0); 32209ec7b004SRick Macklem } 32219ec7b004SRick Macklem 32229ec7b004SRick Macklem /* 32239ec7b004SRick Macklem * nfsv4 set client id service 32249ec7b004SRick Macklem */ 32259ec7b004SRick Macklem APPLESTATIC int 32269ec7b004SRick Macklem nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, 32279ec7b004SRick Macklem __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 32289ec7b004SRick Macklem { 32299ec7b004SRick Macklem u_int32_t *tl; 32309ec7b004SRick Macklem int i; 32319ec7b004SRick Macklem int error = 0, idlen; 32329ec7b004SRick Macklem struct nfsclient *clp = NULL; 32339ec7b004SRick Macklem struct sockaddr_in *rad; 32349ec7b004SRick Macklem u_char *verf, *ucp, *ucp2, addrbuf[24]; 32359ec7b004SRick Macklem nfsquad_t clientid, confirm; 32369ec7b004SRick Macklem 3237c9aad40fSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 32389ec7b004SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 32399ec7b004SRick Macklem return (0); 32409ec7b004SRick Macklem } 32419ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 32429ec7b004SRick Macklem verf = (u_char *)tl; 32439ec7b004SRick Macklem tl += (NFSX_VERF / NFSX_UNSIGNED); 32449ec7b004SRick Macklem i = fxdr_unsigned(int, *tl); 32459ec7b004SRick Macklem if (i > NFSV4_OPAQUELIMIT || i <= 0) { 32469ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 32479ec7b004SRick Macklem return (error); 32489ec7b004SRick Macklem } 32499ec7b004SRick Macklem idlen = i; 32509ec7b004SRick Macklem if (nd->nd_flag & ND_GSS) 32519ec7b004SRick Macklem i += nd->nd_princlen; 32529ec7b004SRick Macklem MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i, 32539ec7b004SRick Macklem M_NFSDCLIENT, M_WAITOK); 32549ec7b004SRick Macklem NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i); 32559ec7b004SRick Macklem NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 32569ec7b004SRick Macklem NFSSOCKADDRALLOC(clp->lc_req.nr_nam); 32579ec7b004SRick Macklem NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in)); 32589ec7b004SRick Macklem clp->lc_req.nr_cred = NULL; 32599ec7b004SRick Macklem NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 32609ec7b004SRick Macklem clp->lc_idlen = idlen; 32619ec7b004SRick Macklem error = nfsrv_mtostr(nd, clp->lc_id, idlen); 32629ec7b004SRick Macklem if (error) 32639ec7b004SRick Macklem goto nfsmout; 32649ec7b004SRick Macklem if (nd->nd_flag & ND_GSS) { 32659ec7b004SRick Macklem clp->lc_flags = LCL_GSS; 32669ec7b004SRick Macklem if (nd->nd_flag & ND_GSSINTEGRITY) 32679ec7b004SRick Macklem clp->lc_flags |= LCL_GSSINTEGRITY; 32689ec7b004SRick Macklem else if (nd->nd_flag & ND_GSSPRIVACY) 32699ec7b004SRick Macklem clp->lc_flags |= LCL_GSSPRIVACY; 32709ec7b004SRick Macklem } else { 32719ec7b004SRick Macklem clp->lc_flags = 0; 32729ec7b004SRick Macklem } 32739ec7b004SRick Macklem if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) { 32749ec7b004SRick Macklem clp->lc_flags |= LCL_NAME; 32759ec7b004SRick Macklem clp->lc_namelen = nd->nd_princlen; 32769ec7b004SRick Macklem clp->lc_name = &clp->lc_id[idlen]; 32779ec7b004SRick Macklem NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 32789ec7b004SRick Macklem } else { 32799ec7b004SRick Macklem clp->lc_uid = nd->nd_cred->cr_uid; 32809ec7b004SRick Macklem clp->lc_gid = nd->nd_cred->cr_gid; 32819ec7b004SRick Macklem } 32829ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 32839ec7b004SRick Macklem clp->lc_program = fxdr_unsigned(u_int32_t, *tl); 32849ec7b004SRick Macklem error = nfsrv_getclientipaddr(nd, clp); 32859ec7b004SRick Macklem if (error) 32869ec7b004SRick Macklem goto nfsmout; 32879ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 32889ec7b004SRick Macklem clp->lc_callback = fxdr_unsigned(u_int32_t, *tl); 32899ec7b004SRick Macklem 32909ec7b004SRick Macklem /* 32919ec7b004SRick Macklem * nfsrv_setclient() does the actual work of adding it to the 32929ec7b004SRick Macklem * client list. If there is no error, the structure has been 32939ec7b004SRick Macklem * linked into the client list and clp should no longer be used 32949ec7b004SRick Macklem * here. When an error is returned, it has not been linked in, 32959ec7b004SRick Macklem * so it should be free'd. 32969ec7b004SRick Macklem */ 32979ec7b004SRick Macklem nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 32989ec7b004SRick Macklem if (nd->nd_repstat == NFSERR_CLIDINUSE) { 32999ec7b004SRick Macklem if (clp->lc_flags & LCL_TCPCALLBACK) 33009ec7b004SRick Macklem (void) nfsm_strtom(nd, "tcp", 3); 33019ec7b004SRick Macklem else 33029ec7b004SRick Macklem (void) nfsm_strtom(nd, "udp", 3); 33039ec7b004SRick Macklem rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *); 33049ec7b004SRick Macklem ucp = (u_char *)&rad->sin_addr.s_addr; 33059ec7b004SRick Macklem ucp2 = (u_char *)&rad->sin_port; 33069ec7b004SRick Macklem sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff, 33079ec7b004SRick Macklem ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff, 33089ec7b004SRick Macklem ucp2[0] & 0xff, ucp2[1] & 0xff); 33099ec7b004SRick Macklem (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf)); 33109ec7b004SRick Macklem } 33119ec7b004SRick Macklem if (clp) { 33129ec7b004SRick Macklem NFSSOCKADDRFREE(clp->lc_req.nr_nam); 33139ec7b004SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 33149ec7b004SRick Macklem free((caddr_t)clp, M_NFSDCLIENT); 33159ec7b004SRick Macklem } 33169ec7b004SRick Macklem if (!nd->nd_repstat) { 33179ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); 33189ec7b004SRick Macklem *tl++ = clientid.lval[0]; 33199ec7b004SRick Macklem *tl++ = clientid.lval[1]; 33209ec7b004SRick Macklem *tl++ = confirm.lval[0]; 33219ec7b004SRick Macklem *tl = confirm.lval[1]; 33229ec7b004SRick Macklem } 33239ec7b004SRick Macklem return (0); 33249ec7b004SRick Macklem nfsmout: 33259ec7b004SRick Macklem if (clp) { 33269ec7b004SRick Macklem NFSSOCKADDRFREE(clp->lc_req.nr_nam); 33279ec7b004SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 33289ec7b004SRick Macklem free((caddr_t)clp, M_NFSDCLIENT); 33299ec7b004SRick Macklem } 33309ec7b004SRick Macklem return (error); 33319ec7b004SRick Macklem } 33329ec7b004SRick Macklem 33339ec7b004SRick Macklem /* 33349ec7b004SRick Macklem * nfsv4 set client id confirm service 33359ec7b004SRick Macklem */ 33369ec7b004SRick Macklem APPLESTATIC int 33379ec7b004SRick Macklem nfsrvd_setclientidcfrm(struct nfsrv_descript *nd, 33389ec7b004SRick Macklem __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p, 33399ec7b004SRick Macklem __unused struct nfsexstuff *exp) 33409ec7b004SRick Macklem { 33419ec7b004SRick Macklem u_int32_t *tl; 33429ec7b004SRick Macklem int error = 0; 33439ec7b004SRick Macklem nfsquad_t clientid, confirm; 33449ec7b004SRick Macklem 3345c9aad40fSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 33469ec7b004SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 33479ec7b004SRick Macklem return (0); 33489ec7b004SRick Macklem } 33499ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER); 33509ec7b004SRick Macklem clientid.lval[0] = *tl++; 33519ec7b004SRick Macklem clientid.lval[1] = *tl++; 33529ec7b004SRick Macklem confirm.lval[0] = *tl++; 33539ec7b004SRick Macklem confirm.lval[1] = *tl; 33549ec7b004SRick Macklem 33559ec7b004SRick Macklem /* 33569ec7b004SRick Macklem * nfsrv_getclient() searches the client list for a match and 33579ec7b004SRick Macklem * returns the appropriate NFSERR status. 33589ec7b004SRick Macklem */ 33599ec7b004SRick Macklem nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW), 33609ec7b004SRick Macklem NULL, confirm, nd, p); 33619ec7b004SRick Macklem nfsmout: 33629ec7b004SRick Macklem return (error); 33639ec7b004SRick Macklem } 33649ec7b004SRick Macklem 33659ec7b004SRick Macklem /* 33669ec7b004SRick Macklem * nfsv4 verify service 33679ec7b004SRick Macklem */ 33689ec7b004SRick Macklem APPLESTATIC int 33699ec7b004SRick Macklem nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, 33709ec7b004SRick Macklem vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 33719ec7b004SRick Macklem { 33729ec7b004SRick Macklem int error = 0, ret, fhsize = NFSX_MYFH; 33739ec7b004SRick Macklem struct nfsvattr nva; 33749ec7b004SRick Macklem struct statfs sf; 33759ec7b004SRick Macklem struct nfsfsinfo fs; 33769ec7b004SRick Macklem fhandle_t fh; 33779ec7b004SRick Macklem 33780cf42b62SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 33799ec7b004SRick Macklem if (!nd->nd_repstat) 3380dfd233edSAttilio Rao nd->nd_repstat = nfsvno_statfs(vp, &sf); 33819ec7b004SRick Macklem if (!nd->nd_repstat) 33829ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 33839ec7b004SRick Macklem if (!nd->nd_repstat) { 33849ec7b004SRick Macklem nfsvno_getfs(&fs, isdgram); 33859ec7b004SRick Macklem error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL, 33869ec7b004SRick Macklem &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred); 33879ec7b004SRick Macklem if (!error) { 33889ec7b004SRick Macklem if (nd->nd_procnum == NFSV4OP_NVERIFY) { 33899ec7b004SRick Macklem if (ret == 0) 33909ec7b004SRick Macklem nd->nd_repstat = NFSERR_SAME; 33919ec7b004SRick Macklem else if (ret != NFSERR_NOTSAME) 33929ec7b004SRick Macklem nd->nd_repstat = ret; 33939ec7b004SRick Macklem } else if (ret) 33949ec7b004SRick Macklem nd->nd_repstat = ret; 33959ec7b004SRick Macklem } 33969ec7b004SRick Macklem } 33979ec7b004SRick Macklem vput(vp); 33989ec7b004SRick Macklem return (error); 33999ec7b004SRick Macklem } 34009ec7b004SRick Macklem 34019ec7b004SRick Macklem /* 34029ec7b004SRick Macklem * nfs openattr rpc 34039ec7b004SRick Macklem */ 34049ec7b004SRick Macklem APPLESTATIC int 34059ec7b004SRick Macklem nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram, 34069ec7b004SRick Macklem vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp, 34079ec7b004SRick Macklem __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 34089ec7b004SRick Macklem { 34099ec7b004SRick Macklem u_int32_t *tl; 34109ec7b004SRick Macklem int error = 0, createdir; 34119ec7b004SRick Macklem 34129ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 34139ec7b004SRick Macklem createdir = fxdr_unsigned(int, *tl); 34149ec7b004SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 34159ec7b004SRick Macklem nfsmout: 34169ec7b004SRick Macklem vrele(dp); 34179ec7b004SRick Macklem return (error); 34189ec7b004SRick Macklem } 34199ec7b004SRick Macklem 34209ec7b004SRick Macklem /* 34219ec7b004SRick Macklem * nfsv4 release lock owner service 34229ec7b004SRick Macklem */ 34239ec7b004SRick Macklem APPLESTATIC int 34249ec7b004SRick Macklem nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram, 34259ec7b004SRick Macklem __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 34269ec7b004SRick Macklem { 34279ec7b004SRick Macklem u_int32_t *tl; 34289ec7b004SRick Macklem struct nfsstate *stp = NULL; 34299ec7b004SRick Macklem int error = 0, len; 34309ec7b004SRick Macklem nfsquad_t clientid; 34319ec7b004SRick Macklem 3432c9aad40fSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3433b1cfc0d9SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3434b1cfc0d9SRick Macklem return (0); 3435b1cfc0d9SRick Macklem } 34369ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 34379ec7b004SRick Macklem len = fxdr_unsigned(int, *(tl + 2)); 34382a45247cSRick Macklem if (len <= 0 || len > NFSV4_OPAQUELIMIT) { 34392a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 34402a45247cSRick Macklem return (0); 34412a45247cSRick Macklem } 34429ec7b004SRick Macklem MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len, 34439ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 34449ec7b004SRick Macklem stp->ls_ownerlen = len; 34459ec7b004SRick Macklem stp->ls_op = NULL; 34469ec7b004SRick Macklem stp->ls_flags = NFSLCK_RELEASE; 34479ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 34489ec7b004SRick Macklem clientid.lval[0] = *tl++; 34499ec7b004SRick Macklem clientid.lval[1] = *tl; 34509ec7b004SRick Macklem if (nd->nd_flag & ND_IMPLIEDCLID) { 34519ec7b004SRick Macklem if (nd->nd_clientid.qval != clientid.qval) 34529ec7b004SRick Macklem printf("EEK! multiple clids\n"); 34539ec7b004SRick Macklem } else { 34549ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 34559ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 34569ec7b004SRick Macklem } 34579ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, len); 34589ec7b004SRick Macklem if (error) 34599ec7b004SRick Macklem goto nfsmout; 34609ec7b004SRick Macklem nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p); 34619ec7b004SRick Macklem FREE((caddr_t)stp, M_NFSDSTATE); 34629ec7b004SRick Macklem return (0); 34639ec7b004SRick Macklem nfsmout: 34649ec7b004SRick Macklem if (stp) 34659ec7b004SRick Macklem free((caddr_t)stp, M_NFSDSTATE); 34669ec7b004SRick Macklem return (error); 34679ec7b004SRick Macklem } 3468