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