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 39ed2f1001SRick Macklem #include "opt_inet.h" 40ed2f1001SRick Macklem #include "opt_inet6.h" 419ec7b004SRick Macklem /* 429ec7b004SRick Macklem * nfs version 2, 3 and 4 server calls to vnode ops 439ec7b004SRick Macklem * - these routines generally have 3 phases 449ec7b004SRick Macklem * 1 - break down and validate rpc request in mbuf list 459ec7b004SRick Macklem * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX() 469ec7b004SRick Macklem * function in nfsd_port.c 479ec7b004SRick Macklem * 3 - build the rpc reply in an mbuf list 489ec7b004SRick Macklem * For nfsv4, these functions are called for each Op within the Compound RPC. 499ec7b004SRick Macklem */ 509ec7b004SRick Macklem 519ec7b004SRick Macklem #ifndef APPLEKEXT 529ec7b004SRick Macklem #include <fs/nfs/nfsport.h> 539ec7b004SRick Macklem 549ec7b004SRick Macklem /* Global vars */ 559ec7b004SRick Macklem extern u_int32_t newnfs_false, newnfs_true; 569ec7b004SRick Macklem extern enum vtype nv34tov_type[8]; 579ec7b004SRick Macklem extern struct timeval nfsboottime; 58c9aad40fSRick Macklem extern int nfs_rootfhset; 5907c0c166SRick Macklem extern int nfsrv_enable_crossmntpt; 601f54e596SRick Macklem extern int nfsrv_statehashsize; 6190d2dfabSRick Macklem extern int nfsrv_layouthashsize; 6290d2dfabSRick Macklem extern time_t nfsdev_time; 6390d2dfabSRick Macklem extern volatile int nfsrv_devidcnt; 6490d2dfabSRick Macklem extern int nfsd_debuglevel; 6590d2dfabSRick Macklem extern u_long sb_max_adj; 6690d2dfabSRick Macklem extern int nfsrv_pnfsatime; 6790d2dfabSRick Macklem extern int nfsrv_maxpnfsmirror; 689ec7b004SRick Macklem #endif /* !APPLEKEXT */ 699ec7b004SRick Macklem 70e4558aacSXin LI static int nfs_async = 0; 71e4558aacSXin LI SYSCTL_DECL(_vfs_nfsd); 72e4558aacSXin LI SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0, 73e4558aacSXin LI "Tell client that writes were synced even though they were not"); 7490d2dfabSRick Macklem extern int nfsrv_doflexfile; 7590d2dfabSRick Macklem SYSCTL_INT(_vfs_nfsd, OID_AUTO, default_flexfile, CTLFLAG_RW, 7690d2dfabSRick Macklem &nfsrv_doflexfile, 0, "Make Flex File Layout the default for pNFS"); 77e4558aacSXin LI 789ec7b004SRick Macklem /* 799ec7b004SRick Macklem * This list defines the GSS mechanisms supported. 809ec7b004SRick Macklem * (Don't ask me how you get these strings from the RFC stuff like 819ec7b004SRick Macklem * iso(1), org(3)... but someone did it, so I don't need to know.) 829ec7b004SRick Macklem */ 839ec7b004SRick Macklem static struct nfsgss_mechlist nfsgss_mechlist[] = { 849ec7b004SRick Macklem { 9, "\052\206\110\206\367\022\001\002\002", 11 }, 859ec7b004SRick Macklem { 0, "", 0 }, 869ec7b004SRick Macklem }; 879ec7b004SRick Macklem 889ec7b004SRick Macklem /* local functions */ 899ec7b004SRick Macklem static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 909ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 919ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 929ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, 939ec7b004SRick Macklem NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 949ec7b004SRick Macklem int pathlen); 959ec7b004SRick Macklem static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 969ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 979ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 989ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 999ec7b004SRick Macklem NFSPROC_T *p, struct nfsexstuff *exp); 1009ec7b004SRick Macklem 1019ec7b004SRick Macklem /* 1029ec7b004SRick Macklem * nfs access service (not a part of NFS V2) 1039ec7b004SRick Macklem */ 1049ec7b004SRick Macklem APPLESTATIC int 1059ec7b004SRick Macklem nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram, 106af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 1079ec7b004SRick Macklem { 1089ec7b004SRick Macklem u_int32_t *tl; 1099ec7b004SRick Macklem int getret, error = 0; 1109ec7b004SRick Macklem struct nfsvattr nva; 1119ec7b004SRick Macklem u_int32_t testmode, nfsmode, supported = 0; 1128da45f2cSRick Macklem accmode_t deletebit; 113af444b18SEdward Tomasz Napierala struct thread *p = curthread; 1149ec7b004SRick Macklem 1159ec7b004SRick Macklem if (nd->nd_repstat) { 1169ec7b004SRick Macklem nfsrv_postopattr(nd, 1, &nva); 117a9285ae5SZack Kirsch goto out; 1189ec7b004SRick Macklem } 1199ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1209ec7b004SRick Macklem nfsmode = fxdr_unsigned(u_int32_t, *tl); 1219ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && 1229ec7b004SRick Macklem (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP | 1239ec7b004SRick Macklem NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE | 1249ec7b004SRick Macklem NFSACCESS_EXECUTE))) { 1259ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 1269ec7b004SRick Macklem vput(vp); 127a9285ae5SZack Kirsch goto out; 1289ec7b004SRick Macklem } 1299ec7b004SRick Macklem if (nfsmode & NFSACCESS_READ) { 1309ec7b004SRick Macklem supported |= NFSACCESS_READ; 1318da45f2cSRick Macklem if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, 1328da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1339ec7b004SRick Macklem nfsmode &= ~NFSACCESS_READ; 1349ec7b004SRick Macklem } 1359ec7b004SRick Macklem if (nfsmode & NFSACCESS_MODIFY) { 1369ec7b004SRick Macklem supported |= NFSACCESS_MODIFY; 1378da45f2cSRick Macklem if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, 1388da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1399ec7b004SRick Macklem nfsmode &= ~NFSACCESS_MODIFY; 1409ec7b004SRick Macklem } 1419ec7b004SRick Macklem if (nfsmode & NFSACCESS_EXTEND) { 1429ec7b004SRick Macklem supported |= NFSACCESS_EXTEND; 1438da45f2cSRick Macklem if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p, 1448da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1459ec7b004SRick Macklem nfsmode &= ~NFSACCESS_EXTEND; 1469ec7b004SRick Macklem } 1479ec7b004SRick Macklem if (nfsmode & NFSACCESS_DELETE) { 1489ec7b004SRick Macklem supported |= NFSACCESS_DELETE; 1498da45f2cSRick Macklem if (vp->v_type == VDIR) 1508da45f2cSRick Macklem deletebit = VDELETE_CHILD; 1518da45f2cSRick Macklem else 1528da45f2cSRick Macklem deletebit = VDELETE; 1538da45f2cSRick Macklem if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p, 1548da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1559ec7b004SRick Macklem nfsmode &= ~NFSACCESS_DELETE; 1569ec7b004SRick Macklem } 1579ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 1589ec7b004SRick Macklem testmode = NFSACCESS_LOOKUP; 1599ec7b004SRick Macklem else 1609ec7b004SRick Macklem testmode = NFSACCESS_EXECUTE; 1619ec7b004SRick Macklem if (nfsmode & testmode) { 1629ec7b004SRick Macklem supported |= (nfsmode & testmode); 1638da45f2cSRick Macklem if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p, 1648da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1659ec7b004SRick Macklem nfsmode &= ~testmode; 1669ec7b004SRick Macklem } 1679ec7b004SRick Macklem nfsmode &= supported; 1689ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 16990d2dfabSRick Macklem getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 1709ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 1719ec7b004SRick Macklem } 1729ec7b004SRick Macklem vput(vp); 1739ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 1749ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1759ec7b004SRick Macklem *tl++ = txdr_unsigned(supported); 1769ec7b004SRick Macklem } else 1779ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1789ec7b004SRick Macklem *tl = txdr_unsigned(nfsmode); 179a9285ae5SZack Kirsch 180a9285ae5SZack Kirsch out: 181a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 1829ec7b004SRick Macklem return (0); 1839ec7b004SRick Macklem nfsmout: 1849ec7b004SRick Macklem vput(vp); 185a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1869ec7b004SRick Macklem return (error); 1879ec7b004SRick Macklem } 1889ec7b004SRick Macklem 1899ec7b004SRick Macklem /* 1909ec7b004SRick Macklem * nfs getattr service 1919ec7b004SRick Macklem */ 1929ec7b004SRick Macklem APPLESTATIC int 1939ec7b004SRick Macklem nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram, 194af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 1959ec7b004SRick Macklem { 1969ec7b004SRick Macklem struct nfsvattr nva; 1979ec7b004SRick Macklem fhandle_t fh; 198a09001a8SRick Macklem int at_root = 0, error = 0, supports_nfsv4acls; 1999ec7b004SRick Macklem struct nfsreferral *refp; 20053f476caSRick Macklem nfsattrbit_t attrbits, tmpbits; 20107c0c166SRick Macklem struct mount *mp; 20207c0c166SRick Macklem struct vnode *tvp = NULL; 20307c0c166SRick Macklem struct vattr va; 20407c0c166SRick Macklem uint64_t mounted_on_fileno = 0; 20553f476caSRick Macklem accmode_t accmode; 206af444b18SEdward Tomasz Napierala struct thread *p = curthread; 2079ec7b004SRick Macklem 2089ec7b004SRick Macklem if (nd->nd_repstat) 209a9285ae5SZack Kirsch goto out; 2109ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 2119ec7b004SRick Macklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 2129ec7b004SRick Macklem if (error) { 2139ec7b004SRick Macklem vput(vp); 214a9285ae5SZack Kirsch goto out; 2159ec7b004SRick Macklem } 2169ec7b004SRick Macklem 2179ec7b004SRick Macklem /* 2189ec7b004SRick Macklem * Check for a referral. 2199ec7b004SRick Macklem */ 2209ec7b004SRick Macklem refp = nfsv4root_getreferral(vp, NULL, 0); 2219ec7b004SRick Macklem if (refp != NULL) { 2229ec7b004SRick Macklem (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1, 2239ec7b004SRick Macklem &nd->nd_repstat); 2249ec7b004SRick Macklem vput(vp); 225a9285ae5SZack Kirsch goto out; 2269ec7b004SRick Macklem } 22753f476caSRick Macklem if (nd->nd_repstat == 0) { 22853f476caSRick Macklem accmode = 0; 22953f476caSRick Macklem NFSSET_ATTRBIT(&tmpbits, &attrbits); 230d8a5961fSMarcelo Araujo 231d8a5961fSMarcelo Araujo /* 232d8a5961fSMarcelo Araujo * GETATTR with write-only attr time_access_set and time_modify_set 233d8a5961fSMarcelo Araujo * should return NFS4ERR_INVAL. 234d8a5961fSMarcelo Araujo */ 235d8a5961fSMarcelo Araujo if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) || 236d8a5961fSMarcelo Araujo NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){ 237d8a5961fSMarcelo Araujo error = NFSERR_INVAL; 238d8a5961fSMarcelo Araujo vput(vp); 239d8a5961fSMarcelo Araujo goto out; 240d8a5961fSMarcelo Araujo } 24153f476caSRick Macklem if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) { 24253f476caSRick Macklem NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL); 24353f476caSRick Macklem accmode |= VREAD_ACL; 24453f476caSRick Macklem } 24553f476caSRick Macklem if (NFSNONZERO_ATTRBIT(&tmpbits)) 24653f476caSRick Macklem accmode |= VREAD_ATTRIBUTES; 24753f476caSRick Macklem if (accmode != 0) 24853f476caSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, accmode, 2498da45f2cSRick Macklem nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, 2508da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 2519ec7b004SRick Macklem } 25253f476caSRick Macklem } 2539ec7b004SRick Macklem if (!nd->nd_repstat) 25490d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); 2559ec7b004SRick Macklem if (!nd->nd_repstat) { 2569ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 2579ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE)) 2589ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 2599ec7b004SRick Macklem if (!nd->nd_repstat) 2609ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkgetattr(nd, vp, 26190d2dfabSRick Macklem &nva, &attrbits, p); 26207c0c166SRick Macklem if (nd->nd_repstat == 0) { 263a09001a8SRick Macklem supports_nfsv4acls = nfs_supportsnfsv4acls(vp); 26407c0c166SRick Macklem mp = vp->v_mount; 26507c0c166SRick Macklem if (nfsrv_enable_crossmntpt != 0 && 26607c0c166SRick Macklem vp->v_type == VDIR && 26707c0c166SRick Macklem (vp->v_vflag & VV_ROOT) != 0 && 26807c0c166SRick Macklem vp != rootvnode) { 26907c0c166SRick Macklem tvp = mp->mnt_vnodecovered; 27007c0c166SRick Macklem VREF(tvp); 27107c0c166SRick Macklem at_root = 1; 27207c0c166SRick Macklem } else 27307c0c166SRick Macklem at_root = 0; 27407c0c166SRick Macklem vfs_ref(mp); 275a9989634SZack Kirsch NFSVOPUNLOCK(vp, 0); 27607c0c166SRick Macklem if (at_root != 0) { 27707c0c166SRick Macklem if ((nd->nd_repstat = 27898f234f3SZack Kirsch NFSVOPLOCK(tvp, LK_SHARED)) == 0) { 27907c0c166SRick Macklem nd->nd_repstat = VOP_GETATTR( 28007c0c166SRick Macklem tvp, &va, nd->nd_cred); 28107c0c166SRick Macklem vput(tvp); 28207c0c166SRick Macklem } else 28307c0c166SRick Macklem vrele(tvp); 28407c0c166SRick Macklem if (nd->nd_repstat == 0) 28507c0c166SRick Macklem mounted_on_fileno = (uint64_t) 28607c0c166SRick Macklem va.va_fileid; 28707c0c166SRick Macklem else 28807c0c166SRick Macklem at_root = 0; 28907c0c166SRick Macklem } 29007c0c166SRick Macklem if (nd->nd_repstat == 0) 29107c0c166SRick Macklem nd->nd_repstat = vfs_busy(mp, 0); 29207c0c166SRick Macklem vfs_rel(mp); 29307c0c166SRick Macklem if (nd->nd_repstat == 0) { 29407c0c166SRick Macklem (void)nfsvno_fillattr(nd, mp, vp, &nva, 29507c0c166SRick Macklem &fh, 0, &attrbits, nd->nd_cred, p, 296a09001a8SRick Macklem isdgram, 1, supports_nfsv4acls, 297a09001a8SRick Macklem at_root, mounted_on_fileno); 29807c0c166SRick Macklem vfs_unbusy(mp); 29907c0c166SRick Macklem } 3009ec7b004SRick Macklem vrele(vp); 30107c0c166SRick Macklem } else 30207c0c166SRick Macklem vput(vp); 3039ec7b004SRick Macklem } else { 3049ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 3059ec7b004SRick Macklem vput(vp); 3069ec7b004SRick Macklem } 3079ec7b004SRick Macklem } else { 3089ec7b004SRick Macklem vput(vp); 3099ec7b004SRick Macklem } 310a9285ae5SZack Kirsch 311a9285ae5SZack Kirsch out: 312a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 313a9285ae5SZack Kirsch return (error); 3149ec7b004SRick Macklem } 3159ec7b004SRick Macklem 3169ec7b004SRick Macklem /* 3179ec7b004SRick Macklem * nfs setattr service 3189ec7b004SRick Macklem */ 3199ec7b004SRick Macklem APPLESTATIC int 3209ec7b004SRick Macklem nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram, 321af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 3229ec7b004SRick Macklem { 3239ec7b004SRick Macklem struct nfsvattr nva, nva2; 3249ec7b004SRick Macklem u_int32_t *tl; 3259ec7b004SRick Macklem int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0; 32690d2dfabSRick Macklem int gotproxystateid; 3279ec7b004SRick Macklem struct timespec guard = { 0, 0 }; 3289ec7b004SRick Macklem nfsattrbit_t attrbits, retbits; 3299ec7b004SRick Macklem nfsv4stateid_t stateid; 3309ec7b004SRick Macklem NFSACL_T *aclp = NULL; 331af444b18SEdward Tomasz Napierala struct thread *p = curthread; 3329ec7b004SRick Macklem 3339ec7b004SRick Macklem if (nd->nd_repstat) { 3349ec7b004SRick Macklem nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 335a9285ae5SZack Kirsch goto out; 3369ec7b004SRick Macklem } 3379ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 338c3e22f83SRick Macklem aclp = acl_alloc(M_WAITOK); 3399ec7b004SRick Macklem aclp->acl_cnt = 0; 3409ec7b004SRick Macklem #endif 34190d2dfabSRick Macklem gotproxystateid = 0; 3429ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 3439ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 3449ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3459ec7b004SRick Macklem stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 34690d2dfabSRick Macklem stateid.other[0] = *tl++; 34790d2dfabSRick Macklem stateid.other[1] = *tl++; 34890d2dfabSRick Macklem stateid.other[2] = *tl; 34990d2dfabSRick Macklem if (stateid.other[0] == 0x55555555 && 35090d2dfabSRick Macklem stateid.other[1] == 0x55555555 && 35190d2dfabSRick Macklem stateid.other[2] == 0x55555555 && 35290d2dfabSRick Macklem stateid.seqid == 0xffffffff) 35390d2dfabSRick Macklem gotproxystateid = 1; 3549ec7b004SRick Macklem } 355d8a5961fSMarcelo Araujo error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p); 3569ec7b004SRick Macklem if (error) 3579ec7b004SRick Macklem goto nfsmout; 35890d2dfabSRick Macklem 35990d2dfabSRick Macklem /* For NFSv4, only va_uid is used from nva2. */ 36090d2dfabSRick Macklem NFSZERO_ATTRBIT(&retbits); 36190d2dfabSRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER); 36290d2dfabSRick Macklem preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits); 3639ec7b004SRick Macklem if (!nd->nd_repstat) 3649ec7b004SRick Macklem nd->nd_repstat = preat_ret; 36590d2dfabSRick Macklem 36690d2dfabSRick Macklem NFSZERO_ATTRBIT(&retbits); 3679ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 3689ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3699ec7b004SRick Macklem gcheck = fxdr_unsigned(int, *tl); 3709ec7b004SRick Macklem if (gcheck) { 3719ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3729ec7b004SRick Macklem fxdr_nfsv3time(tl, &guard); 3739ec7b004SRick Macklem } 3749ec7b004SRick Macklem if (!nd->nd_repstat && gcheck && 3759ec7b004SRick Macklem (nva2.na_ctime.tv_sec != guard.tv_sec || 3769ec7b004SRick Macklem nva2.na_ctime.tv_nsec != guard.tv_nsec)) 3779ec7b004SRick Macklem nd->nd_repstat = NFSERR_NOT_SYNC; 3789ec7b004SRick Macklem if (nd->nd_repstat) { 3799ec7b004SRick Macklem vput(vp); 3809ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 3819ec7b004SRick Macklem acl_free(aclp); 3829ec7b004SRick Macklem #endif 3839ec7b004SRick Macklem nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 384a9285ae5SZack Kirsch goto out; 3859ec7b004SRick Macklem } 3869ec7b004SRick Macklem } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) 3879ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 3889ec7b004SRick Macklem 3899ec7b004SRick Macklem /* 3909ec7b004SRick Macklem * Now that we have all the fields, lets do it. 3919ec7b004SRick Macklem * If the size is being changed write access is required, otherwise 3929ec7b004SRick Macklem * just check for a read only file system. 3939ec7b004SRick Macklem */ 3949ec7b004SRick Macklem if (!nd->nd_repstat) { 3959ec7b004SRick Macklem if (NFSVNO_NOTSETSIZE(&nva)) { 3969ec7b004SRick Macklem if (NFSVNO_EXRDONLY(exp) || 3979ec7b004SRick Macklem (vfs_flags(vnode_mount(vp)) & MNT_RDONLY)) 3989ec7b004SRick Macklem nd->nd_repstat = EROFS; 3999ec7b004SRick Macklem } else { 4009ec7b004SRick Macklem if (vnode_vtype(vp) != VREG) 4019ec7b004SRick Macklem nd->nd_repstat = EINVAL; 4029ec7b004SRick Macklem else if (nva2.na_uid != nd->nd_cred->cr_uid || 4039ec7b004SRick Macklem NFSVNO_EXSTRICTACCESS(exp)) 4049ec7b004SRick Macklem nd->nd_repstat = nfsvno_accchk(vp, 4058da45f2cSRick Macklem VWRITE, nd->nd_cred, exp, p, 4068da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, 4078da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 4089ec7b004SRick Macklem } 4099ec7b004SRick Macklem } 41090d2dfabSRick Macklem /* 41190d2dfabSRick Macklem * Proxy operations from the MDS are allowed via the all 0s special 41290d2dfabSRick Macklem * stateid. 41390d2dfabSRick Macklem */ 41490d2dfabSRick Macklem if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0 && 41590d2dfabSRick Macklem gotproxystateid == 0) 4169ec7b004SRick Macklem nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid, 4179ec7b004SRick Macklem &nva, &attrbits, exp, p); 4189ec7b004SRick Macklem 4199ec7b004SRick Macklem if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 4209ec7b004SRick Macklem /* 4219ec7b004SRick Macklem * For V4, try setting the attrbutes in sets, so that the 4229ec7b004SRick Macklem * reply bitmap will be correct for an error case. 4239ec7b004SRick Macklem */ 4249ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) || 4259ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) { 4269ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 4279ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid); 4289ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid); 4299ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 4309ec7b004SRick Macklem exp); 4319ec7b004SRick Macklem if (!nd->nd_repstat) { 4329ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER)) 4339ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER); 4349ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) 4359ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP); 4369ec7b004SRick Macklem } 4379ec7b004SRick Macklem } 4389ec7b004SRick Macklem if (!nd->nd_repstat && 4399ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) { 4409ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 4419ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, size, nva.na_size); 4429ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 4439ec7b004SRick Macklem exp); 4449ec7b004SRick Macklem if (!nd->nd_repstat) 4459ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE); 4469ec7b004SRick Macklem } 4479ec7b004SRick Macklem if (!nd->nd_repstat && 4489ec7b004SRick Macklem (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) || 4499ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) { 4509ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 4519ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime); 4529ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime); 4539ec7b004SRick Macklem if (nva.na_vaflags & VA_UTIMES_NULL) { 4549ec7b004SRick Macklem nva2.na_vaflags |= VA_UTIMES_NULL; 4559ec7b004SRick Macklem NFSVNO_SETACTIVE(&nva2, vaflags); 4569ec7b004SRick Macklem } 4579ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 4589ec7b004SRick Macklem exp); 4599ec7b004SRick Macklem if (!nd->nd_repstat) { 4609ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET)) 4619ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET); 4629ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET)) 4639ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET); 4649ec7b004SRick Macklem } 4659ec7b004SRick Macklem } 4669ec7b004SRick Macklem if (!nd->nd_repstat && 4679ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) { 4689ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 4699ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode); 4709ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 4719ec7b004SRick Macklem exp); 4729ec7b004SRick Macklem if (!nd->nd_repstat) 4739ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE); 4749ec7b004SRick Macklem } 4759ec7b004SRick Macklem 4769ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 4779ec7b004SRick Macklem if (!nd->nd_repstat && aclp->acl_cnt > 0 && 4789ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) { 4799ec7b004SRick Macklem nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p); 4809ec7b004SRick Macklem if (!nd->nd_repstat) 4819ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL); 4829ec7b004SRick Macklem } 4839ec7b004SRick Macklem #endif 4849ec7b004SRick Macklem } else if (!nd->nd_repstat) { 4859ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p, 4869ec7b004SRick Macklem exp); 4879ec7b004SRick Macklem } 4889ec7b004SRick Macklem if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) { 48990d2dfabSRick Macklem postat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 4909ec7b004SRick Macklem if (!nd->nd_repstat) 4919ec7b004SRick Macklem nd->nd_repstat = postat_ret; 4929ec7b004SRick Macklem } 4939ec7b004SRick Macklem vput(vp); 4949ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 4959ec7b004SRick Macklem acl_free(aclp); 4969ec7b004SRick Macklem #endif 4979ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 4989ec7b004SRick Macklem nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 4999ec7b004SRick Macklem else if (nd->nd_flag & ND_NFSV4) 5009ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &retbits); 5019ec7b004SRick Macklem else if (!nd->nd_repstat) 5029ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 503a9285ae5SZack Kirsch 504a9285ae5SZack Kirsch out: 505a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 5069ec7b004SRick Macklem return (0); 5079ec7b004SRick Macklem nfsmout: 5089ec7b004SRick Macklem vput(vp); 5099ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 5109ec7b004SRick Macklem acl_free(aclp); 5119ec7b004SRick Macklem #endif 5129ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 5139ec7b004SRick Macklem /* 5149ec7b004SRick Macklem * For all nd_repstat, the V4 reply includes a bitmap, 5159ec7b004SRick Macklem * even NFSERR_BADXDR, which is what this will end up 5169ec7b004SRick Macklem * returning. 5179ec7b004SRick Macklem */ 5189ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &retbits); 5199ec7b004SRick Macklem } 520a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 5219ec7b004SRick Macklem return (error); 5229ec7b004SRick Macklem } 5239ec7b004SRick Macklem 5249ec7b004SRick Macklem /* 5259ec7b004SRick Macklem * nfs lookup rpc 5269ec7b004SRick Macklem * (Also performs lookup parent for v4) 5279ec7b004SRick Macklem */ 5289ec7b004SRick Macklem APPLESTATIC int 5299ec7b004SRick Macklem nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram, 530af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 5319ec7b004SRick Macklem { 5329ec7b004SRick Macklem struct nameidata named; 5339ec7b004SRick Macklem vnode_t vp, dirp = NULL; 534a9285ae5SZack Kirsch int error = 0, dattr_ret = 1; 5359ec7b004SRick Macklem struct nfsvattr nva, dattr; 5369ec7b004SRick Macklem char *bufp; 5379ec7b004SRick Macklem u_long *hashp; 538af444b18SEdward Tomasz Napierala struct thread *p = curthread; 5399ec7b004SRick Macklem 5409ec7b004SRick Macklem if (nd->nd_repstat) { 5419ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 542a9285ae5SZack Kirsch goto out; 5439ec7b004SRick Macklem } 5449ec7b004SRick Macklem 5459ec7b004SRick Macklem /* 5469ec7b004SRick Macklem * For some reason, if dp is a symlink, the error 5479ec7b004SRick Macklem * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR. 5489ec7b004SRick Macklem */ 5499ec7b004SRick Macklem if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) { 5509ec7b004SRick Macklem nd->nd_repstat = NFSERR_SYMLINK; 5519ec7b004SRick Macklem vrele(dp); 552a9285ae5SZack Kirsch goto out; 5539ec7b004SRick Macklem } 5549ec7b004SRick Macklem 5559ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 5569ec7b004SRick Macklem LOCKLEAF | SAVESTART); 5579ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 5589ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 5599ec7b004SRick Macklem if (error) { 5609ec7b004SRick Macklem vrele(dp); 5619ec7b004SRick Macklem nfsvno_relpathbuf(&named); 562a9285ae5SZack Kirsch goto out; 5639ec7b004SRick Macklem } 5649ec7b004SRick Macklem if (!nd->nd_repstat) { 5659ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 5669ec7b004SRick Macklem } else { 5679ec7b004SRick Macklem vrele(dp); 5689ec7b004SRick Macklem nfsvno_relpathbuf(&named); 5699ec7b004SRick Macklem } 5709ec7b004SRick Macklem if (nd->nd_repstat) { 5719ec7b004SRick Macklem if (dirp) { 5729ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 57390d2dfabSRick Macklem dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 57490d2dfabSRick Macklem 0, NULL); 5759ec7b004SRick Macklem vrele(dirp); 5769ec7b004SRick Macklem } 5779ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 5789ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 579a9285ae5SZack Kirsch goto out; 5809ec7b004SRick Macklem } 5819ec7b004SRick Macklem if (named.ni_startdir) 5829ec7b004SRick Macklem vrele(named.ni_startdir); 5839ec7b004SRick Macklem nfsvno_relpathbuf(&named); 5849ec7b004SRick Macklem vp = named.ni_vp; 58537b88c2dSRick Macklem if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) && 58637b88c2dSRick Macklem vp->v_type != VDIR && vp->v_type != VLNK) 58737b88c2dSRick Macklem /* 58837b88c2dSRick Macklem * Only allow lookup of VDIR and VLNK for traversal of 58937b88c2dSRick Macklem * non-exported volumes during NFSv4 mounting. 59037b88c2dSRick Macklem */ 59137b88c2dSRick Macklem nd->nd_repstat = ENOENT; 59237b88c2dSRick Macklem if (nd->nd_repstat == 0) 5939ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 5949ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 59590d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 59681f78d99SRick Macklem if (vpp != NULL && nd->nd_repstat == 0) 5979ec7b004SRick Macklem *vpp = vp; 59881f78d99SRick Macklem else 5999ec7b004SRick Macklem vput(vp); 6009ec7b004SRick Macklem if (dirp) { 6019ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 60290d2dfabSRick Macklem dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0, 60390d2dfabSRick Macklem NULL); 6049ec7b004SRick Macklem vrele(dirp); 6059ec7b004SRick Macklem } 6069ec7b004SRick Macklem if (nd->nd_repstat) { 6079ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 6089ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 609a9285ae5SZack Kirsch goto out; 6109ec7b004SRick Macklem } 6119ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 6129ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 6139ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 6149ec7b004SRick Macklem } else if (nd->nd_flag & ND_NFSV3) { 6159ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 6169ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 6179ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 6189ec7b004SRick Macklem } 619a9285ae5SZack Kirsch 620a9285ae5SZack Kirsch out: 621a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 622a9285ae5SZack Kirsch return (error); 6239ec7b004SRick Macklem } 6249ec7b004SRick Macklem 6259ec7b004SRick Macklem /* 6269ec7b004SRick Macklem * nfs readlink service 6279ec7b004SRick Macklem */ 6289ec7b004SRick Macklem APPLESTATIC int 6299ec7b004SRick Macklem nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram, 630af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 6319ec7b004SRick Macklem { 6329ec7b004SRick Macklem u_int32_t *tl; 6339ec7b004SRick Macklem mbuf_t mp = NULL, mpend = NULL; 6349ec7b004SRick Macklem int getret = 1, len; 6359ec7b004SRick Macklem struct nfsvattr nva; 636af444b18SEdward Tomasz Napierala struct thread *p = curthread; 6379ec7b004SRick Macklem 6389ec7b004SRick Macklem if (nd->nd_repstat) { 6399ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 640a9285ae5SZack Kirsch goto out; 6419ec7b004SRick Macklem } 6429ec7b004SRick Macklem if (vnode_vtype(vp) != VLNK) { 6439ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) 6449ec7b004SRick Macklem nd->nd_repstat = ENXIO; 6459ec7b004SRick Macklem else 6469ec7b004SRick Macklem nd->nd_repstat = EINVAL; 6479ec7b004SRick Macklem } 6489ec7b004SRick Macklem if (!nd->nd_repstat) 6499ec7b004SRick Macklem nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p, 6509ec7b004SRick Macklem &mp, &mpend, &len); 6519ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 65290d2dfabSRick Macklem getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 6539ec7b004SRick Macklem vput(vp); 6549ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 6559ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 6569ec7b004SRick Macklem if (nd->nd_repstat) 657a9285ae5SZack Kirsch goto out; 6589ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 6599ec7b004SRick Macklem *tl = txdr_unsigned(len); 6609ec7b004SRick Macklem mbuf_setnext(nd->nd_mb, mp); 6619ec7b004SRick Macklem nd->nd_mb = mpend; 6629ec7b004SRick Macklem nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend); 663a9285ae5SZack Kirsch 664a9285ae5SZack Kirsch out: 665a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 6669ec7b004SRick Macklem return (0); 6679ec7b004SRick Macklem } 6689ec7b004SRick Macklem 6699ec7b004SRick Macklem /* 6709ec7b004SRick Macklem * nfs read service 6719ec7b004SRick Macklem */ 6729ec7b004SRick Macklem APPLESTATIC int 6739ec7b004SRick Macklem nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram, 674af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 6759ec7b004SRick Macklem { 6769ec7b004SRick Macklem u_int32_t *tl; 67790d2dfabSRick Macklem int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0; 6789ec7b004SRick Macklem mbuf_t m2, m3; 6799ec7b004SRick Macklem struct nfsvattr nva; 6809ec7b004SRick Macklem off_t off = 0x0; 6819ec7b004SRick Macklem struct nfsstate st, *stp = &st; 6829ec7b004SRick Macklem struct nfslock lo, *lop = &lo; 6839ec7b004SRick Macklem nfsv4stateid_t stateid; 6849ec7b004SRick Macklem nfsquad_t clientid; 685af444b18SEdward Tomasz Napierala struct thread *p = curthread; 6869ec7b004SRick Macklem 6879ec7b004SRick Macklem if (nd->nd_repstat) { 6889ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 689a9285ae5SZack Kirsch goto out; 6909ec7b004SRick Macklem } 6919ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 6929ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 6939ec7b004SRick Macklem off = (off_t)fxdr_unsigned(u_int32_t, *tl++); 6949ec7b004SRick Macklem reqlen = fxdr_unsigned(int, *tl); 6959ec7b004SRick Macklem } else if (nd->nd_flag & ND_NFSV3) { 6969ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 6979ec7b004SRick Macklem off = fxdr_hyper(tl); 6989ec7b004SRick Macklem tl += 2; 6999ec7b004SRick Macklem reqlen = fxdr_unsigned(int, *tl); 7009ec7b004SRick Macklem } else { 7019ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED); 7029ec7b004SRick Macklem reqlen = fxdr_unsigned(int, *(tl + 6)); 7039ec7b004SRick Macklem } 7049ec7b004SRick Macklem if (reqlen > NFS_SRVMAXDATA(nd)) { 7059ec7b004SRick Macklem reqlen = NFS_SRVMAXDATA(nd); 7069ec7b004SRick Macklem } else if (reqlen < 0) { 7079ec7b004SRick Macklem error = EBADRPC; 7089ec7b004SRick Macklem goto nfsmout; 7099ec7b004SRick Macklem } 71090d2dfabSRick Macklem gotproxystateid = 0; 7119ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 7129ec7b004SRick Macklem stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS); 7139ec7b004SRick Macklem lop->lo_flags = NFSLCK_READ; 7149ec7b004SRick Macklem stp->ls_ownerlen = 0; 7159ec7b004SRick Macklem stp->ls_op = NULL; 7169ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 7179ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 7189ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 7199ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 720c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 721c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 722c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 723c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 724c59e4cc3SRick Macklem printf("EEK1 multiple clids\n"); 7259ec7b004SRick Macklem } else { 726c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 727c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 7289ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 7299ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 7309ec7b004SRick Macklem } 7319ec7b004SRick Macklem stp->ls_stateid.other[2] = *tl++; 73290d2dfabSRick Macklem /* 73390d2dfabSRick Macklem * Don't allow the client to use a special stateid for a DS op. 73490d2dfabSRick Macklem */ 73590d2dfabSRick Macklem if ((nd->nd_flag & ND_DSSERVER) != 0 && 73690d2dfabSRick Macklem ((stp->ls_stateid.other[0] == 0x0 && 73790d2dfabSRick Macklem stp->ls_stateid.other[1] == 0x0 && 73890d2dfabSRick Macklem stp->ls_stateid.other[2] == 0x0) || 73990d2dfabSRick Macklem (stp->ls_stateid.other[0] == 0xffffffff && 74090d2dfabSRick Macklem stp->ls_stateid.other[1] == 0xffffffff && 74190d2dfabSRick Macklem stp->ls_stateid.other[2] == 0xffffffff) || 74290d2dfabSRick Macklem stp->ls_stateid.seqid != 0)) 74390d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 74490d2dfabSRick Macklem /* However, allow the proxy stateid. */ 74590d2dfabSRick Macklem if (stp->ls_stateid.seqid == 0xffffffff && 74690d2dfabSRick Macklem stp->ls_stateid.other[0] == 0x55555555 && 74790d2dfabSRick Macklem stp->ls_stateid.other[1] == 0x55555555 && 74890d2dfabSRick Macklem stp->ls_stateid.other[2] == 0x55555555) 74990d2dfabSRick Macklem gotproxystateid = 1; 7509ec7b004SRick Macklem off = fxdr_hyper(tl); 7519ec7b004SRick Macklem lop->lo_first = off; 7529ec7b004SRick Macklem tl += 2; 7539ec7b004SRick Macklem lop->lo_end = off + reqlen; 7549ec7b004SRick Macklem /* 7559ec7b004SRick Macklem * Paranoia, just in case it wraps around. 7569ec7b004SRick Macklem */ 7579ec7b004SRick Macklem if (lop->lo_end < off) 7589ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 7599ec7b004SRick Macklem } 7609ec7b004SRick Macklem if (vnode_vtype(vp) != VREG) { 7619ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 7629ec7b004SRick Macklem nd->nd_repstat = EINVAL; 7639ec7b004SRick Macklem else 7649ec7b004SRick Macklem nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR : 7659ec7b004SRick Macklem EINVAL; 7669ec7b004SRick Macklem } 76790d2dfabSRick Macklem getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 7689ec7b004SRick Macklem if (!nd->nd_repstat) 7699ec7b004SRick Macklem nd->nd_repstat = getret; 7709ec7b004SRick Macklem if (!nd->nd_repstat && 7719ec7b004SRick Macklem (nva.na_uid != nd->nd_cred->cr_uid || 7729ec7b004SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) { 7738da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, 7749ec7b004SRick Macklem nd->nd_cred, exp, p, 7758da45f2cSRick Macklem NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 7769ec7b004SRick Macklem if (nd->nd_repstat) 7778da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 7788da45f2cSRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 7798da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 7809ec7b004SRick Macklem } 78190d2dfabSRick Macklem /* 78290d2dfabSRick Macklem * DS reads are marked by ND_DSSERVER or use the proxy special 78390d2dfabSRick Macklem * stateid. 78490d2dfabSRick Macklem */ 78590d2dfabSRick Macklem if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) == 78690d2dfabSRick Macklem ND_NFSV4 && gotproxystateid == 0) 7879ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 7889ec7b004SRick Macklem &stateid, exp, nd, p); 7899ec7b004SRick Macklem if (nd->nd_repstat) { 7909ec7b004SRick Macklem vput(vp); 7919ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 7929ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 793a9285ae5SZack Kirsch goto out; 7949ec7b004SRick Macklem } 7959ec7b004SRick Macklem if (off >= nva.na_size) { 7969ec7b004SRick Macklem cnt = 0; 7979ec7b004SRick Macklem eof = 1; 7989ec7b004SRick Macklem } else if (reqlen == 0) 7999ec7b004SRick Macklem cnt = 0; 80006521fbbSZack Kirsch else if ((off + reqlen) >= nva.na_size) { 8019ec7b004SRick Macklem cnt = nva.na_size - off; 80206521fbbSZack Kirsch eof = 1; 80306521fbbSZack Kirsch } else 8049ec7b004SRick Macklem cnt = reqlen; 8059ec7b004SRick Macklem m3 = NULL; 8069ec7b004SRick Macklem if (cnt > 0) { 8079ec7b004SRick Macklem nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p, 8089ec7b004SRick Macklem &m3, &m2); 8099ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV4)) { 81090d2dfabSRick Macklem getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 8119ec7b004SRick Macklem if (!nd->nd_repstat) 8129ec7b004SRick Macklem nd->nd_repstat = getret; 8139ec7b004SRick Macklem } 8149ec7b004SRick Macklem if (nd->nd_repstat) { 8159ec7b004SRick Macklem vput(vp); 8169ec7b004SRick Macklem if (m3) 8179ec7b004SRick Macklem mbuf_freem(m3); 8189ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 8199ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 820a9285ae5SZack Kirsch goto out; 8219ec7b004SRick Macklem } 8229ec7b004SRick Macklem } 8239ec7b004SRick Macklem vput(vp); 8249ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 8259ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 8269ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 8279ec7b004SRick Macklem } else { 8289ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 8299ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 8309ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 8319ec7b004SRick Macklem *tl++ = txdr_unsigned(cnt); 8329ec7b004SRick Macklem } else 8339ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 83406521fbbSZack Kirsch if (eof) 8359ec7b004SRick Macklem *tl++ = newnfs_true; 8369ec7b004SRick Macklem else 8379ec7b004SRick Macklem *tl++ = newnfs_false; 8389ec7b004SRick Macklem } 8399ec7b004SRick Macklem *tl = txdr_unsigned(cnt); 8409ec7b004SRick Macklem if (m3) { 8419ec7b004SRick Macklem mbuf_setnext(nd->nd_mb, m3); 8429ec7b004SRick Macklem nd->nd_mb = m2; 8439ec7b004SRick Macklem nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2); 8449ec7b004SRick Macklem } 845a9285ae5SZack Kirsch 846a9285ae5SZack Kirsch out: 847a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 8489ec7b004SRick Macklem return (0); 8499ec7b004SRick Macklem nfsmout: 8509ec7b004SRick Macklem vput(vp); 851a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 8529ec7b004SRick Macklem return (error); 8539ec7b004SRick Macklem } 8549ec7b004SRick Macklem 8559ec7b004SRick Macklem /* 8569ec7b004SRick Macklem * nfs write service 8579ec7b004SRick Macklem */ 8589ec7b004SRick Macklem APPLESTATIC int 8599ec7b004SRick Macklem nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram, 860af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 8619ec7b004SRick Macklem { 8629ec7b004SRick Macklem int i, cnt; 8639ec7b004SRick Macklem u_int32_t *tl; 8649ec7b004SRick Macklem mbuf_t mp; 8659ec7b004SRick Macklem struct nfsvattr nva, forat; 8669ec7b004SRick Macklem int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1; 86790d2dfabSRick Macklem int gotproxystateid, stable = NFSWRITE_FILESYNC; 8689ec7b004SRick Macklem off_t off; 8699ec7b004SRick Macklem struct nfsstate st, *stp = &st; 8709ec7b004SRick Macklem struct nfslock lo, *lop = &lo; 8719ec7b004SRick Macklem nfsv4stateid_t stateid; 8729ec7b004SRick Macklem nfsquad_t clientid; 87390d2dfabSRick Macklem nfsattrbit_t attrbits; 874af444b18SEdward Tomasz Napierala struct thread *p = curthread; 8759ec7b004SRick Macklem 8769ec7b004SRick Macklem if (nd->nd_repstat) { 8779ec7b004SRick Macklem nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 878a9285ae5SZack Kirsch goto out; 8799ec7b004SRick Macklem } 88090d2dfabSRick Macklem gotproxystateid = 0; 8819ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 8829ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 8839ec7b004SRick Macklem off = (off_t)fxdr_unsigned(u_int32_t, *++tl); 8849ec7b004SRick Macklem tl += 2; 8859ec7b004SRick Macklem retlen = len = fxdr_unsigned(int32_t, *tl); 8869ec7b004SRick Macklem } else if (nd->nd_flag & ND_NFSV3) { 8879ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 8889ec7b004SRick Macklem off = fxdr_hyper(tl); 8899ec7b004SRick Macklem tl += 3; 8909ec7b004SRick Macklem stable = fxdr_unsigned(int, *tl++); 8919ec7b004SRick Macklem retlen = len = fxdr_unsigned(int32_t, *tl); 8929ec7b004SRick Macklem } else { 8939ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED); 8949ec7b004SRick Macklem stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 8959ec7b004SRick Macklem lop->lo_flags = NFSLCK_WRITE; 8969ec7b004SRick Macklem stp->ls_ownerlen = 0; 8979ec7b004SRick Macklem stp->ls_op = NULL; 8989ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 8999ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 9009ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 9019ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 902c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 903c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 904c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 905c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 906c59e4cc3SRick Macklem printf("EEK2 multiple clids\n"); 9079ec7b004SRick Macklem } else { 908c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 909c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 9109ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 9119ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 9129ec7b004SRick Macklem } 9139ec7b004SRick Macklem stp->ls_stateid.other[2] = *tl++; 91490d2dfabSRick Macklem /* 91590d2dfabSRick Macklem * Don't allow the client to use a special stateid for a DS op. 91690d2dfabSRick Macklem */ 91790d2dfabSRick Macklem if ((nd->nd_flag & ND_DSSERVER) != 0 && 91890d2dfabSRick Macklem ((stp->ls_stateid.other[0] == 0x0 && 91990d2dfabSRick Macklem stp->ls_stateid.other[1] == 0x0 && 92090d2dfabSRick Macklem stp->ls_stateid.other[2] == 0x0) || 92190d2dfabSRick Macklem (stp->ls_stateid.other[0] == 0xffffffff && 92290d2dfabSRick Macklem stp->ls_stateid.other[1] == 0xffffffff && 92390d2dfabSRick Macklem stp->ls_stateid.other[2] == 0xffffffff) || 92490d2dfabSRick Macklem stp->ls_stateid.seqid != 0)) 92590d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 92690d2dfabSRick Macklem /* However, allow the proxy stateid. */ 92790d2dfabSRick Macklem if (stp->ls_stateid.seqid == 0xffffffff && 92890d2dfabSRick Macklem stp->ls_stateid.other[0] == 0x55555555 && 92990d2dfabSRick Macklem stp->ls_stateid.other[1] == 0x55555555 && 93090d2dfabSRick Macklem stp->ls_stateid.other[2] == 0x55555555) 93190d2dfabSRick Macklem gotproxystateid = 1; 9329ec7b004SRick Macklem off = fxdr_hyper(tl); 9339ec7b004SRick Macklem lop->lo_first = off; 9349ec7b004SRick Macklem tl += 2; 9359ec7b004SRick Macklem stable = fxdr_unsigned(int, *tl++); 9369ec7b004SRick Macklem retlen = len = fxdr_unsigned(int32_t, *tl); 9379ec7b004SRick Macklem lop->lo_end = off + len; 9389ec7b004SRick Macklem /* 9399ec7b004SRick Macklem * Paranoia, just in case it wraps around, which shouldn't 9409ec7b004SRick Macklem * ever happen anyhow. 9419ec7b004SRick Macklem */ 9429ec7b004SRick Macklem if (lop->lo_end < lop->lo_first) 9439ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 9449ec7b004SRick Macklem } 9459ec7b004SRick Macklem 9469ec7b004SRick Macklem /* 9479ec7b004SRick Macklem * Loop through the mbuf chain, counting how many mbufs are a 9489ec7b004SRick Macklem * part of this write operation, so the iovec size is known. 9499ec7b004SRick Macklem */ 9509ec7b004SRick Macklem cnt = 0; 9519ec7b004SRick Macklem mp = nd->nd_md; 9529ec7b004SRick Macklem i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos; 9539ec7b004SRick Macklem while (len > 0) { 9549ec7b004SRick Macklem if (i > 0) { 9559ec7b004SRick Macklem len -= i; 9569ec7b004SRick Macklem cnt++; 9579ec7b004SRick Macklem } 9589ec7b004SRick Macklem mp = mbuf_next(mp); 9599ec7b004SRick Macklem if (!mp) { 9609ec7b004SRick Macklem if (len > 0) { 9619ec7b004SRick Macklem error = EBADRPC; 9629ec7b004SRick Macklem goto nfsmout; 9639ec7b004SRick Macklem } 9649ec7b004SRick Macklem } else 9659ec7b004SRick Macklem i = mbuf_len(mp); 9669ec7b004SRick Macklem } 9679ec7b004SRick Macklem 96866e80f77SRick Macklem if (retlen > NFS_SRVMAXIO || retlen < 0) 9699ec7b004SRick Macklem nd->nd_repstat = EIO; 9709ec7b004SRick Macklem if (vnode_vtype(vp) != VREG && !nd->nd_repstat) { 9719ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 9729ec7b004SRick Macklem nd->nd_repstat = EINVAL; 9739ec7b004SRick Macklem else 9749ec7b004SRick Macklem nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR : 9759ec7b004SRick Macklem EINVAL; 9769ec7b004SRick Macklem } 97790d2dfabSRick Macklem NFSZERO_ATTRBIT(&attrbits); 97890d2dfabSRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 97990d2dfabSRick Macklem forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits); 9809ec7b004SRick Macklem if (!nd->nd_repstat) 9819ec7b004SRick Macklem nd->nd_repstat = forat_ret; 9829ec7b004SRick Macklem if (!nd->nd_repstat && 9839ec7b004SRick Macklem (forat.na_uid != nd->nd_cred->cr_uid || 9849ec7b004SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) 9858da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 9869ec7b004SRick Macklem nd->nd_cred, exp, p, 9878da45f2cSRick Macklem NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 98890d2dfabSRick Macklem /* 98990d2dfabSRick Macklem * DS reads are marked by ND_DSSERVER or use the proxy special 99090d2dfabSRick Macklem * stateid. 99190d2dfabSRick Macklem */ 99290d2dfabSRick Macklem if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) == 99390d2dfabSRick Macklem ND_NFSV4 && gotproxystateid == 0) 9949ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 9959ec7b004SRick Macklem &stateid, exp, nd, p); 9969ec7b004SRick Macklem if (nd->nd_repstat) { 9979ec7b004SRick Macklem vput(vp); 9989ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 9999ec7b004SRick Macklem nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 1000a9285ae5SZack Kirsch goto out; 10019ec7b004SRick Macklem } 10029ec7b004SRick Macklem 10039ec7b004SRick Macklem /* 10049ec7b004SRick Macklem * For NFS Version 2, it is not obvious what a write of zero length 10059ec7b004SRick Macklem * should do, but I might as well be consistent with Version 3, 10069ec7b004SRick Macklem * which is to return ok so long as there are no permission problems. 10079ec7b004SRick Macklem */ 10089ec7b004SRick Macklem if (retlen > 0) { 100990d2dfabSRick Macklem nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, &stable, 10109ec7b004SRick Macklem nd->nd_md, nd->nd_dpos, nd->nd_cred, p); 10119ec7b004SRick Macklem error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1); 10129ec7b004SRick Macklem if (error) 1013ce8d06feSRick Macklem goto nfsmout; 10149ec7b004SRick Macklem } 10159ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) 10169ec7b004SRick Macklem aftat_ret = 0; 10179ec7b004SRick Macklem else 101890d2dfabSRick Macklem aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 10199ec7b004SRick Macklem vput(vp); 10209ec7b004SRick Macklem if (!nd->nd_repstat) 10219ec7b004SRick Macklem nd->nd_repstat = aftat_ret; 10229ec7b004SRick Macklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 10239ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 10249ec7b004SRick Macklem nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 10259ec7b004SRick Macklem if (nd->nd_repstat) 1026a9285ae5SZack Kirsch goto out; 10279ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 10289ec7b004SRick Macklem *tl++ = txdr_unsigned(retlen); 1029e4558aacSXin LI /* 1030e4558aacSXin LI * If nfs_async is set, then pretend the write was FILESYNC. 1031e4558aacSXin LI * Warning: Doing this violates RFC1813 and runs a risk 1032e4558aacSXin LI * of data written by a client being lost when the server 1033e4558aacSXin LI * crashes/reboots. 1034e4558aacSXin LI */ 1035e4558aacSXin LI if (stable == NFSWRITE_UNSTABLE && nfs_async == 0) 10369ec7b004SRick Macklem *tl++ = txdr_unsigned(stable); 10379ec7b004SRick Macklem else 10389ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSWRITE_FILESYNC); 10399ec7b004SRick Macklem /* 10409ec7b004SRick Macklem * Actually, there is no need to txdr these fields, 10419ec7b004SRick Macklem * but it may make the values more human readable, 10429ec7b004SRick Macklem * for debugging purposes. 10439ec7b004SRick Macklem */ 10449ec7b004SRick Macklem *tl++ = txdr_unsigned(nfsboottime.tv_sec); 10459ec7b004SRick Macklem *tl = txdr_unsigned(nfsboottime.tv_usec); 10469ec7b004SRick Macklem } else if (!nd->nd_repstat) 10479ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 1048a9285ae5SZack Kirsch 1049a9285ae5SZack Kirsch out: 1050a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 10519ec7b004SRick Macklem return (0); 10529ec7b004SRick Macklem nfsmout: 10539ec7b004SRick Macklem vput(vp); 1054a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 10559ec7b004SRick Macklem return (error); 10569ec7b004SRick Macklem } 10579ec7b004SRick Macklem 10589ec7b004SRick Macklem /* 10599ec7b004SRick Macklem * nfs create service (creates regular files for V2 and V3. Spec. files for V2.) 10609ec7b004SRick Macklem * now does a truncate to 0 length via. setattr if it already exists 10619ec7b004SRick Macklem * The core creation routine has been extracted out into nfsrv_creatsub(), 10629ec7b004SRick Macklem * so it can also be used by nfsrv_open() for V4. 10639ec7b004SRick Macklem */ 10649ec7b004SRick Macklem APPLESTATIC int 10659ec7b004SRick Macklem nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram, 1066af444b18SEdward Tomasz Napierala vnode_t dp, struct nfsexstuff *exp) 10679ec7b004SRick Macklem { 10689ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 10699ec7b004SRick Macklem struct nfsv2_sattr *sp; 10709ec7b004SRick Macklem struct nameidata named; 10719ec7b004SRick Macklem u_int32_t *tl; 10729ec7b004SRick Macklem int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1; 10739ec7b004SRick Macklem int how = NFSCREATE_UNCHECKED, exclusive_flag = 0; 10749ec7b004SRick Macklem NFSDEV_T rdev = 0; 10759ec7b004SRick Macklem vnode_t vp = NULL, dirp = NULL; 10769ec7b004SRick Macklem fhandle_t fh; 10779ec7b004SRick Macklem char *bufp; 10789ec7b004SRick Macklem u_long *hashp; 10799ec7b004SRick Macklem enum vtype vtyp; 1080086f6e0cSRick Macklem int32_t cverf[2], tverf[2] = { 0, 0 }; 1081af444b18SEdward Tomasz Napierala struct thread *p = curthread; 10829ec7b004SRick Macklem 10839ec7b004SRick Macklem if (nd->nd_repstat) { 10849ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1085a9285ae5SZack Kirsch goto out; 10869ec7b004SRick Macklem } 10879ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 10886c21f6edSKonstantin Belousov LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE); 10899ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 10909ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1091a9285ae5SZack Kirsch if (error) 1092a9285ae5SZack Kirsch goto nfsmout; 10939ec7b004SRick Macklem if (!nd->nd_repstat) { 10949ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 10959ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 10969ec7b004SRick Macklem NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 10979ec7b004SRick Macklem vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode)); 10989ec7b004SRick Macklem if (vtyp == VNON) 10999ec7b004SRick Macklem vtyp = VREG; 11009ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, type, vtyp); 11019ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, mode, 11029ec7b004SRick Macklem nfstov_mode(sp->sa_mode)); 11039ec7b004SRick Macklem switch (nva.na_type) { 11049ec7b004SRick Macklem case VREG: 11059ec7b004SRick Macklem tsize = fxdr_unsigned(int32_t, sp->sa_size); 11069ec7b004SRick Macklem if (tsize != -1) 11079ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, size, 11089ec7b004SRick Macklem (u_quad_t)tsize); 11099ec7b004SRick Macklem break; 11109ec7b004SRick Macklem case VCHR: 11119ec7b004SRick Macklem case VBLK: 11129ec7b004SRick Macklem case VFIFO: 11139ec7b004SRick Macklem rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size); 11149ec7b004SRick Macklem break; 11159ec7b004SRick Macklem default: 11169ec7b004SRick Macklem break; 111774b8d63dSPedro F. Giffuni } 11189ec7b004SRick Macklem } else { 11199ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 11209ec7b004SRick Macklem how = fxdr_unsigned(int, *tl); 11219ec7b004SRick Macklem switch (how) { 11229ec7b004SRick Macklem case NFSCREATE_GUARDED: 11239ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 1124d8a5961fSMarcelo Araujo error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p); 11259ec7b004SRick Macklem if (error) 11269ec7b004SRick Macklem goto nfsmout; 11279ec7b004SRick Macklem break; 11289ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 1129086f6e0cSRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 1130086f6e0cSRick Macklem cverf[0] = *tl++; 1131086f6e0cSRick Macklem cverf[1] = *tl; 11329ec7b004SRick Macklem exclusive_flag = 1; 11339ec7b004SRick Macklem break; 113474b8d63dSPedro F. Giffuni } 11359ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, type, VREG); 11369ec7b004SRick Macklem } 11379ec7b004SRick Macklem } 11389ec7b004SRick Macklem if (nd->nd_repstat) { 11399ec7b004SRick Macklem nfsvno_relpathbuf(&named); 11409ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 114190d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1, 114290d2dfabSRick Macklem NULL); 11439ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 11449ec7b004SRick Macklem &diraft); 11459ec7b004SRick Macklem } 11469ec7b004SRick Macklem vput(dp); 1147a9285ae5SZack Kirsch goto out; 11489ec7b004SRick Macklem } 11499ec7b004SRick Macklem 11509ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 11519ec7b004SRick Macklem if (dirp) { 11529ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 11539ec7b004SRick Macklem vrele(dirp); 11549ec7b004SRick Macklem dirp = NULL; 11559ec7b004SRick Macklem } else { 115690d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 115790d2dfabSRick Macklem NULL); 11589ec7b004SRick Macklem } 11599ec7b004SRick Macklem } 11609ec7b004SRick Macklem if (nd->nd_repstat) { 11619ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 11629ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 11639ec7b004SRick Macklem &diraft); 11649ec7b004SRick Macklem if (dirp) 11659ec7b004SRick Macklem vrele(dirp); 1166a9285ae5SZack Kirsch goto out; 11679ec7b004SRick Macklem } 11689ec7b004SRick Macklem 11699ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) { 11709ec7b004SRick Macklem switch (how) { 11719ec7b004SRick Macklem case NFSCREATE_GUARDED: 11729ec7b004SRick Macklem if (named.ni_vp) 11739ec7b004SRick Macklem nd->nd_repstat = EEXIST; 11749ec7b004SRick Macklem break; 11759ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 11769ec7b004SRick Macklem break; 11779ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 11789ec7b004SRick Macklem if (named.ni_vp == NULL) 11799ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, mode, 0); 11809ec7b004SRick Macklem break; 118174b8d63dSPedro F. Giffuni } 11829ec7b004SRick Macklem } 11839ec7b004SRick Macklem 11849ec7b004SRick Macklem /* 11859ec7b004SRick Macklem * Iff doesn't exist, create it 11869ec7b004SRick Macklem * otherwise just truncate to 0 length 11879ec7b004SRick Macklem * should I set the mode too ? 11889ec7b004SRick Macklem */ 11899ec7b004SRick Macklem nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva, 1190127152feSEdward Tomasz Napierala &exclusive_flag, cverf, rdev, exp); 11919ec7b004SRick Macklem 11929ec7b004SRick Macklem if (!nd->nd_repstat) { 11939ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 11949ec7b004SRick Macklem if (!nd->nd_repstat) 119590d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, 119690d2dfabSRick Macklem NULL); 11979ec7b004SRick Macklem vput(vp); 1198086f6e0cSRick Macklem if (!nd->nd_repstat) { 1199086f6e0cSRick Macklem tverf[0] = nva.na_atime.tv_sec; 1200086f6e0cSRick Macklem tverf[1] = nva.na_atime.tv_nsec; 1201086f6e0cSRick Macklem } 12029ec7b004SRick Macklem } 12039ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 12049ec7b004SRick Macklem if (!nd->nd_repstat) { 12059ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 12069ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 12079ec7b004SRick Macklem } 12089ec7b004SRick Macklem } else { 1209086f6e0cSRick Macklem if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0] 1210086f6e0cSRick Macklem || cverf[1] != tverf[1])) 12119ec7b004SRick Macklem nd->nd_repstat = EEXIST; 121290d2dfabSRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 12139ec7b004SRick Macklem vrele(dirp); 12149ec7b004SRick Macklem if (!nd->nd_repstat) { 12159ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1); 12169ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 12179ec7b004SRick Macklem } 12189ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 12199ec7b004SRick Macklem } 1220a9285ae5SZack Kirsch 1221a9285ae5SZack Kirsch out: 1222a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 12239ec7b004SRick Macklem return (0); 12249ec7b004SRick Macklem nfsmout: 12259ec7b004SRick Macklem vput(dp); 12269ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1227a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 12289ec7b004SRick Macklem return (error); 12299ec7b004SRick Macklem } 12309ec7b004SRick Macklem 12319ec7b004SRick Macklem /* 12329ec7b004SRick Macklem * nfs v3 mknod service (and v4 create) 12339ec7b004SRick Macklem */ 12349ec7b004SRick Macklem APPLESTATIC int 12359ec7b004SRick Macklem nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram, 1236af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 12379ec7b004SRick Macklem { 12389ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 12399ec7b004SRick Macklem u_int32_t *tl; 12409ec7b004SRick Macklem struct nameidata named; 12419ec7b004SRick Macklem int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 12429ec7b004SRick Macklem u_int32_t major, minor; 12439ec7b004SRick Macklem enum vtype vtyp = VNON; 12449ec7b004SRick Macklem nfstype nfs4type = NFNON; 12459ec7b004SRick Macklem vnode_t vp, dirp = NULL; 12469ec7b004SRick Macklem nfsattrbit_t attrbits; 12479ec7b004SRick Macklem char *bufp = NULL, *pathcp = NULL; 12489ec7b004SRick Macklem u_long *hashp, cnflags; 12499ec7b004SRick Macklem NFSACL_T *aclp = NULL; 1250af444b18SEdward Tomasz Napierala struct thread *p = curthread; 12519ec7b004SRick Macklem 12529ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 12539ec7b004SRick Macklem cnflags = (LOCKPARENT | SAVESTART); 12549ec7b004SRick Macklem if (nd->nd_repstat) { 12559ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1256a9285ae5SZack Kirsch goto out; 12579ec7b004SRick Macklem } 12589ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 1259c3e22f83SRick Macklem aclp = acl_alloc(M_WAITOK); 12609ec7b004SRick Macklem aclp->acl_cnt = 0; 12619ec7b004SRick Macklem #endif 12629ec7b004SRick Macklem 12639ec7b004SRick Macklem /* 12649ec7b004SRick Macklem * For V4, the creation stuff is here, Yuck! 12659ec7b004SRick Macklem */ 12669ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 12679ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 12689ec7b004SRick Macklem vtyp = nfsv34tov_type(*tl); 12699ec7b004SRick Macklem nfs4type = fxdr_unsigned(nfstype, *tl); 12709ec7b004SRick Macklem switch (nfs4type) { 12719ec7b004SRick Macklem case NFLNK: 12729ec7b004SRick Macklem error = nfsvno_getsymlink(nd, &nva, p, &pathcp, 12739ec7b004SRick Macklem &pathlen); 1274a9285ae5SZack Kirsch if (error) 1275a9285ae5SZack Kirsch goto nfsmout; 12769ec7b004SRick Macklem break; 12779ec7b004SRick Macklem case NFCHR: 12789ec7b004SRick Macklem case NFBLK: 12799ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 12809ec7b004SRick Macklem major = fxdr_unsigned(u_int32_t, *tl++); 12819ec7b004SRick Macklem minor = fxdr_unsigned(u_int32_t, *tl); 12829ec7b004SRick Macklem nva.na_rdev = NFSMAKEDEV(major, minor); 12839ec7b004SRick Macklem break; 12849ec7b004SRick Macklem case NFSOCK: 12859ec7b004SRick Macklem case NFFIFO: 12869ec7b004SRick Macklem break; 12879ec7b004SRick Macklem case NFDIR: 1288f61786cbSRick Macklem cnflags = (LOCKPARENT | SAVENAME); 12899ec7b004SRick Macklem break; 12909ec7b004SRick Macklem default: 12919ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADTYPE; 12929ec7b004SRick Macklem vrele(dp); 12939ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 12949ec7b004SRick Macklem acl_free(aclp); 12959ec7b004SRick Macklem #endif 1296a9285ae5SZack Kirsch goto out; 1297a9285ae5SZack Kirsch } 12989ec7b004SRick Macklem } 12996c21f6edSKonstantin Belousov NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE); 13009ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 13019ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1302a9285ae5SZack Kirsch if (error) 1303a9285ae5SZack Kirsch goto nfsmout; 13049ec7b004SRick Macklem if (!nd->nd_repstat) { 13059ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 13069ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 13079ec7b004SRick Macklem vtyp = nfsv34tov_type(*tl); 13089ec7b004SRick Macklem } 1309d8a5961fSMarcelo Araujo error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p); 1310a9285ae5SZack Kirsch if (error) 1311a9285ae5SZack Kirsch goto nfsmout; 13129ec7b004SRick Macklem nva.na_type = vtyp; 13139ec7b004SRick Macklem if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) && 13149ec7b004SRick Macklem (vtyp == VCHR || vtyp == VBLK)) { 13159ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 13169ec7b004SRick Macklem major = fxdr_unsigned(u_int32_t, *tl++); 13179ec7b004SRick Macklem minor = fxdr_unsigned(u_int32_t, *tl); 13189ec7b004SRick Macklem nva.na_rdev = NFSMAKEDEV(major, minor); 13199ec7b004SRick Macklem } 13209ec7b004SRick Macklem } 13219ec7b004SRick Macklem 132290d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL); 13239ec7b004SRick Macklem if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 13249ec7b004SRick Macklem if (!dirfor_ret && NFSVNO_ISSETGID(&nva) && 13259ec7b004SRick Macklem dirfor.na_gid == nva.na_gid) 13269ec7b004SRick Macklem NFSVNO_UNSET(&nva, gid); 13279ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 13289ec7b004SRick Macklem } 13299ec7b004SRick Macklem if (nd->nd_repstat) { 13309ec7b004SRick Macklem vrele(dp); 13319ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 13329ec7b004SRick Macklem acl_free(aclp); 13339ec7b004SRick Macklem #endif 13349ec7b004SRick Macklem nfsvno_relpathbuf(&named); 13359ec7b004SRick Macklem if (pathcp) 1336222daa42SConrad Meyer free(pathcp, M_TEMP); 13379ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 13389ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 13399ec7b004SRick Macklem &diraft); 1340a9285ae5SZack Kirsch goto out; 13419ec7b004SRick Macklem } 13429ec7b004SRick Macklem 13439ec7b004SRick Macklem /* 13449ec7b004SRick Macklem * Yuck! For V4, mkdir and link are here and some V4 clients don't fill 13459ec7b004SRick Macklem * in va_mode, so we'll have to set a default here. 13469ec7b004SRick Macklem */ 13479ec7b004SRick Macklem if (NFSVNO_NOTSETMODE(&nva)) { 13489ec7b004SRick Macklem if (vtyp == VLNK) 13499ec7b004SRick Macklem nva.na_mode = 0755; 13509ec7b004SRick Macklem else 13519ec7b004SRick Macklem nva.na_mode = 0400; 13529ec7b004SRick Macklem } 13539ec7b004SRick Macklem 13549ec7b004SRick Macklem if (vtyp == VDIR) 13559ec7b004SRick Macklem named.ni_cnd.cn_flags |= WILLBEDIR; 13569ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 13579ec7b004SRick Macklem if (nd->nd_repstat) { 13589ec7b004SRick Macklem if (dirp) { 13599ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 136090d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, 136190d2dfabSRick Macklem p, 0, NULL); 13629ec7b004SRick Macklem vrele(dirp); 13639ec7b004SRick Macklem } 13649ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 13659ec7b004SRick Macklem acl_free(aclp); 13669ec7b004SRick Macklem #endif 13679ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 13689ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 13699ec7b004SRick Macklem &diraft); 1370a9285ae5SZack Kirsch goto out; 13719ec7b004SRick Macklem } 13729ec7b004SRick Macklem if (dirp) 137390d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); 13749ec7b004SRick Macklem 13759ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) { 13769ec7b004SRick Macklem if (vtyp == VDIR) { 13779ec7b004SRick Macklem nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, 13789ec7b004SRick Macklem &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p, 13799ec7b004SRick Macklem exp); 13809ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 13819ec7b004SRick Macklem acl_free(aclp); 13829ec7b004SRick Macklem #endif 1383a9285ae5SZack Kirsch goto out; 13849ec7b004SRick Macklem } else if (vtyp == VLNK) { 13859ec7b004SRick Macklem nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 13869ec7b004SRick Macklem &dirfor, &diraft, &diraft_ret, &attrbits, 13879ec7b004SRick Macklem aclp, p, exp, pathcp, pathlen); 13889ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 13899ec7b004SRick Macklem acl_free(aclp); 13909ec7b004SRick Macklem #endif 1391222daa42SConrad Meyer free(pathcp, M_TEMP); 1392a9285ae5SZack Kirsch goto out; 13939ec7b004SRick Macklem } 13949ec7b004SRick Macklem } 13959ec7b004SRick Macklem 13969ec7b004SRick Macklem nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p); 13979ec7b004SRick Macklem if (!nd->nd_repstat) { 13989ec7b004SRick Macklem vp = named.ni_vp; 13999ec7b004SRick Macklem nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp); 14009ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 14019ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat) 140290d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, 140390d2dfabSRick Macklem NULL); 140481f78d99SRick Macklem if (vpp != NULL && nd->nd_repstat == 0) { 1405a9989634SZack Kirsch NFSVOPUNLOCK(vp, 0); 14069ec7b004SRick Macklem *vpp = vp; 140781f78d99SRick Macklem } else 14089ec7b004SRick Macklem vput(vp); 14099ec7b004SRick Macklem } 14109ec7b004SRick Macklem 141190d2dfabSRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 14129ec7b004SRick Macklem vrele(dirp); 14139ec7b004SRick Macklem if (!nd->nd_repstat) { 14149ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 14159ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 14169ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 14179ec7b004SRick Macklem } else { 14189ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 14199ec7b004SRick Macklem *tl++ = newnfs_false; 14209ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 14219ec7b004SRick Macklem tl += 2; 14229ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 14239ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &attrbits); 14249ec7b004SRick Macklem } 14259ec7b004SRick Macklem } 14269ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 14279ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 14289ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 14299ec7b004SRick Macklem acl_free(aclp); 14309ec7b004SRick Macklem #endif 1431a9285ae5SZack Kirsch 1432a9285ae5SZack Kirsch out: 1433a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 14349ec7b004SRick Macklem return (0); 14359ec7b004SRick Macklem nfsmout: 14369ec7b004SRick Macklem vrele(dp); 14379ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 14389ec7b004SRick Macklem acl_free(aclp); 14399ec7b004SRick Macklem #endif 14409ec7b004SRick Macklem if (bufp) 14419ec7b004SRick Macklem nfsvno_relpathbuf(&named); 14429ec7b004SRick Macklem if (pathcp) 1443222daa42SConrad Meyer free(pathcp, M_TEMP); 1444a9285ae5SZack Kirsch 1445a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 14469ec7b004SRick Macklem return (error); 14479ec7b004SRick Macklem } 14489ec7b004SRick Macklem 14499ec7b004SRick Macklem /* 14509ec7b004SRick Macklem * nfs remove service 14519ec7b004SRick Macklem */ 14529ec7b004SRick Macklem APPLESTATIC int 14539ec7b004SRick Macklem nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram, 1454af444b18SEdward Tomasz Napierala vnode_t dp, struct nfsexstuff *exp) 14559ec7b004SRick Macklem { 14569ec7b004SRick Macklem struct nameidata named; 14579ec7b004SRick Macklem u_int32_t *tl; 1458a9285ae5SZack Kirsch int error = 0, dirfor_ret = 1, diraft_ret = 1; 14599ec7b004SRick Macklem vnode_t dirp = NULL; 14609ec7b004SRick Macklem struct nfsvattr dirfor, diraft; 14619ec7b004SRick Macklem char *bufp; 14629ec7b004SRick Macklem u_long *hashp; 1463af444b18SEdward Tomasz Napierala struct thread *p = curthread; 14649ec7b004SRick Macklem 14659ec7b004SRick Macklem if (nd->nd_repstat) { 14669ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1467a9285ae5SZack Kirsch goto out; 14689ec7b004SRick Macklem } 14699ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE, 14709ec7b004SRick Macklem LOCKPARENT | LOCKLEAF); 14719ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 14729ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 14739ec7b004SRick Macklem if (error) { 14749ec7b004SRick Macklem vput(dp); 14759ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1476a9285ae5SZack Kirsch goto out; 14779ec7b004SRick Macklem } 14789ec7b004SRick Macklem if (!nd->nd_repstat) { 14799ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 14809ec7b004SRick Macklem } else { 14819ec7b004SRick Macklem vput(dp); 14829ec7b004SRick Macklem nfsvno_relpathbuf(&named); 14839ec7b004SRick Macklem } 14849ec7b004SRick Macklem if (dirp) { 14859ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) { 148690d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 148790d2dfabSRick Macklem NULL); 14889ec7b004SRick Macklem } else { 14899ec7b004SRick Macklem vrele(dirp); 14909ec7b004SRick Macklem dirp = NULL; 14919ec7b004SRick Macklem } 14929ec7b004SRick Macklem } 14939ec7b004SRick Macklem if (!nd->nd_repstat) { 14949ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 14959ec7b004SRick Macklem if (vnode_vtype(named.ni_vp) == VDIR) 14969ec7b004SRick Macklem nd->nd_repstat = nfsvno_rmdirsub(&named, 1, 14979ec7b004SRick Macklem nd->nd_cred, p, exp); 14989ec7b004SRick Macklem else 14999ec7b004SRick Macklem nd->nd_repstat = nfsvno_removesub(&named, 1, 15009ec7b004SRick Macklem nd->nd_cred, p, exp); 15019ec7b004SRick Macklem } else if (nd->nd_procnum == NFSPROC_RMDIR) { 15029ec7b004SRick Macklem nd->nd_repstat = nfsvno_rmdirsub(&named, 0, 15039ec7b004SRick Macklem nd->nd_cred, p, exp); 15049ec7b004SRick Macklem } else { 15059ec7b004SRick Macklem nd->nd_repstat = nfsvno_removesub(&named, 0, 15069ec7b004SRick Macklem nd->nd_cred, p, exp); 15079ec7b004SRick Macklem } 15089ec7b004SRick Macklem } 15099ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) { 15109ec7b004SRick Macklem if (dirp) { 151190d2dfabSRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, 151290d2dfabSRick Macklem NULL); 15139ec7b004SRick Macklem vrele(dirp); 15149ec7b004SRick Macklem } 15159ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 15169ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 15179ec7b004SRick Macklem &diraft); 15189ec7b004SRick Macklem } else if (!nd->nd_repstat) { 15199ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 15209ec7b004SRick Macklem *tl++ = newnfs_false; 15219ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 15229ec7b004SRick Macklem tl += 2; 15239ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 15249ec7b004SRick Macklem } 15259ec7b004SRick Macklem } 1526a9285ae5SZack Kirsch 1527a9285ae5SZack Kirsch out: 1528a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1529a9285ae5SZack Kirsch return (error); 15309ec7b004SRick Macklem } 15319ec7b004SRick Macklem 15329ec7b004SRick Macklem /* 15339ec7b004SRick Macklem * nfs rename service 15349ec7b004SRick Macklem */ 15359ec7b004SRick Macklem APPLESTATIC int 15369ec7b004SRick Macklem nfsrvd_rename(struct nfsrv_descript *nd, int isdgram, 1537af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t todp, struct nfsexstuff *exp, struct nfsexstuff *toexp) 15389ec7b004SRick Macklem { 15399ec7b004SRick Macklem u_int32_t *tl; 1540a9285ae5SZack Kirsch int error = 0, fdirfor_ret = 1, fdiraft_ret = 1; 15419ec7b004SRick Macklem int tdirfor_ret = 1, tdiraft_ret = 1; 15429ec7b004SRick Macklem struct nameidata fromnd, tond; 15439ec7b004SRick Macklem vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL; 15449ec7b004SRick Macklem struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft; 15459ec7b004SRick Macklem struct nfsexstuff tnes; 15469ec7b004SRick Macklem struct nfsrvfh tfh; 15479ec7b004SRick Macklem char *bufp, *tbufp = NULL; 15489ec7b004SRick Macklem u_long *hashp; 15496b3dfc6aSRick Macklem fhandle_t fh; 1550af444b18SEdward Tomasz Napierala struct thread *p = curthread; 15519ec7b004SRick Macklem 15529ec7b004SRick Macklem if (nd->nd_repstat) { 15539ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 15549ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 1555a9285ae5SZack Kirsch goto out; 15569ec7b004SRick Macklem } 15579ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) 155890d2dfabSRick Macklem fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL); 15599ec7b004SRick Macklem tond.ni_cnd.cn_nameiop = 0; 15609ec7b004SRick Macklem tond.ni_startdir = NULL; 15619ec7b004SRick Macklem NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART); 15629ec7b004SRick Macklem nfsvno_setpathbuf(&fromnd, &bufp, &hashp); 15639ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen); 15649ec7b004SRick Macklem if (error) { 15659ec7b004SRick Macklem vput(dp); 15669ec7b004SRick Macklem if (todp) 15679ec7b004SRick Macklem vrele(todp); 15689ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 1569a9285ae5SZack Kirsch goto out; 15709ec7b004SRick Macklem } 157125bfde79SXin LI /* 157225bfde79SXin LI * Unlock dp in this code section, so it is unlocked before 157325bfde79SXin LI * tdp gets locked. This avoids a potential LOR if tdp is the 157425bfde79SXin LI * parent directory of dp. 157525bfde79SXin LI */ 15769ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 15779ec7b004SRick Macklem tdp = todp; 15789ec7b004SRick Macklem tnes = *toexp; 157925bfde79SXin LI if (dp != tdp) { 158025bfde79SXin LI NFSVOPUNLOCK(dp, 0); 158190d2dfabSRick Macklem /* Might lock tdp. */ 158290d2dfabSRick Macklem tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0, 158390d2dfabSRick Macklem NULL); 158425bfde79SXin LI } else { 158590d2dfabSRick Macklem tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1, 158690d2dfabSRick Macklem NULL); 158725bfde79SXin LI NFSVOPUNLOCK(dp, 0); 158825bfde79SXin LI } 15899ec7b004SRick Macklem } else { 15906b3dfc6aSRick Macklem tfh.nfsrvfh_len = 0; 15919ec7b004SRick Macklem error = nfsrv_mtofh(nd, &tfh); 15926b3dfc6aSRick Macklem if (error == 0) 15936b3dfc6aSRick Macklem error = nfsvno_getfh(dp, &fh, p); 15949ec7b004SRick Macklem if (error) { 15959ec7b004SRick Macklem vput(dp); 15969ec7b004SRick Macklem /* todp is always NULL except NFSv4 */ 15979ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 1598a9285ae5SZack Kirsch goto out; 15999ec7b004SRick Macklem } 16006b3dfc6aSRick Macklem 16016b3dfc6aSRick Macklem /* If this is the same file handle, just VREF() the vnode. */ 16026b3dfc6aSRick Macklem if (tfh.nfsrvfh_len == NFSX_MYFH && 16036b3dfc6aSRick Macklem !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) { 16046b3dfc6aSRick Macklem VREF(dp); 16056b3dfc6aSRick Macklem tdp = dp; 16066b3dfc6aSRick Macklem tnes = *exp; 160790d2dfabSRick Macklem tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1, 160890d2dfabSRick Macklem NULL); 160925bfde79SXin LI NFSVOPUNLOCK(dp, 0); 16106b3dfc6aSRick Macklem } else { 161125bfde79SXin LI NFSVOPUNLOCK(dp, 0); 16126b3dfc6aSRick Macklem nd->nd_cred->cr_uid = nd->nd_saveduid; 16136b3dfc6aSRick Macklem nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL, 16145edc9102SEdward Tomasz Napierala 0); /* Locks tdp. */ 16156b3dfc6aSRick Macklem if (tdp) { 161690d2dfabSRick Macklem tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, 161790d2dfabSRick Macklem p, 1, NULL); 1618c383087cSZack Kirsch NFSVOPUNLOCK(tdp, 0); 16199ec7b004SRick Macklem } 16209ec7b004SRick Macklem } 16216b3dfc6aSRick Macklem } 16229ec7b004SRick Macklem NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART); 16239ec7b004SRick Macklem nfsvno_setpathbuf(&tond, &tbufp, &hashp); 16249ec7b004SRick Macklem if (!nd->nd_repstat) { 16259ec7b004SRick Macklem error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen); 16269ec7b004SRick Macklem if (error) { 16278974bc2fSRick Macklem if (tdp) 16289ec7b004SRick Macklem vrele(tdp); 162925bfde79SXin LI vrele(dp); 16309ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 16319ec7b004SRick Macklem nfsvno_relpathbuf(&tond); 1632a9285ae5SZack Kirsch goto out; 16339ec7b004SRick Macklem } 16349ec7b004SRick Macklem } 16359ec7b004SRick Macklem if (nd->nd_repstat) { 16369ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 16379ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 16389ec7b004SRick Macklem &fdiraft); 16399ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 16409ec7b004SRick Macklem &tdiraft); 16419ec7b004SRick Macklem } 16428974bc2fSRick Macklem if (tdp) 16439ec7b004SRick Macklem vrele(tdp); 164425bfde79SXin LI vrele(dp); 16459ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 16469ec7b004SRick Macklem nfsvno_relpathbuf(&tond); 1647a9285ae5SZack Kirsch goto out; 16489ec7b004SRick Macklem } 16499ec7b004SRick Macklem 16509ec7b004SRick Macklem /* 16519ec7b004SRick Macklem * Done parsing, now down to business. 16529ec7b004SRick Macklem */ 165325bfde79SXin LI nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp); 16549ec7b004SRick Macklem if (nd->nd_repstat) { 16559ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 16569ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 16579ec7b004SRick Macklem &fdiraft); 16589ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 16599ec7b004SRick Macklem &tdiraft); 16609ec7b004SRick Macklem } 16619ec7b004SRick Macklem if (fdirp) 16629ec7b004SRick Macklem vrele(fdirp); 16638974bc2fSRick Macklem if (tdp) 16649ec7b004SRick Macklem vrele(tdp); 16659ec7b004SRick Macklem nfsvno_relpathbuf(&tond); 1666a9285ae5SZack Kirsch goto out; 16679ec7b004SRick Macklem } 16689ec7b004SRick Macklem if (vnode_vtype(fromnd.ni_vp) == VDIR) 16699ec7b004SRick Macklem tond.ni_cnd.cn_flags |= WILLBEDIR; 16709ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp); 16719ec7b004SRick Macklem nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat, 16729ec7b004SRick Macklem nd->nd_flag, nd->nd_cred, p); 16739ec7b004SRick Macklem if (fdirp) 167490d2dfabSRick Macklem fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL); 16759ec7b004SRick Macklem if (tdirp) 167690d2dfabSRick Macklem tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL); 16779ec7b004SRick Macklem if (fdirp) 16789ec7b004SRick Macklem vrele(fdirp); 16799ec7b004SRick Macklem if (tdirp) 16809ec7b004SRick Macklem vrele(tdirp); 16819ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 16829ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 16839ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 16849ec7b004SRick Macklem } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 16859ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED); 16869ec7b004SRick Macklem *tl++ = newnfs_false; 16879ec7b004SRick Macklem txdr_hyper(fdirfor.na_filerev, tl); 16889ec7b004SRick Macklem tl += 2; 16899ec7b004SRick Macklem txdr_hyper(fdiraft.na_filerev, tl); 16909ec7b004SRick Macklem tl += 2; 16919ec7b004SRick Macklem *tl++ = newnfs_false; 16929ec7b004SRick Macklem txdr_hyper(tdirfor.na_filerev, tl); 16939ec7b004SRick Macklem tl += 2; 16949ec7b004SRick Macklem txdr_hyper(tdiraft.na_filerev, tl); 16959ec7b004SRick Macklem } 1696a9285ae5SZack Kirsch 1697a9285ae5SZack Kirsch out: 1698a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1699a9285ae5SZack Kirsch return (error); 17009ec7b004SRick Macklem } 17019ec7b004SRick Macklem 17029ec7b004SRick Macklem /* 17039ec7b004SRick Macklem * nfs link service 17049ec7b004SRick Macklem */ 17059ec7b004SRick Macklem APPLESTATIC int 17069ec7b004SRick Macklem nfsrvd_link(struct nfsrv_descript *nd, int isdgram, 1707af444b18SEdward Tomasz Napierala vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp) 17089ec7b004SRick Macklem { 17099ec7b004SRick Macklem struct nameidata named; 17109ec7b004SRick Macklem u_int32_t *tl; 17119ec7b004SRick Macklem int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1; 17129ec7b004SRick Macklem vnode_t dirp = NULL, dp = NULL; 17139ec7b004SRick Macklem struct nfsvattr dirfor, diraft, at; 17149ec7b004SRick Macklem struct nfsexstuff tnes; 17159ec7b004SRick Macklem struct nfsrvfh dfh; 17169ec7b004SRick Macklem char *bufp; 17179ec7b004SRick Macklem u_long *hashp; 1718af444b18SEdward Tomasz Napierala struct thread *p = curthread; 17199ec7b004SRick Macklem 17209ec7b004SRick Macklem if (nd->nd_repstat) { 17219ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 17229ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1723a9285ae5SZack Kirsch goto out; 17249ec7b004SRick Macklem } 1725c383087cSZack Kirsch NFSVOPUNLOCK(vp, 0); 17269ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) { 17279ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) 17289ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 17299ec7b004SRick Macklem else 17309ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 17319ec7b004SRick Macklem if (tovp) 17329ec7b004SRick Macklem vrele(tovp); 17339ec7b004SRick Macklem } 17349ec7b004SRick Macklem if (!nd->nd_repstat) { 17359ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 17369ec7b004SRick Macklem dp = tovp; 17379ec7b004SRick Macklem tnes = *toexp; 17389ec7b004SRick Macklem } else { 17399ec7b004SRick Macklem error = nfsrv_mtofh(nd, &dfh); 17409ec7b004SRick Macklem if (error) { 17419ec7b004SRick Macklem vrele(vp); 17429ec7b004SRick Macklem /* tovp is always NULL unless NFSv4 */ 1743a9285ae5SZack Kirsch goto out; 17449ec7b004SRick Macklem } 17455edc9102SEdward Tomasz Napierala nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0); 17469ec7b004SRick Macklem if (dp) 1747c383087cSZack Kirsch NFSVOPUNLOCK(dp, 0); 17489ec7b004SRick Macklem } 17499ec7b004SRick Macklem } 1750f61786cbSRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 17516c21f6edSKonstantin Belousov LOCKPARENT | SAVENAME | NOCACHE); 17529ec7b004SRick Macklem if (!nd->nd_repstat) { 17539ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 17549ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 17559ec7b004SRick Macklem if (error) { 17569ec7b004SRick Macklem vrele(vp); 17578974bc2fSRick Macklem if (dp) 17589ec7b004SRick Macklem vrele(dp); 17599ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1760a9285ae5SZack Kirsch goto out; 17619ec7b004SRick Macklem } 17629ec7b004SRick Macklem if (!nd->nd_repstat) { 17639ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes, 17649ec7b004SRick Macklem p, &dirp); 17659ec7b004SRick Macklem } else { 17669ec7b004SRick Macklem if (dp) 17679ec7b004SRick Macklem vrele(dp); 17689ec7b004SRick Macklem nfsvno_relpathbuf(&named); 17699ec7b004SRick Macklem } 17709ec7b004SRick Macklem } 17719ec7b004SRick Macklem if (dirp) { 17729ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 17739ec7b004SRick Macklem vrele(dirp); 17749ec7b004SRick Macklem dirp = NULL; 17759ec7b004SRick Macklem } else { 177690d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 177790d2dfabSRick Macklem NULL); 17789ec7b004SRick Macklem } 17799ec7b004SRick Macklem } 17809ec7b004SRick Macklem if (!nd->nd_repstat) 17819ec7b004SRick Macklem nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp); 17829ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 178390d2dfabSRick Macklem getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL); 17849ec7b004SRick Macklem if (dirp) { 178590d2dfabSRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 17869ec7b004SRick Macklem vrele(dirp); 17879ec7b004SRick Macklem } 17889ec7b004SRick Macklem vrele(vp); 17899ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 17909ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 17919ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 17929ec7b004SRick Macklem } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 17939ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 17949ec7b004SRick Macklem *tl++ = newnfs_false; 17959ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 17969ec7b004SRick Macklem tl += 2; 17979ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 17989ec7b004SRick Macklem } 1799a9285ae5SZack Kirsch 1800a9285ae5SZack Kirsch out: 1801a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1802a9285ae5SZack Kirsch return (error); 18039ec7b004SRick Macklem } 18049ec7b004SRick Macklem 18059ec7b004SRick Macklem /* 18069ec7b004SRick Macklem * nfs symbolic link service 18079ec7b004SRick Macklem */ 18089ec7b004SRick Macklem APPLESTATIC int 18099ec7b004SRick Macklem nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram, 1810af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 18119ec7b004SRick Macklem { 18129ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 18139ec7b004SRick Macklem struct nameidata named; 1814a9285ae5SZack Kirsch int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 18159ec7b004SRick Macklem vnode_t dirp = NULL; 18169ec7b004SRick Macklem char *bufp, *pathcp = NULL; 18179ec7b004SRick Macklem u_long *hashp; 1818af444b18SEdward Tomasz Napierala struct thread *p = curthread; 18199ec7b004SRick Macklem 18209ec7b004SRick Macklem if (nd->nd_repstat) { 18219ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1822a9285ae5SZack Kirsch goto out; 18239ec7b004SRick Macklem } 18249ec7b004SRick Macklem if (vpp) 18259ec7b004SRick Macklem *vpp = NULL; 18269ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 18279ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 18286c21f6edSKonstantin Belousov LOCKPARENT | SAVESTART | NOCACHE); 18299ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 18309ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 18319ec7b004SRick Macklem if (!error && !nd->nd_repstat) 18329ec7b004SRick Macklem error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen); 18339ec7b004SRick Macklem if (error) { 18349ec7b004SRick Macklem vrele(dp); 18359ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1836a9285ae5SZack Kirsch goto out; 18379ec7b004SRick Macklem } 18389ec7b004SRick Macklem if (!nd->nd_repstat) { 18399ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 18409ec7b004SRick Macklem } else { 18419ec7b004SRick Macklem vrele(dp); 18429ec7b004SRick Macklem nfsvno_relpathbuf(&named); 18439ec7b004SRick Macklem } 18449ec7b004SRick Macklem if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 18459ec7b004SRick Macklem vrele(dirp); 18469ec7b004SRick Macklem dirp = NULL; 18479ec7b004SRick Macklem } 18489ec7b004SRick Macklem 18499ec7b004SRick Macklem /* 18509ec7b004SRick Macklem * And call nfsrvd_symlinksub() to do the common code. It will 18519ec7b004SRick Macklem * return EBADRPC upon a parsing error, 0 otherwise. 18529ec7b004SRick Macklem */ 18539ec7b004SRick Macklem if (!nd->nd_repstat) { 18549ec7b004SRick Macklem if (dirp != NULL) 185590d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 185690d2dfabSRick Macklem NULL); 18579ec7b004SRick Macklem nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 18589ec7b004SRick Macklem &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp, 18599ec7b004SRick Macklem pathcp, pathlen); 18609ec7b004SRick Macklem } else if (dirp != NULL) { 186190d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); 18629ec7b004SRick Macklem vrele(dirp); 18639ec7b004SRick Macklem } 18649ec7b004SRick Macklem if (pathcp) 1865222daa42SConrad Meyer free(pathcp, M_TEMP); 18669ec7b004SRick Macklem 18679ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 18689ec7b004SRick Macklem if (!nd->nd_repstat) { 18699ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 18709ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 18719ec7b004SRick Macklem } 18729ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 18739ec7b004SRick Macklem } 1874a9285ae5SZack Kirsch 1875a9285ae5SZack Kirsch out: 1876a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1877a9285ae5SZack Kirsch return (error); 18789ec7b004SRick Macklem } 18799ec7b004SRick Macklem 18809ec7b004SRick Macklem /* 18819ec7b004SRick Macklem * Common code for creating a symbolic link. 18829ec7b004SRick Macklem */ 18839ec7b004SRick Macklem static void 18849ec7b004SRick Macklem nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 18859ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 18869ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 18879ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, 18889ec7b004SRick Macklem NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 18899ec7b004SRick Macklem int pathlen) 18909ec7b004SRick Macklem { 18919ec7b004SRick Macklem u_int32_t *tl; 18929ec7b004SRick Macklem 18939ec7b004SRick Macklem nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen, 18949ec7b004SRick Macklem !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp); 18959ec7b004SRick Macklem if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) { 18969ec7b004SRick Macklem nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp); 18979ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 18989ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p); 18999ec7b004SRick Macklem if (!nd->nd_repstat) 19009ec7b004SRick Macklem nd->nd_repstat = nfsvno_getattr(ndp->ni_vp, 190190d2dfabSRick Macklem nvap, nd, p, 1, NULL); 19029ec7b004SRick Macklem } 190381f78d99SRick Macklem if (vpp != NULL && nd->nd_repstat == 0) { 1904a9989634SZack Kirsch NFSVOPUNLOCK(ndp->ni_vp, 0); 19059ec7b004SRick Macklem *vpp = ndp->ni_vp; 190681f78d99SRick Macklem } else 19079ec7b004SRick Macklem vput(ndp->ni_vp); 19089ec7b004SRick Macklem } 19099ec7b004SRick Macklem if (dirp) { 191090d2dfabSRick Macklem *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL); 19119ec7b004SRick Macklem vrele(dirp); 19129ec7b004SRick Macklem } 19139ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 19149ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 19159ec7b004SRick Macklem *tl++ = newnfs_false; 19169ec7b004SRick Macklem txdr_hyper(dirforp->na_filerev, tl); 19179ec7b004SRick Macklem tl += 2; 19189ec7b004SRick Macklem txdr_hyper(diraftp->na_filerev, tl); 19199ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, attrbitp); 19209ec7b004SRick Macklem } 1921a9285ae5SZack Kirsch 1922a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 19239ec7b004SRick Macklem } 19249ec7b004SRick Macklem 19259ec7b004SRick Macklem /* 19269ec7b004SRick Macklem * nfs mkdir service 19279ec7b004SRick Macklem */ 19289ec7b004SRick Macklem APPLESTATIC int 19299ec7b004SRick Macklem nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram, 1930af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 19319ec7b004SRick Macklem { 19329ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 19339ec7b004SRick Macklem struct nameidata named; 19349ec7b004SRick Macklem u_int32_t *tl; 1935a9285ae5SZack Kirsch int error = 0, dirfor_ret = 1, diraft_ret = 1; 19369ec7b004SRick Macklem vnode_t dirp = NULL; 19379ec7b004SRick Macklem char *bufp; 19389ec7b004SRick Macklem u_long *hashp; 1939af444b18SEdward Tomasz Napierala struct thread *p = curthread; 19409ec7b004SRick Macklem 19419ec7b004SRick Macklem if (nd->nd_repstat) { 19429ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1943a9285ae5SZack Kirsch goto out; 19449ec7b004SRick Macklem } 1945f61786cbSRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 19466c21f6edSKonstantin Belousov LOCKPARENT | SAVENAME | NOCACHE); 19479ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 19489ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1949a9285ae5SZack Kirsch if (error) 1950a9285ae5SZack Kirsch goto nfsmout; 19519ec7b004SRick Macklem if (!nd->nd_repstat) { 19529ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 19539ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 1954d8a5961fSMarcelo Araujo error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p); 1955a9285ae5SZack Kirsch if (error) 1956a9285ae5SZack Kirsch goto nfsmout; 19579ec7b004SRick Macklem } else { 19589ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 19599ec7b004SRick Macklem nva.na_mode = nfstov_mode(*tl++); 19609ec7b004SRick Macklem } 19619ec7b004SRick Macklem } 19629ec7b004SRick Macklem if (!nd->nd_repstat) { 19639ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 19649ec7b004SRick Macklem } else { 19659ec7b004SRick Macklem vrele(dp); 19669ec7b004SRick Macklem nfsvno_relpathbuf(&named); 19679ec7b004SRick Macklem } 19689ec7b004SRick Macklem if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 19699ec7b004SRick Macklem vrele(dirp); 19709ec7b004SRick Macklem dirp = NULL; 19719ec7b004SRick Macklem } 19729ec7b004SRick Macklem if (nd->nd_repstat) { 19739ec7b004SRick Macklem if (dirp != NULL) { 197490d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 197590d2dfabSRick Macklem NULL); 19769ec7b004SRick Macklem vrele(dirp); 19779ec7b004SRick Macklem } 19789ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 19799ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 19809ec7b004SRick Macklem &diraft); 1981a9285ae5SZack Kirsch goto out; 19829ec7b004SRick Macklem } 19839ec7b004SRick Macklem if (dirp != NULL) 198490d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); 19859ec7b004SRick Macklem 19869ec7b004SRick Macklem /* 19879ec7b004SRick Macklem * Call nfsrvd_mkdirsub() for the code common to V4 as well. 19889ec7b004SRick Macklem */ 19899ec7b004SRick Macklem nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft, 19909ec7b004SRick Macklem &diraft_ret, NULL, NULL, p, exp); 19919ec7b004SRick Macklem 19929ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 19939ec7b004SRick Macklem if (!nd->nd_repstat) { 19949ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 19959ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 19969ec7b004SRick Macklem } 19979ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 19989ec7b004SRick Macklem } else if (!nd->nd_repstat) { 19999ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 20009ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 20019ec7b004SRick Macklem } 2002a9285ae5SZack Kirsch 2003a9285ae5SZack Kirsch out: 2004a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 20059ec7b004SRick Macklem return (0); 20069ec7b004SRick Macklem nfsmout: 20079ec7b004SRick Macklem vrele(dp); 20089ec7b004SRick Macklem nfsvno_relpathbuf(&named); 2009a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 20109ec7b004SRick Macklem return (error); 20119ec7b004SRick Macklem } 20129ec7b004SRick Macklem 20139ec7b004SRick Macklem /* 20149ec7b004SRick Macklem * Code common to mkdir for V2,3 and 4. 20159ec7b004SRick Macklem */ 20169ec7b004SRick Macklem static void 20179ec7b004SRick Macklem nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 20189ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 20199ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 20209ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 20219ec7b004SRick Macklem NFSPROC_T *p, struct nfsexstuff *exp) 20229ec7b004SRick Macklem { 20239ec7b004SRick Macklem vnode_t vp; 20249ec7b004SRick Macklem u_int32_t *tl; 20259ec7b004SRick Macklem 20269ec7b004SRick Macklem NFSVNO_SETATTRVAL(nvap, type, VDIR); 20279ec7b004SRick Macklem nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid, 20289ec7b004SRick Macklem nd->nd_cred, p, exp); 20299ec7b004SRick Macklem if (!nd->nd_repstat) { 20309ec7b004SRick Macklem vp = ndp->ni_vp; 20319ec7b004SRick Macklem nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp); 20329ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 20339ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 203490d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1, 203590d2dfabSRick Macklem NULL); 20369ec7b004SRick Macklem if (vpp && !nd->nd_repstat) { 2037c383087cSZack Kirsch NFSVOPUNLOCK(vp, 0); 20389ec7b004SRick Macklem *vpp = vp; 20399ec7b004SRick Macklem } else { 20409ec7b004SRick Macklem vput(vp); 20419ec7b004SRick Macklem } 20429ec7b004SRick Macklem } 20439ec7b004SRick Macklem if (dirp) { 204490d2dfabSRick Macklem *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL); 20459ec7b004SRick Macklem vrele(dirp); 20469ec7b004SRick Macklem } 20479ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 20489ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 20499ec7b004SRick Macklem *tl++ = newnfs_false; 20509ec7b004SRick Macklem txdr_hyper(dirforp->na_filerev, tl); 20519ec7b004SRick Macklem tl += 2; 20529ec7b004SRick Macklem txdr_hyper(diraftp->na_filerev, tl); 20539ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, attrbitp); 20549ec7b004SRick Macklem } 2055a9285ae5SZack Kirsch 2056a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 20579ec7b004SRick Macklem } 20589ec7b004SRick Macklem 20599ec7b004SRick Macklem /* 20609ec7b004SRick Macklem * nfs commit service 20619ec7b004SRick Macklem */ 20629ec7b004SRick Macklem APPLESTATIC int 20639ec7b004SRick Macklem nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram, 2064af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 20659ec7b004SRick Macklem { 20669ec7b004SRick Macklem struct nfsvattr bfor, aft; 20679ec7b004SRick Macklem u_int32_t *tl; 20689ec7b004SRick Macklem int error = 0, for_ret = 1, aft_ret = 1, cnt; 20699ec7b004SRick Macklem u_int64_t off; 2070af444b18SEdward Tomasz Napierala struct thread *p = curthread; 20719ec7b004SRick Macklem 20729ec7b004SRick Macklem if (nd->nd_repstat) { 20739ec7b004SRick Macklem nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 2074a9285ae5SZack Kirsch goto out; 20759ec7b004SRick Macklem } 2076d8a5961fSMarcelo Araujo 2077d8a5961fSMarcelo Araujo /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */ 2078d8a5961fSMarcelo Araujo if (vp->v_type != VREG) { 2079d8a5961fSMarcelo Araujo if (nd->nd_flag & ND_NFSV3) 2080d8a5961fSMarcelo Araujo error = NFSERR_NOTSUPP; 2081d8a5961fSMarcelo Araujo else 2082d8a5961fSMarcelo Araujo error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL; 2083d8a5961fSMarcelo Araujo goto nfsmout; 2084d8a5961fSMarcelo Araujo } 20859ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2086d8a5961fSMarcelo Araujo 20879ec7b004SRick Macklem /* 20889ec7b004SRick Macklem * XXX At this time VOP_FSYNC() does not accept offset and byte 20899ec7b004SRick Macklem * count parameters, so these arguments are useless (someday maybe). 20909ec7b004SRick Macklem */ 20919ec7b004SRick Macklem off = fxdr_hyper(tl); 20929ec7b004SRick Macklem tl += 2; 20939ec7b004SRick Macklem cnt = fxdr_unsigned(int, *tl); 20949ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 209590d2dfabSRick Macklem for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL); 20969ec7b004SRick Macklem nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p); 20979ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 209890d2dfabSRick Macklem aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL); 20999ec7b004SRick Macklem nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 21009ec7b004SRick Macklem } 21019ec7b004SRick Macklem vput(vp); 21029ec7b004SRick Macklem if (!nd->nd_repstat) { 21039ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 21049ec7b004SRick Macklem *tl++ = txdr_unsigned(nfsboottime.tv_sec); 21059ec7b004SRick Macklem *tl = txdr_unsigned(nfsboottime.tv_usec); 21069ec7b004SRick Macklem } 2107a9285ae5SZack Kirsch 2108a9285ae5SZack Kirsch out: 2109a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 21109ec7b004SRick Macklem return (0); 21119ec7b004SRick Macklem nfsmout: 21129ec7b004SRick Macklem vput(vp); 2113a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 21149ec7b004SRick Macklem return (error); 21159ec7b004SRick Macklem } 21169ec7b004SRick Macklem 21179ec7b004SRick Macklem /* 21189ec7b004SRick Macklem * nfs statfs service 21199ec7b004SRick Macklem */ 21209ec7b004SRick Macklem APPLESTATIC int 21219ec7b004SRick Macklem nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram, 2122af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 21239ec7b004SRick Macklem { 21249ec7b004SRick Macklem struct statfs *sf; 21259ec7b004SRick Macklem u_int32_t *tl; 21269ec7b004SRick Macklem int getret = 1; 21279ec7b004SRick Macklem struct nfsvattr at; 21289ec7b004SRick Macklem u_quad_t tval; 2129af444b18SEdward Tomasz Napierala struct thread *p = curthread; 21309ec7b004SRick Macklem 21312f304845SKonstantin Belousov sf = NULL; 21329ec7b004SRick Macklem if (nd->nd_repstat) { 21339ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 2134a9285ae5SZack Kirsch goto out; 21359ec7b004SRick Macklem } 21362f304845SKonstantin Belousov sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 2137dfd233edSAttilio Rao nd->nd_repstat = nfsvno_statfs(vp, sf); 213890d2dfabSRick Macklem getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); 21399ec7b004SRick Macklem vput(vp); 21409ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 21419ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 21429ec7b004SRick Macklem if (nd->nd_repstat) 2143a9285ae5SZack Kirsch goto out; 21449ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 21459ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS); 21469ec7b004SRick Macklem *tl++ = txdr_unsigned(NFS_V2MAXDATA); 21479ec7b004SRick Macklem *tl++ = txdr_unsigned(sf->f_bsize); 21489ec7b004SRick Macklem *tl++ = txdr_unsigned(sf->f_blocks); 21499ec7b004SRick Macklem *tl++ = txdr_unsigned(sf->f_bfree); 21509ec7b004SRick Macklem *tl = txdr_unsigned(sf->f_bavail); 21519ec7b004SRick Macklem } else { 21529ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS); 21539ec7b004SRick Macklem tval = (u_quad_t)sf->f_blocks; 21549ec7b004SRick Macklem tval *= (u_quad_t)sf->f_bsize; 21559ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 21569ec7b004SRick Macklem tval = (u_quad_t)sf->f_bfree; 21579ec7b004SRick Macklem tval *= (u_quad_t)sf->f_bsize; 21589ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 21599ec7b004SRick Macklem tval = (u_quad_t)sf->f_bavail; 21609ec7b004SRick Macklem tval *= (u_quad_t)sf->f_bsize; 21619ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 21629ec7b004SRick Macklem tval = (u_quad_t)sf->f_files; 21639ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 21649ec7b004SRick Macklem tval = (u_quad_t)sf->f_ffree; 21659ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 21669ec7b004SRick Macklem tval = (u_quad_t)sf->f_ffree; 21679ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 21689ec7b004SRick Macklem *tl = 0; 21699ec7b004SRick Macklem } 2170a9285ae5SZack Kirsch 2171a9285ae5SZack Kirsch out: 21722f304845SKonstantin Belousov free(sf, M_STATFS); 2173a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 21749ec7b004SRick Macklem return (0); 21759ec7b004SRick Macklem } 21769ec7b004SRick Macklem 21779ec7b004SRick Macklem /* 21789ec7b004SRick Macklem * nfs fsinfo service 21799ec7b004SRick Macklem */ 21809ec7b004SRick Macklem APPLESTATIC int 21819ec7b004SRick Macklem nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram, 2182af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 21839ec7b004SRick Macklem { 21849ec7b004SRick Macklem u_int32_t *tl; 21859ec7b004SRick Macklem struct nfsfsinfo fs; 21869ec7b004SRick Macklem int getret = 1; 21879ec7b004SRick Macklem struct nfsvattr at; 2188af444b18SEdward Tomasz Napierala struct thread *p = curthread; 21899ec7b004SRick Macklem 21909ec7b004SRick Macklem if (nd->nd_repstat) { 21919ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 2192a9285ae5SZack Kirsch goto out; 21939ec7b004SRick Macklem } 219490d2dfabSRick Macklem getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); 21959ec7b004SRick Macklem nfsvno_getfs(&fs, isdgram); 21969ec7b004SRick Macklem vput(vp); 21979ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 21989ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO); 21999ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_rtmax); 22009ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_rtpref); 22019ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_rtmult); 22029ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_wtmax); 22039ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_wtpref); 22049ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_wtmult); 22059ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_dtpref); 22069ec7b004SRick Macklem txdr_hyper(fs.fs_maxfilesize, tl); 22079ec7b004SRick Macklem tl += 2; 22089ec7b004SRick Macklem txdr_nfsv3time(&fs.fs_timedelta, tl); 22099ec7b004SRick Macklem tl += 2; 22109ec7b004SRick Macklem *tl = txdr_unsigned(fs.fs_properties); 2211a9285ae5SZack Kirsch 2212a9285ae5SZack Kirsch out: 2213a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 22149ec7b004SRick Macklem return (0); 22159ec7b004SRick Macklem } 22169ec7b004SRick Macklem 22179ec7b004SRick Macklem /* 22189ec7b004SRick Macklem * nfs pathconf service 22199ec7b004SRick Macklem */ 22209ec7b004SRick Macklem APPLESTATIC int 22219ec7b004SRick Macklem nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram, 2222af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 22239ec7b004SRick Macklem { 22249ec7b004SRick Macklem struct nfsv3_pathconf *pc; 22259ec7b004SRick Macklem int getret = 1; 2226b1288166SJohn Baldwin long linkmax, namemax, chownres, notrunc; 22279ec7b004SRick Macklem struct nfsvattr at; 2228af444b18SEdward Tomasz Napierala struct thread *p = curthread; 22299ec7b004SRick Macklem 22309ec7b004SRick Macklem if (nd->nd_repstat) { 22319ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 2232a9285ae5SZack Kirsch goto out; 22339ec7b004SRick Macklem } 22349ec7b004SRick Macklem nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax, 22359ec7b004SRick Macklem nd->nd_cred, p); 22369ec7b004SRick Macklem if (!nd->nd_repstat) 22379ec7b004SRick Macklem nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax, 22389ec7b004SRick Macklem nd->nd_cred, p); 22399ec7b004SRick Macklem if (!nd->nd_repstat) 22409ec7b004SRick Macklem nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED, 22419ec7b004SRick Macklem &chownres, nd->nd_cred, p); 22429ec7b004SRick Macklem if (!nd->nd_repstat) 22439ec7b004SRick Macklem nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc, 22449ec7b004SRick Macklem nd->nd_cred, p); 224590d2dfabSRick Macklem getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); 22469ec7b004SRick Macklem vput(vp); 22479ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 22489ec7b004SRick Macklem if (!nd->nd_repstat) { 22499ec7b004SRick Macklem NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); 22509ec7b004SRick Macklem pc->pc_linkmax = txdr_unsigned(linkmax); 22519ec7b004SRick Macklem pc->pc_namemax = txdr_unsigned(namemax); 22529ec7b004SRick Macklem pc->pc_notrunc = txdr_unsigned(notrunc); 22539ec7b004SRick Macklem pc->pc_chownrestricted = txdr_unsigned(chownres); 22549ec7b004SRick Macklem 22559ec7b004SRick Macklem /* 22569ec7b004SRick Macklem * These should probably be supported by VOP_PATHCONF(), but 22579ec7b004SRick Macklem * until msdosfs is exportable (why would you want to?), the 22589ec7b004SRick Macklem * Unix defaults should be ok. 22599ec7b004SRick Macklem */ 22609ec7b004SRick Macklem pc->pc_caseinsensitive = newnfs_false; 22619ec7b004SRick Macklem pc->pc_casepreserving = newnfs_true; 22629ec7b004SRick Macklem } 2263a9285ae5SZack Kirsch 2264a9285ae5SZack Kirsch out: 2265a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 22669ec7b004SRick Macklem return (0); 22679ec7b004SRick Macklem } 22689ec7b004SRick Macklem 22699ec7b004SRick Macklem /* 22709ec7b004SRick Macklem * nfsv4 lock service 22719ec7b004SRick Macklem */ 22729ec7b004SRick Macklem APPLESTATIC int 22739ec7b004SRick Macklem nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram, 2274af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 22759ec7b004SRick Macklem { 22769ec7b004SRick Macklem u_int32_t *tl; 22779ec7b004SRick Macklem int i; 22789ec7b004SRick Macklem struct nfsstate *stp = NULL; 22799ec7b004SRick Macklem struct nfslock *lop; 22809ec7b004SRick Macklem struct nfslockconflict cf; 22819ec7b004SRick Macklem int error = 0; 22829ec7b004SRick Macklem u_short flags = NFSLCK_LOCK, lflags; 22839ec7b004SRick Macklem u_int64_t offset, len; 22849ec7b004SRick Macklem nfsv4stateid_t stateid; 22859ec7b004SRick Macklem nfsquad_t clientid; 2286af444b18SEdward Tomasz Napierala struct thread *p = curthread; 22879ec7b004SRick Macklem 22889ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 22899ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 22909ec7b004SRick Macklem switch (i) { 22919ec7b004SRick Macklem case NFSV4LOCKT_READW: 22929ec7b004SRick Macklem flags |= NFSLCK_BLOCKING; 22939ec7b004SRick Macklem case NFSV4LOCKT_READ: 22949ec7b004SRick Macklem lflags = NFSLCK_READ; 22959ec7b004SRick Macklem break; 22969ec7b004SRick Macklem case NFSV4LOCKT_WRITEW: 22979ec7b004SRick Macklem flags |= NFSLCK_BLOCKING; 22989ec7b004SRick Macklem case NFSV4LOCKT_WRITE: 22999ec7b004SRick Macklem lflags = NFSLCK_WRITE; 23009ec7b004SRick Macklem break; 23019ec7b004SRick Macklem default: 23029ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 23039ec7b004SRick Macklem goto nfsmout; 230474b8d63dSPedro F. Giffuni } 23059ec7b004SRick Macklem if (*tl++ == newnfs_true) 23069ec7b004SRick Macklem flags |= NFSLCK_RECLAIM; 23079ec7b004SRick Macklem offset = fxdr_hyper(tl); 23089ec7b004SRick Macklem tl += 2; 23099ec7b004SRick Macklem len = fxdr_hyper(tl); 23109ec7b004SRick Macklem tl += 2; 23119ec7b004SRick Macklem if (*tl == newnfs_true) 23129ec7b004SRick Macklem flags |= NFSLCK_OPENTOLOCK; 23139ec7b004SRick Macklem if (flags & NFSLCK_OPENTOLOCK) { 23149ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID); 23159ec7b004SRick Macklem i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED))); 23162a45247cSRick Macklem if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 23172a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 23182a45247cSRick Macklem goto nfsmout; 23192a45247cSRick Macklem } 2320222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate) + i, 23219ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 23229ec7b004SRick Macklem stp->ls_ownerlen = i; 23239ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 23249ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(int, *tl++); 23259ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 23269ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 23279ec7b004SRick Macklem NFSX_STATEIDOTHER); 23289ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 232990d2dfabSRick Macklem 233090d2dfabSRick Macklem /* 233190d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set 233290d2dfabSRick Macklem * the stateid to the current stateid, if it is set. 233390d2dfabSRick Macklem */ 233490d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 && 233590d2dfabSRick Macklem stp->ls_stateid.seqid == 1 && 233690d2dfabSRick Macklem stp->ls_stateid.other[0] == 0 && 233790d2dfabSRick Macklem stp->ls_stateid.other[1] == 0 && 233890d2dfabSRick Macklem stp->ls_stateid.other[2] == 0) { 233990d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 234090d2dfabSRick Macklem stp->ls_stateid = nd->nd_curstateid; 234190d2dfabSRick Macklem stp->ls_stateid.seqid = 0; 234290d2dfabSRick Macklem } else { 234390d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 234490d2dfabSRick Macklem goto nfsmout; 234590d2dfabSRick Macklem } 234690d2dfabSRick Macklem } 234790d2dfabSRick Macklem 23489ec7b004SRick Macklem stp->ls_opentolockseq = fxdr_unsigned(int, *tl++); 23499ec7b004SRick Macklem clientid.lval[0] = *tl++; 23509ec7b004SRick Macklem clientid.lval[1] = *tl++; 2351c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2352c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2353c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2354c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2355c59e4cc3SRick Macklem printf("EEK3 multiple clids\n"); 23569ec7b004SRick Macklem } else { 2357c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2358c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 23599ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 23609ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 23619ec7b004SRick Macklem } 23629ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 23639ec7b004SRick Macklem if (error) 23649ec7b004SRick Macklem goto nfsmout; 23659ec7b004SRick Macklem } else { 23669ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 2367222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate), 23689ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 23699ec7b004SRick Macklem stp->ls_ownerlen = 0; 23709ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 23719ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 23729ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 23739ec7b004SRick Macklem NFSX_STATEIDOTHER); 23749ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 237590d2dfabSRick Macklem 237690d2dfabSRick Macklem /* 237790d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set 237890d2dfabSRick Macklem * the stateid to the current stateid, if it is set. 237990d2dfabSRick Macklem */ 238090d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 && 238190d2dfabSRick Macklem stp->ls_stateid.seqid == 1 && 238290d2dfabSRick Macklem stp->ls_stateid.other[0] == 0 && 238390d2dfabSRick Macklem stp->ls_stateid.other[1] == 0 && 238490d2dfabSRick Macklem stp->ls_stateid.other[2] == 0) { 238590d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 238690d2dfabSRick Macklem stp->ls_stateid = nd->nd_curstateid; 238790d2dfabSRick Macklem stp->ls_stateid.seqid = 0; 238890d2dfabSRick Macklem } else { 238990d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 239090d2dfabSRick Macklem goto nfsmout; 239190d2dfabSRick Macklem } 239290d2dfabSRick Macklem } 239390d2dfabSRick Macklem 23949ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(int, *tl); 23959ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 23969ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 2397c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2398c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2399c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2400c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2401c59e4cc3SRick Macklem printf("EEK4 multiple clids\n"); 24029ec7b004SRick Macklem } else { 2403c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2404c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 24059ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 24069ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 24079ec7b004SRick Macklem } 24089ec7b004SRick Macklem } 2409222daa42SConrad Meyer lop = malloc(sizeof (struct nfslock), 24109ec7b004SRick Macklem M_NFSDLOCK, M_WAITOK); 24119ec7b004SRick Macklem lop->lo_first = offset; 24129ec7b004SRick Macklem if (len == NFS64BITSSET) { 24139ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 24149ec7b004SRick Macklem } else { 24159ec7b004SRick Macklem lop->lo_end = offset + len; 24169ec7b004SRick Macklem if (lop->lo_end <= lop->lo_first) 24179ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 24189ec7b004SRick Macklem } 24199ec7b004SRick Macklem lop->lo_flags = lflags; 24209ec7b004SRick Macklem stp->ls_flags = flags; 24219ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 24229ec7b004SRick Macklem 24239ec7b004SRick Macklem /* 24249ec7b004SRick Macklem * Do basic access checking. 24259ec7b004SRick Macklem */ 24269ec7b004SRick Macklem if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 24279ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 24289ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 24299ec7b004SRick Macklem else 24309ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 24319ec7b004SRick Macklem } 24329ec7b004SRick Macklem if (!nd->nd_repstat) { 24339ec7b004SRick Macklem if (lflags & NFSLCK_WRITE) { 24348da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 24359ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 24368da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 24379ec7b004SRick Macklem } else { 24388da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, 24399ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 24408da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 24419ec7b004SRick Macklem if (nd->nd_repstat) 24428da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 24439ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 24448da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 24459ec7b004SRick Macklem } 24469ec7b004SRick Macklem } 24479ec7b004SRick Macklem 24489ec7b004SRick Macklem /* 24499ec7b004SRick Macklem * We call nfsrv_lockctrl() even if nd_repstat set, so that the 24509ec7b004SRick Macklem * seqid# gets updated. nfsrv_lockctrl() will return the value 24519ec7b004SRick Macklem * of nd_repstat, if it gets that far. 24529ec7b004SRick Macklem */ 24539ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 24549ec7b004SRick Macklem &stateid, exp, nd, p); 24559ec7b004SRick Macklem if (lop) 2456222daa42SConrad Meyer free(lop, M_NFSDLOCK); 24579ec7b004SRick Macklem if (stp) 2458222daa42SConrad Meyer free(stp, M_NFSDSTATE); 24599ec7b004SRick Macklem if (!nd->nd_repstat) { 246090d2dfabSRick Macklem /* For NFSv4.1, set the Current StateID. */ 246190d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 246290d2dfabSRick Macklem nd->nd_curstateid = stateid; 246390d2dfabSRick Macklem nd->nd_flag |= ND_CURSTATEID; 246490d2dfabSRick Macklem } 24659ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 24669ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 24679ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 24689ec7b004SRick Macklem } else if (nd->nd_repstat == NFSERR_DENIED) { 24699ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 24709ec7b004SRick Macklem txdr_hyper(cf.cl_first, tl); 24719ec7b004SRick Macklem tl += 2; 24729ec7b004SRick Macklem if (cf.cl_end == NFS64BITSSET) 24739ec7b004SRick Macklem len = NFS64BITSSET; 24749ec7b004SRick Macklem else 24759ec7b004SRick Macklem len = cf.cl_end - cf.cl_first; 24769ec7b004SRick Macklem txdr_hyper(len, tl); 24779ec7b004SRick Macklem tl += 2; 24789ec7b004SRick Macklem if (cf.cl_flags == NFSLCK_WRITE) 24799ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 24809ec7b004SRick Macklem else 24819ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 24829ec7b004SRick Macklem *tl++ = stateid.other[0]; 24839ec7b004SRick Macklem *tl = stateid.other[1]; 24849ec7b004SRick Macklem (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 24859ec7b004SRick Macklem } 24869ec7b004SRick Macklem vput(vp); 2487a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 24889ec7b004SRick Macklem return (0); 24899ec7b004SRick Macklem nfsmout: 24909ec7b004SRick Macklem vput(vp); 24919ec7b004SRick Macklem if (stp) 2492222daa42SConrad Meyer free(stp, M_NFSDSTATE); 2493a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 24949ec7b004SRick Macklem return (error); 24959ec7b004SRick Macklem } 24969ec7b004SRick Macklem 24979ec7b004SRick Macklem /* 24989ec7b004SRick Macklem * nfsv4 lock test service 24999ec7b004SRick Macklem */ 25009ec7b004SRick Macklem APPLESTATIC int 25019ec7b004SRick Macklem nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram, 2502af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 25039ec7b004SRick Macklem { 25049ec7b004SRick Macklem u_int32_t *tl; 25059ec7b004SRick Macklem int i; 25069ec7b004SRick Macklem struct nfsstate *stp = NULL; 25079ec7b004SRick Macklem struct nfslock lo, *lop = &lo; 25089ec7b004SRick Macklem struct nfslockconflict cf; 25099ec7b004SRick Macklem int error = 0; 25109ec7b004SRick Macklem nfsv4stateid_t stateid; 25119ec7b004SRick Macklem nfsquad_t clientid; 25129ec7b004SRick Macklem u_int64_t len; 2513af444b18SEdward Tomasz Napierala struct thread *p = curthread; 25149ec7b004SRick Macklem 25159ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 25169ec7b004SRick Macklem i = fxdr_unsigned(int, *(tl + 7)); 25172a45247cSRick Macklem if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 25182a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 25192a45247cSRick Macklem goto nfsmout; 25202a45247cSRick Macklem } 2521222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate) + i, 25229ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 25239ec7b004SRick Macklem stp->ls_ownerlen = i; 25249ec7b004SRick Macklem stp->ls_op = NULL; 25259ec7b004SRick Macklem stp->ls_flags = NFSLCK_TEST; 25269ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 25279ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 25289ec7b004SRick Macklem switch (i) { 25299ec7b004SRick Macklem case NFSV4LOCKT_READW: 25309ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 25319ec7b004SRick Macklem case NFSV4LOCKT_READ: 25329ec7b004SRick Macklem lo.lo_flags = NFSLCK_READ; 25339ec7b004SRick Macklem break; 25349ec7b004SRick Macklem case NFSV4LOCKT_WRITEW: 25359ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 25369ec7b004SRick Macklem case NFSV4LOCKT_WRITE: 25379ec7b004SRick Macklem lo.lo_flags = NFSLCK_WRITE; 25389ec7b004SRick Macklem break; 25399ec7b004SRick Macklem default: 25409ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 25419ec7b004SRick Macklem goto nfsmout; 254274b8d63dSPedro F. Giffuni } 25439ec7b004SRick Macklem lo.lo_first = fxdr_hyper(tl); 25449ec7b004SRick Macklem tl += 2; 25459ec7b004SRick Macklem len = fxdr_hyper(tl); 25469ec7b004SRick Macklem if (len == NFS64BITSSET) { 25479ec7b004SRick Macklem lo.lo_end = NFS64BITSSET; 25489ec7b004SRick Macklem } else { 25499ec7b004SRick Macklem lo.lo_end = lo.lo_first + len; 25509ec7b004SRick Macklem if (lo.lo_end <= lo.lo_first) 25519ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 25529ec7b004SRick Macklem } 25539ec7b004SRick Macklem tl += 2; 25549ec7b004SRick Macklem clientid.lval[0] = *tl++; 25559ec7b004SRick Macklem clientid.lval[1] = *tl; 2556c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2557c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2558c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2559c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2560c59e4cc3SRick Macklem printf("EEK5 multiple clids\n"); 25619ec7b004SRick Macklem } else { 2562c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2563c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 25649ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 25659ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 25669ec7b004SRick Macklem } 25679ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 25689ec7b004SRick Macklem if (error) 25699ec7b004SRick Macklem goto nfsmout; 25709ec7b004SRick Macklem if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 25719ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 25729ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 25739ec7b004SRick Macklem else 25749ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 25759ec7b004SRick Macklem } 25769ec7b004SRick Macklem if (!nd->nd_repstat) 25779ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 25789ec7b004SRick Macklem &stateid, exp, nd, p); 25799ec7b004SRick Macklem if (nd->nd_repstat) { 25809ec7b004SRick Macklem if (nd->nd_repstat == NFSERR_DENIED) { 25819ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 25829ec7b004SRick Macklem txdr_hyper(cf.cl_first, tl); 25839ec7b004SRick Macklem tl += 2; 25849ec7b004SRick Macklem if (cf.cl_end == NFS64BITSSET) 25859ec7b004SRick Macklem len = NFS64BITSSET; 25869ec7b004SRick Macklem else 25879ec7b004SRick Macklem len = cf.cl_end - cf.cl_first; 25889ec7b004SRick Macklem txdr_hyper(len, tl); 25899ec7b004SRick Macklem tl += 2; 25909ec7b004SRick Macklem if (cf.cl_flags == NFSLCK_WRITE) 25919ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 25929ec7b004SRick Macklem else 25939ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 25949ec7b004SRick Macklem *tl++ = stp->ls_stateid.other[0]; 25959ec7b004SRick Macklem *tl = stp->ls_stateid.other[1]; 25969ec7b004SRick Macklem (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 25979ec7b004SRick Macklem } 25989ec7b004SRick Macklem } 25999ec7b004SRick Macklem vput(vp); 26005ecc225fSConrad Meyer if (stp) 2601222daa42SConrad Meyer free(stp, M_NFSDSTATE); 2602a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 26039ec7b004SRick Macklem return (0); 26049ec7b004SRick Macklem nfsmout: 26059ec7b004SRick Macklem vput(vp); 26069ec7b004SRick Macklem if (stp) 2607222daa42SConrad Meyer free(stp, M_NFSDSTATE); 2608a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 26099ec7b004SRick Macklem return (error); 26109ec7b004SRick Macklem } 26119ec7b004SRick Macklem 26129ec7b004SRick Macklem /* 26139ec7b004SRick Macklem * nfsv4 unlock service 26149ec7b004SRick Macklem */ 26159ec7b004SRick Macklem APPLESTATIC int 26169ec7b004SRick Macklem nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram, 2617af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 26189ec7b004SRick Macklem { 26199ec7b004SRick Macklem u_int32_t *tl; 26209ec7b004SRick Macklem int i; 26219ec7b004SRick Macklem struct nfsstate *stp; 26229ec7b004SRick Macklem struct nfslock *lop; 26239ec7b004SRick Macklem int error = 0; 26249ec7b004SRick Macklem nfsv4stateid_t stateid; 26259ec7b004SRick Macklem nfsquad_t clientid; 26269ec7b004SRick Macklem u_int64_t len; 2627af444b18SEdward Tomasz Napierala struct thread *p = curthread; 26289ec7b004SRick Macklem 26299ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID); 2630222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate), 26319ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 2632222daa42SConrad Meyer lop = malloc(sizeof (struct nfslock), 26339ec7b004SRick Macklem M_NFSDLOCK, M_WAITOK); 26349ec7b004SRick Macklem stp->ls_flags = NFSLCK_UNLOCK; 26359ec7b004SRick Macklem lop->lo_flags = NFSLCK_UNLOCK; 26369ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 26379ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 26389ec7b004SRick Macklem switch (i) { 26399ec7b004SRick Macklem case NFSV4LOCKT_READW: 26409ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 26419ec7b004SRick Macklem case NFSV4LOCKT_READ: 26429ec7b004SRick Macklem break; 26439ec7b004SRick Macklem case NFSV4LOCKT_WRITEW: 26449ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 26459ec7b004SRick Macklem case NFSV4LOCKT_WRITE: 26469ec7b004SRick Macklem break; 26479ec7b004SRick Macklem default: 26489ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 26492a45247cSRick Macklem free(stp, M_NFSDSTATE); 26502a45247cSRick Macklem free(lop, M_NFSDLOCK); 26519ec7b004SRick Macklem goto nfsmout; 265274b8d63dSPedro F. Giffuni } 26539ec7b004SRick Macklem stp->ls_ownerlen = 0; 26549ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 26559ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(int, *tl++); 26569ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 26579ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 26589ec7b004SRick Macklem NFSX_STATEIDOTHER); 26599ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 266090d2dfabSRick Macklem 266190d2dfabSRick Macklem /* 266290d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 266390d2dfabSRick Macklem * stateid to the current stateid, if it is set. 266490d2dfabSRick Macklem */ 266590d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 266690d2dfabSRick Macklem stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 266790d2dfabSRick Macklem stp->ls_stateid.other[2] == 0) { 266890d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 266990d2dfabSRick Macklem stp->ls_stateid = nd->nd_curstateid; 267090d2dfabSRick Macklem stp->ls_stateid.seqid = 0; 267190d2dfabSRick Macklem } else { 267290d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 267390d2dfabSRick Macklem goto nfsmout; 267490d2dfabSRick Macklem } 267590d2dfabSRick Macklem } 267690d2dfabSRick Macklem 26779ec7b004SRick Macklem lop->lo_first = fxdr_hyper(tl); 26789ec7b004SRick Macklem tl += 2; 26799ec7b004SRick Macklem len = fxdr_hyper(tl); 26809ec7b004SRick Macklem if (len == NFS64BITSSET) { 26819ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 26829ec7b004SRick Macklem } else { 26839ec7b004SRick Macklem lop->lo_end = lop->lo_first + len; 26849ec7b004SRick Macklem if (lop->lo_end <= lop->lo_first) 26859ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 26869ec7b004SRick Macklem } 26879ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 26889ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 2689c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2690c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2691c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2692c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2693c59e4cc3SRick Macklem printf("EEK6 multiple clids\n"); 26949ec7b004SRick Macklem } else { 2695c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2696c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 26979ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 26989ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 26999ec7b004SRick Macklem } 27009ec7b004SRick Macklem if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 27019ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 27029ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 27039ec7b004SRick Macklem else 27049ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 27059ec7b004SRick Macklem } 27069ec7b004SRick Macklem /* 27079ec7b004SRick Macklem * Call nfsrv_lockctrl() even if nd_repstat is set, so that the 27089ec7b004SRick Macklem * seqid# gets incremented. nfsrv_lockctrl() will return the 27099ec7b004SRick Macklem * value of nd_repstat, if it gets that far. 27109ec7b004SRick Macklem */ 27119ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 27129ec7b004SRick Macklem &stateid, exp, nd, p); 27139ec7b004SRick Macklem if (stp) 2714222daa42SConrad Meyer free(stp, M_NFSDSTATE); 27159ec7b004SRick Macklem if (lop) 2716222daa42SConrad Meyer free(lop, M_NFSDLOCK); 27179ec7b004SRick Macklem if (!nd->nd_repstat) { 27189ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 27199ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 27209ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 27219ec7b004SRick Macklem } 27229ec7b004SRick Macklem nfsmout: 27239ec7b004SRick Macklem vput(vp); 2724a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 27259ec7b004SRick Macklem return (error); 27269ec7b004SRick Macklem } 27279ec7b004SRick Macklem 27289ec7b004SRick Macklem /* 27299ec7b004SRick Macklem * nfsv4 open service 27309ec7b004SRick Macklem */ 27319ec7b004SRick Macklem APPLESTATIC int 27329ec7b004SRick Macklem nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram, 2733af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp) 27349ec7b004SRick Macklem { 27359ec7b004SRick Macklem u_int32_t *tl; 2736c59e4cc3SRick Macklem int i, retext; 27379ec7b004SRick Macklem struct nfsstate *stp = NULL; 27389ec7b004SRick Macklem int error = 0, create, claim, exclusive_flag = 0; 27399ec7b004SRick Macklem u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask; 27409ec7b004SRick Macklem int how = NFSCREATE_UNCHECKED; 2741086f6e0cSRick Macklem int32_t cverf[2], tverf[2] = { 0, 0 }; 27429ec7b004SRick Macklem vnode_t vp = NULL, dirp = NULL; 27439ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 27449ec7b004SRick Macklem struct nameidata named; 27459ec7b004SRick Macklem nfsv4stateid_t stateid, delegstateid; 27469ec7b004SRick Macklem nfsattrbit_t attrbits; 27479ec7b004SRick Macklem nfsquad_t clientid; 27489ec7b004SRick Macklem char *bufp = NULL; 27499ec7b004SRick Macklem u_long *hashp; 27509ec7b004SRick Macklem NFSACL_T *aclp = NULL; 2751af444b18SEdward Tomasz Napierala struct thread *p = curthread; 27529ec7b004SRick Macklem 27539ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 2754c3e22f83SRick Macklem aclp = acl_alloc(M_WAITOK); 27559ec7b004SRick Macklem aclp->acl_cnt = 0; 27569ec7b004SRick Macklem #endif 27579ec7b004SRick Macklem NFSZERO_ATTRBIT(&attrbits); 27589ec7b004SRick Macklem named.ni_startdir = NULL; 27599ec7b004SRick Macklem named.ni_cnd.cn_nameiop = 0; 27609ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 27619ec7b004SRick Macklem i = fxdr_unsigned(int, *(tl + 5)); 27622a45247cSRick Macklem if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 27632a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 2764a9285ae5SZack Kirsch goto nfsmout; 27652a45247cSRick Macklem } 2766222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate) + i, 27679ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 27689ec7b004SRick Macklem stp->ls_ownerlen = i; 27699ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 27709ec7b004SRick Macklem stp->ls_flags = NFSLCK_OPEN; 27719ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 27729ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 27739ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 2774c59e4cc3SRick Macklem retext = 0; 2775c59e4cc3SRick Macklem if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG | 2776c59e4cc3SRick Macklem NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) { 2777c59e4cc3SRick Macklem retext = 1; 2778c59e4cc3SRick Macklem /* For now, ignore these. */ 2779c59e4cc3SRick Macklem i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG); 2780c59e4cc3SRick Macklem switch (i & NFSV4OPEN_WANTDELEGMASK) { 2781c59e4cc3SRick Macklem case NFSV4OPEN_WANTANYDELEG: 2782c59e4cc3SRick Macklem stp->ls_flags |= (NFSLCK_WANTRDELEG | 2783c59e4cc3SRick Macklem NFSLCK_WANTWDELEG); 2784c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2785c59e4cc3SRick Macklem break; 2786c59e4cc3SRick Macklem case NFSV4OPEN_WANTREADDELEG: 2787c59e4cc3SRick Macklem stp->ls_flags |= NFSLCK_WANTRDELEG; 2788c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2789c59e4cc3SRick Macklem break; 2790c59e4cc3SRick Macklem case NFSV4OPEN_WANTWRITEDELEG: 2791c59e4cc3SRick Macklem stp->ls_flags |= NFSLCK_WANTWDELEG; 2792c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2793c59e4cc3SRick Macklem break; 2794c59e4cc3SRick Macklem case NFSV4OPEN_WANTNODELEG: 2795c59e4cc3SRick Macklem stp->ls_flags |= NFSLCK_WANTNODELEG; 2796c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2797c59e4cc3SRick Macklem break; 2798c59e4cc3SRick Macklem case NFSV4OPEN_WANTCANCEL: 2799c59e4cc3SRick Macklem printf("NFSv4: ignore Open WantCancel\n"); 2800c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2801c59e4cc3SRick Macklem break; 2802c59e4cc3SRick Macklem default: 2803c59e4cc3SRick Macklem /* nd_repstat will be set to NFSERR_INVAL below. */ 2804c59e4cc3SRick Macklem break; 280574b8d63dSPedro F. Giffuni } 2806c59e4cc3SRick Macklem } 28079ec7b004SRick Macklem switch (i) { 28089ec7b004SRick Macklem case NFSV4OPEN_ACCESSREAD: 28099ec7b004SRick Macklem stp->ls_flags |= NFSLCK_READACCESS; 28109ec7b004SRick Macklem break; 28119ec7b004SRick Macklem case NFSV4OPEN_ACCESSWRITE: 28129ec7b004SRick Macklem stp->ls_flags |= NFSLCK_WRITEACCESS; 28139ec7b004SRick Macklem break; 28149ec7b004SRick Macklem case NFSV4OPEN_ACCESSBOTH: 28159ec7b004SRick Macklem stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 28169ec7b004SRick Macklem break; 28179ec7b004SRick Macklem default: 28189ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 281974b8d63dSPedro F. Giffuni } 28209ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 28219ec7b004SRick Macklem switch (i) { 28229ec7b004SRick Macklem case NFSV4OPEN_DENYNONE: 28239ec7b004SRick Macklem break; 28249ec7b004SRick Macklem case NFSV4OPEN_DENYREAD: 28259ec7b004SRick Macklem stp->ls_flags |= NFSLCK_READDENY; 28269ec7b004SRick Macklem break; 28279ec7b004SRick Macklem case NFSV4OPEN_DENYWRITE: 28289ec7b004SRick Macklem stp->ls_flags |= NFSLCK_WRITEDENY; 28299ec7b004SRick Macklem break; 28309ec7b004SRick Macklem case NFSV4OPEN_DENYBOTH: 28319ec7b004SRick Macklem stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 28329ec7b004SRick Macklem break; 28339ec7b004SRick Macklem default: 28349ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 283574b8d63dSPedro F. Giffuni } 28369ec7b004SRick Macklem clientid.lval[0] = *tl++; 28379ec7b004SRick Macklem clientid.lval[1] = *tl; 2838c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2839c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2840c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2841c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2842c59e4cc3SRick Macklem printf("EEK7 multiple clids\n"); 28439ec7b004SRick Macklem } else { 2844c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2845c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 28469ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 28479ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 28489ec7b004SRick Macklem } 28499ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2850a9285ae5SZack Kirsch if (error) 2851a9285ae5SZack Kirsch goto nfsmout; 28529ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 28539ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 28549ec7b004SRick Macklem create = fxdr_unsigned(int, *tl); 28559ec7b004SRick Macklem if (!nd->nd_repstat) 285690d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL); 28579ec7b004SRick Macklem if (create == NFSV4OPEN_CREATE) { 28589ec7b004SRick Macklem nva.na_type = VREG; 28599ec7b004SRick Macklem nva.na_mode = 0; 28609ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 28619ec7b004SRick Macklem how = fxdr_unsigned(int, *tl); 28629ec7b004SRick Macklem switch (how) { 28639ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 28649ec7b004SRick Macklem case NFSCREATE_GUARDED: 2865d8a5961fSMarcelo Araujo error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p); 2866a9285ae5SZack Kirsch if (error) 2867a9285ae5SZack Kirsch goto nfsmout; 28689ec7b004SRick Macklem /* 28699ec7b004SRick Macklem * If the na_gid being set is the same as that of 28709ec7b004SRick Macklem * the directory it is going in, clear it, since 28719ec7b004SRick Macklem * that is what will be set by default. This allows 28729ec7b004SRick Macklem * a user that isn't in that group to do the create. 28739ec7b004SRick Macklem */ 28749ec7b004SRick Macklem if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) && 28759ec7b004SRick Macklem nva.na_gid == dirfor.na_gid) 28769ec7b004SRick Macklem NFSVNO_UNSET(&nva, gid); 28779ec7b004SRick Macklem if (!nd->nd_repstat) 28789ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 28799ec7b004SRick Macklem break; 28809ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 28819ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2882086f6e0cSRick Macklem cverf[0] = *tl++; 2883086f6e0cSRick Macklem cverf[1] = *tl; 28849ec7b004SRick Macklem break; 2885c59e4cc3SRick Macklem case NFSCREATE_EXCLUSIVE41: 2886c59e4cc3SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2887c59e4cc3SRick Macklem cverf[0] = *tl++; 2888c59e4cc3SRick Macklem cverf[1] = *tl; 2889*b4645807SRick Macklem error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p); 2890c59e4cc3SRick Macklem if (error != 0) 2891c59e4cc3SRick Macklem goto nfsmout; 2892c59e4cc3SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, 2893c59e4cc3SRick Macklem NFSATTRBIT_TIMEACCESSSET)) 2894c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_INVAL; 2895c59e4cc3SRick Macklem /* 2896c59e4cc3SRick Macklem * If the na_gid being set is the same as that of 2897c59e4cc3SRick Macklem * the directory it is going in, clear it, since 2898c59e4cc3SRick Macklem * that is what will be set by default. This allows 2899c59e4cc3SRick Macklem * a user that isn't in that group to do the create. 2900c59e4cc3SRick Macklem */ 2901c59e4cc3SRick Macklem if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) && 2902c59e4cc3SRick Macklem nva.na_gid == dirfor.na_gid) 2903c59e4cc3SRick Macklem NFSVNO_UNSET(&nva, gid); 2904c59e4cc3SRick Macklem if (nd->nd_repstat == 0) 2905c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2906c59e4cc3SRick Macklem break; 29079ec7b004SRick Macklem default: 29089ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 2909a9285ae5SZack Kirsch goto nfsmout; 291074b8d63dSPedro F. Giffuni } 29119ec7b004SRick Macklem } else if (create != NFSV4OPEN_NOCREATE) { 29129ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 2913a9285ae5SZack Kirsch goto nfsmout; 29149ec7b004SRick Macklem } 29159ec7b004SRick Macklem 29169ec7b004SRick Macklem /* 29179ec7b004SRick Macklem * Now, handle the claim, which usually includes looking up a 29189ec7b004SRick Macklem * name in the directory referenced by dp. The exception is 29199ec7b004SRick Macklem * NFSV4OPEN_CLAIMPREVIOUS. 29209ec7b004SRick Macklem */ 29219ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 29229ec7b004SRick Macklem claim = fxdr_unsigned(int, *tl); 29239ec7b004SRick Macklem if (claim == NFSV4OPEN_CLAIMDELEGATECUR) { 29249ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 29259ec7b004SRick Macklem stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 29269ec7b004SRick Macklem NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 29279ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGCUR; 29289ec7b004SRick Macklem } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 29299ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGPREV; 29309ec7b004SRick Macklem } 29319ec7b004SRick Macklem if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR 29329ec7b004SRick Macklem || claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 29339ec7b004SRick Macklem if (!nd->nd_repstat && create == NFSV4OPEN_CREATE && 29349ec7b004SRick Macklem claim != NFSV4OPEN_CLAIMNULL) 29359ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 29369ec7b004SRick Macklem if (nd->nd_repstat) { 29379ec7b004SRick Macklem nd->nd_repstat = nfsrv_opencheck(clientid, 29389ec7b004SRick Macklem &stateid, stp, NULL, nd, p, nd->nd_repstat); 2939a9285ae5SZack Kirsch goto nfsmout; 29409ec7b004SRick Macklem } 29419ec7b004SRick Macklem if (create == NFSV4OPEN_CREATE) 29429ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 29436c21f6edSKonstantin Belousov LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE); 29449ec7b004SRick Macklem else 29459ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 29469ec7b004SRick Macklem LOCKLEAF | SAVESTART); 29479ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 29489ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 29499ec7b004SRick Macklem if (error) { 29509ec7b004SRick Macklem vrele(dp); 29519ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 29529ec7b004SRick Macklem acl_free(aclp); 29539ec7b004SRick Macklem #endif 2954222daa42SConrad Meyer free(stp, M_NFSDSTATE); 29559ec7b004SRick Macklem nfsvno_relpathbuf(&named); 2956a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 29579ec7b004SRick Macklem return (error); 29589ec7b004SRick Macklem } 29599ec7b004SRick Macklem if (!nd->nd_repstat) { 29609ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, 29619ec7b004SRick Macklem p, &dirp); 29629ec7b004SRick Macklem } else { 29639ec7b004SRick Macklem vrele(dp); 29649ec7b004SRick Macklem nfsvno_relpathbuf(&named); 29659ec7b004SRick Macklem } 29669ec7b004SRick Macklem if (create == NFSV4OPEN_CREATE) { 29679ec7b004SRick Macklem switch (how) { 29689ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 29699ec7b004SRick Macklem if (named.ni_vp) { 29709ec7b004SRick Macklem /* 29719ec7b004SRick Macklem * Clear the setable attribute bits, except 29729ec7b004SRick Macklem * for Size, if it is being truncated. 29739ec7b004SRick Macklem */ 29749ec7b004SRick Macklem NFSZERO_ATTRBIT(&attrbits); 29759ec7b004SRick Macklem if (NFSVNO_ISSETSIZE(&nva)) 29769ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, 29779ec7b004SRick Macklem NFSATTRBIT_SIZE); 29789ec7b004SRick Macklem } 29799ec7b004SRick Macklem break; 29809ec7b004SRick Macklem case NFSCREATE_GUARDED: 29819ec7b004SRick Macklem if (named.ni_vp && !nd->nd_repstat) 29829ec7b004SRick Macklem nd->nd_repstat = EEXIST; 29839ec7b004SRick Macklem break; 29849ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 29859ec7b004SRick Macklem exclusive_flag = 1; 29869ec7b004SRick Macklem if (!named.ni_vp) 29879ec7b004SRick Macklem nva.na_mode = 0; 2988c59e4cc3SRick Macklem break; 2989c59e4cc3SRick Macklem case NFSCREATE_EXCLUSIVE41: 2990c59e4cc3SRick Macklem exclusive_flag = 1; 2991c59e4cc3SRick Macklem break; 299274b8d63dSPedro F. Giffuni } 29939ec7b004SRick Macklem } 29949ec7b004SRick Macklem nfsvno_open(nd, &named, clientid, &stateid, stp, 29959ec7b004SRick Macklem &exclusive_flag, &nva, cverf, create, aclp, &attrbits, 299601c27978SEdward Tomasz Napierala nd->nd_cred, exp, &vp); 2997c59e4cc3SRick Macklem } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim == 2998c59e4cc3SRick Macklem NFSV4OPEN_CLAIMFH) { 2999c59e4cc3SRick Macklem if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 30009ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 30019ec7b004SRick Macklem i = fxdr_unsigned(int, *tl); 30029ec7b004SRick Macklem switch (i) { 30039ec7b004SRick Macklem case NFSV4OPEN_DELEGATEREAD: 30049ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGREAD; 30059ec7b004SRick Macklem break; 30069ec7b004SRick Macklem case NFSV4OPEN_DELEGATEWRITE: 30079ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGWRITE; 30089ec7b004SRick Macklem case NFSV4OPEN_DELEGATENONE: 30099ec7b004SRick Macklem break; 30109ec7b004SRick Macklem default: 30119ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 3012a9285ae5SZack Kirsch goto nfsmout; 301374b8d63dSPedro F. Giffuni } 30149ec7b004SRick Macklem stp->ls_flags |= NFSLCK_RECLAIM; 3015c59e4cc3SRick Macklem } else { 3016c59e4cc3SRick Macklem /* CLAIM_NULL_FH */ 3017c59e4cc3SRick Macklem if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE) 3018c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_INVAL; 3019c59e4cc3SRick Macklem } 30209ec7b004SRick Macklem vp = dp; 302198f234f3SZack Kirsch NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 3022629fa50eSRick Macklem if ((vp->v_iflag & VI_DOOMED) == 0) 3023629fa50eSRick Macklem nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, 3024629fa50eSRick Macklem stp, vp, nd, p, nd->nd_repstat); 3025629fa50eSRick Macklem else 3026629fa50eSRick Macklem nd->nd_repstat = NFSERR_PERM; 30279ec7b004SRick Macklem } else { 30289ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 3029a9285ae5SZack Kirsch goto nfsmout; 30309ec7b004SRick Macklem } 30319ec7b004SRick Macklem 30329ec7b004SRick Macklem /* 30339ec7b004SRick Macklem * Do basic access checking. 30349ec7b004SRick Macklem */ 30359ec7b004SRick Macklem if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 3036de67b496SRick Macklem /* 3037de67b496SRick Macklem * The IETF working group decided that this is the correct 3038de67b496SRick Macklem * error return for all non-regular files. 3039de67b496SRick Macklem */ 3040d8a5961fSMarcelo Araujo nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK; 30419ec7b004SRick Macklem } 30429ec7b004SRick Macklem if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS)) 30438da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, 30448da45f2cSRick Macklem exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 30459ec7b004SRick Macklem if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) { 30468da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, 30478da45f2cSRick Macklem exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 30489ec7b004SRick Macklem if (nd->nd_repstat) 30498da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 30509ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 30518da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 30529ec7b004SRick Macklem } 30539ec7b004SRick Macklem 3054086f6e0cSRick Macklem if (!nd->nd_repstat) { 305590d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 3056086f6e0cSRick Macklem if (!nd->nd_repstat) { 3057086f6e0cSRick Macklem tverf[0] = nva.na_atime.tv_sec; 3058086f6e0cSRick Macklem tverf[1] = nva.na_atime.tv_nsec; 3059086f6e0cSRick Macklem } 3060086f6e0cSRick Macklem } 3061086f6e0cSRick Macklem if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] || 3062086f6e0cSRick Macklem cverf[1] != tverf[1])) 30639ec7b004SRick Macklem nd->nd_repstat = EEXIST; 30649ec7b004SRick Macklem /* 30659ec7b004SRick Macklem * Do the open locking/delegation stuff. 30669ec7b004SRick Macklem */ 30679ec7b004SRick Macklem if (!nd->nd_repstat) 30689ec7b004SRick Macklem nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid, 30699ec7b004SRick Macklem &delegstateid, &rflags, exp, p, nva.na_filerev); 30709ec7b004SRick Macklem 30719ec7b004SRick Macklem /* 30729ec7b004SRick Macklem * vp must be unlocked before the call to nfsvno_getattr(dirp,...) 30739ec7b004SRick Macklem * below, to avoid a deadlock with the lookup in nfsvno_namei() above. 30749ec7b004SRick Macklem * (ie: Leave the NFSVOPUNLOCK() about here.) 30759ec7b004SRick Macklem */ 30769ec7b004SRick Macklem if (vp) 3077c383087cSZack Kirsch NFSVOPUNLOCK(vp, 0); 30789ec7b004SRick Macklem if (stp) 3079222daa42SConrad Meyer free(stp, M_NFSDSTATE); 30809ec7b004SRick Macklem if (!nd->nd_repstat && dirp) 308190d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 30829ec7b004SRick Macklem if (!nd->nd_repstat) { 308390d2dfabSRick Macklem /* For NFSv4.1, set the Current StateID. */ 308490d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 308590d2dfabSRick Macklem nd->nd_curstateid = stateid; 308690d2dfabSRick Macklem nd->nd_flag |= ND_CURSTATEID; 308790d2dfabSRick Macklem } 30889ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 30899ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 30909ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 30919ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 30929ec7b004SRick Macklem if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 30939ec7b004SRick Macklem *tl++ = newnfs_true; 30949ec7b004SRick Macklem *tl++ = 0; 30959ec7b004SRick Macklem *tl++ = 0; 30969ec7b004SRick Macklem *tl++ = 0; 30979ec7b004SRick Macklem *tl++ = 0; 30989ec7b004SRick Macklem } else { 30999ec7b004SRick Macklem *tl++ = newnfs_false; /* Since dirp is not locked */ 31009ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 31019ec7b004SRick Macklem tl += 2; 31029ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 31039ec7b004SRick Macklem tl += 2; 31049ec7b004SRick Macklem } 31059ec7b004SRick Macklem *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS); 31069ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &attrbits); 31079ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 31089ec7b004SRick Macklem if (rflags & NFSV4OPEN_READDELEGATE) 31099ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD); 31109ec7b004SRick Macklem else if (rflags & NFSV4OPEN_WRITEDELEGATE) 31119ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE); 3112c59e4cc3SRick Macklem else if (retext != 0) { 3113c59e4cc3SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT); 31145d54f186SRick Macklem if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) { 31155d54f186SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 31165d54f186SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 31175d54f186SRick Macklem } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) { 31185d54f186SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 31195d54f186SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE); 31205d54f186SRick Macklem } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) { 3121c59e4cc3SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3122c59e4cc3SRick Macklem *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION); 3123c59e4cc3SRick Macklem *tl = newnfs_false; 3124c59e4cc3SRick Macklem } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) { 3125c59e4cc3SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3126c59e4cc3SRick Macklem *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE); 3127c59e4cc3SRick Macklem *tl = newnfs_false; 3128c59e4cc3SRick Macklem } else { 3129c59e4cc3SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3130c59e4cc3SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 3131c59e4cc3SRick Macklem } 3132c59e4cc3SRick Macklem } else 31339ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE); 31349ec7b004SRick Macklem if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) { 31359ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED); 31369ec7b004SRick Macklem *tl++ = txdr_unsigned(delegstateid.seqid); 31379ec7b004SRick Macklem NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl, 31389ec7b004SRick Macklem NFSX_STATEIDOTHER); 31399ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 31409ec7b004SRick Macklem if (rflags & NFSV4OPEN_RECALL) 31419ec7b004SRick Macklem *tl = newnfs_true; 31429ec7b004SRick Macklem else 31439ec7b004SRick Macklem *tl = newnfs_false; 31449ec7b004SRick Macklem if (rflags & NFSV4OPEN_WRITEDELEGATE) { 31459ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 31469ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE); 31479ec7b004SRick Macklem txdr_hyper(nva.na_size, tl); 31489ec7b004SRick Macklem } 31499ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 31509ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE); 31519ec7b004SRick Macklem *tl++ = txdr_unsigned(0x0); 31529ec7b004SRick Macklem acemask = NFSV4ACE_ALLFILESMASK; 31539ec7b004SRick Macklem if (nva.na_mode & S_IRUSR) 31549ec7b004SRick Macklem acemask |= NFSV4ACE_READMASK; 31559ec7b004SRick Macklem if (nva.na_mode & S_IWUSR) 31569ec7b004SRick Macklem acemask |= NFSV4ACE_WRITEMASK; 31579ec7b004SRick Macklem if (nva.na_mode & S_IXUSR) 31589ec7b004SRick Macklem acemask |= NFSV4ACE_EXECUTEMASK; 31599ec7b004SRick Macklem *tl = txdr_unsigned(acemask); 31609ec7b004SRick Macklem (void) nfsm_strtom(nd, "OWNER@", 6); 31619ec7b004SRick Macklem } 31629ec7b004SRick Macklem *vpp = vp; 31639ec7b004SRick Macklem } else if (vp) { 31649ec7b004SRick Macklem vrele(vp); 31659ec7b004SRick Macklem } 31669ec7b004SRick Macklem if (dirp) 31679ec7b004SRick Macklem vrele(dirp); 31689ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 31699ec7b004SRick Macklem acl_free(aclp); 31709ec7b004SRick Macklem #endif 3171a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 31729ec7b004SRick Macklem return (0); 31739ec7b004SRick Macklem nfsmout: 31749ec7b004SRick Macklem vrele(dp); 31759ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 31769ec7b004SRick Macklem acl_free(aclp); 31779ec7b004SRick Macklem #endif 31789ec7b004SRick Macklem if (stp) 3179222daa42SConrad Meyer free(stp, M_NFSDSTATE); 3180a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 31819ec7b004SRick Macklem return (error); 31829ec7b004SRick Macklem } 31839ec7b004SRick Macklem 31849ec7b004SRick Macklem /* 31859ec7b004SRick Macklem * nfsv4 close service 31869ec7b004SRick Macklem */ 31879ec7b004SRick Macklem APPLESTATIC int 31889ec7b004SRick Macklem nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram, 3189af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 31909ec7b004SRick Macklem { 31919ec7b004SRick Macklem u_int32_t *tl; 31929ec7b004SRick Macklem struct nfsstate st, *stp = &st; 319390d2dfabSRick Macklem int error = 0, writeacc; 31949ec7b004SRick Macklem nfsv4stateid_t stateid; 31959ec7b004SRick Macklem nfsquad_t clientid; 319690d2dfabSRick Macklem struct nfsvattr na; 3197af444b18SEdward Tomasz Napierala struct thread *p = curthread; 31989ec7b004SRick Macklem 31999ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 32009ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 32019ec7b004SRick Macklem stp->ls_ownerlen = 0; 32029ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 32039ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 32049ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 32059ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 32069ec7b004SRick Macklem NFSX_STATEIDOTHER); 320790d2dfabSRick Macklem 320890d2dfabSRick Macklem /* 320990d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 321090d2dfabSRick Macklem * stateid to the current stateid, if it is set. 321190d2dfabSRick Macklem */ 321290d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 321390d2dfabSRick Macklem stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 321490d2dfabSRick Macklem stp->ls_stateid.other[2] == 0) { 321590d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) 321690d2dfabSRick Macklem stp->ls_stateid = nd->nd_curstateid; 321790d2dfabSRick Macklem else { 321890d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 321990d2dfabSRick Macklem goto nfsmout; 322090d2dfabSRick Macklem } 322190d2dfabSRick Macklem } 322290d2dfabSRick Macklem 32239ec7b004SRick Macklem stp->ls_flags = NFSLCK_CLOSE; 32249ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 32259ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 3226c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3227c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3228c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3229c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3230c59e4cc3SRick Macklem printf("EEK8 multiple clids\n"); 32319ec7b004SRick Macklem } else { 3232c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3233c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 32349ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 32359ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 32369ec7b004SRick Macklem } 323790d2dfabSRick Macklem nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, 323890d2dfabSRick Macklem &writeacc); 323990d2dfabSRick Macklem /* For pNFS, update the attributes. */ 324090d2dfabSRick Macklem if (writeacc != 0 || nfsrv_pnfsatime != 0) 324190d2dfabSRick Macklem nfsrv_updatemdsattr(vp, &na, p); 32429ec7b004SRick Macklem vput(vp); 32439ec7b004SRick Macklem if (!nd->nd_repstat) { 324490d2dfabSRick Macklem /* 324590d2dfabSRick Macklem * If the stateid that has been closed is the current stateid, 324690d2dfabSRick Macklem * unset it. 324790d2dfabSRick Macklem */ 324890d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0 && 324990d2dfabSRick Macklem stateid.other[0] == nd->nd_curstateid.other[0] && 325090d2dfabSRick Macklem stateid.other[1] == nd->nd_curstateid.other[1] && 325190d2dfabSRick Macklem stateid.other[2] == nd->nd_curstateid.other[2]) 325290d2dfabSRick Macklem nd->nd_flag &= ~ND_CURSTATEID; 32539ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 32549ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 32559ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 32569ec7b004SRick Macklem } 3257a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 32589ec7b004SRick Macklem return (0); 32599ec7b004SRick Macklem nfsmout: 32609ec7b004SRick Macklem vput(vp); 3261a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 32629ec7b004SRick Macklem return (error); 32639ec7b004SRick Macklem } 32649ec7b004SRick Macklem 32659ec7b004SRick Macklem /* 32669ec7b004SRick Macklem * nfsv4 delegpurge service 32679ec7b004SRick Macklem */ 32689ec7b004SRick Macklem APPLESTATIC int 32699ec7b004SRick Macklem nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram, 3270af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 32719ec7b004SRick Macklem { 32729ec7b004SRick Macklem u_int32_t *tl; 32739ec7b004SRick Macklem int error = 0; 32749ec7b004SRick Macklem nfsquad_t clientid; 3275af444b18SEdward Tomasz Napierala struct thread *p = curthread; 32769ec7b004SRick Macklem 3277c9aad40fSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3278b1cfc0d9SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3279a9285ae5SZack Kirsch goto nfsmout; 3280b1cfc0d9SRick Macklem } 32819ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 32829ec7b004SRick Macklem clientid.lval[0] = *tl++; 32839ec7b004SRick Macklem clientid.lval[1] = *tl; 3284c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3285c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3286c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3287c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3288c59e4cc3SRick Macklem printf("EEK9 multiple clids\n"); 32899ec7b004SRick Macklem } else { 3290c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3291c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 32929ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 32939ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 32949ec7b004SRick Macklem } 3295c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL, 329690d2dfabSRick Macklem NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL); 32979ec7b004SRick Macklem nfsmout: 3298a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 32999ec7b004SRick Macklem return (error); 33009ec7b004SRick Macklem } 33019ec7b004SRick Macklem 33029ec7b004SRick Macklem /* 33039ec7b004SRick Macklem * nfsv4 delegreturn service 33049ec7b004SRick Macklem */ 33059ec7b004SRick Macklem APPLESTATIC int 33069ec7b004SRick Macklem nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram, 3307af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 33089ec7b004SRick Macklem { 33099ec7b004SRick Macklem u_int32_t *tl; 331090d2dfabSRick Macklem int error = 0, writeacc; 33119ec7b004SRick Macklem nfsv4stateid_t stateid; 33129ec7b004SRick Macklem nfsquad_t clientid; 331390d2dfabSRick Macklem struct nfsvattr na; 3314af444b18SEdward Tomasz Napierala struct thread *p = curthread; 33159ec7b004SRick Macklem 33169ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 33179ec7b004SRick Macklem stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 33189ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER); 33199ec7b004SRick Macklem clientid.lval[0] = stateid.other[0]; 33209ec7b004SRick Macklem clientid.lval[1] = stateid.other[1]; 3321c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3322c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3323c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3324c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3325c59e4cc3SRick Macklem printf("EEK10 multiple clids\n"); 33269ec7b004SRick Macklem } else { 3327c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3328c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 33299ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 33309ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 33319ec7b004SRick Macklem } 3332c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp, 333390d2dfabSRick Macklem NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc); 333490d2dfabSRick Macklem /* For pNFS, update the attributes. */ 333590d2dfabSRick Macklem if (writeacc != 0 || nfsrv_pnfsatime != 0) 333690d2dfabSRick Macklem nfsrv_updatemdsattr(vp, &na, p); 33379ec7b004SRick Macklem nfsmout: 33389ec7b004SRick Macklem vput(vp); 3339a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 33409ec7b004SRick Macklem return (error); 33419ec7b004SRick Macklem } 33429ec7b004SRick Macklem 33439ec7b004SRick Macklem /* 33449ec7b004SRick Macklem * nfsv4 get file handle service 33459ec7b004SRick Macklem */ 33469ec7b004SRick Macklem APPLESTATIC int 33479ec7b004SRick Macklem nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram, 3348af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 33499ec7b004SRick Macklem { 33509ec7b004SRick Macklem fhandle_t fh; 3351af444b18SEdward Tomasz Napierala struct thread *p = curthread; 33529ec7b004SRick Macklem 33539ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 33549ec7b004SRick Macklem vput(vp); 33559ec7b004SRick Macklem if (!nd->nd_repstat) 33569ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 3357a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 33589ec7b004SRick Macklem return (0); 33599ec7b004SRick Macklem } 33609ec7b004SRick Macklem 33619ec7b004SRick Macklem /* 33629ec7b004SRick Macklem * nfsv4 open confirm service 33639ec7b004SRick Macklem */ 33649ec7b004SRick Macklem APPLESTATIC int 33659ec7b004SRick Macklem nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram, 3366af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 33679ec7b004SRick Macklem { 33689ec7b004SRick Macklem u_int32_t *tl; 33699ec7b004SRick Macklem struct nfsstate st, *stp = &st; 33709ec7b004SRick Macklem int error = 0; 33719ec7b004SRick Macklem nfsv4stateid_t stateid; 33729ec7b004SRick Macklem nfsquad_t clientid; 3373af444b18SEdward Tomasz Napierala struct thread *p = curthread; 33749ec7b004SRick Macklem 3375c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3376c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3377c59e4cc3SRick Macklem goto nfsmout; 3378c59e4cc3SRick Macklem } 33799ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 33809ec7b004SRick Macklem stp->ls_ownerlen = 0; 33819ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 33829ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 33839ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 33849ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 33859ec7b004SRick Macklem NFSX_STATEIDOTHER); 33869ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 33879ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl); 33889ec7b004SRick Macklem stp->ls_flags = NFSLCK_CONFIRM; 33899ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 33909ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 3391c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3392c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3393c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3394c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3395c59e4cc3SRick Macklem printf("EEK11 multiple clids\n"); 33969ec7b004SRick Macklem } else { 3397c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3398c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 33999ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 34009ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 34019ec7b004SRick Macklem } 340290d2dfabSRick Macklem nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, 340390d2dfabSRick Macklem NULL); 34049ec7b004SRick Macklem if (!nd->nd_repstat) { 34059ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 34069ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 34079ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 34089ec7b004SRick Macklem } 34099ec7b004SRick Macklem nfsmout: 34109ec7b004SRick Macklem vput(vp); 3411a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 34129ec7b004SRick Macklem return (error); 34139ec7b004SRick Macklem } 34149ec7b004SRick Macklem 34159ec7b004SRick Macklem /* 34169ec7b004SRick Macklem * nfsv4 open downgrade service 34179ec7b004SRick Macklem */ 34189ec7b004SRick Macklem APPLESTATIC int 34199ec7b004SRick Macklem nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram, 3420af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 34219ec7b004SRick Macklem { 34229ec7b004SRick Macklem u_int32_t *tl; 34239ec7b004SRick Macklem int i; 34249ec7b004SRick Macklem struct nfsstate st, *stp = &st; 34259ec7b004SRick Macklem int error = 0; 34269ec7b004SRick Macklem nfsv4stateid_t stateid; 34279ec7b004SRick Macklem nfsquad_t clientid; 3428af444b18SEdward Tomasz Napierala struct thread *p = curthread; 34299ec7b004SRick Macklem 3430d8a5961fSMarcelo Araujo /* opendowngrade can only work on a file object.*/ 3431d8a5961fSMarcelo Araujo if (vp->v_type != VREG) { 3432d8a5961fSMarcelo Araujo error = NFSERR_INVAL; 3433d8a5961fSMarcelo Araujo goto nfsmout; 3434d8a5961fSMarcelo Araujo } 34359ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 34369ec7b004SRick Macklem stp->ls_ownerlen = 0; 34379ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 34389ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 34399ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 34409ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 34419ec7b004SRick Macklem NFSX_STATEIDOTHER); 34429ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 344390d2dfabSRick Macklem 344490d2dfabSRick Macklem /* 344590d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 344690d2dfabSRick Macklem * stateid to the current stateid, if it is set. 344790d2dfabSRick Macklem */ 344890d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 344990d2dfabSRick Macklem stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 345090d2dfabSRick Macklem stp->ls_stateid.other[2] == 0) { 345190d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) 345290d2dfabSRick Macklem stp->ls_stateid = nd->nd_curstateid; 345390d2dfabSRick Macklem else { 345490d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 345590d2dfabSRick Macklem goto nfsmout; 345690d2dfabSRick Macklem } 345790d2dfabSRick Macklem } 345890d2dfabSRick Macklem 34599ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 34609ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 34616269d663SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 34626269d663SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 34639ec7b004SRick Macklem switch (i) { 34649ec7b004SRick Macklem case NFSV4OPEN_ACCESSREAD: 34659ec7b004SRick Macklem stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE); 34669ec7b004SRick Macklem break; 34679ec7b004SRick Macklem case NFSV4OPEN_ACCESSWRITE: 34689ec7b004SRick Macklem stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); 34699ec7b004SRick Macklem break; 34709ec7b004SRick Macklem case NFSV4OPEN_ACCESSBOTH: 34719ec7b004SRick Macklem stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS | 34729ec7b004SRick Macklem NFSLCK_DOWNGRADE); 34739ec7b004SRick Macklem break; 34749ec7b004SRick Macklem default: 34756269d663SRick Macklem nd->nd_repstat = NFSERR_INVAL; 347674b8d63dSPedro F. Giffuni } 34779ec7b004SRick Macklem i = fxdr_unsigned(int, *tl); 34789ec7b004SRick Macklem switch (i) { 34799ec7b004SRick Macklem case NFSV4OPEN_DENYNONE: 34809ec7b004SRick Macklem break; 34819ec7b004SRick Macklem case NFSV4OPEN_DENYREAD: 34829ec7b004SRick Macklem stp->ls_flags |= NFSLCK_READDENY; 34839ec7b004SRick Macklem break; 34849ec7b004SRick Macklem case NFSV4OPEN_DENYWRITE: 34859ec7b004SRick Macklem stp->ls_flags |= NFSLCK_WRITEDENY; 34869ec7b004SRick Macklem break; 34879ec7b004SRick Macklem case NFSV4OPEN_DENYBOTH: 34889ec7b004SRick Macklem stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 34899ec7b004SRick Macklem break; 34909ec7b004SRick Macklem default: 34916269d663SRick Macklem nd->nd_repstat = NFSERR_INVAL; 349274b8d63dSPedro F. Giffuni } 34939ec7b004SRick Macklem 34949ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 34959ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 3496c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3497c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3498c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3499c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3500c59e4cc3SRick Macklem printf("EEK12 multiple clids\n"); 35019ec7b004SRick Macklem } else { 3502c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3503c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 35049ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 35059ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 35069ec7b004SRick Macklem } 35079ec7b004SRick Macklem if (!nd->nd_repstat) 35089ec7b004SRick Macklem nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, 350990d2dfabSRick Macklem nd, p, NULL); 35109ec7b004SRick Macklem if (!nd->nd_repstat) { 351190d2dfabSRick Macklem /* For NFSv4.1, set the Current StateID. */ 351290d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 351390d2dfabSRick Macklem nd->nd_curstateid = stateid; 351490d2dfabSRick Macklem nd->nd_flag |= ND_CURSTATEID; 351590d2dfabSRick Macklem } 35169ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 35179ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 35189ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 35199ec7b004SRick Macklem } 35209ec7b004SRick Macklem nfsmout: 35219ec7b004SRick Macklem vput(vp); 3522a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 35239ec7b004SRick Macklem return (error); 35249ec7b004SRick Macklem } 35259ec7b004SRick Macklem 35269ec7b004SRick Macklem /* 35279ec7b004SRick Macklem * nfsv4 renew lease service 35289ec7b004SRick Macklem */ 35299ec7b004SRick Macklem APPLESTATIC int 35309ec7b004SRick Macklem nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram, 3531af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 35329ec7b004SRick Macklem { 35339ec7b004SRick Macklem u_int32_t *tl; 35349ec7b004SRick Macklem int error = 0; 35359ec7b004SRick Macklem nfsquad_t clientid; 3536af444b18SEdward Tomasz Napierala struct thread *p = curthread; 35379ec7b004SRick Macklem 3538c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3539c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3540c59e4cc3SRick Macklem goto nfsmout; 3541c59e4cc3SRick Macklem } 3542c9aad40fSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3543b1cfc0d9SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3544a9285ae5SZack Kirsch goto nfsmout; 3545b1cfc0d9SRick Macklem } 35469ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 35479ec7b004SRick Macklem clientid.lval[0] = *tl++; 35489ec7b004SRick Macklem clientid.lval[1] = *tl; 3549c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3550c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3551c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3552c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3553c59e4cc3SRick Macklem printf("EEK13 multiple clids\n"); 35549ec7b004SRick Macklem } else { 3555c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3556c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 35579ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 35589ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 35599ec7b004SRick Macklem } 35609ec7b004SRick Macklem nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW), 3561c59e4cc3SRick Macklem NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p); 35629ec7b004SRick Macklem nfsmout: 3563a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 35649ec7b004SRick Macklem return (error); 35659ec7b004SRick Macklem } 35669ec7b004SRick Macklem 35679ec7b004SRick Macklem /* 35689ec7b004SRick Macklem * nfsv4 security info service 35699ec7b004SRick Macklem */ 35709ec7b004SRick Macklem APPLESTATIC int 35719ec7b004SRick Macklem nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram, 3572af444b18SEdward Tomasz Napierala vnode_t dp, struct nfsexstuff *exp) 35739ec7b004SRick Macklem { 35749ec7b004SRick Macklem u_int32_t *tl; 35759ec7b004SRick Macklem int len; 35769ec7b004SRick Macklem struct nameidata named; 35779ec7b004SRick Macklem vnode_t dirp = NULL, vp; 35789ec7b004SRick Macklem struct nfsrvfh fh; 35799ec7b004SRick Macklem struct nfsexstuff retnes; 35809ec7b004SRick Macklem u_int32_t *sizp; 3581a9285ae5SZack Kirsch int error = 0, savflag, i; 35829ec7b004SRick Macklem char *bufp; 35839ec7b004SRick Macklem u_long *hashp; 3584af444b18SEdward Tomasz Napierala struct thread *p = curthread; 35859ec7b004SRick Macklem 35869ec7b004SRick Macklem /* 35879ec7b004SRick Macklem * All this just to get the export flags for the name. 35889ec7b004SRick Macklem */ 35899ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 35909ec7b004SRick Macklem LOCKLEAF | SAVESTART); 35919ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 35929ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 35939ec7b004SRick Macklem if (error) { 35949ec7b004SRick Macklem vput(dp); 35959ec7b004SRick Macklem nfsvno_relpathbuf(&named); 3596a9285ae5SZack Kirsch goto out; 35979ec7b004SRick Macklem } 35989ec7b004SRick Macklem if (!nd->nd_repstat) { 35999ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 36009ec7b004SRick Macklem } else { 36019ec7b004SRick Macklem vput(dp); 36029ec7b004SRick Macklem nfsvno_relpathbuf(&named); 36039ec7b004SRick Macklem } 36049ec7b004SRick Macklem if (dirp) 36059ec7b004SRick Macklem vrele(dirp); 36069ec7b004SRick Macklem if (nd->nd_repstat) 3607a9285ae5SZack Kirsch goto out; 36089ec7b004SRick Macklem vrele(named.ni_startdir); 36099ec7b004SRick Macklem nfsvno_relpathbuf(&named); 36109ec7b004SRick Macklem fh.nfsrvfh_len = NFSX_MYFH; 36119ec7b004SRick Macklem vp = named.ni_vp; 36129ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 36139ec7b004SRick Macklem vput(vp); 36149ec7b004SRick Macklem savflag = nd->nd_flag; 36159ec7b004SRick Macklem if (!nd->nd_repstat) { 36165edc9102SEdward Tomasz Napierala nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0); 36179ec7b004SRick Macklem if (vp) 36189ec7b004SRick Macklem vput(vp); 36199ec7b004SRick Macklem } 36209ec7b004SRick Macklem nd->nd_flag = savflag; 36219ec7b004SRick Macklem if (nd->nd_repstat) 3622a9285ae5SZack Kirsch goto out; 36239ec7b004SRick Macklem 36249ec7b004SRick Macklem /* 36259ec7b004SRick Macklem * Finally have the export flags for name, so we can create 36269ec7b004SRick Macklem * the security info. 36279ec7b004SRick Macklem */ 36289ec7b004SRick Macklem len = 0; 36299ec7b004SRick Macklem NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED); 363098ad4453SRick Macklem for (i = 0; i < retnes.nes_numsecflavor; i++) { 363198ad4453SRick Macklem if (retnes.nes_secflavors[i] == AUTH_SYS) { 36329ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 36339ec7b004SRick Macklem *tl = txdr_unsigned(RPCAUTH_UNIX); 36349ec7b004SRick Macklem len++; 363598ad4453SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 36369ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 36379ec7b004SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_GSS); 36389ec7b004SRick Macklem (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 36399ec7b004SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 36409ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 36419ec7b004SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 364298ad4453SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 36439ec7b004SRick Macklem len++; 364498ad4453SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 364598ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 364698ad4453SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_GSS); 364798ad4453SRick Macklem (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 364898ad4453SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 364998ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 365098ad4453SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 365198ad4453SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 365298ad4453SRick Macklem len++; 365398ad4453SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 365498ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 365598ad4453SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_GSS); 365698ad4453SRick Macklem (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 365798ad4453SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 365898ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 365998ad4453SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 366098ad4453SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 366198ad4453SRick Macklem len++; 366298ad4453SRick Macklem } 36639ec7b004SRick Macklem } 36649ec7b004SRick Macklem *sizp = txdr_unsigned(len); 3665a9285ae5SZack Kirsch 3666a9285ae5SZack Kirsch out: 3667a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 3668a9285ae5SZack Kirsch return (error); 36699ec7b004SRick Macklem } 36709ec7b004SRick Macklem 36719ec7b004SRick Macklem /* 36729ec7b004SRick Macklem * nfsv4 set client id service 36739ec7b004SRick Macklem */ 36749ec7b004SRick Macklem APPLESTATIC int 36759ec7b004SRick Macklem nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, 3676af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 36779ec7b004SRick Macklem { 36789ec7b004SRick Macklem u_int32_t *tl; 36799ec7b004SRick Macklem int i; 36809ec7b004SRick Macklem int error = 0, idlen; 36819ec7b004SRick Macklem struct nfsclient *clp = NULL; 3682ed2f1001SRick Macklem #ifdef INET 3683ed2f1001SRick Macklem struct sockaddr_in *rin; 3684ed2f1001SRick Macklem #endif 3685ed2f1001SRick Macklem #ifdef INET6 3686ed2f1001SRick Macklem struct sockaddr_in6 *rin6; 3687ed2f1001SRick Macklem #endif 3688ed2f1001SRick Macklem #if defined(INET) || defined(INET6) 3689ed2f1001SRick Macklem u_char *ucp, *ucp2; 3690ed2f1001SRick Macklem #endif 3691ed2f1001SRick Macklem u_char *verf, *addrbuf; 36929ec7b004SRick Macklem nfsquad_t clientid, confirm; 3693af444b18SEdward Tomasz Napierala struct thread *p = curthread; 36949ec7b004SRick Macklem 3695c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3696c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3697c59e4cc3SRick Macklem goto nfsmout; 3698c59e4cc3SRick Macklem } 3699c9aad40fSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 37009ec7b004SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3701a9285ae5SZack Kirsch goto out; 37029ec7b004SRick Macklem } 37039ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 37049ec7b004SRick Macklem verf = (u_char *)tl; 37059ec7b004SRick Macklem tl += (NFSX_VERF / NFSX_UNSIGNED); 37069ec7b004SRick Macklem i = fxdr_unsigned(int, *tl); 37079ec7b004SRick Macklem if (i > NFSV4_OPAQUELIMIT || i <= 0) { 37089ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 3709a9285ae5SZack Kirsch goto nfsmout; 37109ec7b004SRick Macklem } 37119ec7b004SRick Macklem idlen = i; 37129ec7b004SRick Macklem if (nd->nd_flag & ND_GSS) 37139ec7b004SRick Macklem i += nd->nd_princlen; 37141f54e596SRick Macklem clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 37151f54e596SRick Macklem M_ZERO); 37161f54e596SRick Macklem clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 37171f54e596SRick Macklem nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 37189ec7b004SRick Macklem NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3719ed2f1001SRick Macklem /* Allocated large enough for an AF_INET or AF_INET6 socket. */ 3720ed2f1001SRick Macklem clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, 3721b97b91b5SConrad Meyer M_WAITOK | M_ZERO); 37229ec7b004SRick Macklem clp->lc_req.nr_cred = NULL; 37239ec7b004SRick Macklem NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 37249ec7b004SRick Macklem clp->lc_idlen = idlen; 37259ec7b004SRick Macklem error = nfsrv_mtostr(nd, clp->lc_id, idlen); 37269ec7b004SRick Macklem if (error) 37279ec7b004SRick Macklem goto nfsmout; 37289ec7b004SRick Macklem if (nd->nd_flag & ND_GSS) { 37299ec7b004SRick Macklem clp->lc_flags = LCL_GSS; 37309ec7b004SRick Macklem if (nd->nd_flag & ND_GSSINTEGRITY) 37319ec7b004SRick Macklem clp->lc_flags |= LCL_GSSINTEGRITY; 37329ec7b004SRick Macklem else if (nd->nd_flag & ND_GSSPRIVACY) 37339ec7b004SRick Macklem clp->lc_flags |= LCL_GSSPRIVACY; 37349ec7b004SRick Macklem } else { 37359ec7b004SRick Macklem clp->lc_flags = 0; 37369ec7b004SRick Macklem } 37379ec7b004SRick Macklem if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) { 37389ec7b004SRick Macklem clp->lc_flags |= LCL_NAME; 37399ec7b004SRick Macklem clp->lc_namelen = nd->nd_princlen; 37409ec7b004SRick Macklem clp->lc_name = &clp->lc_id[idlen]; 37419ec7b004SRick Macklem NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 37429ec7b004SRick Macklem } else { 37439ec7b004SRick Macklem clp->lc_uid = nd->nd_cred->cr_uid; 37449ec7b004SRick Macklem clp->lc_gid = nd->nd_cred->cr_gid; 37459ec7b004SRick Macklem } 37469ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 37479ec7b004SRick Macklem clp->lc_program = fxdr_unsigned(u_int32_t, *tl); 37489ec7b004SRick Macklem error = nfsrv_getclientipaddr(nd, clp); 37499ec7b004SRick Macklem if (error) 37509ec7b004SRick Macklem goto nfsmout; 37519ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 37529ec7b004SRick Macklem clp->lc_callback = fxdr_unsigned(u_int32_t, *tl); 37539ec7b004SRick Macklem 37549ec7b004SRick Macklem /* 37559ec7b004SRick Macklem * nfsrv_setclient() does the actual work of adding it to the 37569ec7b004SRick Macklem * client list. If there is no error, the structure has been 37579ec7b004SRick Macklem * linked into the client list and clp should no longer be used 37589ec7b004SRick Macklem * here. When an error is returned, it has not been linked in, 37599ec7b004SRick Macklem * so it should be free'd. 37609ec7b004SRick Macklem */ 37619ec7b004SRick Macklem nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 37629ec7b004SRick Macklem if (nd->nd_repstat == NFSERR_CLIDINUSE) { 3763ed2f1001SRick Macklem /* 3764ed2f1001SRick Macklem * 8 is the maximum length of the port# string. 3765ed2f1001SRick Macklem */ 3766ed2f1001SRick Macklem addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK); 3767ed2f1001SRick Macklem switch (clp->lc_req.nr_nam->sa_family) { 3768ed2f1001SRick Macklem #ifdef INET 3769ed2f1001SRick Macklem case AF_INET: 37709ec7b004SRick Macklem if (clp->lc_flags & LCL_TCPCALLBACK) 37719ec7b004SRick Macklem (void) nfsm_strtom(nd, "tcp", 3); 37729ec7b004SRick Macklem else 37739ec7b004SRick Macklem (void) nfsm_strtom(nd, "udp", 3); 3774ed2f1001SRick Macklem rin = (struct sockaddr_in *)clp->lc_req.nr_nam; 3775ed2f1001SRick Macklem ucp = (u_char *)&rin->sin_addr.s_addr; 3776ed2f1001SRick Macklem ucp2 = (u_char *)&rin->sin_port; 37779ec7b004SRick Macklem sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff, 37789ec7b004SRick Macklem ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff, 37799ec7b004SRick Macklem ucp2[0] & 0xff, ucp2[1] & 0xff); 3780ed2f1001SRick Macklem break; 3781ed2f1001SRick Macklem #endif 3782ed2f1001SRick Macklem #ifdef INET6 3783ed2f1001SRick Macklem case AF_INET6: 3784ed2f1001SRick Macklem if (clp->lc_flags & LCL_TCPCALLBACK) 3785ed2f1001SRick Macklem (void) nfsm_strtom(nd, "tcp6", 4); 3786ed2f1001SRick Macklem else 3787ed2f1001SRick Macklem (void) nfsm_strtom(nd, "udp6", 4); 3788ed2f1001SRick Macklem rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam; 3789ed2f1001SRick Macklem ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf, 3790ed2f1001SRick Macklem INET6_ADDRSTRLEN); 3791ed2f1001SRick Macklem if (ucp != NULL) 3792ed2f1001SRick Macklem i = strlen(ucp); 3793ed2f1001SRick Macklem else 3794ed2f1001SRick Macklem i = 0; 3795ed2f1001SRick Macklem ucp2 = (u_char *)&rin6->sin6_port; 3796ed2f1001SRick Macklem sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff, 3797ed2f1001SRick Macklem ucp2[1] & 0xff); 3798ed2f1001SRick Macklem break; 3799ed2f1001SRick Macklem #endif 3800ed2f1001SRick Macklem } 38019ec7b004SRick Macklem (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf)); 3802ed2f1001SRick Macklem free(addrbuf, M_TEMP); 38039ec7b004SRick Macklem } 38049ec7b004SRick Macklem if (clp) { 3805b97b91b5SConrad Meyer free(clp->lc_req.nr_nam, M_SONAME); 38069ec7b004SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 38071f54e596SRick Macklem free(clp->lc_stateid, M_NFSDCLIENT); 38081f54e596SRick Macklem free(clp, M_NFSDCLIENT); 38099ec7b004SRick Macklem } 38109ec7b004SRick Macklem if (!nd->nd_repstat) { 38119ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); 38129ec7b004SRick Macklem *tl++ = clientid.lval[0]; 38139ec7b004SRick Macklem *tl++ = clientid.lval[1]; 38149ec7b004SRick Macklem *tl++ = confirm.lval[0]; 38159ec7b004SRick Macklem *tl = confirm.lval[1]; 38169ec7b004SRick Macklem } 3817a9285ae5SZack Kirsch 3818a9285ae5SZack Kirsch out: 3819a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 38209ec7b004SRick Macklem return (0); 38219ec7b004SRick Macklem nfsmout: 38229ec7b004SRick Macklem if (clp) { 3823b97b91b5SConrad Meyer free(clp->lc_req.nr_nam, M_SONAME); 38249ec7b004SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 38251f54e596SRick Macklem free(clp->lc_stateid, M_NFSDCLIENT); 38261f54e596SRick Macklem free(clp, M_NFSDCLIENT); 38279ec7b004SRick Macklem } 3828a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 38299ec7b004SRick Macklem return (error); 38309ec7b004SRick Macklem } 38319ec7b004SRick Macklem 38329ec7b004SRick Macklem /* 38339ec7b004SRick Macklem * nfsv4 set client id confirm service 38349ec7b004SRick Macklem */ 38359ec7b004SRick Macklem APPLESTATIC int 38369ec7b004SRick Macklem nfsrvd_setclientidcfrm(struct nfsrv_descript *nd, 3837af444b18SEdward Tomasz Napierala __unused int isdgram, __unused vnode_t vp, 38389ec7b004SRick Macklem __unused struct nfsexstuff *exp) 38399ec7b004SRick Macklem { 38409ec7b004SRick Macklem u_int32_t *tl; 38419ec7b004SRick Macklem int error = 0; 38429ec7b004SRick Macklem nfsquad_t clientid, confirm; 3843af444b18SEdward Tomasz Napierala struct thread *p = curthread; 38449ec7b004SRick Macklem 3845c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3846c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3847c59e4cc3SRick Macklem goto nfsmout; 3848c59e4cc3SRick Macklem } 3849c9aad40fSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 38509ec7b004SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3851a9285ae5SZack Kirsch goto nfsmout; 38529ec7b004SRick Macklem } 38539ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER); 38549ec7b004SRick Macklem clientid.lval[0] = *tl++; 38559ec7b004SRick Macklem clientid.lval[1] = *tl++; 38569ec7b004SRick Macklem confirm.lval[0] = *tl++; 38579ec7b004SRick Macklem confirm.lval[1] = *tl; 38589ec7b004SRick Macklem 38599ec7b004SRick Macklem /* 38609ec7b004SRick Macklem * nfsrv_getclient() searches the client list for a match and 38619ec7b004SRick Macklem * returns the appropriate NFSERR status. 38629ec7b004SRick Macklem */ 38639ec7b004SRick Macklem nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW), 3864c59e4cc3SRick Macklem NULL, NULL, confirm, 0, nd, p); 38659ec7b004SRick Macklem nfsmout: 3866a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 38679ec7b004SRick Macklem return (error); 38689ec7b004SRick Macklem } 38699ec7b004SRick Macklem 38709ec7b004SRick Macklem /* 38719ec7b004SRick Macklem * nfsv4 verify service 38729ec7b004SRick Macklem */ 38739ec7b004SRick Macklem APPLESTATIC int 38749ec7b004SRick Macklem nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, 3875af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 38769ec7b004SRick Macklem { 38779ec7b004SRick Macklem int error = 0, ret, fhsize = NFSX_MYFH; 38789ec7b004SRick Macklem struct nfsvattr nva; 38792f304845SKonstantin Belousov struct statfs *sf; 38809ec7b004SRick Macklem struct nfsfsinfo fs; 38819ec7b004SRick Macklem fhandle_t fh; 3882af444b18SEdward Tomasz Napierala struct thread *p = curthread; 38839ec7b004SRick Macklem 38842f304845SKonstantin Belousov sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 388590d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 38869ec7b004SRick Macklem if (!nd->nd_repstat) 38872f304845SKonstantin Belousov nd->nd_repstat = nfsvno_statfs(vp, sf); 38889ec7b004SRick Macklem if (!nd->nd_repstat) 38899ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 38909ec7b004SRick Macklem if (!nd->nd_repstat) { 38919ec7b004SRick Macklem nfsvno_getfs(&fs, isdgram); 38929ec7b004SRick Macklem error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL, 38932f304845SKonstantin Belousov sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred); 38949ec7b004SRick Macklem if (!error) { 38959ec7b004SRick Macklem if (nd->nd_procnum == NFSV4OP_NVERIFY) { 38969ec7b004SRick Macklem if (ret == 0) 38979ec7b004SRick Macklem nd->nd_repstat = NFSERR_SAME; 38989ec7b004SRick Macklem else if (ret != NFSERR_NOTSAME) 38999ec7b004SRick Macklem nd->nd_repstat = ret; 39009ec7b004SRick Macklem } else if (ret) 39019ec7b004SRick Macklem nd->nd_repstat = ret; 39029ec7b004SRick Macklem } 39039ec7b004SRick Macklem } 39049ec7b004SRick Macklem vput(vp); 39052f304845SKonstantin Belousov free(sf, M_STATFS); 3906a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 39079ec7b004SRick Macklem return (error); 39089ec7b004SRick Macklem } 39099ec7b004SRick Macklem 39109ec7b004SRick Macklem /* 39119ec7b004SRick Macklem * nfs openattr rpc 39129ec7b004SRick Macklem */ 39139ec7b004SRick Macklem APPLESTATIC int 39149ec7b004SRick Macklem nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram, 39159ec7b004SRick Macklem vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp, 3916af444b18SEdward Tomasz Napierala __unused struct nfsexstuff *exp) 39179ec7b004SRick Macklem { 39189ec7b004SRick Macklem u_int32_t *tl; 39198014c971SRick Macklem int error = 0, createdir __unused; 39209ec7b004SRick Macklem 39219ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 39229ec7b004SRick Macklem createdir = fxdr_unsigned(int, *tl); 39239ec7b004SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 39249ec7b004SRick Macklem nfsmout: 39259ec7b004SRick Macklem vrele(dp); 3926a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 39279ec7b004SRick Macklem return (error); 39289ec7b004SRick Macklem } 39299ec7b004SRick Macklem 39309ec7b004SRick Macklem /* 39319ec7b004SRick Macklem * nfsv4 release lock owner service 39329ec7b004SRick Macklem */ 39339ec7b004SRick Macklem APPLESTATIC int 39349ec7b004SRick Macklem nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram, 3935af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 39369ec7b004SRick Macklem { 39379ec7b004SRick Macklem u_int32_t *tl; 39389ec7b004SRick Macklem struct nfsstate *stp = NULL; 39399ec7b004SRick Macklem int error = 0, len; 39409ec7b004SRick Macklem nfsquad_t clientid; 3941af444b18SEdward Tomasz Napierala struct thread *p = curthread; 39429ec7b004SRick Macklem 3943c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3944c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3945c59e4cc3SRick Macklem goto nfsmout; 3946c59e4cc3SRick Macklem } 3947c9aad40fSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3948b1cfc0d9SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3949a9285ae5SZack Kirsch goto nfsmout; 3950b1cfc0d9SRick Macklem } 39519ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 39529ec7b004SRick Macklem len = fxdr_unsigned(int, *(tl + 2)); 39532a45247cSRick Macklem if (len <= 0 || len > NFSV4_OPAQUELIMIT) { 39542a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 3955a9285ae5SZack Kirsch goto nfsmout; 39562a45247cSRick Macklem } 3957222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate) + len, 39589ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 39599ec7b004SRick Macklem stp->ls_ownerlen = len; 39609ec7b004SRick Macklem stp->ls_op = NULL; 39619ec7b004SRick Macklem stp->ls_flags = NFSLCK_RELEASE; 39629ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 39639ec7b004SRick Macklem clientid.lval[0] = *tl++; 39649ec7b004SRick Macklem clientid.lval[1] = *tl; 3965c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3966c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3967c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3968c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3969c59e4cc3SRick Macklem printf("EEK14 multiple clids\n"); 39709ec7b004SRick Macklem } else { 3971c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3972c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 39739ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 39749ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 39759ec7b004SRick Macklem } 39769ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, len); 39779ec7b004SRick Macklem if (error) 39789ec7b004SRick Macklem goto nfsmout; 39799ec7b004SRick Macklem nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p); 3980222daa42SConrad Meyer free(stp, M_NFSDSTATE); 3981a9285ae5SZack Kirsch 3982a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 39839ec7b004SRick Macklem return (0); 39849ec7b004SRick Macklem nfsmout: 39859ec7b004SRick Macklem if (stp) 3986222daa42SConrad Meyer free(stp, M_NFSDSTATE); 3987a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 39889ec7b004SRick Macklem return (error); 39899ec7b004SRick Macklem } 3990c59e4cc3SRick Macklem 3991c59e4cc3SRick Macklem /* 3992c59e4cc3SRick Macklem * nfsv4 exchange_id service 3993c59e4cc3SRick Macklem */ 3994c59e4cc3SRick Macklem APPLESTATIC int 3995c59e4cc3SRick Macklem nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram, 3996af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 3997c59e4cc3SRick Macklem { 3998c59e4cc3SRick Macklem uint32_t *tl; 3999c59e4cc3SRick Macklem int error = 0, i, idlen; 4000c59e4cc3SRick Macklem struct nfsclient *clp = NULL; 4001c59e4cc3SRick Macklem nfsquad_t clientid, confirm; 4002c59e4cc3SRick Macklem uint8_t *verf; 4003c59e4cc3SRick Macklem uint32_t sp4type, v41flags; 4004c59e4cc3SRick Macklem uint64_t owner_minor; 4005c59e4cc3SRick Macklem struct timespec verstime; 4006ed2f1001SRick Macklem #ifdef INET 4007ed2f1001SRick Macklem struct sockaddr_in *sin, *rin; 4008ed2f1001SRick Macklem #endif 4009ed2f1001SRick Macklem #ifdef INET6 4010ed2f1001SRick Macklem struct sockaddr_in6 *sin6, *rin6; 4011ed2f1001SRick Macklem #endif 4012af444b18SEdward Tomasz Napierala struct thread *p = curthread; 4013c59e4cc3SRick Macklem 4014c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4015c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 4016c59e4cc3SRick Macklem goto nfsmout; 4017c59e4cc3SRick Macklem } 4018c59e4cc3SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 4019c59e4cc3SRick Macklem verf = (uint8_t *)tl; 4020c59e4cc3SRick Macklem tl += (NFSX_VERF / NFSX_UNSIGNED); 4021c59e4cc3SRick Macklem i = fxdr_unsigned(int, *tl); 4022c59e4cc3SRick Macklem if (i > NFSV4_OPAQUELIMIT || i <= 0) { 4023c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 4024c59e4cc3SRick Macklem goto nfsmout; 4025c59e4cc3SRick Macklem } 4026c59e4cc3SRick Macklem idlen = i; 4027c59e4cc3SRick Macklem if (nd->nd_flag & ND_GSS) 4028c59e4cc3SRick Macklem i += nd->nd_princlen; 40291f54e596SRick Macklem clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 40301f54e596SRick Macklem M_ZERO); 40311f54e596SRick Macklem clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 40321f54e596SRick Macklem nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 4033c59e4cc3SRick Macklem NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 4034ed2f1001SRick Macklem /* Allocated large enough for an AF_INET or AF_INET6 socket. */ 4035ed2f1001SRick Macklem clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, 4036b97b91b5SConrad Meyer M_WAITOK | M_ZERO); 4037ed2f1001SRick Macklem switch (nd->nd_nam->sa_family) { 4038ed2f1001SRick Macklem #ifdef INET 4039ed2f1001SRick Macklem case AF_INET: 4040ed2f1001SRick Macklem rin = (struct sockaddr_in *)clp->lc_req.nr_nam; 4041ed2f1001SRick Macklem sin = (struct sockaddr_in *)nd->nd_nam; 4042ed2f1001SRick Macklem rin->sin_family = AF_INET; 4043ed2f1001SRick Macklem rin->sin_len = sizeof(struct sockaddr_in); 4044ed2f1001SRick Macklem rin->sin_port = 0; 4045ed2f1001SRick Macklem rin->sin_addr.s_addr = sin->sin_addr.s_addr; 4046ed2f1001SRick Macklem break; 4047ed2f1001SRick Macklem #endif 4048ed2f1001SRick Macklem #ifdef INET6 4049ed2f1001SRick Macklem case AF_INET6: 4050ed2f1001SRick Macklem rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam; 4051ed2f1001SRick Macklem sin6 = (struct sockaddr_in6 *)nd->nd_nam; 4052ed2f1001SRick Macklem rin6->sin6_family = AF_INET6; 4053ed2f1001SRick Macklem rin6->sin6_len = sizeof(struct sockaddr_in6); 4054ed2f1001SRick Macklem rin6->sin6_port = 0; 4055ed2f1001SRick Macklem rin6->sin6_addr = sin6->sin6_addr; 4056ed2f1001SRick Macklem break; 4057ed2f1001SRick Macklem #endif 4058ed2f1001SRick Macklem } 4059c59e4cc3SRick Macklem clp->lc_req.nr_cred = NULL; 4060c59e4cc3SRick Macklem NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 4061c59e4cc3SRick Macklem clp->lc_idlen = idlen; 4062c59e4cc3SRick Macklem error = nfsrv_mtostr(nd, clp->lc_id, idlen); 4063c59e4cc3SRick Macklem if (error != 0) 4064c59e4cc3SRick Macklem goto nfsmout; 4065c59e4cc3SRick Macklem if ((nd->nd_flag & ND_GSS) != 0) { 4066c59e4cc3SRick Macklem clp->lc_flags = LCL_GSS | LCL_NFSV41; 4067c59e4cc3SRick Macklem if ((nd->nd_flag & ND_GSSINTEGRITY) != 0) 4068c59e4cc3SRick Macklem clp->lc_flags |= LCL_GSSINTEGRITY; 4069c59e4cc3SRick Macklem else if ((nd->nd_flag & ND_GSSPRIVACY) != 0) 4070c59e4cc3SRick Macklem clp->lc_flags |= LCL_GSSPRIVACY; 4071c59e4cc3SRick Macklem } else 4072c59e4cc3SRick Macklem clp->lc_flags = LCL_NFSV41; 4073c59e4cc3SRick Macklem if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) { 4074c59e4cc3SRick Macklem clp->lc_flags |= LCL_NAME; 4075c59e4cc3SRick Macklem clp->lc_namelen = nd->nd_princlen; 4076c59e4cc3SRick Macklem clp->lc_name = &clp->lc_id[idlen]; 4077c59e4cc3SRick Macklem NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 4078c59e4cc3SRick Macklem } else { 4079c59e4cc3SRick Macklem clp->lc_uid = nd->nd_cred->cr_uid; 4080c59e4cc3SRick Macklem clp->lc_gid = nd->nd_cred->cr_gid; 4081c59e4cc3SRick Macklem } 4082c59e4cc3SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4083c59e4cc3SRick Macklem v41flags = fxdr_unsigned(uint32_t, *tl++); 4084c59e4cc3SRick Macklem if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR | 4085c59e4cc3SRick Macklem NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS | 4086c59e4cc3SRick Macklem NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) { 4087c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_INVAL; 4088c59e4cc3SRick Macklem goto nfsmout; 4089c59e4cc3SRick Macklem } 4090c59e4cc3SRick Macklem if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0) 4091c59e4cc3SRick Macklem confirm.lval[1] = 1; 4092c59e4cc3SRick Macklem else 4093c59e4cc3SRick Macklem confirm.lval[1] = 0; 409490d2dfabSRick Macklem if (nfsrv_devidcnt == 0) 409590d2dfabSRick Macklem v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS; 409690d2dfabSRick Macklem else 409790d2dfabSRick Macklem v41flags = NFSV4EXCH_USEPNFSMDS; 4098c59e4cc3SRick Macklem sp4type = fxdr_unsigned(uint32_t, *tl); 4099c59e4cc3SRick Macklem if (sp4type != NFSV4EXCH_SP4NONE) { 4100c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 4101c59e4cc3SRick Macklem goto nfsmout; 4102c59e4cc3SRick Macklem } 4103c59e4cc3SRick Macklem 4104c59e4cc3SRick Macklem /* 4105c59e4cc3SRick Macklem * nfsrv_setclient() does the actual work of adding it to the 4106c59e4cc3SRick Macklem * client list. If there is no error, the structure has been 4107c59e4cc3SRick Macklem * linked into the client list and clp should no longer be used 4108c59e4cc3SRick Macklem * here. When an error is returned, it has not been linked in, 4109c59e4cc3SRick Macklem * so it should be free'd. 4110c59e4cc3SRick Macklem */ 4111c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 4112c59e4cc3SRick Macklem if (clp != NULL) { 4113b97b91b5SConrad Meyer free(clp->lc_req.nr_nam, M_SONAME); 4114c59e4cc3SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 41151f54e596SRick Macklem free(clp->lc_stateid, M_NFSDCLIENT); 4116c59e4cc3SRick Macklem free(clp, M_NFSDCLIENT); 4117c59e4cc3SRick Macklem } 4118c59e4cc3SRick Macklem if (nd->nd_repstat == 0) { 4119c59e4cc3SRick Macklem if (confirm.lval[1] != 0) 4120c59e4cc3SRick Macklem v41flags |= NFSV4EXCH_CONFIRMEDR; 4121c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED); 4122c59e4cc3SRick Macklem *tl++ = clientid.lval[0]; /* ClientID */ 4123c59e4cc3SRick Macklem *tl++ = clientid.lval[1]; 4124c59e4cc3SRick Macklem *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */ 4125c59e4cc3SRick Macklem *tl++ = txdr_unsigned(v41flags); /* Exch flags */ 4126c59e4cc3SRick Macklem *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */ 4127c59e4cc3SRick Macklem owner_minor = 0; /* Owner */ 4128c59e4cc3SRick Macklem txdr_hyper(owner_minor, tl); /* Minor */ 4129c59e4cc3SRick Macklem (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid, 4130c59e4cc3SRick Macklem strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */ 41318932a483SRick Macklem (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid, 41328932a483SRick Macklem strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Scope */ 41338932a483SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4134c59e4cc3SRick Macklem *tl = txdr_unsigned(1); 4135c59e4cc3SRick Macklem (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 4136c59e4cc3SRick Macklem (void)nfsm_strtom(nd, version, strlen(version)); 4137c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 4138c59e4cc3SRick Macklem verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 4139c59e4cc3SRick Macklem verstime.tv_nsec = 0; 4140c59e4cc3SRick Macklem txdr_nfsv4time(&verstime, tl); 4141c59e4cc3SRick Macklem } 4142c59e4cc3SRick Macklem NFSEXITCODE2(0, nd); 4143c59e4cc3SRick Macklem return (0); 4144c59e4cc3SRick Macklem nfsmout: 4145c59e4cc3SRick Macklem if (clp != NULL) { 4146b97b91b5SConrad Meyer free(clp->lc_req.nr_nam, M_SONAME); 4147c59e4cc3SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 41481f54e596SRick Macklem free(clp->lc_stateid, M_NFSDCLIENT); 4149c59e4cc3SRick Macklem free(clp, M_NFSDCLIENT); 4150c59e4cc3SRick Macklem } 4151c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4152c59e4cc3SRick Macklem return (error); 4153c59e4cc3SRick Macklem } 4154c59e4cc3SRick Macklem 4155c59e4cc3SRick Macklem /* 4156c59e4cc3SRick Macklem * nfsv4 create session service 4157c59e4cc3SRick Macklem */ 4158c59e4cc3SRick Macklem APPLESTATIC int 4159c59e4cc3SRick Macklem nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram, 4160af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4161c59e4cc3SRick Macklem { 4162c59e4cc3SRick Macklem uint32_t *tl; 4163c59e4cc3SRick Macklem int error = 0; 4164c59e4cc3SRick Macklem nfsquad_t clientid, confirm; 4165c59e4cc3SRick Macklem struct nfsdsession *sep = NULL; 4166c59e4cc3SRick Macklem uint32_t rdmacnt; 4167af444b18SEdward Tomasz Napierala struct thread *p = curthread; 4168c59e4cc3SRick Macklem 4169c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4170c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 4171c59e4cc3SRick Macklem goto nfsmout; 4172c59e4cc3SRick Macklem } 4173c59e4cc3SRick Macklem sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession), 4174c59e4cc3SRick Macklem M_NFSDSESSION, M_WAITOK | M_ZERO); 4175c59e4cc3SRick Macklem sep->sess_refcnt = 1; 4176c59e4cc3SRick Macklem mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF); 4177c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 4178c59e4cc3SRick Macklem clientid.lval[0] = *tl++; 4179c59e4cc3SRick Macklem clientid.lval[1] = *tl++; 4180c59e4cc3SRick Macklem confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++); 4181c59e4cc3SRick Macklem sep->sess_crflags = fxdr_unsigned(uint32_t, *tl); 4182c59e4cc3SRick Macklem /* Persistent sessions and RDMA are not supported. */ 4183c59e4cc3SRick Macklem sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN; 4184c59e4cc3SRick Macklem 4185c59e4cc3SRick Macklem /* Fore channel attributes. */ 4186c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4187c59e4cc3SRick Macklem tl++; /* Header pad always 0. */ 4188c59e4cc3SRick Macklem sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++); 418990d2dfabSRick Macklem if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) { 419090d2dfabSRick Macklem sep->sess_maxreq = sb_max_adj - NFS_MAXXDR; 419190d2dfabSRick Macklem printf("Consider increasing kern.ipc.maxsockbuf\n"); 419290d2dfabSRick Macklem } 4193c59e4cc3SRick Macklem sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++); 419490d2dfabSRick Macklem if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) { 419590d2dfabSRick Macklem sep->sess_maxresp = sb_max_adj - NFS_MAXXDR; 419690d2dfabSRick Macklem printf("Consider increasing kern.ipc.maxsockbuf\n"); 419790d2dfabSRick Macklem } 4198c59e4cc3SRick Macklem sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++); 4199c59e4cc3SRick Macklem sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++); 4200c59e4cc3SRick Macklem sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++); 4201c59e4cc3SRick Macklem if (sep->sess_maxslots > NFSV4_SLOTS) 4202c59e4cc3SRick Macklem sep->sess_maxslots = NFSV4_SLOTS; 4203c59e4cc3SRick Macklem rdmacnt = fxdr_unsigned(uint32_t, *tl); 4204c59e4cc3SRick Macklem if (rdmacnt > 1) { 4205c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 4206c59e4cc3SRick Macklem goto nfsmout; 4207c59e4cc3SRick Macklem } else if (rdmacnt == 1) 4208c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4209c59e4cc3SRick Macklem 4210c59e4cc3SRick Macklem /* Back channel attributes. */ 4211c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4212c59e4cc3SRick Macklem tl++; /* Header pad always 0. */ 4213c59e4cc3SRick Macklem sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++); 4214c59e4cc3SRick Macklem sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++); 4215c59e4cc3SRick Macklem sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++); 4216c59e4cc3SRick Macklem sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++); 4217c59e4cc3SRick Macklem sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++); 4218c59e4cc3SRick Macklem rdmacnt = fxdr_unsigned(uint32_t, *tl); 4219c59e4cc3SRick Macklem if (rdmacnt > 1) { 4220c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 4221c59e4cc3SRick Macklem goto nfsmout; 4222c59e4cc3SRick Macklem } else if (rdmacnt == 1) 4223c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4224c59e4cc3SRick Macklem 4225c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4226c59e4cc3SRick Macklem sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl); 4227c59e4cc3SRick Macklem 4228c59e4cc3SRick Macklem /* 4229c59e4cc3SRick Macklem * nfsrv_getclient() searches the client list for a match and 4230c59e4cc3SRick Macklem * returns the appropriate NFSERR status. 4231c59e4cc3SRick Macklem */ 4232c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW, 4233c59e4cc3SRick Macklem NULL, sep, confirm, sep->sess_cbprogram, nd, p); 4234c59e4cc3SRick Macklem if (nd->nd_repstat == 0) { 4235c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4236c59e4cc3SRick Macklem NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID); 4237c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED); 4238c59e4cc3SRick Macklem *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */ 4239c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_crflags); 4240c59e4cc3SRick Macklem 4241c59e4cc3SRick Macklem /* Fore channel attributes. */ 4242c59e4cc3SRick Macklem *tl++ = 0; 4243c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxreq); 4244c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxresp); 4245c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxrespcached); 4246c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxops); 4247c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxslots); 4248c59e4cc3SRick Macklem *tl++ = txdr_unsigned(1); 4249c59e4cc3SRick Macklem *tl++ = txdr_unsigned(0); /* No RDMA. */ 4250c59e4cc3SRick Macklem 4251c59e4cc3SRick Macklem /* Back channel attributes. */ 4252c59e4cc3SRick Macklem *tl++ = 0; 4253c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbmaxreq); 4254c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbmaxresp); 4255c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached); 4256c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbmaxops); 4257c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots); 4258c59e4cc3SRick Macklem *tl++ = txdr_unsigned(1); 4259c59e4cc3SRick Macklem *tl = txdr_unsigned(0); /* No RDMA. */ 4260c59e4cc3SRick Macklem } 4261c59e4cc3SRick Macklem nfsmout: 4262c59e4cc3SRick Macklem if (nd->nd_repstat != 0 && sep != NULL) 4263c59e4cc3SRick Macklem free(sep, M_NFSDSESSION); 4264c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4265c59e4cc3SRick Macklem return (error); 4266c59e4cc3SRick Macklem } 4267c59e4cc3SRick Macklem 4268c59e4cc3SRick Macklem /* 4269c59e4cc3SRick Macklem * nfsv4 sequence service 4270c59e4cc3SRick Macklem */ 4271c59e4cc3SRick Macklem APPLESTATIC int 4272c59e4cc3SRick Macklem nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram, 4273af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4274c59e4cc3SRick Macklem { 4275c59e4cc3SRick Macklem uint32_t *tl; 4276c59e4cc3SRick Macklem uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid; 4277c59e4cc3SRick Macklem int cache_this, error = 0; 4278af444b18SEdward Tomasz Napierala struct thread *p = curthread; 4279c59e4cc3SRick Macklem 4280c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4281c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 4282c59e4cc3SRick Macklem goto nfsmout; 4283c59e4cc3SRick Macklem } 4284c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID); 4285c59e4cc3SRick Macklem NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID); 4286c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 4287c59e4cc3SRick Macklem sequenceid = fxdr_unsigned(uint32_t, *tl++); 4288c59e4cc3SRick Macklem nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++); 4289c59e4cc3SRick Macklem highest_slotid = fxdr_unsigned(uint32_t, *tl++); 4290c59e4cc3SRick Macklem if (*tl == newnfs_true) 4291c59e4cc3SRick Macklem cache_this = 1; 4292c59e4cc3SRick Macklem else 4293c59e4cc3SRick Macklem cache_this = 0; 4294c59e4cc3SRick Macklem nd->nd_flag |= ND_HASSEQUENCE; 4295c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid, 4296c59e4cc3SRick Macklem &target_highest_slotid, cache_this, &sflags, p); 4297c59e4cc3SRick Macklem if (nd->nd_repstat == 0) { 4298c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4299c59e4cc3SRick Macklem NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID); 4300c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 4301c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sequenceid); 4302c59e4cc3SRick Macklem *tl++ = txdr_unsigned(nd->nd_slotid); 4303c59e4cc3SRick Macklem *tl++ = txdr_unsigned(highest_slotid); 4304c59e4cc3SRick Macklem *tl++ = txdr_unsigned(target_highest_slotid); 4305c59e4cc3SRick Macklem *tl = txdr_unsigned(sflags); 4306c59e4cc3SRick Macklem } 4307c59e4cc3SRick Macklem nfsmout: 4308c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4309c59e4cc3SRick Macklem return (error); 4310c59e4cc3SRick Macklem } 4311c59e4cc3SRick Macklem 4312c59e4cc3SRick Macklem /* 4313c59e4cc3SRick Macklem * nfsv4 reclaim complete service 4314c59e4cc3SRick Macklem */ 4315c59e4cc3SRick Macklem APPLESTATIC int 4316c59e4cc3SRick Macklem nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram, 4317af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4318c59e4cc3SRick Macklem { 4319c59e4cc3SRick Macklem uint32_t *tl; 4320a3e709cdSRick Macklem int error = 0, onefs; 4321c59e4cc3SRick Macklem 4322c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4323c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 4324c59e4cc3SRick Macklem goto nfsmout; 4325c59e4cc3SRick Macklem } 4326c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4327a3e709cdSRick Macklem /* 4328a3e709cdSRick Macklem * I believe that a ReclaimComplete with rca_one_fs == TRUE is only 4329a3e709cdSRick Macklem * to be used after a file system has been transferred to a different 4330a3e709cdSRick Macklem * file server. However, RFC5661 is somewhat vague w.r.t. this and 4331a3e709cdSRick Macklem * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs 4332a3e709cdSRick Macklem * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE. 4333a3e709cdSRick Macklem * Therefore, just ignore the rca_one_fs == TRUE operation and return 4334a3e709cdSRick Macklem * NFS_OK without doing anything. 4335a3e709cdSRick Macklem */ 4336a3e709cdSRick Macklem onefs = 0; 4337c59e4cc3SRick Macklem if (*tl == newnfs_true) 4338a3e709cdSRick Macklem onefs = 1; 4339a3e709cdSRick Macklem nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs); 4340c59e4cc3SRick Macklem nfsmout: 4341c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4342c59e4cc3SRick Macklem return (error); 4343c59e4cc3SRick Macklem } 4344c59e4cc3SRick Macklem 4345c59e4cc3SRick Macklem /* 4346c59e4cc3SRick Macklem * nfsv4 destroy clientid service 4347c59e4cc3SRick Macklem */ 4348c59e4cc3SRick Macklem APPLESTATIC int 4349c59e4cc3SRick Macklem nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram, 4350af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4351c59e4cc3SRick Macklem { 4352c59e4cc3SRick Macklem uint32_t *tl; 4353c59e4cc3SRick Macklem nfsquad_t clientid; 4354c59e4cc3SRick Macklem int error = 0; 4355af444b18SEdward Tomasz Napierala struct thread *p = curthread; 4356c59e4cc3SRick Macklem 4357c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4358c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 4359c59e4cc3SRick Macklem goto nfsmout; 4360c59e4cc3SRick Macklem } 4361c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4362c59e4cc3SRick Macklem clientid.lval[0] = *tl++; 4363c59e4cc3SRick Macklem clientid.lval[1] = *tl; 4364c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_destroyclient(clientid, p); 4365c59e4cc3SRick Macklem nfsmout: 4366c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4367c59e4cc3SRick Macklem return (error); 4368c59e4cc3SRick Macklem } 4369c59e4cc3SRick Macklem 4370c59e4cc3SRick Macklem /* 43719442a64eSRick Macklem * nfsv4 bind connection to session service 43729442a64eSRick Macklem */ 43739442a64eSRick Macklem APPLESTATIC int 43749442a64eSRick Macklem nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram, 4375af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 43769442a64eSRick Macklem { 43779442a64eSRick Macklem uint32_t *tl; 43789442a64eSRick Macklem uint8_t sessid[NFSX_V4SESSIONID]; 43799442a64eSRick Macklem int error = 0, foreaft; 43809442a64eSRick Macklem 43819442a64eSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 43829442a64eSRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 43839442a64eSRick Macklem goto nfsmout; 43849442a64eSRick Macklem } 43859442a64eSRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED); 43869442a64eSRick Macklem NFSBCOPY(tl, sessid, NFSX_V4SESSIONID); 43879442a64eSRick Macklem tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); 43889442a64eSRick Macklem foreaft = fxdr_unsigned(int, *tl++); 43899442a64eSRick Macklem if (*tl == newnfs_true) { 43909442a64eSRick Macklem /* RDMA is not supported. */ 43919442a64eSRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 43929442a64eSRick Macklem goto nfsmout; 43939442a64eSRick Macklem } 43949442a64eSRick Macklem 43959442a64eSRick Macklem nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft); 43969442a64eSRick Macklem if (nd->nd_repstat == 0) { 43979442a64eSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 * 43989442a64eSRick Macklem NFSX_UNSIGNED); 43999442a64eSRick Macklem NFSBCOPY(sessid, tl, NFSX_V4SESSIONID); 44009442a64eSRick Macklem tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); 44019442a64eSRick Macklem *tl++ = txdr_unsigned(foreaft); 44029442a64eSRick Macklem *tl = newnfs_false; 44039442a64eSRick Macklem } 44049442a64eSRick Macklem nfsmout: 44059442a64eSRick Macklem NFSEXITCODE2(error, nd); 44069442a64eSRick Macklem return (error); 44079442a64eSRick Macklem } 44089442a64eSRick Macklem 44099442a64eSRick Macklem /* 4410c59e4cc3SRick Macklem * nfsv4 destroy session service 4411c59e4cc3SRick Macklem */ 4412c59e4cc3SRick Macklem APPLESTATIC int 4413c59e4cc3SRick Macklem nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram, 4414af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4415c59e4cc3SRick Macklem { 4416c59e4cc3SRick Macklem uint8_t *cp, sessid[NFSX_V4SESSIONID]; 4417c59e4cc3SRick Macklem int error = 0; 4418c59e4cc3SRick Macklem 4419c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4420c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 4421c59e4cc3SRick Macklem goto nfsmout; 4422c59e4cc3SRick Macklem } 4423c59e4cc3SRick Macklem NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID); 4424c59e4cc3SRick Macklem NFSBCOPY(cp, sessid, NFSX_V4SESSIONID); 4425c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_destroysession(nd, sessid); 4426c59e4cc3SRick Macklem nfsmout: 4427c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4428c59e4cc3SRick Macklem return (error); 4429c59e4cc3SRick Macklem } 4430c59e4cc3SRick Macklem 4431c59e4cc3SRick Macklem /* 4432c59e4cc3SRick Macklem * nfsv4 free stateid service 4433c59e4cc3SRick Macklem */ 4434c59e4cc3SRick Macklem APPLESTATIC int 4435c59e4cc3SRick Macklem nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram, 4436af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4437c59e4cc3SRick Macklem { 4438c59e4cc3SRick Macklem uint32_t *tl; 4439c59e4cc3SRick Macklem nfsv4stateid_t stateid; 4440c59e4cc3SRick Macklem int error = 0; 4441af444b18SEdward Tomasz Napierala struct thread *p = curthread; 4442c59e4cc3SRick Macklem 4443c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4444c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 4445c59e4cc3SRick Macklem goto nfsmout; 4446c59e4cc3SRick Macklem } 4447c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 4448c59e4cc3SRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4449c59e4cc3SRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 445090d2dfabSRick Macklem 445190d2dfabSRick Macklem /* 445290d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 445390d2dfabSRick Macklem * stateid to the current stateid, if it is set. 445490d2dfabSRick Macklem */ 445590d2dfabSRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 445690d2dfabSRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 445790d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 445890d2dfabSRick Macklem stateid = nd->nd_curstateid; 445990d2dfabSRick Macklem stateid.seqid = 0; 446090d2dfabSRick Macklem } else { 446190d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 446290d2dfabSRick Macklem goto nfsmout; 446390d2dfabSRick Macklem } 446490d2dfabSRick Macklem } 446590d2dfabSRick Macklem 4466c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p); 446790d2dfabSRick Macklem 446890d2dfabSRick Macklem /* If the current stateid has been free'd, unset it. */ 446990d2dfabSRick Macklem if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 && 447090d2dfabSRick Macklem stateid.other[0] == nd->nd_curstateid.other[0] && 447190d2dfabSRick Macklem stateid.other[1] == nd->nd_curstateid.other[1] && 447290d2dfabSRick Macklem stateid.other[2] == nd->nd_curstateid.other[2]) 447390d2dfabSRick Macklem nd->nd_flag &= ~ND_CURSTATEID; 447490d2dfabSRick Macklem nfsmout: 447590d2dfabSRick Macklem NFSEXITCODE2(error, nd); 447690d2dfabSRick Macklem return (error); 447790d2dfabSRick Macklem } 447890d2dfabSRick Macklem 447990d2dfabSRick Macklem /* 448090d2dfabSRick Macklem * nfsv4 layoutget service 448190d2dfabSRick Macklem */ 448290d2dfabSRick Macklem APPLESTATIC int 448390d2dfabSRick Macklem nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram, 4484af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 448590d2dfabSRick Macklem { 448690d2dfabSRick Macklem uint32_t *tl; 448790d2dfabSRick Macklem nfsv4stateid_t stateid; 448890d2dfabSRick Macklem int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose; 448990d2dfabSRick Macklem uint64_t offset, len, minlen; 449090d2dfabSRick Macklem char *layp; 4491af444b18SEdward Tomasz Napierala struct thread *p = curthread; 449290d2dfabSRick Macklem 449390d2dfabSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 449490d2dfabSRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 449590d2dfabSRick Macklem goto nfsmout; 449690d2dfabSRick Macklem } 449790d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 449890d2dfabSRick Macklem NFSX_STATEID); 449990d2dfabSRick Macklem tl++; /* Signal layout available. Ignore for now. */ 450090d2dfabSRick Macklem layouttype = fxdr_unsigned(int, *tl++); 450190d2dfabSRick Macklem iomode = fxdr_unsigned(int, *tl++); 450290d2dfabSRick Macklem offset = fxdr_hyper(tl); tl += 2; 450390d2dfabSRick Macklem len = fxdr_hyper(tl); tl += 2; 450490d2dfabSRick Macklem minlen = fxdr_hyper(tl); tl += 2; 450590d2dfabSRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 450690d2dfabSRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 450790d2dfabSRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 450890d2dfabSRick Macklem maxcnt = fxdr_unsigned(int, *tl); 450990d2dfabSRick Macklem NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n", 451090d2dfabSRick Macklem layouttype, iomode, (uintmax_t)offset, (uintmax_t)len, 451190d2dfabSRick Macklem (uintmax_t)minlen); 451290d2dfabSRick Macklem if (len < minlen || 451390d2dfabSRick Macklem (minlen != UINT64_MAX && offset + minlen < offset) || 451490d2dfabSRick Macklem (len != UINT64_MAX && offset + len < offset)) { 451590d2dfabSRick Macklem nd->nd_repstat = NFSERR_INVAL; 451690d2dfabSRick Macklem goto nfsmout; 451790d2dfabSRick Macklem } 451890d2dfabSRick Macklem 451990d2dfabSRick Macklem /* 452090d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 452190d2dfabSRick Macklem * stateid to the current stateid, if it is set. 452290d2dfabSRick Macklem */ 452390d2dfabSRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 452490d2dfabSRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 452590d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 452690d2dfabSRick Macklem stateid = nd->nd_curstateid; 452790d2dfabSRick Macklem stateid.seqid = 0; 452890d2dfabSRick Macklem } else { 452990d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 453090d2dfabSRick Macklem goto nfsmout; 453190d2dfabSRick Macklem } 453290d2dfabSRick Macklem } 453390d2dfabSRick Macklem 453490d2dfabSRick Macklem layp = NULL; 453590d2dfabSRick Macklem if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1) 453690d2dfabSRick Macklem layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK); 453790d2dfabSRick Macklem else if (layouttype == NFSLAYOUT_FLEXFILE) 453890d2dfabSRick Macklem layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP, 453990d2dfabSRick Macklem M_WAITOK); 454090d2dfabSRick Macklem else 454190d2dfabSRick Macklem nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE; 454290d2dfabSRick Macklem if (layp != NULL) 454390d2dfabSRick Macklem nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype, 454490d2dfabSRick Macklem &iomode, &offset, &len, minlen, &stateid, maxcnt, 454590d2dfabSRick Macklem &retonclose, &layoutlen, layp, nd->nd_cred, p); 454690d2dfabSRick Macklem NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat, 454790d2dfabSRick Macklem layoutlen); 454890d2dfabSRick Macklem if (nd->nd_repstat == 0) { 454990d2dfabSRick Macklem /* For NFSv4.1, set the Current StateID. */ 455090d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 455190d2dfabSRick Macklem nd->nd_curstateid = stateid; 455290d2dfabSRick Macklem nd->nd_flag |= ND_CURSTATEID; 455390d2dfabSRick Macklem } 455490d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID + 455590d2dfabSRick Macklem 2 * NFSX_HYPER); 455690d2dfabSRick Macklem *tl++ = txdr_unsigned(retonclose); 455790d2dfabSRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 455890d2dfabSRick Macklem NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER); 455990d2dfabSRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 456090d2dfabSRick Macklem *tl++ = txdr_unsigned(1); /* Only returns one layout. */ 456190d2dfabSRick Macklem txdr_hyper(offset, tl); tl += 2; 456290d2dfabSRick Macklem txdr_hyper(len, tl); tl += 2; 456390d2dfabSRick Macklem *tl++ = txdr_unsigned(iomode); 456490d2dfabSRick Macklem *tl = txdr_unsigned(layouttype); 456590d2dfabSRick Macklem nfsm_strtom(nd, layp, layoutlen); 456690d2dfabSRick Macklem } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) { 456790d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 456890d2dfabSRick Macklem *tl = newnfs_false; 456990d2dfabSRick Macklem } 457090d2dfabSRick Macklem free(layp, M_TEMP); 457190d2dfabSRick Macklem nfsmout: 457290d2dfabSRick Macklem vput(vp); 457390d2dfabSRick Macklem NFSEXITCODE2(error, nd); 457490d2dfabSRick Macklem return (error); 457590d2dfabSRick Macklem } 457690d2dfabSRick Macklem 457790d2dfabSRick Macklem /* 457890d2dfabSRick Macklem * nfsv4 layoutcommit service 457990d2dfabSRick Macklem */ 458090d2dfabSRick Macklem APPLESTATIC int 458190d2dfabSRick Macklem nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram, 4582af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 458390d2dfabSRick Macklem { 458490d2dfabSRick Macklem uint32_t *tl; 458590d2dfabSRick Macklem nfsv4stateid_t stateid; 458690d2dfabSRick Macklem int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim; 458790d2dfabSRick Macklem int hasnewsize; 458890d2dfabSRick Macklem uint64_t offset, len, newoff, newsize; 458990d2dfabSRick Macklem struct timespec newmtime; 459090d2dfabSRick Macklem char *layp; 4591af444b18SEdward Tomasz Napierala struct thread *p = curthread; 459290d2dfabSRick Macklem 459390d2dfabSRick Macklem layp = NULL; 459490d2dfabSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 459590d2dfabSRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 459690d2dfabSRick Macklem goto nfsmout; 459790d2dfabSRick Macklem } 459890d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER + 459990d2dfabSRick Macklem NFSX_STATEID); 460090d2dfabSRick Macklem offset = fxdr_hyper(tl); tl += 2; 460190d2dfabSRick Macklem len = fxdr_hyper(tl); tl += 2; 460290d2dfabSRick Macklem reclaim = fxdr_unsigned(int, *tl++); 460390d2dfabSRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 460490d2dfabSRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 460590d2dfabSRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 460690d2dfabSRick Macklem /* 460790d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 460890d2dfabSRick Macklem * stateid to the current stateid, if it is set. 460990d2dfabSRick Macklem */ 461090d2dfabSRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 461190d2dfabSRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 461290d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 461390d2dfabSRick Macklem stateid = nd->nd_curstateid; 461490d2dfabSRick Macklem stateid.seqid = 0; 461590d2dfabSRick Macklem } else { 461690d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 461790d2dfabSRick Macklem goto nfsmout; 461890d2dfabSRick Macklem } 461990d2dfabSRick Macklem } 462090d2dfabSRick Macklem 462190d2dfabSRick Macklem hasnewoff = fxdr_unsigned(int, *tl); 462290d2dfabSRick Macklem if (hasnewoff != 0) { 462390d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 462490d2dfabSRick Macklem newoff = fxdr_hyper(tl); tl += 2; 462590d2dfabSRick Macklem } else 462690d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 462790d2dfabSRick Macklem hasnewmtime = fxdr_unsigned(int, *tl); 462890d2dfabSRick Macklem if (hasnewmtime != 0) { 462990d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED); 463090d2dfabSRick Macklem fxdr_nfsv4time(tl, &newmtime); 463190d2dfabSRick Macklem tl += (NFSX_V4TIME / NFSX_UNSIGNED); 463290d2dfabSRick Macklem } else 463390d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 463490d2dfabSRick Macklem layouttype = fxdr_unsigned(int, *tl++); 463590d2dfabSRick Macklem maxcnt = fxdr_unsigned(int, *tl); 463690d2dfabSRick Macklem if (maxcnt > 0) { 463790d2dfabSRick Macklem layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK); 463890d2dfabSRick Macklem error = nfsrv_mtostr(nd, layp, maxcnt); 463990d2dfabSRick Macklem if (error != 0) 464090d2dfabSRick Macklem goto nfsmout; 464190d2dfabSRick Macklem } 464290d2dfabSRick Macklem nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff, 464390d2dfabSRick Macklem newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid, 464490d2dfabSRick Macklem maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p); 464590d2dfabSRick Macklem NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat); 464690d2dfabSRick Macklem if (nd->nd_repstat == 0) { 464790d2dfabSRick Macklem if (hasnewsize != 0) { 464890d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); 464990d2dfabSRick Macklem *tl++ = newnfs_true; 465090d2dfabSRick Macklem txdr_hyper(newsize, tl); 465190d2dfabSRick Macklem } else { 465290d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 465390d2dfabSRick Macklem *tl = newnfs_false; 465490d2dfabSRick Macklem } 465590d2dfabSRick Macklem } 465690d2dfabSRick Macklem nfsmout: 465790d2dfabSRick Macklem free(layp, M_TEMP); 465890d2dfabSRick Macklem vput(vp); 465990d2dfabSRick Macklem NFSEXITCODE2(error, nd); 466090d2dfabSRick Macklem return (error); 466190d2dfabSRick Macklem } 466290d2dfabSRick Macklem 466390d2dfabSRick Macklem /* 466490d2dfabSRick Macklem * nfsv4 layoutreturn service 466590d2dfabSRick Macklem */ 466690d2dfabSRick Macklem APPLESTATIC int 466790d2dfabSRick Macklem nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram, 4668af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 466990d2dfabSRick Macklem { 467090d2dfabSRick Macklem uint32_t *tl, *layp; 467190d2dfabSRick Macklem nfsv4stateid_t stateid; 467290d2dfabSRick Macklem int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim; 467390d2dfabSRick Macklem uint64_t offset, len; 4674af444b18SEdward Tomasz Napierala struct thread *p = curthread; 467590d2dfabSRick Macklem 467690d2dfabSRick Macklem layp = NULL; 467790d2dfabSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 467890d2dfabSRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 467990d2dfabSRick Macklem goto nfsmout; 468090d2dfabSRick Macklem } 468190d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 468290d2dfabSRick Macklem reclaim = *tl++; 468390d2dfabSRick Macklem layouttype = fxdr_unsigned(int, *tl++); 468490d2dfabSRick Macklem iomode = fxdr_unsigned(int, *tl++); 468590d2dfabSRick Macklem kind = fxdr_unsigned(int, *tl); 468690d2dfabSRick Macklem NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim, 468790d2dfabSRick Macklem layouttype, iomode, kind); 468890d2dfabSRick Macklem if (kind == NFSV4LAYOUTRET_FILE) { 468990d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 469090d2dfabSRick Macklem NFSX_UNSIGNED); 469190d2dfabSRick Macklem offset = fxdr_hyper(tl); tl += 2; 469290d2dfabSRick Macklem len = fxdr_hyper(tl); tl += 2; 469390d2dfabSRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 469490d2dfabSRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 469590d2dfabSRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 469690d2dfabSRick Macklem 469790d2dfabSRick Macklem /* 469890d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set 469990d2dfabSRick Macklem * the stateid to the current stateid, if it is set. 470090d2dfabSRick Macklem */ 470190d2dfabSRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 470290d2dfabSRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 470390d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 470490d2dfabSRick Macklem stateid = nd->nd_curstateid; 470590d2dfabSRick Macklem stateid.seqid = 0; 470690d2dfabSRick Macklem } else { 470790d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 470890d2dfabSRick Macklem goto nfsmout; 470990d2dfabSRick Macklem } 471090d2dfabSRick Macklem } 471190d2dfabSRick Macklem 471290d2dfabSRick Macklem maxcnt = fxdr_unsigned(int, *tl); 471390d2dfabSRick Macklem if (maxcnt > 0) { 471490d2dfabSRick Macklem layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK); 471590d2dfabSRick Macklem error = nfsrv_mtostr(nd, (char *)layp, maxcnt); 471690d2dfabSRick Macklem if (error != 0) 471790d2dfabSRick Macklem goto nfsmout; 471890d2dfabSRick Macklem } 471990d2dfabSRick Macklem } else { 472090d2dfabSRick Macklem if (reclaim == newnfs_true) { 472190d2dfabSRick Macklem nd->nd_repstat = NFSERR_INVAL; 472290d2dfabSRick Macklem goto nfsmout; 472390d2dfabSRick Macklem } 472490d2dfabSRick Macklem offset = len = 0; 472590d2dfabSRick Macklem maxcnt = 0; 472690d2dfabSRick Macklem } 472790d2dfabSRick Macklem nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode, 472890d2dfabSRick Macklem offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd, 472990d2dfabSRick Macklem nd->nd_cred, p); 473090d2dfabSRick Macklem NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat, 473190d2dfabSRick Macklem fnd); 473290d2dfabSRick Macklem if (nd->nd_repstat == 0) { 473390d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 473490d2dfabSRick Macklem if (fnd != 0) { 473590d2dfabSRick Macklem *tl = newnfs_true; 473690d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_STATEID); 473790d2dfabSRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 473890d2dfabSRick Macklem NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER); 473990d2dfabSRick Macklem } else 474090d2dfabSRick Macklem *tl = newnfs_false; 474190d2dfabSRick Macklem } 474290d2dfabSRick Macklem nfsmout: 474390d2dfabSRick Macklem free(layp, M_TEMP); 474490d2dfabSRick Macklem vput(vp); 474590d2dfabSRick Macklem NFSEXITCODE2(error, nd); 474690d2dfabSRick Macklem return (error); 474790d2dfabSRick Macklem } 474890d2dfabSRick Macklem 474990d2dfabSRick Macklem /* 475090d2dfabSRick Macklem * nfsv4 getdeviceinfo service 475190d2dfabSRick Macklem */ 475290d2dfabSRick Macklem APPLESTATIC int 475390d2dfabSRick Macklem nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram, 4754af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 475590d2dfabSRick Macklem { 475690d2dfabSRick Macklem uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP]; 475790d2dfabSRick Macklem int cnt, devaddrlen, error = 0, i, layouttype; 475890d2dfabSRick Macklem char devid[NFSX_V4DEVICEID], *devaddr; 475990d2dfabSRick Macklem time_t dev_time; 476090d2dfabSRick Macklem 476190d2dfabSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 476290d2dfabSRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 476390d2dfabSRick Macklem goto nfsmout; 476490d2dfabSRick Macklem } 476590d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID); 476690d2dfabSRick Macklem NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 476790d2dfabSRick Macklem tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 476890d2dfabSRick Macklem layouttype = fxdr_unsigned(int, *tl++); 476990d2dfabSRick Macklem maxcnt = fxdr_unsigned(uint32_t, *tl++); 477090d2dfabSRick Macklem cnt = fxdr_unsigned(int, *tl); 477190d2dfabSRick Macklem NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype, 477290d2dfabSRick Macklem maxcnt, cnt); 477390d2dfabSRick Macklem if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) { 477490d2dfabSRick Macklem nd->nd_repstat = NFSERR_INVAL; 477590d2dfabSRick Macklem goto nfsmout; 477690d2dfabSRick Macklem } 477790d2dfabSRick Macklem if (cnt > 0) { 477890d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED); 477990d2dfabSRick Macklem for (i = 0; i < cnt; i++) 478090d2dfabSRick Macklem notify[i] = fxdr_unsigned(uint32_t, *tl++); 478190d2dfabSRick Macklem } 478290d2dfabSRick Macklem for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++) 478390d2dfabSRick Macklem notify[i] = 0; 478490d2dfabSRick Macklem 478590d2dfabSRick Macklem /* 478690d2dfabSRick Macklem * Check that the device id is not stale. Device ids are recreated 478790d2dfabSRick Macklem * each time the nfsd threads are restarted. 478890d2dfabSRick Macklem */ 478990d2dfabSRick Macklem NFSBCOPY(devid, &dev_time, sizeof(dev_time)); 479090d2dfabSRick Macklem if (dev_time != nfsdev_time) { 479190d2dfabSRick Macklem nd->nd_repstat = NFSERR_NOENT; 479290d2dfabSRick Macklem goto nfsmout; 479390d2dfabSRick Macklem } 479490d2dfabSRick Macklem 479590d2dfabSRick Macklem /* Look for the device id. */ 479690d2dfabSRick Macklem nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt, 479790d2dfabSRick Macklem notify, &devaddrlen, &devaddr); 479890d2dfabSRick Macklem NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat); 479990d2dfabSRick Macklem if (nd->nd_repstat == 0) { 480090d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 480190d2dfabSRick Macklem *tl = txdr_unsigned(layouttype); 480290d2dfabSRick Macklem nfsm_strtom(nd, devaddr, devaddrlen); 480390d2dfabSRick Macklem cnt = 0; 480490d2dfabSRick Macklem for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) { 480590d2dfabSRick Macklem if (notify[i] != 0) 480690d2dfabSRick Macklem cnt = i + 1; 480790d2dfabSRick Macklem } 480890d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED); 480990d2dfabSRick Macklem *tl++ = txdr_unsigned(cnt); 481090d2dfabSRick Macklem for (i = 0; i < cnt; i++) 481190d2dfabSRick Macklem *tl++ = txdr_unsigned(notify[i]); 481290d2dfabSRick Macklem } else if (nd->nd_repstat == NFSERR_TOOSMALL) { 481390d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 481490d2dfabSRick Macklem *tl = txdr_unsigned(maxcnt); 481590d2dfabSRick Macklem } 4816c59e4cc3SRick Macklem nfsmout: 4817c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4818c59e4cc3SRick Macklem return (error); 4819c59e4cc3SRick Macklem } 4820c59e4cc3SRick Macklem 4821c59e4cc3SRick Macklem /* 48225d4835e4SRick Macklem * nfsv4 test stateid service 48235d4835e4SRick Macklem */ 48245d4835e4SRick Macklem APPLESTATIC int 48255d4835e4SRick Macklem nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram, 4826af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 48275d4835e4SRick Macklem { 48285d4835e4SRick Macklem uint32_t *tl; 48295d4835e4SRick Macklem nfsv4stateid_t *stateidp = NULL, *tstateidp; 48305d4835e4SRick Macklem int cnt, error = 0, i, ret; 4831af444b18SEdward Tomasz Napierala struct thread *p = curthread; 48325d4835e4SRick Macklem 48335d4835e4SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 48345d4835e4SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 48355d4835e4SRick Macklem goto nfsmout; 48365d4835e4SRick Macklem } 48375d4835e4SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 48385d4835e4SRick Macklem cnt = fxdr_unsigned(int, *tl); 48395d4835e4SRick Macklem if (cnt <= 0 || cnt > 1024) { 48405d4835e4SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 48415d4835e4SRick Macklem goto nfsmout; 48425d4835e4SRick Macklem } 48435d4835e4SRick Macklem stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK); 48445d4835e4SRick Macklem tstateidp = stateidp; 48455d4835e4SRick Macklem for (i = 0; i < cnt; i++) { 48465d4835e4SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 48475d4835e4SRick Macklem tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 48485d4835e4SRick Macklem NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER); 48495d4835e4SRick Macklem tstateidp++; 48505d4835e4SRick Macklem } 48515d4835e4SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 48525d4835e4SRick Macklem *tl = txdr_unsigned(cnt); 48535d4835e4SRick Macklem tstateidp = stateidp; 48545d4835e4SRick Macklem for (i = 0; i < cnt; i++) { 48555d4835e4SRick Macklem ret = nfsrv_teststateid(nd, tstateidp, p); 48565d4835e4SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 48575d4835e4SRick Macklem *tl = txdr_unsigned(ret); 48585d4835e4SRick Macklem tstateidp++; 48595d4835e4SRick Macklem } 48605d4835e4SRick Macklem nfsmout: 48615d4835e4SRick Macklem free(stateidp, M_TEMP); 48625d4835e4SRick Macklem NFSEXITCODE2(error, nd); 48635d4835e4SRick Macklem return (error); 48645d4835e4SRick Macklem } 48655d4835e4SRick Macklem 48665d4835e4SRick Macklem /* 4867c59e4cc3SRick Macklem * nfsv4 service not supported 4868c59e4cc3SRick Macklem */ 4869c59e4cc3SRick Macklem APPLESTATIC int 4870c59e4cc3SRick Macklem nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram, 4871af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4872c59e4cc3SRick Macklem { 4873c59e4cc3SRick Macklem 4874c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 4875c59e4cc3SRick Macklem NFSEXITCODE2(0, nd); 4876c59e4cc3SRick Macklem return (0); 4877c59e4cc3SRick Macklem } 4878c59e4cc3SRick Macklem 4879