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> 37ed2f1001SRick Macklem #include "opt_inet.h" 38ed2f1001SRick Macklem #include "opt_inet6.h" 399ec7b004SRick Macklem /* 409ec7b004SRick Macklem * nfs version 2, 3 and 4 server calls to vnode ops 419ec7b004SRick Macklem * - these routines generally have 3 phases 429ec7b004SRick Macklem * 1 - break down and validate rpc request in mbuf list 439ec7b004SRick Macklem * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX() 449ec7b004SRick Macklem * function in nfsd_port.c 459ec7b004SRick Macklem * 3 - build the rpc reply in an mbuf list 469ec7b004SRick Macklem * For nfsv4, these functions are called for each Op within the Compound RPC. 479ec7b004SRick Macklem */ 489ec7b004SRick Macklem 499ec7b004SRick Macklem #include <fs/nfs/nfsport.h> 50c057a378SRick Macklem #include <sys/extattr.h> 51c057a378SRick Macklem #include <sys/filio.h> 529ec7b004SRick Macklem 539ec7b004SRick Macklem /* Global vars */ 549ec7b004SRick Macklem extern u_int32_t newnfs_false, newnfs_true; 55ba8cc6d7SMateusz Guzik extern __enum_uint8(vtype) nv34tov_type[8]; 569ec7b004SRick Macklem extern struct timeval nfsboottime; 5707c0c166SRick Macklem extern int nfsrv_enable_crossmntpt; 581f54e596SRick Macklem extern int nfsrv_statehashsize; 5990d2dfabSRick Macklem extern int nfsrv_layouthashsize; 6090d2dfabSRick Macklem extern time_t nfsdev_time; 6190d2dfabSRick Macklem extern volatile int nfsrv_devidcnt; 6290d2dfabSRick Macklem extern int nfsd_debuglevel; 6390d2dfabSRick Macklem extern u_long sb_max_adj; 6490d2dfabSRick Macklem extern int nfsrv_pnfsatime; 6590d2dfabSRick Macklem extern int nfsrv_maxpnfsmirror; 66ee29e6f3SRick Macklem extern uint32_t nfs_srvmaxio; 679ec7b004SRick Macklem 68e4558aacSXin LI static int nfs_async = 0; 69e4558aacSXin LI SYSCTL_DECL(_vfs_nfsd); 70e4558aacSXin LI SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0, 71e4558aacSXin LI "Tell client that writes were synced even though they were not"); 7290d2dfabSRick Macklem extern int nfsrv_doflexfile; 7390d2dfabSRick Macklem SYSCTL_INT(_vfs_nfsd, OID_AUTO, default_flexfile, CTLFLAG_RW, 7490d2dfabSRick Macklem &nfsrv_doflexfile, 0, "Make Flex File Layout the default for pNFS"); 75c057a378SRick Macklem static int nfsrv_linux42server = 1; 76c057a378SRick Macklem SYSCTL_INT(_vfs_nfsd, OID_AUTO, linux42server, CTLFLAG_RW, 77c057a378SRick Macklem &nfsrv_linux42server, 0, 78c057a378SRick Macklem "Enable Linux style NFSv4.2 server (non-RFC compliant)"); 79b0b7d978SRick Macklem static bool nfsrv_openaccess = true; 80b0b7d978SRick Macklem SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, v4openaccess, CTLFLAG_RW, 81b0b7d978SRick Macklem &nfsrv_openaccess, 0, 82b0b7d978SRick Macklem "Enable Linux style NFSv4 Open access check"); 83272c4a4dSAlexander Motin static char nfsrv_scope[NFSV4_OPAQUELIMIT]; 84272c4a4dSAlexander Motin SYSCTL_STRING(_vfs_nfsd, OID_AUTO, scope, CTLFLAG_RWTUN, 85272c4a4dSAlexander Motin &nfsrv_scope, NFSV4_OPAQUELIMIT, "Server scope"); 86272c4a4dSAlexander Motin static char nfsrv_owner_major[NFSV4_OPAQUELIMIT]; 87272c4a4dSAlexander Motin SYSCTL_STRING(_vfs_nfsd, OID_AUTO, owner_major, CTLFLAG_RWTUN, 88272c4a4dSAlexander Motin &nfsrv_owner_major, NFSV4_OPAQUELIMIT, "Server owner major"); 89272c4a4dSAlexander Motin static uint64_t nfsrv_owner_minor; 90272c4a4dSAlexander Motin SYSCTL_U64(_vfs_nfsd, OID_AUTO, owner_minor, CTLFLAG_RWTUN, 91272c4a4dSAlexander Motin &nfsrv_owner_minor, 0, "Server owner minor"); 92dfe887b7SRick Macklem /* 93dfe887b7SRick Macklem * Only enable this if all your exported file systems 94dfe887b7SRick Macklem * (or pNFS DSs for the pNFS case) support VOP_ALLOCATE. 95dfe887b7SRick Macklem */ 96dfe887b7SRick Macklem static bool nfsrv_doallocate = false; 97dfe887b7SRick Macklem SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, enable_v42allocate, CTLFLAG_RW, 98dfe887b7SRick Macklem &nfsrv_doallocate, 0, 99dfe887b7SRick Macklem "Enable NFSv4.2 Allocate operation"); 100748f56c5SRick Macklem static uint64_t nfsrv_maxcopyrange = SSIZE_MAX; 101748f56c5SRick Macklem SYSCTL_U64(_vfs_nfsd, OID_AUTO, maxcopyrange, CTLFLAG_RW, 102748f56c5SRick Macklem &nfsrv_maxcopyrange, 0, "Max size of a Copy so RPC times reasonable"); 103e4558aacSXin LI 1049ec7b004SRick Macklem /* 1059ec7b004SRick Macklem * This list defines the GSS mechanisms supported. 1069ec7b004SRick Macklem * (Don't ask me how you get these strings from the RFC stuff like 1079ec7b004SRick Macklem * iso(1), org(3)... but someone did it, so I don't need to know.) 1089ec7b004SRick Macklem */ 1099ec7b004SRick Macklem static struct nfsgss_mechlist nfsgss_mechlist[] = { 1109ec7b004SRick Macklem { 9, "\052\206\110\206\367\022\001\002\002", 11 }, 1119ec7b004SRick Macklem { 0, "", 0 }, 1129ec7b004SRick Macklem }; 1139ec7b004SRick Macklem 1149ec7b004SRick Macklem /* local functions */ 1159ec7b004SRick Macklem static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 1169ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 1179ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 1189ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, 1199ec7b004SRick Macklem NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 1209ec7b004SRick Macklem int pathlen); 1219ec7b004SRick Macklem static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 1229ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 1239ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 1249ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 1259ec7b004SRick Macklem NFSPROC_T *p, struct nfsexstuff *exp); 1269ec7b004SRick Macklem 1279ec7b004SRick Macklem /* 1289ec7b004SRick Macklem * nfs access service (not a part of NFS V2) 1299ec7b004SRick Macklem */ 130b9cc3262SRyan Moeller int 1319ec7b004SRick Macklem nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram, 132af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 1339ec7b004SRick Macklem { 1349ec7b004SRick Macklem u_int32_t *tl; 1359ec7b004SRick Macklem int getret, error = 0; 1369ec7b004SRick Macklem struct nfsvattr nva; 1379ec7b004SRick Macklem u_int32_t testmode, nfsmode, supported = 0; 1388da45f2cSRick Macklem accmode_t deletebit; 139af444b18SEdward Tomasz Napierala struct thread *p = curthread; 1409ec7b004SRick Macklem 1419ec7b004SRick Macklem if (nd->nd_repstat) { 1429ec7b004SRick Macklem nfsrv_postopattr(nd, 1, &nva); 143a9285ae5SZack Kirsch goto out; 1449ec7b004SRick Macklem } 1459ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1469ec7b004SRick Macklem nfsmode = fxdr_unsigned(u_int32_t, *tl); 1479ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && 1489ec7b004SRick Macklem (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP | 1499ec7b004SRick Macklem NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE | 150c057a378SRick Macklem NFSACCESS_EXECUTE | NFSACCESS_XAREAD | NFSACCESS_XAWRITE | 151c057a378SRick Macklem NFSACCESS_XALIST))) { 1529ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 1539ec7b004SRick Macklem vput(vp); 154a9285ae5SZack Kirsch goto out; 1559ec7b004SRick Macklem } 1569ec7b004SRick Macklem if (nfsmode & NFSACCESS_READ) { 1579ec7b004SRick Macklem supported |= NFSACCESS_READ; 1588da45f2cSRick Macklem if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, 1598da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1609ec7b004SRick Macklem nfsmode &= ~NFSACCESS_READ; 1619ec7b004SRick Macklem } 1629ec7b004SRick Macklem if (nfsmode & NFSACCESS_MODIFY) { 1639ec7b004SRick Macklem supported |= NFSACCESS_MODIFY; 1648da45f2cSRick Macklem if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, 1658da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1669ec7b004SRick Macklem nfsmode &= ~NFSACCESS_MODIFY; 1679ec7b004SRick Macklem } 1689ec7b004SRick Macklem if (nfsmode & NFSACCESS_EXTEND) { 1699ec7b004SRick Macklem supported |= NFSACCESS_EXTEND; 1708da45f2cSRick Macklem if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p, 1718da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1729ec7b004SRick Macklem nfsmode &= ~NFSACCESS_EXTEND; 1739ec7b004SRick Macklem } 174c057a378SRick Macklem if (nfsmode & NFSACCESS_XAREAD) { 175c057a378SRick Macklem supported |= NFSACCESS_XAREAD; 176c057a378SRick Macklem if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, 177c057a378SRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 178c057a378SRick Macklem nfsmode &= ~NFSACCESS_XAREAD; 179c057a378SRick Macklem } 180c057a378SRick Macklem if (nfsmode & NFSACCESS_XAWRITE) { 181c057a378SRick Macklem supported |= NFSACCESS_XAWRITE; 182c057a378SRick Macklem if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, 183c057a378SRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 184c057a378SRick Macklem nfsmode &= ~NFSACCESS_XAWRITE; 185c057a378SRick Macklem } 186c057a378SRick Macklem if (nfsmode & NFSACCESS_XALIST) { 187c057a378SRick Macklem supported |= NFSACCESS_XALIST; 188c057a378SRick Macklem if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, 189c057a378SRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 190c057a378SRick Macklem nfsmode &= ~NFSACCESS_XALIST; 191c057a378SRick Macklem } 1929ec7b004SRick Macklem if (nfsmode & NFSACCESS_DELETE) { 1939ec7b004SRick Macklem supported |= NFSACCESS_DELETE; 1948da45f2cSRick Macklem if (vp->v_type == VDIR) 1958da45f2cSRick Macklem deletebit = VDELETE_CHILD; 1968da45f2cSRick Macklem else 1978da45f2cSRick Macklem deletebit = VDELETE; 1988da45f2cSRick Macklem if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p, 1998da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 2009ec7b004SRick Macklem nfsmode &= ~NFSACCESS_DELETE; 2019ec7b004SRick Macklem } 2025d3fe02cSRick Macklem if (vp->v_type == VDIR) 2039ec7b004SRick Macklem testmode = NFSACCESS_LOOKUP; 2049ec7b004SRick Macklem else 2059ec7b004SRick Macklem testmode = NFSACCESS_EXECUTE; 2069ec7b004SRick Macklem if (nfsmode & testmode) { 2079ec7b004SRick Macklem supported |= (nfsmode & testmode); 2088da45f2cSRick Macklem if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p, 2098da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 2109ec7b004SRick Macklem nfsmode &= ~testmode; 2119ec7b004SRick Macklem } 2129ec7b004SRick Macklem nfsmode &= supported; 2139ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 21490d2dfabSRick Macklem getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 2159ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 2169ec7b004SRick Macklem } 2179ec7b004SRick Macklem vput(vp); 2189ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 2199ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2209ec7b004SRick Macklem *tl++ = txdr_unsigned(supported); 2219ec7b004SRick Macklem } else 2229ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2239ec7b004SRick Macklem *tl = txdr_unsigned(nfsmode); 224a9285ae5SZack Kirsch 225a9285ae5SZack Kirsch out: 226a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 2279ec7b004SRick Macklem return (0); 2289ec7b004SRick Macklem nfsmout: 2299ec7b004SRick Macklem vput(vp); 230a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 2319ec7b004SRick Macklem return (error); 2329ec7b004SRick Macklem } 2339ec7b004SRick Macklem 2349ec7b004SRick Macklem /* 2359ec7b004SRick Macklem * nfs getattr service 2369ec7b004SRick Macklem */ 237b9cc3262SRyan Moeller int 2389ec7b004SRick Macklem nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram, 239af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 2409ec7b004SRick Macklem { 2419ec7b004SRick Macklem struct nfsvattr nva; 2429ec7b004SRick Macklem fhandle_t fh; 243a09001a8SRick Macklem int at_root = 0, error = 0, supports_nfsv4acls; 2449ec7b004SRick Macklem struct nfsreferral *refp; 24553f476caSRick Macklem nfsattrbit_t attrbits, tmpbits; 24607c0c166SRick Macklem struct mount *mp; 24707c0c166SRick Macklem struct vnode *tvp = NULL; 24807c0c166SRick Macklem struct vattr va; 24907c0c166SRick Macklem uint64_t mounted_on_fileno = 0; 25053f476caSRick Macklem accmode_t accmode; 251af444b18SEdward Tomasz Napierala struct thread *p = curthread; 2529ec7b004SRick Macklem 2539ec7b004SRick Macklem if (nd->nd_repstat) 254a9285ae5SZack Kirsch goto out; 2559ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 2569ec7b004SRick Macklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 2579ec7b004SRick Macklem if (error) { 2589ec7b004SRick Macklem vput(vp); 259a9285ae5SZack Kirsch goto out; 2609ec7b004SRick Macklem } 2619ec7b004SRick Macklem 2629ec7b004SRick Macklem /* 2639ec7b004SRick Macklem * Check for a referral. 2649ec7b004SRick Macklem */ 2659ec7b004SRick Macklem refp = nfsv4root_getreferral(vp, NULL, 0); 2669ec7b004SRick Macklem if (refp != NULL) { 2679ec7b004SRick Macklem (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1, 2689ec7b004SRick Macklem &nd->nd_repstat); 2699ec7b004SRick Macklem vput(vp); 270a9285ae5SZack Kirsch goto out; 2719ec7b004SRick Macklem } 27253f476caSRick Macklem if (nd->nd_repstat == 0) { 27353f476caSRick Macklem accmode = 0; 27453f476caSRick Macklem NFSSET_ATTRBIT(&tmpbits, &attrbits); 275d8a5961fSMarcelo Araujo 276d8a5961fSMarcelo Araujo /* 277d8a5961fSMarcelo Araujo * GETATTR with write-only attr time_access_set and time_modify_set 278d8a5961fSMarcelo Araujo * should return NFS4ERR_INVAL. 279d8a5961fSMarcelo Araujo */ 280d8a5961fSMarcelo Araujo if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) || 281d8a5961fSMarcelo Araujo NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){ 282d8a5961fSMarcelo Araujo error = NFSERR_INVAL; 283d8a5961fSMarcelo Araujo vput(vp); 284d8a5961fSMarcelo Araujo goto out; 285d8a5961fSMarcelo Araujo } 28653f476caSRick Macklem if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) { 28753f476caSRick Macklem NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL); 28853f476caSRick Macklem accmode |= VREAD_ACL; 28953f476caSRick Macklem } 29053f476caSRick Macklem if (NFSNONZERO_ATTRBIT(&tmpbits)) 29153f476caSRick Macklem accmode |= VREAD_ATTRIBUTES; 29253f476caSRick Macklem if (accmode != 0) 29353f476caSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, accmode, 2948da45f2cSRick Macklem nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, 2958da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 2969ec7b004SRick Macklem } 29753f476caSRick Macklem } 2989ec7b004SRick Macklem if (!nd->nd_repstat) 29990d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); 3009ec7b004SRick Macklem if (!nd->nd_repstat) { 3019ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 3029ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE)) 3039ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3049ec7b004SRick Macklem if (!nd->nd_repstat) 3059ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkgetattr(nd, vp, 30690d2dfabSRick Macklem &nva, &attrbits, p); 30707c0c166SRick Macklem if (nd->nd_repstat == 0) { 308a09001a8SRick Macklem supports_nfsv4acls = nfs_supportsnfsv4acls(vp); 30907c0c166SRick Macklem mp = vp->v_mount; 31007c0c166SRick Macklem if (nfsrv_enable_crossmntpt != 0 && 31107c0c166SRick Macklem vp->v_type == VDIR && 31207c0c166SRick Macklem (vp->v_vflag & VV_ROOT) != 0 && 31307c0c166SRick Macklem vp != rootvnode) { 31407c0c166SRick Macklem tvp = mp->mnt_vnodecovered; 31507c0c166SRick Macklem VREF(tvp); 31607c0c166SRick Macklem at_root = 1; 31707c0c166SRick Macklem } else 31807c0c166SRick Macklem at_root = 0; 31907c0c166SRick Macklem vfs_ref(mp); 320b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 32107c0c166SRick Macklem if (at_root != 0) { 32207c0c166SRick Macklem if ((nd->nd_repstat = 32398f234f3SZack Kirsch NFSVOPLOCK(tvp, LK_SHARED)) == 0) { 32407c0c166SRick Macklem nd->nd_repstat = VOP_GETATTR( 32507c0c166SRick Macklem tvp, &va, nd->nd_cred); 32607c0c166SRick Macklem vput(tvp); 32707c0c166SRick Macklem } else 32807c0c166SRick Macklem vrele(tvp); 32907c0c166SRick Macklem if (nd->nd_repstat == 0) 33007c0c166SRick Macklem mounted_on_fileno = (uint64_t) 33107c0c166SRick Macklem va.va_fileid; 33207c0c166SRick Macklem else 33307c0c166SRick Macklem at_root = 0; 33407c0c166SRick Macklem } 33507c0c166SRick Macklem if (nd->nd_repstat == 0) 33607c0c166SRick Macklem nd->nd_repstat = vfs_busy(mp, 0); 33707c0c166SRick Macklem vfs_rel(mp); 33807c0c166SRick Macklem if (nd->nd_repstat == 0) { 33907c0c166SRick Macklem (void)nfsvno_fillattr(nd, mp, vp, &nva, 34007c0c166SRick Macklem &fh, 0, &attrbits, nd->nd_cred, p, 341a09001a8SRick Macklem isdgram, 1, supports_nfsv4acls, 342a09001a8SRick Macklem at_root, mounted_on_fileno); 34307c0c166SRick Macklem vfs_unbusy(mp); 34407c0c166SRick Macklem } 3459ec7b004SRick Macklem vrele(vp); 34607c0c166SRick Macklem } else 34707c0c166SRick Macklem vput(vp); 3489ec7b004SRick Macklem } else { 3499ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 3509ec7b004SRick Macklem vput(vp); 3519ec7b004SRick Macklem } 3529ec7b004SRick Macklem } else { 3539ec7b004SRick Macklem vput(vp); 3549ec7b004SRick Macklem } 355a9285ae5SZack Kirsch 356a9285ae5SZack Kirsch out: 357a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 358a9285ae5SZack Kirsch return (error); 3599ec7b004SRick Macklem } 3609ec7b004SRick Macklem 3619ec7b004SRick Macklem /* 3629ec7b004SRick Macklem * nfs setattr service 3639ec7b004SRick Macklem */ 364b9cc3262SRyan Moeller int 3659ec7b004SRick Macklem nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram, 366af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 3679ec7b004SRick Macklem { 3689ec7b004SRick Macklem struct nfsvattr nva, nva2; 3699ec7b004SRick Macklem u_int32_t *tl; 3709ec7b004SRick Macklem int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0; 37190d2dfabSRick Macklem int gotproxystateid; 3729ec7b004SRick Macklem struct timespec guard = { 0, 0 }; 3739ec7b004SRick Macklem nfsattrbit_t attrbits, retbits; 3749ec7b004SRick Macklem nfsv4stateid_t stateid; 3759ec7b004SRick Macklem NFSACL_T *aclp = NULL; 376af444b18SEdward Tomasz Napierala struct thread *p = curthread; 3779ec7b004SRick Macklem 3789ec7b004SRick Macklem if (nd->nd_repstat) { 3799ec7b004SRick Macklem nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 380a9285ae5SZack Kirsch goto out; 3819ec7b004SRick Macklem } 3829ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 383c3e22f83SRick Macklem aclp = acl_alloc(M_WAITOK); 3849ec7b004SRick Macklem aclp->acl_cnt = 0; 3859ec7b004SRick Macklem #endif 38690d2dfabSRick Macklem gotproxystateid = 0; 3879ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 3889ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 3899ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3909ec7b004SRick Macklem stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 39190d2dfabSRick Macklem stateid.other[0] = *tl++; 39290d2dfabSRick Macklem stateid.other[1] = *tl++; 39390d2dfabSRick Macklem stateid.other[2] = *tl; 39490d2dfabSRick Macklem if (stateid.other[0] == 0x55555555 && 39590d2dfabSRick Macklem stateid.other[1] == 0x55555555 && 39690d2dfabSRick Macklem stateid.other[2] == 0x55555555 && 39790d2dfabSRick Macklem stateid.seqid == 0xffffffff) 39890d2dfabSRick Macklem gotproxystateid = 1; 3999ec7b004SRick Macklem } 400d8a5961fSMarcelo Araujo error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p); 4019ec7b004SRick Macklem if (error) 4029ec7b004SRick Macklem goto nfsmout; 40390d2dfabSRick Macklem 40490d2dfabSRick Macklem /* For NFSv4, only va_uid is used from nva2. */ 40590d2dfabSRick Macklem NFSZERO_ATTRBIT(&retbits); 40690d2dfabSRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER); 40790d2dfabSRick Macklem preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits); 4089ec7b004SRick Macklem if (!nd->nd_repstat) 4099ec7b004SRick Macklem nd->nd_repstat = preat_ret; 41090d2dfabSRick Macklem 41190d2dfabSRick Macklem NFSZERO_ATTRBIT(&retbits); 4129ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 4139ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4149ec7b004SRick Macklem gcheck = fxdr_unsigned(int, *tl); 4159ec7b004SRick Macklem if (gcheck) { 4169ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4179ec7b004SRick Macklem fxdr_nfsv3time(tl, &guard); 4189ec7b004SRick Macklem } 4199ec7b004SRick Macklem if (!nd->nd_repstat && gcheck && 4209ec7b004SRick Macklem (nva2.na_ctime.tv_sec != guard.tv_sec || 4219ec7b004SRick Macklem nva2.na_ctime.tv_nsec != guard.tv_nsec)) 4229ec7b004SRick Macklem nd->nd_repstat = NFSERR_NOT_SYNC; 4239ec7b004SRick Macklem if (nd->nd_repstat) { 4249ec7b004SRick Macklem vput(vp); 4259ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 4269ec7b004SRick Macklem acl_free(aclp); 4279ec7b004SRick Macklem #endif 4289ec7b004SRick Macklem nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 429a9285ae5SZack Kirsch goto out; 4309ec7b004SRick Macklem } 4319ec7b004SRick Macklem } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) 4329ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 4339ec7b004SRick Macklem 4349ec7b004SRick Macklem /* 4359ec7b004SRick Macklem * Now that we have all the fields, lets do it. 4369ec7b004SRick Macklem * If the size is being changed write access is required, otherwise 4379ec7b004SRick Macklem * just check for a read only file system. 4389ec7b004SRick Macklem */ 4399ec7b004SRick Macklem if (!nd->nd_repstat) { 4409ec7b004SRick Macklem if (NFSVNO_NOTSETSIZE(&nva)) { 4419ec7b004SRick Macklem if (NFSVNO_EXRDONLY(exp) || 4420586a129SRick Macklem (vp->v_mount->mnt_flag & MNT_RDONLY)) 4439ec7b004SRick Macklem nd->nd_repstat = EROFS; 4449ec7b004SRick Macklem } else { 4455d3fe02cSRick Macklem if (vp->v_type != VREG) 4469ec7b004SRick Macklem nd->nd_repstat = EINVAL; 4479ec7b004SRick Macklem else if (nva2.na_uid != nd->nd_cred->cr_uid || 4489ec7b004SRick Macklem NFSVNO_EXSTRICTACCESS(exp)) 4499ec7b004SRick Macklem nd->nd_repstat = nfsvno_accchk(vp, 4508da45f2cSRick Macklem VWRITE, nd->nd_cred, exp, p, 4518da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, 4528da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 4539ec7b004SRick Macklem } 4549ec7b004SRick Macklem } 45590d2dfabSRick Macklem /* 45690d2dfabSRick Macklem * Proxy operations from the MDS are allowed via the all 0s special 45790d2dfabSRick Macklem * stateid. 45890d2dfabSRick Macklem */ 45990d2dfabSRick Macklem if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0 && 46090d2dfabSRick Macklem gotproxystateid == 0) 4619ec7b004SRick Macklem nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid, 4629ec7b004SRick Macklem &nva, &attrbits, exp, p); 4639ec7b004SRick Macklem 4649ec7b004SRick Macklem if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 4659ec7b004SRick Macklem /* 466bf312482SGordon Bergling * For V4, try setting the attributes in sets, so that the 4679ec7b004SRick Macklem * reply bitmap will be correct for an error case. 4689ec7b004SRick Macklem */ 4699ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) || 4709ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) { 4719ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 4729ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid); 4739ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid); 4749ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 4759ec7b004SRick Macklem exp); 4769ec7b004SRick Macklem if (!nd->nd_repstat) { 4779ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER)) 4789ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER); 4799ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) 4809ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP); 4819ec7b004SRick Macklem } 4829ec7b004SRick Macklem } 4839ec7b004SRick Macklem if (!nd->nd_repstat && 4849ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) { 4859ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 4869ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, size, nva.na_size); 4879ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 4889ec7b004SRick Macklem exp); 4899ec7b004SRick Macklem if (!nd->nd_repstat) 4909ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE); 4919ec7b004SRick Macklem } 4929ec7b004SRick Macklem if (!nd->nd_repstat && 4939ec7b004SRick Macklem (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) || 4949ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) { 4959ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 4969ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime); 4979ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime); 4989ec7b004SRick Macklem if (nva.na_vaflags & VA_UTIMES_NULL) { 4999ec7b004SRick Macklem nva2.na_vaflags |= VA_UTIMES_NULL; 5009ec7b004SRick Macklem NFSVNO_SETACTIVE(&nva2, vaflags); 5019ec7b004SRick Macklem } 5029ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 5039ec7b004SRick Macklem exp); 5049ec7b004SRick Macklem if (!nd->nd_repstat) { 5059ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET)) 5069ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET); 5079ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET)) 5089ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET); 5099ec7b004SRick Macklem } 5109ec7b004SRick Macklem } 5119ec7b004SRick Macklem if (!nd->nd_repstat && 512dd02d9d6SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE)) { 513dd02d9d6SRick Macklem NFSVNO_ATTRINIT(&nva2); 514dd02d9d6SRick Macklem NFSVNO_SETATTRVAL(&nva2, btime, nva.na_btime); 515dd02d9d6SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 516dd02d9d6SRick Macklem exp); 517dd02d9d6SRick Macklem if (!nd->nd_repstat) 518dd02d9d6SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMECREATE); 519dd02d9d6SRick Macklem } 520dd02d9d6SRick Macklem if (!nd->nd_repstat && 521b4372164SRick Macklem (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE) || 522b4372164SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))) { 5239ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 5249ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode); 5259ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 5269ec7b004SRick Macklem exp); 527b4372164SRick Macklem if (!nd->nd_repstat) { 528b4372164SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) 5299ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE); 530b4372164SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED)) 531b4372164SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODESETMASKED); 532b4372164SRick Macklem } 5339ec7b004SRick Macklem } 5349ec7b004SRick Macklem 5359ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 5369ec7b004SRick Macklem if (!nd->nd_repstat && aclp->acl_cnt > 0 && 5379ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) { 5389ec7b004SRick Macklem nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p); 5399ec7b004SRick Macklem if (!nd->nd_repstat) 5409ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL); 5419ec7b004SRick Macklem } 5429ec7b004SRick Macklem #endif 5439ec7b004SRick Macklem } else if (!nd->nd_repstat) { 5449ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p, 5459ec7b004SRick Macklem exp); 5469ec7b004SRick Macklem } 5479ec7b004SRick Macklem if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) { 54890d2dfabSRick Macklem postat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 5499ec7b004SRick Macklem if (!nd->nd_repstat) 5509ec7b004SRick Macklem nd->nd_repstat = postat_ret; 5519ec7b004SRick Macklem } 5529ec7b004SRick Macklem vput(vp); 5539ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 5549ec7b004SRick Macklem acl_free(aclp); 5559ec7b004SRick Macklem #endif 5569ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 5579ec7b004SRick Macklem nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 5589ec7b004SRick Macklem else if (nd->nd_flag & ND_NFSV4) 5599ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &retbits); 5609ec7b004SRick Macklem else if (!nd->nd_repstat) 5619ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 562a9285ae5SZack Kirsch 563a9285ae5SZack Kirsch out: 564a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 5659ec7b004SRick Macklem return (0); 5669ec7b004SRick Macklem nfsmout: 5679ec7b004SRick Macklem vput(vp); 5689ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 5699ec7b004SRick Macklem acl_free(aclp); 5709ec7b004SRick Macklem #endif 5719ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 5729ec7b004SRick Macklem /* 5739ec7b004SRick Macklem * For all nd_repstat, the V4 reply includes a bitmap, 5749ec7b004SRick Macklem * even NFSERR_BADXDR, which is what this will end up 5759ec7b004SRick Macklem * returning. 5769ec7b004SRick Macklem */ 5779ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &retbits); 5789ec7b004SRick Macklem } 579a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 5809ec7b004SRick Macklem return (error); 5819ec7b004SRick Macklem } 5829ec7b004SRick Macklem 5839ec7b004SRick Macklem /* 5849ec7b004SRick Macklem * nfs lookup rpc 5859ec7b004SRick Macklem * (Also performs lookup parent for v4) 5869ec7b004SRick Macklem */ 587b9cc3262SRyan Moeller int 5889ec7b004SRick Macklem nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram, 589af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 5909ec7b004SRick Macklem { 5919ec7b004SRick Macklem struct nameidata named; 5929ec7b004SRick Macklem vnode_t vp, dirp = NULL; 593a9285ae5SZack Kirsch int error = 0, dattr_ret = 1; 5949ec7b004SRick Macklem struct nfsvattr nva, dattr; 5959ec7b004SRick Macklem char *bufp; 5969ec7b004SRick Macklem u_long *hashp; 597af444b18SEdward Tomasz Napierala struct thread *p = curthread; 5989ec7b004SRick Macklem 5999ec7b004SRick Macklem if (nd->nd_repstat) { 6009ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 601a9285ae5SZack Kirsch goto out; 6029ec7b004SRick Macklem } 6039ec7b004SRick Macklem 6049ec7b004SRick Macklem /* 6059ec7b004SRick Macklem * For some reason, if dp is a symlink, the error 6069ec7b004SRick Macklem * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR. 6079ec7b004SRick Macklem */ 6089ec7b004SRick Macklem if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) { 6099ec7b004SRick Macklem nd->nd_repstat = NFSERR_SYMLINK; 6109ec7b004SRick Macklem vrele(dp); 611a9285ae5SZack Kirsch goto out; 6129ec7b004SRick Macklem } 6139ec7b004SRick Macklem 6149ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 61565127e98SMateusz Guzik LOCKLEAF); 6169ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 6179ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 6189ec7b004SRick Macklem if (error) { 6199ec7b004SRick Macklem vrele(dp); 6209ec7b004SRick Macklem nfsvno_relpathbuf(&named); 621a9285ae5SZack Kirsch goto out; 6229ec7b004SRick Macklem } 6239ec7b004SRick Macklem if (!nd->nd_repstat) { 624ef7d2c1fSMateusz Guzik nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp); 6259ec7b004SRick Macklem } else { 6269ec7b004SRick Macklem vrele(dp); 6279ec7b004SRick Macklem nfsvno_relpathbuf(&named); 6289ec7b004SRick Macklem } 6299ec7b004SRick Macklem if (nd->nd_repstat) { 6309ec7b004SRick Macklem if (dirp) { 6319ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 63290d2dfabSRick Macklem dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 63390d2dfabSRick Macklem 0, NULL); 6349ec7b004SRick Macklem vrele(dirp); 6359ec7b004SRick Macklem } 6369ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 6379ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 638a9285ae5SZack Kirsch goto out; 6399ec7b004SRick Macklem } 6409ec7b004SRick Macklem nfsvno_relpathbuf(&named); 6419ec7b004SRick Macklem vp = named.ni_vp; 64237b88c2dSRick Macklem if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) && 64337b88c2dSRick Macklem vp->v_type != VDIR && vp->v_type != VLNK) 64437b88c2dSRick Macklem /* 64537b88c2dSRick Macklem * Only allow lookup of VDIR and VLNK for traversal of 64637b88c2dSRick Macklem * non-exported volumes during NFSv4 mounting. 64737b88c2dSRick Macklem */ 64837b88c2dSRick Macklem nd->nd_repstat = ENOENT; 6496fd6a0e3SRick Macklem if (nd->nd_repstat == 0) { 6509ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 6516fd6a0e3SRick Macklem /* 6526fd6a0e3SRick Macklem * EOPNOTSUPP indicates the file system cannot be exported, 6536fd6a0e3SRick Macklem * so just pretend the entry does not exist. 6546fd6a0e3SRick Macklem */ 6556fd6a0e3SRick Macklem if (nd->nd_repstat == EOPNOTSUPP) 6566fd6a0e3SRick Macklem nd->nd_repstat = ENOENT; 6576fd6a0e3SRick Macklem } 6589ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 65990d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 66081f78d99SRick Macklem if (vpp != NULL && nd->nd_repstat == 0) 6619ec7b004SRick Macklem *vpp = vp; 66281f78d99SRick Macklem else 6639ec7b004SRick Macklem vput(vp); 6649ec7b004SRick Macklem if (dirp) { 6659ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 66690d2dfabSRick Macklem dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0, 66790d2dfabSRick Macklem NULL); 6689ec7b004SRick Macklem vrele(dirp); 6699ec7b004SRick Macklem } 6709ec7b004SRick Macklem if (nd->nd_repstat) { 6719ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 6729ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 673a9285ae5SZack Kirsch goto out; 6749ec7b004SRick Macklem } 6759ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 676695d87baSRick Macklem (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0); 6779ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 6789ec7b004SRick Macklem } else if (nd->nd_flag & ND_NFSV3) { 679695d87baSRick Macklem (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0); 6809ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 6819ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 6829ec7b004SRick Macklem } 683a9285ae5SZack Kirsch 684a9285ae5SZack Kirsch out: 685a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 686a9285ae5SZack Kirsch return (error); 6879ec7b004SRick Macklem } 6889ec7b004SRick Macklem 6899ec7b004SRick Macklem /* 6909ec7b004SRick Macklem * nfs readlink service 6919ec7b004SRick Macklem */ 692b9cc3262SRyan Moeller int 6939ec7b004SRick Macklem nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram, 694af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 6959ec7b004SRick Macklem { 6969ec7b004SRick Macklem u_int32_t *tl; 697ae070589SRick Macklem struct mbuf *mp = NULL, *mpend = NULL; 6989ec7b004SRick Macklem int getret = 1, len; 6999ec7b004SRick Macklem struct nfsvattr nva; 700af444b18SEdward Tomasz Napierala struct thread *p = curthread; 701cb889ce6SRick Macklem uint16_t off; 7029ec7b004SRick Macklem 7039ec7b004SRick Macklem if (nd->nd_repstat) { 7049ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 705a9285ae5SZack Kirsch goto out; 7069ec7b004SRick Macklem } 7075d3fe02cSRick Macklem if (vp->v_type != VLNK) { 7089ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) 7099ec7b004SRick Macklem nd->nd_repstat = ENXIO; 7109ec7b004SRick Macklem else 7119ec7b004SRick Macklem nd->nd_repstat = EINVAL; 7129ec7b004SRick Macklem } 713cb889ce6SRick Macklem if (nd->nd_repstat == 0) { 714cb889ce6SRick Macklem if ((nd->nd_flag & ND_EXTPG) != 0) 715cb889ce6SRick Macklem nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, 716cb889ce6SRick Macklem nd->nd_maxextsiz, p, &mp, &mpend, &len); 717cb889ce6SRick Macklem else 718cb889ce6SRick Macklem nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, 719cb889ce6SRick Macklem 0, p, &mp, &mpend, &len); 720cb889ce6SRick Macklem } 7219ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 72290d2dfabSRick Macklem getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 7239ec7b004SRick Macklem vput(vp); 7249ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 7259ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 7269ec7b004SRick Macklem if (nd->nd_repstat) 727a9285ae5SZack Kirsch goto out; 7289ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 7299ec7b004SRick Macklem *tl = txdr_unsigned(len); 73018a48314SRick Macklem if (mp != NULL) { 7319f6624d3SRick Macklem nd->nd_mb->m_next = mp; 7329ec7b004SRick Macklem nd->nd_mb = mpend; 733cb889ce6SRick Macklem if ((mpend->m_flags & M_EXTPG) != 0) { 734cb889ce6SRick Macklem nd->nd_bextpg = mpend->m_epg_npgs - 1; 735cb889ce6SRick Macklem nd->nd_bpos = (char *)(void *) 736cb889ce6SRick Macklem PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]); 737cb889ce6SRick Macklem off = (nd->nd_bextpg == 0) ? mpend->m_epg_1st_off : 0; 738cb889ce6SRick Macklem nd->nd_bpos += off + mpend->m_epg_last_len; 739cb889ce6SRick Macklem nd->nd_bextpgsiz = PAGE_SIZE - mpend->m_epg_last_len - 740cb889ce6SRick Macklem off; 741cb889ce6SRick Macklem } else 742cb889ce6SRick Macklem nd->nd_bpos = mtod(mpend, char *) + mpend->m_len; 74318a48314SRick Macklem } 744a9285ae5SZack Kirsch 745a9285ae5SZack Kirsch out: 746a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 7479ec7b004SRick Macklem return (0); 7489ec7b004SRick Macklem } 7499ec7b004SRick Macklem 7509ec7b004SRick Macklem /* 7519ec7b004SRick Macklem * nfs read service 7529ec7b004SRick Macklem */ 753b9cc3262SRyan Moeller int 7549ec7b004SRick Macklem nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram, 755af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 7569ec7b004SRick Macklem { 7579ec7b004SRick Macklem u_int32_t *tl; 75890d2dfabSRick Macklem int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0; 759ae070589SRick Macklem struct mbuf *m2, *m3; 7609ec7b004SRick Macklem struct nfsvattr nva; 7619ec7b004SRick Macklem off_t off = 0x0; 7629ec7b004SRick Macklem struct nfsstate st, *stp = &st; 7639ec7b004SRick Macklem struct nfslock lo, *lop = &lo; 7649ec7b004SRick Macklem nfsv4stateid_t stateid; 7659ec7b004SRick Macklem nfsquad_t clientid; 766af444b18SEdward Tomasz Napierala struct thread *p = curthread; 767cb889ce6SRick Macklem uint16_t poff; 7689ec7b004SRick Macklem 7699ec7b004SRick Macklem if (nd->nd_repstat) { 7709ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 771a9285ae5SZack Kirsch goto out; 7729ec7b004SRick Macklem } 7739ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 7749ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 7759ec7b004SRick Macklem off = (off_t)fxdr_unsigned(u_int32_t, *tl++); 7769ec7b004SRick Macklem reqlen = fxdr_unsigned(int, *tl); 7779ec7b004SRick Macklem } else if (nd->nd_flag & ND_NFSV3) { 7789ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 7799ec7b004SRick Macklem off = fxdr_hyper(tl); 7809ec7b004SRick Macklem tl += 2; 7819ec7b004SRick Macklem reqlen = fxdr_unsigned(int, *tl); 7829ec7b004SRick Macklem } else { 7839ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED); 7849ec7b004SRick Macklem reqlen = fxdr_unsigned(int, *(tl + 6)); 7859ec7b004SRick Macklem } 7869ec7b004SRick Macklem if (reqlen > NFS_SRVMAXDATA(nd)) { 7879ec7b004SRick Macklem reqlen = NFS_SRVMAXDATA(nd); 7889ec7b004SRick Macklem } else if (reqlen < 0) { 7899ec7b004SRick Macklem error = EBADRPC; 7909ec7b004SRick Macklem goto nfsmout; 7919ec7b004SRick Macklem } 79290d2dfabSRick Macklem gotproxystateid = 0; 7939ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 7949ec7b004SRick Macklem stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS); 7959ec7b004SRick Macklem lop->lo_flags = NFSLCK_READ; 7969ec7b004SRick Macklem stp->ls_ownerlen = 0; 7979ec7b004SRick Macklem stp->ls_op = NULL; 7989ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 7999ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 8009ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 8019ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 802c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 803c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 804c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 805c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 806c59e4cc3SRick Macklem printf("EEK1 multiple clids\n"); 8079ec7b004SRick Macklem } else { 808c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 809c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 8109ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 8119ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 8129ec7b004SRick Macklem } 8139ec7b004SRick Macklem stp->ls_stateid.other[2] = *tl++; 81490d2dfabSRick Macklem /* 81590d2dfabSRick Macklem * Don't allow the client to use a special stateid for a DS op. 81690d2dfabSRick Macklem */ 81790d2dfabSRick Macklem if ((nd->nd_flag & ND_DSSERVER) != 0 && 81890d2dfabSRick Macklem ((stp->ls_stateid.other[0] == 0x0 && 81990d2dfabSRick Macklem stp->ls_stateid.other[1] == 0x0 && 82090d2dfabSRick Macklem stp->ls_stateid.other[2] == 0x0) || 82190d2dfabSRick Macklem (stp->ls_stateid.other[0] == 0xffffffff && 82290d2dfabSRick Macklem stp->ls_stateid.other[1] == 0xffffffff && 82390d2dfabSRick Macklem stp->ls_stateid.other[2] == 0xffffffff) || 82490d2dfabSRick Macklem stp->ls_stateid.seqid != 0)) 82590d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 82690d2dfabSRick Macklem /* However, allow the proxy stateid. */ 82790d2dfabSRick Macklem if (stp->ls_stateid.seqid == 0xffffffff && 82890d2dfabSRick Macklem stp->ls_stateid.other[0] == 0x55555555 && 82990d2dfabSRick Macklem stp->ls_stateid.other[1] == 0x55555555 && 83090d2dfabSRick Macklem stp->ls_stateid.other[2] == 0x55555555) 83190d2dfabSRick Macklem gotproxystateid = 1; 8329ec7b004SRick Macklem off = fxdr_hyper(tl); 8339ec7b004SRick Macklem lop->lo_first = off; 8349ec7b004SRick Macklem tl += 2; 8359ec7b004SRick Macklem lop->lo_end = off + reqlen; 8369ec7b004SRick Macklem /* 8379ec7b004SRick Macklem * Paranoia, just in case it wraps around. 8389ec7b004SRick Macklem */ 8399ec7b004SRick Macklem if (lop->lo_end < off) 8409ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 8419ec7b004SRick Macklem } 8425d3fe02cSRick Macklem if (vp->v_type != VREG) { 8439ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 8449ec7b004SRick Macklem nd->nd_repstat = EINVAL; 8459ec7b004SRick Macklem else 8465d3fe02cSRick Macklem nd->nd_repstat = (vp->v_type == VDIR) ? EISDIR : 8479ec7b004SRick Macklem EINVAL; 8489ec7b004SRick Macklem } 84990d2dfabSRick Macklem getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 8509ec7b004SRick Macklem if (!nd->nd_repstat) 8519ec7b004SRick Macklem nd->nd_repstat = getret; 8529ec7b004SRick Macklem if (!nd->nd_repstat && 8539ec7b004SRick Macklem (nva.na_uid != nd->nd_cred->cr_uid || 8549ec7b004SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) { 8558da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, 8569ec7b004SRick Macklem nd->nd_cred, exp, p, 8578da45f2cSRick Macklem NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 8589ec7b004SRick Macklem if (nd->nd_repstat) 8598da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 8608da45f2cSRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 8618da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 8629ec7b004SRick Macklem } 86390d2dfabSRick Macklem /* 86490d2dfabSRick Macklem * DS reads are marked by ND_DSSERVER or use the proxy special 86590d2dfabSRick Macklem * stateid. 86690d2dfabSRick Macklem */ 86790d2dfabSRick Macklem if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) == 86890d2dfabSRick Macklem ND_NFSV4 && gotproxystateid == 0) 8699ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 8709ec7b004SRick Macklem &stateid, exp, nd, p); 8719ec7b004SRick Macklem if (nd->nd_repstat) { 8729ec7b004SRick Macklem vput(vp); 8739ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 8749ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 875a9285ae5SZack Kirsch goto out; 8769ec7b004SRick Macklem } 8779ec7b004SRick Macklem if (off >= nva.na_size) { 8789ec7b004SRick Macklem cnt = 0; 8799ec7b004SRick Macklem eof = 1; 8809ec7b004SRick Macklem } else if (reqlen == 0) 8819ec7b004SRick Macklem cnt = 0; 88206521fbbSZack Kirsch else if ((off + reqlen) >= nva.na_size) { 8839ec7b004SRick Macklem cnt = nva.na_size - off; 88406521fbbSZack Kirsch eof = 1; 88506521fbbSZack Kirsch } else 8869ec7b004SRick Macklem cnt = reqlen; 8879ec7b004SRick Macklem m3 = NULL; 8889ec7b004SRick Macklem if (cnt > 0) { 889cb889ce6SRick Macklem /* 890cb889ce6SRick Macklem * If cnt > MCLBYTES and the reply will not be saved, use 891cb889ce6SRick Macklem * ext_pgs mbufs for TLS. 892cb889ce6SRick Macklem * For NFSv4.0, we do not know for sure if the reply will 893cb889ce6SRick Macklem * be saved, so do not use ext_pgs mbufs for NFSv4.0. 894cb889ce6SRick Macklem * Always use ext_pgs mbufs if ND_EXTPG is set. 895cb889ce6SRick Macklem */ 896cb889ce6SRick Macklem if ((nd->nd_flag & ND_EXTPG) != 0 || (cnt > MCLBYTES && 897cb889ce6SRick Macklem (nd->nd_flag & (ND_TLS | ND_SAVEREPLY)) == ND_TLS && 898cb889ce6SRick Macklem (nd->nd_flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4)) 899cb889ce6SRick Macklem nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, 900cb889ce6SRick Macklem nd->nd_maxextsiz, p, &m3, &m2); 901cb889ce6SRick Macklem else 902cb889ce6SRick Macklem nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, 903cb889ce6SRick Macklem 0, p, &m3, &m2); 9049ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV4)) { 90590d2dfabSRick Macklem getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 9069ec7b004SRick Macklem if (!nd->nd_repstat) 9079ec7b004SRick Macklem nd->nd_repstat = getret; 9089ec7b004SRick Macklem } 9099ec7b004SRick Macklem if (nd->nd_repstat) { 9109ec7b004SRick Macklem vput(vp); 9119ec7b004SRick Macklem if (m3) 9129f6624d3SRick Macklem m_freem(m3); 9139ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 9149ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 915a9285ae5SZack Kirsch goto out; 9169ec7b004SRick Macklem } 9179ec7b004SRick Macklem } 9189ec7b004SRick Macklem vput(vp); 9199ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 9209ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 9219ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 9229ec7b004SRick Macklem } else { 9239ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 9249ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 9259ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 9269ec7b004SRick Macklem *tl++ = txdr_unsigned(cnt); 9279ec7b004SRick Macklem } else 9289ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 92906521fbbSZack Kirsch if (eof) 9309ec7b004SRick Macklem *tl++ = newnfs_true; 9319ec7b004SRick Macklem else 9329ec7b004SRick Macklem *tl++ = newnfs_false; 9339ec7b004SRick Macklem } 9349ec7b004SRick Macklem *tl = txdr_unsigned(cnt); 9359ec7b004SRick Macklem if (m3) { 9369f6624d3SRick Macklem nd->nd_mb->m_next = m3; 9379ec7b004SRick Macklem nd->nd_mb = m2; 938cb889ce6SRick Macklem if ((m2->m_flags & M_EXTPG) != 0) { 939cb889ce6SRick Macklem nd->nd_flag |= ND_EXTPG; 940cb889ce6SRick Macklem nd->nd_bextpg = m2->m_epg_npgs - 1; 941cb889ce6SRick Macklem nd->nd_bpos = (char *)(void *) 942cb889ce6SRick Macklem PHYS_TO_DMAP(m2->m_epg_pa[nd->nd_bextpg]); 943cb889ce6SRick Macklem poff = (nd->nd_bextpg == 0) ? m2->m_epg_1st_off : 0; 944cb889ce6SRick Macklem nd->nd_bpos += poff + m2->m_epg_last_len; 945cb889ce6SRick Macklem nd->nd_bextpgsiz = PAGE_SIZE - m2->m_epg_last_len - 946cb889ce6SRick Macklem poff; 947cb889ce6SRick Macklem } else 948cb889ce6SRick Macklem nd->nd_bpos = mtod(m2, char *) + m2->m_len; 9499ec7b004SRick Macklem } 950a9285ae5SZack Kirsch 951a9285ae5SZack Kirsch out: 952a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 9539ec7b004SRick Macklem return (0); 9549ec7b004SRick Macklem nfsmout: 9559ec7b004SRick Macklem vput(vp); 956a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 9579ec7b004SRick Macklem return (error); 9589ec7b004SRick Macklem } 9599ec7b004SRick Macklem 9609ec7b004SRick Macklem /* 9619ec7b004SRick Macklem * nfs write service 9629ec7b004SRick Macklem */ 963b9cc3262SRyan Moeller int 9649ec7b004SRick Macklem nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram, 965af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 9669ec7b004SRick Macklem { 9679ec7b004SRick Macklem u_int32_t *tl; 9689ec7b004SRick Macklem struct nfsvattr nva, forat; 9699ec7b004SRick Macklem int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1; 97090d2dfabSRick Macklem int gotproxystateid, stable = NFSWRITE_FILESYNC; 9719ec7b004SRick Macklem off_t off; 9729ec7b004SRick Macklem struct nfsstate st, *stp = &st; 9739ec7b004SRick Macklem struct nfslock lo, *lop = &lo; 9749ec7b004SRick Macklem nfsv4stateid_t stateid; 9759ec7b004SRick Macklem nfsquad_t clientid; 97690d2dfabSRick Macklem nfsattrbit_t attrbits; 977af444b18SEdward Tomasz Napierala struct thread *p = curthread; 9789ec7b004SRick Macklem 9799ec7b004SRick Macklem if (nd->nd_repstat) { 9809ec7b004SRick Macklem nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 981a9285ae5SZack Kirsch goto out; 9829ec7b004SRick Macklem } 98390d2dfabSRick Macklem gotproxystateid = 0; 9849ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 9859ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 9869ec7b004SRick Macklem off = (off_t)fxdr_unsigned(u_int32_t, *++tl); 9879ec7b004SRick Macklem tl += 2; 9889ec7b004SRick Macklem retlen = len = fxdr_unsigned(int32_t, *tl); 9899ec7b004SRick Macklem } else if (nd->nd_flag & ND_NFSV3) { 9909ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 9919ec7b004SRick Macklem off = fxdr_hyper(tl); 9929ec7b004SRick Macklem tl += 3; 9939ec7b004SRick Macklem stable = fxdr_unsigned(int, *tl++); 9949ec7b004SRick Macklem retlen = len = fxdr_unsigned(int32_t, *tl); 9959ec7b004SRick Macklem } else { 9969ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED); 9979ec7b004SRick Macklem stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 9989ec7b004SRick Macklem lop->lo_flags = NFSLCK_WRITE; 9999ec7b004SRick Macklem stp->ls_ownerlen = 0; 10009ec7b004SRick Macklem stp->ls_op = NULL; 10019ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 10029ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 10039ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 10049ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 1005c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 1006c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 1007c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 1008c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 1009c59e4cc3SRick Macklem printf("EEK2 multiple clids\n"); 10109ec7b004SRick Macklem } else { 1011c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 1012c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 10139ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 10149ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 10159ec7b004SRick Macklem } 10169ec7b004SRick Macklem stp->ls_stateid.other[2] = *tl++; 101790d2dfabSRick Macklem /* 101890d2dfabSRick Macklem * Don't allow the client to use a special stateid for a DS op. 101990d2dfabSRick Macklem */ 102090d2dfabSRick Macklem if ((nd->nd_flag & ND_DSSERVER) != 0 && 102190d2dfabSRick Macklem ((stp->ls_stateid.other[0] == 0x0 && 102290d2dfabSRick Macklem stp->ls_stateid.other[1] == 0x0 && 102390d2dfabSRick Macklem stp->ls_stateid.other[2] == 0x0) || 102490d2dfabSRick Macklem (stp->ls_stateid.other[0] == 0xffffffff && 102590d2dfabSRick Macklem stp->ls_stateid.other[1] == 0xffffffff && 102690d2dfabSRick Macklem stp->ls_stateid.other[2] == 0xffffffff) || 102790d2dfabSRick Macklem stp->ls_stateid.seqid != 0)) 102890d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 102990d2dfabSRick Macklem /* However, allow the proxy stateid. */ 103090d2dfabSRick Macklem if (stp->ls_stateid.seqid == 0xffffffff && 103190d2dfabSRick Macklem stp->ls_stateid.other[0] == 0x55555555 && 103290d2dfabSRick Macklem stp->ls_stateid.other[1] == 0x55555555 && 103390d2dfabSRick Macklem stp->ls_stateid.other[2] == 0x55555555) 103490d2dfabSRick Macklem gotproxystateid = 1; 10359ec7b004SRick Macklem off = fxdr_hyper(tl); 10369ec7b004SRick Macklem lop->lo_first = off; 10379ec7b004SRick Macklem tl += 2; 10389ec7b004SRick Macklem stable = fxdr_unsigned(int, *tl++); 10399ec7b004SRick Macklem retlen = len = fxdr_unsigned(int32_t, *tl); 10409ec7b004SRick Macklem lop->lo_end = off + len; 10419ec7b004SRick Macklem /* 10429ec7b004SRick Macklem * Paranoia, just in case it wraps around, which shouldn't 10439ec7b004SRick Macklem * ever happen anyhow. 10449ec7b004SRick Macklem */ 10459ec7b004SRick Macklem if (lop->lo_end < lop->lo_first) 10469ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 10479ec7b004SRick Macklem } 10489ec7b004SRick Macklem 1049ee29e6f3SRick Macklem if (retlen > nfs_srvmaxio || retlen < 0) 10509ec7b004SRick Macklem nd->nd_repstat = EIO; 10515d3fe02cSRick Macklem if (vp->v_type != VREG && !nd->nd_repstat) { 10529ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 10539ec7b004SRick Macklem nd->nd_repstat = EINVAL; 10549ec7b004SRick Macklem else 10555d3fe02cSRick Macklem nd->nd_repstat = (vp->v_type == VDIR) ? EISDIR : 10569ec7b004SRick Macklem EINVAL; 10579ec7b004SRick Macklem } 105890d2dfabSRick Macklem NFSZERO_ATTRBIT(&attrbits); 105990d2dfabSRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 106090d2dfabSRick Macklem forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits); 10619ec7b004SRick Macklem if (!nd->nd_repstat) 10629ec7b004SRick Macklem nd->nd_repstat = forat_ret; 10639ec7b004SRick Macklem if (!nd->nd_repstat && 10649ec7b004SRick Macklem (forat.na_uid != nd->nd_cred->cr_uid || 10659ec7b004SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) 10668da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 10679ec7b004SRick Macklem nd->nd_cred, exp, p, 10688da45f2cSRick Macklem NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 106990d2dfabSRick Macklem /* 107090d2dfabSRick Macklem * DS reads are marked by ND_DSSERVER or use the proxy special 107190d2dfabSRick Macklem * stateid. 107290d2dfabSRick Macklem */ 107390d2dfabSRick Macklem if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) == 107490d2dfabSRick Macklem ND_NFSV4 && gotproxystateid == 0) 10759ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 10769ec7b004SRick Macklem &stateid, exp, nd, p); 10779ec7b004SRick Macklem if (nd->nd_repstat) { 10789ec7b004SRick Macklem vput(vp); 10799ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 10809ec7b004SRick Macklem nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 1081a9285ae5SZack Kirsch goto out; 10829ec7b004SRick Macklem } 10839ec7b004SRick Macklem 10849ec7b004SRick Macklem /* 10859ec7b004SRick Macklem * For NFS Version 2, it is not obvious what a write of zero length 10869ec7b004SRick Macklem * should do, but I might as well be consistent with Version 3, 10879ec7b004SRick Macklem * which is to return ok so long as there are no permission problems. 10889ec7b004SRick Macklem */ 10899ec7b004SRick Macklem if (retlen > 0) { 1090c057a378SRick Macklem nd->nd_repstat = nfsvno_write(vp, off, retlen, &stable, 10919ec7b004SRick Macklem nd->nd_md, nd->nd_dpos, nd->nd_cred, p); 10929ec7b004SRick Macklem error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1); 10939ec7b004SRick Macklem if (error) 1094ce8d06feSRick Macklem goto nfsmout; 10959ec7b004SRick Macklem } 10969ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) 10979ec7b004SRick Macklem aftat_ret = 0; 10989ec7b004SRick Macklem else 109990d2dfabSRick Macklem aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 11009ec7b004SRick Macklem vput(vp); 11019ec7b004SRick Macklem if (!nd->nd_repstat) 11029ec7b004SRick Macklem nd->nd_repstat = aftat_ret; 11039ec7b004SRick Macklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 11049ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 11059ec7b004SRick Macklem nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 11069ec7b004SRick Macklem if (nd->nd_repstat) 1107a9285ae5SZack Kirsch goto out; 11089ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 11099ec7b004SRick Macklem *tl++ = txdr_unsigned(retlen); 1110e4558aacSXin LI /* 1111e4558aacSXin LI * If nfs_async is set, then pretend the write was FILESYNC. 1112e4558aacSXin LI * Warning: Doing this violates RFC1813 and runs a risk 1113e4558aacSXin LI * of data written by a client being lost when the server 1114e4558aacSXin LI * crashes/reboots. 1115e4558aacSXin LI */ 1116e4558aacSXin LI if (stable == NFSWRITE_UNSTABLE && nfs_async == 0) 11179ec7b004SRick Macklem *tl++ = txdr_unsigned(stable); 11189ec7b004SRick Macklem else 11199ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSWRITE_FILESYNC); 11209ec7b004SRick Macklem /* 11219ec7b004SRick Macklem * Actually, there is no need to txdr these fields, 11229ec7b004SRick Macklem * but it may make the values more human readable, 11239ec7b004SRick Macklem * for debugging purposes. 11249ec7b004SRick Macklem */ 11259ec7b004SRick Macklem *tl++ = txdr_unsigned(nfsboottime.tv_sec); 11269ec7b004SRick Macklem *tl = txdr_unsigned(nfsboottime.tv_usec); 11279ec7b004SRick Macklem } else if (!nd->nd_repstat) 11289ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 1129a9285ae5SZack Kirsch 1130a9285ae5SZack Kirsch out: 1131a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 11329ec7b004SRick Macklem return (0); 11339ec7b004SRick Macklem nfsmout: 11349ec7b004SRick Macklem vput(vp); 1135a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 11369ec7b004SRick Macklem return (error); 11379ec7b004SRick Macklem } 11389ec7b004SRick Macklem 11399ec7b004SRick Macklem /* 11409ec7b004SRick Macklem * nfs create service (creates regular files for V2 and V3. Spec. files for V2.) 11419ec7b004SRick Macklem * now does a truncate to 0 length via. setattr if it already exists 11429ec7b004SRick Macklem * The core creation routine has been extracted out into nfsrv_creatsub(), 11439ec7b004SRick Macklem * so it can also be used by nfsrv_open() for V4. 11449ec7b004SRick Macklem */ 1145b9cc3262SRyan Moeller int 11469ec7b004SRick Macklem nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram, 1147af444b18SEdward Tomasz Napierala vnode_t dp, struct nfsexstuff *exp) 11489ec7b004SRick Macklem { 11499ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 11509ec7b004SRick Macklem struct nfsv2_sattr *sp; 11519ec7b004SRick Macklem struct nameidata named; 11529ec7b004SRick Macklem u_int32_t *tl; 11539ec7b004SRick Macklem int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1; 11549ec7b004SRick Macklem int how = NFSCREATE_UNCHECKED, exclusive_flag = 0; 11559ec7b004SRick Macklem NFSDEV_T rdev = 0; 11569ec7b004SRick Macklem vnode_t vp = NULL, dirp = NULL; 11579ec7b004SRick Macklem fhandle_t fh; 11589ec7b004SRick Macklem char *bufp; 11599ec7b004SRick Macklem u_long *hashp; 1160ba8cc6d7SMateusz Guzik __enum_uint8(vtype) vtyp; 1161086f6e0cSRick Macklem int32_t cverf[2], tverf[2] = { 0, 0 }; 1162af444b18SEdward Tomasz Napierala struct thread *p = curthread; 11639ec7b004SRick Macklem 11649ec7b004SRick Macklem if (nd->nd_repstat) { 11659ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1166a9285ae5SZack Kirsch goto out; 11679ec7b004SRick Macklem } 11689ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 116965127e98SMateusz Guzik LOCKPARENT | LOCKLEAF | NOCACHE); 11709ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 11719ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1172a9285ae5SZack Kirsch if (error) 1173a9285ae5SZack Kirsch goto nfsmout; 11749ec7b004SRick Macklem if (!nd->nd_repstat) { 11759ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 11769ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 11779ec7b004SRick Macklem NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 11789ec7b004SRick Macklem vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode)); 11799ec7b004SRick Macklem if (vtyp == VNON) 11809ec7b004SRick Macklem vtyp = VREG; 11819ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, type, vtyp); 11829ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, mode, 11839ec7b004SRick Macklem nfstov_mode(sp->sa_mode)); 11849ec7b004SRick Macklem switch (nva.na_type) { 11859ec7b004SRick Macklem case VREG: 11869ec7b004SRick Macklem tsize = fxdr_unsigned(int32_t, sp->sa_size); 11879ec7b004SRick Macklem if (tsize != -1) 11889ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, size, 11899ec7b004SRick Macklem (u_quad_t)tsize); 11909ec7b004SRick Macklem break; 11919ec7b004SRick Macklem case VCHR: 11929ec7b004SRick Macklem case VBLK: 11939ec7b004SRick Macklem case VFIFO: 11949ec7b004SRick Macklem rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size); 11959ec7b004SRick Macklem break; 11969ec7b004SRick Macklem default: 11979ec7b004SRick Macklem break; 119874b8d63dSPedro F. Giffuni } 11999ec7b004SRick Macklem } else { 12009ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 12019ec7b004SRick Macklem how = fxdr_unsigned(int, *tl); 12029ec7b004SRick Macklem switch (how) { 12039ec7b004SRick Macklem case NFSCREATE_GUARDED: 12049ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 1205d8a5961fSMarcelo Araujo error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p); 12069ec7b004SRick Macklem if (error) 12079ec7b004SRick Macklem goto nfsmout; 12089ec7b004SRick Macklem break; 12099ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 1210086f6e0cSRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 1211086f6e0cSRick Macklem cverf[0] = *tl++; 1212086f6e0cSRick Macklem cverf[1] = *tl; 12139ec7b004SRick Macklem exclusive_flag = 1; 12149ec7b004SRick Macklem break; 121574b8d63dSPedro F. Giffuni } 12169ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, type, VREG); 12179ec7b004SRick Macklem } 12189ec7b004SRick Macklem } 12199ec7b004SRick Macklem if (nd->nd_repstat) { 12209ec7b004SRick Macklem nfsvno_relpathbuf(&named); 12219ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 122290d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1, 122390d2dfabSRick Macklem NULL); 12249ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 12259ec7b004SRick Macklem &diraft); 12269ec7b004SRick Macklem } 12279ec7b004SRick Macklem vput(dp); 1228a9285ae5SZack Kirsch goto out; 12299ec7b004SRick Macklem } 12309ec7b004SRick Macklem 1231ef7d2c1fSMateusz Guzik nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp); 12329ec7b004SRick Macklem if (dirp) { 12339ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 12349ec7b004SRick Macklem vrele(dirp); 12359ec7b004SRick Macklem dirp = NULL; 12369ec7b004SRick Macklem } else { 123790d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 123890d2dfabSRick Macklem NULL); 12399ec7b004SRick Macklem } 12409ec7b004SRick Macklem } 12419ec7b004SRick Macklem if (nd->nd_repstat) { 12429ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 12439ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 12449ec7b004SRick Macklem &diraft); 12459ec7b004SRick Macklem if (dirp) 12469ec7b004SRick Macklem vrele(dirp); 1247a9285ae5SZack Kirsch goto out; 12489ec7b004SRick Macklem } 12499ec7b004SRick Macklem 12509ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) { 12519ec7b004SRick Macklem switch (how) { 12529ec7b004SRick Macklem case NFSCREATE_GUARDED: 12539ec7b004SRick Macklem if (named.ni_vp) 12549ec7b004SRick Macklem nd->nd_repstat = EEXIST; 12559ec7b004SRick Macklem break; 12569ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 12579ec7b004SRick Macklem break; 12589ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 12599ec7b004SRick Macklem if (named.ni_vp == NULL) 12609ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, mode, 0); 12619ec7b004SRick Macklem break; 126274b8d63dSPedro F. Giffuni } 12639ec7b004SRick Macklem } 12649ec7b004SRick Macklem 12659ec7b004SRick Macklem /* 12669ec7b004SRick Macklem * Iff doesn't exist, create it 12679ec7b004SRick Macklem * otherwise just truncate to 0 length 12689ec7b004SRick Macklem * should I set the mode too ? 12699ec7b004SRick Macklem */ 12709ec7b004SRick Macklem nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva, 1271127152feSEdward Tomasz Napierala &exclusive_flag, cverf, rdev, exp); 12729ec7b004SRick Macklem 12739ec7b004SRick Macklem if (!nd->nd_repstat) { 12749ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 12759ec7b004SRick Macklem if (!nd->nd_repstat) 127690d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, 127790d2dfabSRick Macklem NULL); 12789ec7b004SRick Macklem vput(vp); 1279086f6e0cSRick Macklem if (!nd->nd_repstat) { 1280086f6e0cSRick Macklem tverf[0] = nva.na_atime.tv_sec; 1281086f6e0cSRick Macklem tverf[1] = nva.na_atime.tv_nsec; 1282086f6e0cSRick Macklem } 12839ec7b004SRick Macklem } 12849ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 12859ec7b004SRick Macklem if (!nd->nd_repstat) { 1286695d87baSRick Macklem (void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 0); 12879ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 12889ec7b004SRick Macklem } 12899ec7b004SRick Macklem } else { 1290086f6e0cSRick Macklem if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0] 1291086f6e0cSRick Macklem || cverf[1] != tverf[1])) 12929ec7b004SRick Macklem nd->nd_repstat = EEXIST; 129390d2dfabSRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 12949ec7b004SRick Macklem vrele(dirp); 12959ec7b004SRick Macklem if (!nd->nd_repstat) { 1296695d87baSRick Macklem (void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 1); 12979ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 12989ec7b004SRick Macklem } 12999ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 13009ec7b004SRick Macklem } 1301a9285ae5SZack Kirsch 1302a9285ae5SZack Kirsch out: 1303a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 13049ec7b004SRick Macklem return (0); 13059ec7b004SRick Macklem nfsmout: 13069ec7b004SRick Macklem vput(dp); 13079ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1308a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 13099ec7b004SRick Macklem return (error); 13109ec7b004SRick Macklem } 13119ec7b004SRick Macklem 13129ec7b004SRick Macklem /* 13139ec7b004SRick Macklem * nfs v3 mknod service (and v4 create) 13149ec7b004SRick Macklem */ 1315b9cc3262SRyan Moeller int 13169ec7b004SRick Macklem nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram, 1317af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 13189ec7b004SRick Macklem { 13199ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 13209ec7b004SRick Macklem u_int32_t *tl; 13219ec7b004SRick Macklem struct nameidata named; 13229ec7b004SRick Macklem int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 13239ec7b004SRick Macklem u_int32_t major, minor; 1324ba8cc6d7SMateusz Guzik __enum_uint8(vtype) vtyp = VNON; 13259ec7b004SRick Macklem nfstype nfs4type = NFNON; 13269ec7b004SRick Macklem vnode_t vp, dirp = NULL; 13279ec7b004SRick Macklem nfsattrbit_t attrbits; 13289ec7b004SRick Macklem char *bufp = NULL, *pathcp = NULL; 13299ec7b004SRick Macklem u_long *hashp, cnflags; 13309ec7b004SRick Macklem NFSACL_T *aclp = NULL; 1331af444b18SEdward Tomasz Napierala struct thread *p = curthread; 13329ec7b004SRick Macklem 13339ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 133465127e98SMateusz Guzik cnflags = LOCKPARENT; 13359ec7b004SRick Macklem if (nd->nd_repstat) { 13369ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1337a9285ae5SZack Kirsch goto out; 13389ec7b004SRick Macklem } 13399ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 1340c3e22f83SRick Macklem aclp = acl_alloc(M_WAITOK); 13419ec7b004SRick Macklem aclp->acl_cnt = 0; 13429ec7b004SRick Macklem #endif 13439ec7b004SRick Macklem 13449ec7b004SRick Macklem /* 13459ec7b004SRick Macklem * For V4, the creation stuff is here, Yuck! 13469ec7b004SRick Macklem */ 13479ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 13489ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 13499ec7b004SRick Macklem vtyp = nfsv34tov_type(*tl); 13509ec7b004SRick Macklem nfs4type = fxdr_unsigned(nfstype, *tl); 13519ec7b004SRick Macklem switch (nfs4type) { 13529ec7b004SRick Macklem case NFLNK: 13539ec7b004SRick Macklem error = nfsvno_getsymlink(nd, &nva, p, &pathcp, 13549ec7b004SRick Macklem &pathlen); 1355a9285ae5SZack Kirsch if (error) 1356a9285ae5SZack Kirsch goto nfsmout; 13579ec7b004SRick Macklem break; 13589ec7b004SRick Macklem case NFCHR: 13599ec7b004SRick Macklem case NFBLK: 13609ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 13619ec7b004SRick Macklem major = fxdr_unsigned(u_int32_t, *tl++); 13629ec7b004SRick Macklem minor = fxdr_unsigned(u_int32_t, *tl); 13639ec7b004SRick Macklem nva.na_rdev = NFSMAKEDEV(major, minor); 13649ec7b004SRick Macklem break; 13659ec7b004SRick Macklem case NFSOCK: 13669ec7b004SRick Macklem case NFFIFO: 13679ec7b004SRick Macklem break; 13689ec7b004SRick Macklem case NFDIR: 13695b5b7e2cSMateusz Guzik cnflags = LOCKPARENT; 13709ec7b004SRick Macklem break; 13719ec7b004SRick Macklem default: 13729ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADTYPE; 13739ec7b004SRick Macklem vrele(dp); 13749ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 13759ec7b004SRick Macklem acl_free(aclp); 13769ec7b004SRick Macklem #endif 1377a9285ae5SZack Kirsch goto out; 1378a9285ae5SZack Kirsch } 13799ec7b004SRick Macklem } 13806c21f6edSKonstantin Belousov NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE); 13819ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 13829ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1383a9285ae5SZack Kirsch if (error) 1384a9285ae5SZack Kirsch goto nfsmout; 13859ec7b004SRick Macklem if (!nd->nd_repstat) { 13869ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 13879ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 13889ec7b004SRick Macklem vtyp = nfsv34tov_type(*tl); 13899ec7b004SRick Macklem } 1390d8a5961fSMarcelo Araujo error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p); 1391a9285ae5SZack Kirsch if (error) 1392a9285ae5SZack Kirsch goto nfsmout; 13939ec7b004SRick Macklem nva.na_type = vtyp; 13949ec7b004SRick Macklem if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) && 13959ec7b004SRick Macklem (vtyp == VCHR || vtyp == VBLK)) { 13969ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 13979ec7b004SRick Macklem major = fxdr_unsigned(u_int32_t, *tl++); 13989ec7b004SRick Macklem minor = fxdr_unsigned(u_int32_t, *tl); 13999ec7b004SRick Macklem nva.na_rdev = NFSMAKEDEV(major, minor); 14009ec7b004SRick Macklem } 14019ec7b004SRick Macklem } 14029ec7b004SRick Macklem 140390d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL); 14049ec7b004SRick Macklem if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 14059ec7b004SRick Macklem if (!dirfor_ret && NFSVNO_ISSETGID(&nva) && 14069ec7b004SRick Macklem dirfor.na_gid == nva.na_gid) 14079ec7b004SRick Macklem NFSVNO_UNSET(&nva, gid); 14089ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 14099ec7b004SRick Macklem } 14109ec7b004SRick Macklem if (nd->nd_repstat) { 14119ec7b004SRick Macklem vrele(dp); 14129ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 14139ec7b004SRick Macklem acl_free(aclp); 14149ec7b004SRick Macklem #endif 14159ec7b004SRick Macklem nfsvno_relpathbuf(&named); 14169ec7b004SRick Macklem if (pathcp) 1417222daa42SConrad Meyer free(pathcp, M_TEMP); 14189ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 14199ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 14209ec7b004SRick Macklem &diraft); 1421a9285ae5SZack Kirsch goto out; 14229ec7b004SRick Macklem } 14239ec7b004SRick Macklem 14249ec7b004SRick Macklem /* 14259ec7b004SRick Macklem * Yuck! For V4, mkdir and link are here and some V4 clients don't fill 14269ec7b004SRick Macklem * in va_mode, so we'll have to set a default here. 14279ec7b004SRick Macklem */ 14289ec7b004SRick Macklem if (NFSVNO_NOTSETMODE(&nva)) { 14299ec7b004SRick Macklem if (vtyp == VLNK) 14309ec7b004SRick Macklem nva.na_mode = 0755; 14319ec7b004SRick Macklem else 14329ec7b004SRick Macklem nva.na_mode = 0400; 14339ec7b004SRick Macklem } 14349ec7b004SRick Macklem 14359ec7b004SRick Macklem if (vtyp == VDIR) 14369ec7b004SRick Macklem named.ni_cnd.cn_flags |= WILLBEDIR; 1437ef7d2c1fSMateusz Guzik nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp); 14389ec7b004SRick Macklem if (nd->nd_repstat) { 14399ec7b004SRick Macklem if (dirp) { 14409ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 144190d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, 144290d2dfabSRick Macklem p, 0, NULL); 14439ec7b004SRick Macklem vrele(dirp); 14449ec7b004SRick Macklem } 14459ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 14469ec7b004SRick Macklem acl_free(aclp); 14479ec7b004SRick Macklem #endif 14489ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 14499ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 14509ec7b004SRick Macklem &diraft); 1451a9285ae5SZack Kirsch goto out; 14529ec7b004SRick Macklem } 14539ec7b004SRick Macklem if (dirp) 145490d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); 14559ec7b004SRick Macklem 14569ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) { 14579ec7b004SRick Macklem if (vtyp == VDIR) { 14589ec7b004SRick Macklem nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, 14599ec7b004SRick Macklem &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p, 14609ec7b004SRick Macklem exp); 14619ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 14629ec7b004SRick Macklem acl_free(aclp); 14639ec7b004SRick Macklem #endif 1464a9285ae5SZack Kirsch goto out; 14659ec7b004SRick Macklem } else if (vtyp == VLNK) { 14669ec7b004SRick Macklem nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 14679ec7b004SRick Macklem &dirfor, &diraft, &diraft_ret, &attrbits, 14689ec7b004SRick Macklem aclp, p, exp, pathcp, pathlen); 14699ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 14709ec7b004SRick Macklem acl_free(aclp); 14719ec7b004SRick Macklem #endif 1472222daa42SConrad Meyer free(pathcp, M_TEMP); 1473a9285ae5SZack Kirsch goto out; 14749ec7b004SRick Macklem } 14759ec7b004SRick Macklem } 14769ec7b004SRick Macklem 14779ec7b004SRick Macklem nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p); 14789ec7b004SRick Macklem if (!nd->nd_repstat) { 14799ec7b004SRick Macklem vp = named.ni_vp; 14809ec7b004SRick Macklem nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp); 14819ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 14829ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat) 148390d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, 148490d2dfabSRick Macklem NULL); 148581f78d99SRick Macklem if (vpp != NULL && nd->nd_repstat == 0) { 1486b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 14879ec7b004SRick Macklem *vpp = vp; 148881f78d99SRick Macklem } else 14899ec7b004SRick Macklem vput(vp); 14909ec7b004SRick Macklem } 14919ec7b004SRick Macklem 149290d2dfabSRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 14939ec7b004SRick Macklem vrele(dirp); 14949ec7b004SRick Macklem if (!nd->nd_repstat) { 14959ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 1496695d87baSRick Macklem (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1); 14979ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 14989ec7b004SRick Macklem } else { 14999ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 15009ec7b004SRick Macklem *tl++ = newnfs_false; 15019ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 15029ec7b004SRick Macklem tl += 2; 15039ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 15049ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &attrbits); 15059ec7b004SRick Macklem } 15069ec7b004SRick Macklem } 15079ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 15089ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 15099ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 15109ec7b004SRick Macklem acl_free(aclp); 15119ec7b004SRick Macklem #endif 1512a9285ae5SZack Kirsch 1513a9285ae5SZack Kirsch out: 1514a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 15159ec7b004SRick Macklem return (0); 15169ec7b004SRick Macklem nfsmout: 15179ec7b004SRick Macklem vrele(dp); 15189ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 15199ec7b004SRick Macklem acl_free(aclp); 15209ec7b004SRick Macklem #endif 15219ec7b004SRick Macklem if (bufp) 15229ec7b004SRick Macklem nfsvno_relpathbuf(&named); 15239ec7b004SRick Macklem if (pathcp) 1524222daa42SConrad Meyer free(pathcp, M_TEMP); 1525a9285ae5SZack Kirsch 1526a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 15279ec7b004SRick Macklem return (error); 15289ec7b004SRick Macklem } 15299ec7b004SRick Macklem 15309ec7b004SRick Macklem /* 15319ec7b004SRick Macklem * nfs remove service 15329ec7b004SRick Macklem */ 1533b9cc3262SRyan Moeller int 15349ec7b004SRick Macklem nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram, 1535af444b18SEdward Tomasz Napierala vnode_t dp, struct nfsexstuff *exp) 15369ec7b004SRick Macklem { 15379ec7b004SRick Macklem struct nameidata named; 15389ec7b004SRick Macklem u_int32_t *tl; 1539a9285ae5SZack Kirsch int error = 0, dirfor_ret = 1, diraft_ret = 1; 15409ec7b004SRick Macklem vnode_t dirp = NULL; 15419ec7b004SRick Macklem struct nfsvattr dirfor, diraft; 15429ec7b004SRick Macklem char *bufp; 15439ec7b004SRick Macklem u_long *hashp; 1544af444b18SEdward Tomasz Napierala struct thread *p = curthread; 15459ec7b004SRick Macklem 15469ec7b004SRick Macklem if (nd->nd_repstat) { 15479ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1548a9285ae5SZack Kirsch goto out; 15499ec7b004SRick Macklem } 15509ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE, 15519ec7b004SRick Macklem LOCKPARENT | LOCKLEAF); 15529ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 15539ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 15549ec7b004SRick Macklem if (error) { 15559ec7b004SRick Macklem vput(dp); 15569ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1557a9285ae5SZack Kirsch goto out; 15589ec7b004SRick Macklem } 15599ec7b004SRick Macklem if (!nd->nd_repstat) { 1560ef7d2c1fSMateusz Guzik nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp); 15619ec7b004SRick Macklem } else { 15629ec7b004SRick Macklem vput(dp); 15639ec7b004SRick Macklem nfsvno_relpathbuf(&named); 15649ec7b004SRick Macklem } 15659ec7b004SRick Macklem if (dirp) { 15669ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) { 156790d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 156890d2dfabSRick Macklem NULL); 15699ec7b004SRick Macklem } else { 15709ec7b004SRick Macklem vrele(dirp); 15719ec7b004SRick Macklem dirp = NULL; 15729ec7b004SRick Macklem } 15739ec7b004SRick Macklem } 15749ec7b004SRick Macklem if (!nd->nd_repstat) { 15759ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 15765d3fe02cSRick Macklem if (named.ni_vp->v_type == VDIR) 15779ec7b004SRick Macklem nd->nd_repstat = nfsvno_rmdirsub(&named, 1, 15789ec7b004SRick Macklem nd->nd_cred, p, exp); 15799ec7b004SRick Macklem else 15809ec7b004SRick Macklem nd->nd_repstat = nfsvno_removesub(&named, 1, 15819ec7b004SRick Macklem nd->nd_cred, p, exp); 15829ec7b004SRick Macklem } else if (nd->nd_procnum == NFSPROC_RMDIR) { 15839ec7b004SRick Macklem nd->nd_repstat = nfsvno_rmdirsub(&named, 0, 15849ec7b004SRick Macklem nd->nd_cred, p, exp); 15859ec7b004SRick Macklem } else { 15869ec7b004SRick Macklem nd->nd_repstat = nfsvno_removesub(&named, 0, 15879ec7b004SRick Macklem nd->nd_cred, p, exp); 15889ec7b004SRick Macklem } 15899ec7b004SRick Macklem } 15909ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) { 15919ec7b004SRick Macklem if (dirp) { 159290d2dfabSRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, 159390d2dfabSRick Macklem NULL); 15949ec7b004SRick Macklem vrele(dirp); 15959ec7b004SRick Macklem } 15969ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 15979ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 15989ec7b004SRick Macklem &diraft); 15999ec7b004SRick Macklem } else if (!nd->nd_repstat) { 16009ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 16019ec7b004SRick Macklem *tl++ = newnfs_false; 16029ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 16039ec7b004SRick Macklem tl += 2; 16049ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 16059ec7b004SRick Macklem } 16069ec7b004SRick Macklem } 1607a9285ae5SZack Kirsch 1608a9285ae5SZack Kirsch out: 1609a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1610a9285ae5SZack Kirsch return (error); 16119ec7b004SRick Macklem } 16129ec7b004SRick Macklem 16139ec7b004SRick Macklem /* 16149ec7b004SRick Macklem * nfs rename service 16159ec7b004SRick Macklem */ 1616b9cc3262SRyan Moeller int 16179ec7b004SRick Macklem nfsrvd_rename(struct nfsrv_descript *nd, int isdgram, 1618af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t todp, struct nfsexstuff *exp, struct nfsexstuff *toexp) 16199ec7b004SRick Macklem { 16209ec7b004SRick Macklem u_int32_t *tl; 1621a9285ae5SZack Kirsch int error = 0, fdirfor_ret = 1, fdiraft_ret = 1; 16229ec7b004SRick Macklem int tdirfor_ret = 1, tdiraft_ret = 1; 16239ec7b004SRick Macklem struct nameidata fromnd, tond; 16249ec7b004SRick Macklem vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL; 16259ec7b004SRick Macklem struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft; 16269ec7b004SRick Macklem struct nfsexstuff tnes; 16279ec7b004SRick Macklem struct nfsrvfh tfh; 16289ec7b004SRick Macklem char *bufp, *tbufp = NULL; 16299ec7b004SRick Macklem u_long *hashp; 16306b3dfc6aSRick Macklem fhandle_t fh; 1631af444b18SEdward Tomasz Napierala struct thread *p = curthread; 16329ec7b004SRick Macklem 16339ec7b004SRick Macklem if (nd->nd_repstat) { 16349ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 16359ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 1636a9285ae5SZack Kirsch goto out; 16379ec7b004SRick Macklem } 16389ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) 163990d2dfabSRick Macklem fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL); 16409ec7b004SRick Macklem tond.ni_cnd.cn_nameiop = 0; 16419ec7b004SRick Macklem tond.ni_startdir = NULL; 164265127e98SMateusz Guzik NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT); 16439ec7b004SRick Macklem nfsvno_setpathbuf(&fromnd, &bufp, &hashp); 16449ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen); 16459ec7b004SRick Macklem if (error) { 16469ec7b004SRick Macklem vput(dp); 16479ec7b004SRick Macklem if (todp) 16489ec7b004SRick Macklem vrele(todp); 16499ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 1650a9285ae5SZack Kirsch goto out; 16519ec7b004SRick Macklem } 165225bfde79SXin LI /* 165325bfde79SXin LI * Unlock dp in this code section, so it is unlocked before 165425bfde79SXin LI * tdp gets locked. This avoids a potential LOR if tdp is the 165525bfde79SXin LI * parent directory of dp. 165625bfde79SXin LI */ 16579ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 16589ec7b004SRick Macklem tdp = todp; 16599ec7b004SRick Macklem tnes = *toexp; 166025bfde79SXin LI if (dp != tdp) { 1661b249ce48SMateusz Guzik NFSVOPUNLOCK(dp); 166290d2dfabSRick Macklem /* Might lock tdp. */ 166390d2dfabSRick Macklem tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0, 166490d2dfabSRick Macklem NULL); 166525bfde79SXin LI } else { 166690d2dfabSRick Macklem tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1, 166790d2dfabSRick Macklem NULL); 1668b249ce48SMateusz Guzik NFSVOPUNLOCK(dp); 166925bfde79SXin LI } 16709ec7b004SRick Macklem } else { 16716b3dfc6aSRick Macklem tfh.nfsrvfh_len = 0; 16729ec7b004SRick Macklem error = nfsrv_mtofh(nd, &tfh); 16736b3dfc6aSRick Macklem if (error == 0) 16746b3dfc6aSRick Macklem error = nfsvno_getfh(dp, &fh, p); 16759ec7b004SRick Macklem if (error) { 16769ec7b004SRick Macklem vput(dp); 16779ec7b004SRick Macklem /* todp is always NULL except NFSv4 */ 16789ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 1679a9285ae5SZack Kirsch goto out; 16809ec7b004SRick Macklem } 16816b3dfc6aSRick Macklem 16826b3dfc6aSRick Macklem /* If this is the same file handle, just VREF() the vnode. */ 16836b3dfc6aSRick Macklem if (tfh.nfsrvfh_len == NFSX_MYFH && 16846b3dfc6aSRick Macklem !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) { 16856b3dfc6aSRick Macklem VREF(dp); 16866b3dfc6aSRick Macklem tdp = dp; 16876b3dfc6aSRick Macklem tnes = *exp; 168890d2dfabSRick Macklem tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1, 168990d2dfabSRick Macklem NULL); 1690b249ce48SMateusz Guzik NFSVOPUNLOCK(dp); 16916b3dfc6aSRick Macklem } else { 1692b249ce48SMateusz Guzik NFSVOPUNLOCK(dp); 16936b3dfc6aSRick Macklem nd->nd_cred->cr_uid = nd->nd_saveduid; 16946b3dfc6aSRick Macklem nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL, 1695a5df139eSRick Macklem 0, -1); /* Locks tdp. */ 16966b3dfc6aSRick Macklem if (tdp) { 169790d2dfabSRick Macklem tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, 169890d2dfabSRick Macklem p, 1, NULL); 1699b249ce48SMateusz Guzik NFSVOPUNLOCK(tdp); 17009ec7b004SRick Macklem } 17019ec7b004SRick Macklem } 17026b3dfc6aSRick Macklem } 170365127e98SMateusz Guzik NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE); 17049ec7b004SRick Macklem nfsvno_setpathbuf(&tond, &tbufp, &hashp); 17059ec7b004SRick Macklem if (!nd->nd_repstat) { 17069ec7b004SRick Macklem error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen); 17079ec7b004SRick Macklem if (error) { 17088974bc2fSRick Macklem if (tdp) 17099ec7b004SRick Macklem vrele(tdp); 171025bfde79SXin LI vrele(dp); 17119ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 17129ec7b004SRick Macklem nfsvno_relpathbuf(&tond); 1713a9285ae5SZack Kirsch goto out; 17149ec7b004SRick Macklem } 17159ec7b004SRick Macklem } 17169ec7b004SRick Macklem if (nd->nd_repstat) { 17179ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 17189ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 17199ec7b004SRick Macklem &fdiraft); 17209ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 17219ec7b004SRick Macklem &tdiraft); 17229ec7b004SRick Macklem } 17238974bc2fSRick Macklem if (tdp) 17249ec7b004SRick Macklem vrele(tdp); 172525bfde79SXin LI vrele(dp); 17269ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 17279ec7b004SRick Macklem nfsvno_relpathbuf(&tond); 1728a9285ae5SZack Kirsch goto out; 17299ec7b004SRick Macklem } 17309ec7b004SRick Macklem 17319ec7b004SRick Macklem /* 17329ec7b004SRick Macklem * Done parsing, now down to business. 17339ec7b004SRick Macklem */ 1734ef7d2c1fSMateusz Guzik nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, &fdirp); 17359ec7b004SRick Macklem if (nd->nd_repstat) { 17369ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 17379ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 17389ec7b004SRick Macklem &fdiraft); 17399ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 17409ec7b004SRick Macklem &tdiraft); 17419ec7b004SRick Macklem } 17429ec7b004SRick Macklem if (fdirp) 17439ec7b004SRick Macklem vrele(fdirp); 17448974bc2fSRick Macklem if (tdp) 17459ec7b004SRick Macklem vrele(tdp); 17469ec7b004SRick Macklem nfsvno_relpathbuf(&tond); 1747a9285ae5SZack Kirsch goto out; 17489ec7b004SRick Macklem } 17495d3fe02cSRick Macklem if (fromnd.ni_vp->v_type == VDIR) 17509ec7b004SRick Macklem tond.ni_cnd.cn_flags |= WILLBEDIR; 1751ef7d2c1fSMateusz Guzik nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, &tdirp); 17529ec7b004SRick Macklem nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat, 17539ec7b004SRick Macklem nd->nd_flag, nd->nd_cred, p); 17549ec7b004SRick Macklem if (fdirp) 175590d2dfabSRick Macklem fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL); 17569ec7b004SRick Macklem if (tdirp) 175790d2dfabSRick Macklem tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL); 17589ec7b004SRick Macklem if (fdirp) 17599ec7b004SRick Macklem vrele(fdirp); 17609ec7b004SRick Macklem if (tdirp) 17619ec7b004SRick Macklem vrele(tdirp); 17629ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 17639ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 17649ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 17659ec7b004SRick Macklem } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 17669ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED); 17679ec7b004SRick Macklem *tl++ = newnfs_false; 17689ec7b004SRick Macklem txdr_hyper(fdirfor.na_filerev, tl); 17699ec7b004SRick Macklem tl += 2; 17709ec7b004SRick Macklem txdr_hyper(fdiraft.na_filerev, tl); 17719ec7b004SRick Macklem tl += 2; 17729ec7b004SRick Macklem *tl++ = newnfs_false; 17739ec7b004SRick Macklem txdr_hyper(tdirfor.na_filerev, tl); 17749ec7b004SRick Macklem tl += 2; 17759ec7b004SRick Macklem txdr_hyper(tdiraft.na_filerev, tl); 17769ec7b004SRick Macklem } 1777a9285ae5SZack Kirsch 1778a9285ae5SZack Kirsch out: 1779a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1780a9285ae5SZack Kirsch return (error); 17819ec7b004SRick Macklem } 17829ec7b004SRick Macklem 17839ec7b004SRick Macklem /* 17849ec7b004SRick Macklem * nfs link service 17859ec7b004SRick Macklem */ 1786b9cc3262SRyan Moeller int 17879ec7b004SRick Macklem nfsrvd_link(struct nfsrv_descript *nd, int isdgram, 1788af444b18SEdward Tomasz Napierala vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp) 17899ec7b004SRick Macklem { 17909ec7b004SRick Macklem struct nameidata named; 17919ec7b004SRick Macklem u_int32_t *tl; 17929ec7b004SRick Macklem int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1; 17939ec7b004SRick Macklem vnode_t dirp = NULL, dp = NULL; 17949ec7b004SRick Macklem struct nfsvattr dirfor, diraft, at; 17959ec7b004SRick Macklem struct nfsexstuff tnes; 17969ec7b004SRick Macklem struct nfsrvfh dfh; 17979ec7b004SRick Macklem char *bufp; 17989ec7b004SRick Macklem u_long *hashp; 1799af444b18SEdward Tomasz Napierala struct thread *p = curthread; 1800*3f65000bSRick Macklem nfsquad_t clientid; 18019ec7b004SRick Macklem 18029ec7b004SRick Macklem if (nd->nd_repstat) { 18039ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 18049ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1805a9285ae5SZack Kirsch goto out; 18069ec7b004SRick Macklem } 1807b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 18085d3fe02cSRick Macklem if (vp->v_type == VDIR) { 18099ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) 18109ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 18119ec7b004SRick Macklem else 18129ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 18139ec7b004SRick Macklem if (tovp) 18149ec7b004SRick Macklem vrele(tovp); 18159ec7b004SRick Macklem } 18169ec7b004SRick Macklem if (!nd->nd_repstat) { 18179ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 18189ec7b004SRick Macklem dp = tovp; 18199ec7b004SRick Macklem tnes = *toexp; 18209ec7b004SRick Macklem } else { 18219ec7b004SRick Macklem error = nfsrv_mtofh(nd, &dfh); 18229ec7b004SRick Macklem if (error) { 18239ec7b004SRick Macklem vrele(vp); 18249ec7b004SRick Macklem /* tovp is always NULL unless NFSv4 */ 1825a9285ae5SZack Kirsch goto out; 18269ec7b004SRick Macklem } 1827a5df139eSRick Macklem nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 1828a5df139eSRick Macklem 0, -1); 18299ec7b004SRick Macklem if (dp) 1830b249ce48SMateusz Guzik NFSVOPUNLOCK(dp); 18319ec7b004SRick Macklem } 18329ec7b004SRick Macklem } 18335b5b7e2cSMateusz Guzik NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT | NOCACHE); 18349ec7b004SRick Macklem if (!nd->nd_repstat) { 18359ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 18369ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 18379ec7b004SRick Macklem if (error) { 18389ec7b004SRick Macklem vrele(vp); 18398974bc2fSRick Macklem if (dp) 18409ec7b004SRick Macklem vrele(dp); 18419ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1842a9285ae5SZack Kirsch goto out; 18439ec7b004SRick Macklem } 18449ec7b004SRick Macklem if (!nd->nd_repstat) { 18459ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes, 1846ef7d2c1fSMateusz Guzik &dirp); 18479ec7b004SRick Macklem } else { 18489ec7b004SRick Macklem if (dp) 18499ec7b004SRick Macklem vrele(dp); 18509ec7b004SRick Macklem nfsvno_relpathbuf(&named); 18519ec7b004SRick Macklem } 18529ec7b004SRick Macklem } 18539ec7b004SRick Macklem if (dirp) { 18549ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 18559ec7b004SRick Macklem vrele(dirp); 18569ec7b004SRick Macklem dirp = NULL; 18579ec7b004SRick Macklem } else { 185890d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 185990d2dfabSRick Macklem NULL); 18609ec7b004SRick Macklem } 18619ec7b004SRick Macklem } 1862*3f65000bSRick Macklem if (!nd->nd_repstat) { 1863*3f65000bSRick Macklem clientid.qval = 0; 1864*3f65000bSRick Macklem if ((nd->nd_flag & (ND_IMPLIEDCLID | ND_NFSV41)) == 1865*3f65000bSRick Macklem (ND_IMPLIEDCLID | ND_NFSV41)) 1866*3f65000bSRick Macklem clientid.qval = nd->nd_clientid.qval; 1867*3f65000bSRick Macklem nd->nd_repstat = nfsvno_link(&named, vp, clientid, nd->nd_cred, 1868*3f65000bSRick Macklem p, exp); 1869*3f65000bSRick Macklem } 18709ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 187190d2dfabSRick Macklem getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL); 18729ec7b004SRick Macklem if (dirp) { 187390d2dfabSRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 18749ec7b004SRick Macklem vrele(dirp); 18759ec7b004SRick Macklem } 18769ec7b004SRick Macklem vrele(vp); 18779ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 18789ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 18799ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 18809ec7b004SRick Macklem } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 18819ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 18829ec7b004SRick Macklem *tl++ = newnfs_false; 18839ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 18849ec7b004SRick Macklem tl += 2; 18859ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 18869ec7b004SRick Macklem } 1887a9285ae5SZack Kirsch 1888a9285ae5SZack Kirsch out: 1889a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1890a9285ae5SZack Kirsch return (error); 18919ec7b004SRick Macklem } 18929ec7b004SRick Macklem 18939ec7b004SRick Macklem /* 18949ec7b004SRick Macklem * nfs symbolic link service 18959ec7b004SRick Macklem */ 1896b9cc3262SRyan Moeller int 18979ec7b004SRick Macklem nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram, 1898af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 18999ec7b004SRick Macklem { 19009ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 19019ec7b004SRick Macklem struct nameidata named; 1902a9285ae5SZack Kirsch int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 19039ec7b004SRick Macklem vnode_t dirp = NULL; 19049ec7b004SRick Macklem char *bufp, *pathcp = NULL; 19059ec7b004SRick Macklem u_long *hashp; 1906af444b18SEdward Tomasz Napierala struct thread *p = curthread; 19079ec7b004SRick Macklem 19089ec7b004SRick Macklem if (nd->nd_repstat) { 19099ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1910a9285ae5SZack Kirsch goto out; 19119ec7b004SRick Macklem } 19129ec7b004SRick Macklem if (vpp) 19139ec7b004SRick Macklem *vpp = NULL; 19149ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 19159ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 191665127e98SMateusz Guzik LOCKPARENT | NOCACHE); 19179ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 19189ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 19199ec7b004SRick Macklem if (!error && !nd->nd_repstat) 19209ec7b004SRick Macklem error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen); 19219ec7b004SRick Macklem if (error) { 19229ec7b004SRick Macklem vrele(dp); 19239ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1924a9285ae5SZack Kirsch goto out; 19259ec7b004SRick Macklem } 19269ec7b004SRick Macklem if (!nd->nd_repstat) { 1927ef7d2c1fSMateusz Guzik nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp); 19289ec7b004SRick Macklem } else { 19299ec7b004SRick Macklem vrele(dp); 19309ec7b004SRick Macklem nfsvno_relpathbuf(&named); 19319ec7b004SRick Macklem } 19329ec7b004SRick Macklem if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 19339ec7b004SRick Macklem vrele(dirp); 19349ec7b004SRick Macklem dirp = NULL; 19359ec7b004SRick Macklem } 19369ec7b004SRick Macklem 19379ec7b004SRick Macklem /* 19389ec7b004SRick Macklem * And call nfsrvd_symlinksub() to do the common code. It will 19399ec7b004SRick Macklem * return EBADRPC upon a parsing error, 0 otherwise. 19409ec7b004SRick Macklem */ 19419ec7b004SRick Macklem if (!nd->nd_repstat) { 19429ec7b004SRick Macklem if (dirp != NULL) 194390d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 194490d2dfabSRick Macklem NULL); 19459ec7b004SRick Macklem nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 19469ec7b004SRick Macklem &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp, 19479ec7b004SRick Macklem pathcp, pathlen); 19489ec7b004SRick Macklem } else if (dirp != NULL) { 194990d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); 19509ec7b004SRick Macklem vrele(dirp); 19519ec7b004SRick Macklem } 19529ec7b004SRick Macklem if (pathcp) 1953222daa42SConrad Meyer free(pathcp, M_TEMP); 19549ec7b004SRick Macklem 19559ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 19569ec7b004SRick Macklem if (!nd->nd_repstat) { 1957695d87baSRick Macklem (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1); 19589ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 19599ec7b004SRick Macklem } 19609ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 19619ec7b004SRick Macklem } 1962a9285ae5SZack Kirsch 1963a9285ae5SZack Kirsch out: 1964a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1965a9285ae5SZack Kirsch return (error); 19669ec7b004SRick Macklem } 19679ec7b004SRick Macklem 19689ec7b004SRick Macklem /* 19699ec7b004SRick Macklem * Common code for creating a symbolic link. 19709ec7b004SRick Macklem */ 19719ec7b004SRick Macklem static void 19729ec7b004SRick Macklem nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 19739ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 19749ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 19759ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, 19769ec7b004SRick Macklem NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 19779ec7b004SRick Macklem int pathlen) 19789ec7b004SRick Macklem { 19799ec7b004SRick Macklem u_int32_t *tl; 19809ec7b004SRick Macklem 19819ec7b004SRick Macklem nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen, 19829ec7b004SRick Macklem !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp); 19839ec7b004SRick Macklem if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) { 19849ec7b004SRick Macklem nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp); 19859ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 19869ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p); 19879ec7b004SRick Macklem if (!nd->nd_repstat) 19889ec7b004SRick Macklem nd->nd_repstat = nfsvno_getattr(ndp->ni_vp, 198990d2dfabSRick Macklem nvap, nd, p, 1, NULL); 19909ec7b004SRick Macklem } 199181f78d99SRick Macklem if (vpp != NULL && nd->nd_repstat == 0) { 1992b249ce48SMateusz Guzik NFSVOPUNLOCK(ndp->ni_vp); 19939ec7b004SRick Macklem *vpp = ndp->ni_vp; 199481f78d99SRick Macklem } else 19959ec7b004SRick Macklem vput(ndp->ni_vp); 19969ec7b004SRick Macklem } 19979ec7b004SRick Macklem if (dirp) { 199890d2dfabSRick Macklem *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL); 19999ec7b004SRick Macklem vrele(dirp); 20009ec7b004SRick Macklem } 20019ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 20029ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 20039ec7b004SRick Macklem *tl++ = newnfs_false; 20049ec7b004SRick Macklem txdr_hyper(dirforp->na_filerev, tl); 20059ec7b004SRick Macklem tl += 2; 20069ec7b004SRick Macklem txdr_hyper(diraftp->na_filerev, tl); 20079ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, attrbitp); 20089ec7b004SRick Macklem } 2009a9285ae5SZack Kirsch 2010a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 20119ec7b004SRick Macklem } 20129ec7b004SRick Macklem 20139ec7b004SRick Macklem /* 20149ec7b004SRick Macklem * nfs mkdir service 20159ec7b004SRick Macklem */ 2016b9cc3262SRyan Moeller int 20179ec7b004SRick Macklem nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram, 2018af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 20199ec7b004SRick Macklem { 20209ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 20219ec7b004SRick Macklem struct nameidata named; 20229ec7b004SRick Macklem u_int32_t *tl; 2023a9285ae5SZack Kirsch int error = 0, dirfor_ret = 1, diraft_ret = 1; 20249ec7b004SRick Macklem vnode_t dirp = NULL; 20259ec7b004SRick Macklem char *bufp; 20269ec7b004SRick Macklem u_long *hashp; 2027af444b18SEdward Tomasz Napierala struct thread *p = curthread; 20289ec7b004SRick Macklem 20299ec7b004SRick Macklem if (nd->nd_repstat) { 20309ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 2031a9285ae5SZack Kirsch goto out; 20329ec7b004SRick Macklem } 20335b5b7e2cSMateusz Guzik NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT | NOCACHE); 20349ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 20359ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 2036a9285ae5SZack Kirsch if (error) 2037a9285ae5SZack Kirsch goto nfsmout; 20389ec7b004SRick Macklem if (!nd->nd_repstat) { 20399ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 20409ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 2041d8a5961fSMarcelo Araujo error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p); 2042a9285ae5SZack Kirsch if (error) 2043a9285ae5SZack Kirsch goto nfsmout; 20449ec7b004SRick Macklem } else { 20459ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 20469ec7b004SRick Macklem nva.na_mode = nfstov_mode(*tl++); 20479ec7b004SRick Macklem } 20489ec7b004SRick Macklem } 20499ec7b004SRick Macklem if (!nd->nd_repstat) { 2050ef7d2c1fSMateusz Guzik nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp); 20519ec7b004SRick Macklem } else { 20529ec7b004SRick Macklem vrele(dp); 20539ec7b004SRick Macklem nfsvno_relpathbuf(&named); 20549ec7b004SRick Macklem } 20559ec7b004SRick Macklem if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 20569ec7b004SRick Macklem vrele(dirp); 20579ec7b004SRick Macklem dirp = NULL; 20589ec7b004SRick Macklem } 20599ec7b004SRick Macklem if (nd->nd_repstat) { 20609ec7b004SRick Macklem if (dirp != NULL) { 206190d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 206290d2dfabSRick Macklem NULL); 20639ec7b004SRick Macklem vrele(dirp); 20649ec7b004SRick Macklem } 20659ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 20669ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 20679ec7b004SRick Macklem &diraft); 2068a9285ae5SZack Kirsch goto out; 20699ec7b004SRick Macklem } 20709ec7b004SRick Macklem if (dirp != NULL) 207190d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); 20729ec7b004SRick Macklem 20739ec7b004SRick Macklem /* 20749ec7b004SRick Macklem * Call nfsrvd_mkdirsub() for the code common to V4 as well. 20759ec7b004SRick Macklem */ 20769ec7b004SRick Macklem nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft, 20779ec7b004SRick Macklem &diraft_ret, NULL, NULL, p, exp); 20789ec7b004SRick Macklem 20799ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 20809ec7b004SRick Macklem if (!nd->nd_repstat) { 2081695d87baSRick Macklem (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1); 20829ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 20839ec7b004SRick Macklem } 20849ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 20859ec7b004SRick Macklem } else if (!nd->nd_repstat) { 2086695d87baSRick Macklem (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0); 20879ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 20889ec7b004SRick Macklem } 2089a9285ae5SZack Kirsch 2090a9285ae5SZack Kirsch out: 2091a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 20929ec7b004SRick Macklem return (0); 20939ec7b004SRick Macklem nfsmout: 20949ec7b004SRick Macklem vrele(dp); 20959ec7b004SRick Macklem nfsvno_relpathbuf(&named); 2096a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 20979ec7b004SRick Macklem return (error); 20989ec7b004SRick Macklem } 20999ec7b004SRick Macklem 21009ec7b004SRick Macklem /* 21019ec7b004SRick Macklem * Code common to mkdir for V2,3 and 4. 21029ec7b004SRick Macklem */ 21039ec7b004SRick Macklem static void 21049ec7b004SRick Macklem nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 21059ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 21069ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 21079ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 21089ec7b004SRick Macklem NFSPROC_T *p, struct nfsexstuff *exp) 21099ec7b004SRick Macklem { 21109ec7b004SRick Macklem vnode_t vp; 21119ec7b004SRick Macklem u_int32_t *tl; 21129ec7b004SRick Macklem 21139ec7b004SRick Macklem NFSVNO_SETATTRVAL(nvap, type, VDIR); 21149ec7b004SRick Macklem nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid, 21159ec7b004SRick Macklem nd->nd_cred, p, exp); 21169ec7b004SRick Macklem if (!nd->nd_repstat) { 21179ec7b004SRick Macklem vp = ndp->ni_vp; 21189ec7b004SRick Macklem nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp); 21199ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 21209ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 212190d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1, 212290d2dfabSRick Macklem NULL); 21239ec7b004SRick Macklem if (vpp && !nd->nd_repstat) { 2124b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 21259ec7b004SRick Macklem *vpp = vp; 21269ec7b004SRick Macklem } else { 21279ec7b004SRick Macklem vput(vp); 21289ec7b004SRick Macklem } 21299ec7b004SRick Macklem } 21309ec7b004SRick Macklem if (dirp) { 213190d2dfabSRick Macklem *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL); 21329ec7b004SRick Macklem vrele(dirp); 21339ec7b004SRick Macklem } 21349ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 21359ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 21369ec7b004SRick Macklem *tl++ = newnfs_false; 21379ec7b004SRick Macklem txdr_hyper(dirforp->na_filerev, tl); 21389ec7b004SRick Macklem tl += 2; 21399ec7b004SRick Macklem txdr_hyper(diraftp->na_filerev, tl); 21409ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, attrbitp); 21419ec7b004SRick Macklem } 2142a9285ae5SZack Kirsch 2143a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 21449ec7b004SRick Macklem } 21459ec7b004SRick Macklem 21469ec7b004SRick Macklem /* 21479ec7b004SRick Macklem * nfs commit service 21489ec7b004SRick Macklem */ 2149b9cc3262SRyan Moeller int 21509ec7b004SRick Macklem nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram, 2151af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 21529ec7b004SRick Macklem { 21539ec7b004SRick Macklem struct nfsvattr bfor, aft; 21549ec7b004SRick Macklem u_int32_t *tl; 21559ec7b004SRick Macklem int error = 0, for_ret = 1, aft_ret = 1, cnt; 21569ec7b004SRick Macklem u_int64_t off; 2157af444b18SEdward Tomasz Napierala struct thread *p = curthread; 21589ec7b004SRick Macklem 21599ec7b004SRick Macklem if (nd->nd_repstat) { 21609ec7b004SRick Macklem nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 2161a9285ae5SZack Kirsch goto out; 21629ec7b004SRick Macklem } 2163d8a5961fSMarcelo Araujo 2164d8a5961fSMarcelo Araujo /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */ 2165d8a5961fSMarcelo Araujo if (vp->v_type != VREG) { 2166d8a5961fSMarcelo Araujo if (nd->nd_flag & ND_NFSV3) 2167d8a5961fSMarcelo Araujo error = NFSERR_NOTSUPP; 2168d8a5961fSMarcelo Araujo else 2169d8a5961fSMarcelo Araujo error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL; 2170d8a5961fSMarcelo Araujo goto nfsmout; 2171d8a5961fSMarcelo Araujo } 21729ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2173d8a5961fSMarcelo Araujo 21749ec7b004SRick Macklem /* 21759ec7b004SRick Macklem * XXX At this time VOP_FSYNC() does not accept offset and byte 21769ec7b004SRick Macklem * count parameters, so these arguments are useless (someday maybe). 21779ec7b004SRick Macklem */ 21789ec7b004SRick Macklem off = fxdr_hyper(tl); 21799ec7b004SRick Macklem tl += 2; 21809ec7b004SRick Macklem cnt = fxdr_unsigned(int, *tl); 21819ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 218290d2dfabSRick Macklem for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL); 21839ec7b004SRick Macklem nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p); 21849ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 218590d2dfabSRick Macklem aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL); 21869ec7b004SRick Macklem nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 21879ec7b004SRick Macklem } 21889ec7b004SRick Macklem vput(vp); 21899ec7b004SRick Macklem if (!nd->nd_repstat) { 21909ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 21919ec7b004SRick Macklem *tl++ = txdr_unsigned(nfsboottime.tv_sec); 21929ec7b004SRick Macklem *tl = txdr_unsigned(nfsboottime.tv_usec); 21939ec7b004SRick Macklem } 2194a9285ae5SZack Kirsch 2195a9285ae5SZack Kirsch out: 2196a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 21979ec7b004SRick Macklem return (0); 21989ec7b004SRick Macklem nfsmout: 21999ec7b004SRick Macklem vput(vp); 2200a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 22019ec7b004SRick Macklem return (error); 22029ec7b004SRick Macklem } 22039ec7b004SRick Macklem 22049ec7b004SRick Macklem /* 22059ec7b004SRick Macklem * nfs statfs service 22069ec7b004SRick Macklem */ 2207b9cc3262SRyan Moeller int 22089ec7b004SRick Macklem nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram, 2209af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 22109ec7b004SRick Macklem { 22119ec7b004SRick Macklem struct statfs *sf; 22129ec7b004SRick Macklem u_int32_t *tl; 22139ec7b004SRick Macklem int getret = 1; 22149ec7b004SRick Macklem struct nfsvattr at; 22159ec7b004SRick Macklem u_quad_t tval; 2216af444b18SEdward Tomasz Napierala struct thread *p = curthread; 22179ec7b004SRick Macklem 22182f304845SKonstantin Belousov sf = NULL; 22199ec7b004SRick Macklem if (nd->nd_repstat) { 22209ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 2221a9285ae5SZack Kirsch goto out; 22229ec7b004SRick Macklem } 22232f304845SKonstantin Belousov sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 2224dfd233edSAttilio Rao nd->nd_repstat = nfsvno_statfs(vp, sf); 222590d2dfabSRick Macklem getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); 22269ec7b004SRick Macklem vput(vp); 22279ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 22289ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 22299ec7b004SRick Macklem if (nd->nd_repstat) 2230a9285ae5SZack Kirsch goto out; 22319ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 22329ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS); 22339ec7b004SRick Macklem *tl++ = txdr_unsigned(NFS_V2MAXDATA); 22349ec7b004SRick Macklem *tl++ = txdr_unsigned(sf->f_bsize); 22359ec7b004SRick Macklem *tl++ = txdr_unsigned(sf->f_blocks); 22369ec7b004SRick Macklem *tl++ = txdr_unsigned(sf->f_bfree); 22379ec7b004SRick Macklem *tl = txdr_unsigned(sf->f_bavail); 22389ec7b004SRick Macklem } else { 22399ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS); 22409ec7b004SRick Macklem tval = (u_quad_t)sf->f_blocks; 22419ec7b004SRick Macklem tval *= (u_quad_t)sf->f_bsize; 22429ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 22439ec7b004SRick Macklem tval = (u_quad_t)sf->f_bfree; 22449ec7b004SRick Macklem tval *= (u_quad_t)sf->f_bsize; 22459ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 22469ec7b004SRick Macklem tval = (u_quad_t)sf->f_bavail; 22479ec7b004SRick Macklem tval *= (u_quad_t)sf->f_bsize; 22489ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 22499ec7b004SRick Macklem tval = (u_quad_t)sf->f_files; 22509ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 22519ec7b004SRick Macklem tval = (u_quad_t)sf->f_ffree; 22529ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 22539ec7b004SRick Macklem tval = (u_quad_t)sf->f_ffree; 22549ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 22559ec7b004SRick Macklem *tl = 0; 22569ec7b004SRick Macklem } 2257a9285ae5SZack Kirsch 2258a9285ae5SZack Kirsch out: 22592f304845SKonstantin Belousov free(sf, M_STATFS); 2260a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 22619ec7b004SRick Macklem return (0); 22629ec7b004SRick Macklem } 22639ec7b004SRick Macklem 22649ec7b004SRick Macklem /* 22659ec7b004SRick Macklem * nfs fsinfo service 22669ec7b004SRick Macklem */ 2267b9cc3262SRyan Moeller int 22689ec7b004SRick Macklem nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram, 2269af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 22709ec7b004SRick Macklem { 22719ec7b004SRick Macklem u_int32_t *tl; 22729ec7b004SRick Macklem struct nfsfsinfo fs; 22739ec7b004SRick Macklem int getret = 1; 22749ec7b004SRick Macklem struct nfsvattr at; 2275af444b18SEdward Tomasz Napierala struct thread *p = curthread; 22769ec7b004SRick Macklem 22779ec7b004SRick Macklem if (nd->nd_repstat) { 22789ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 2279a9285ae5SZack Kirsch goto out; 22809ec7b004SRick Macklem } 228190d2dfabSRick Macklem getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); 22829ec7b004SRick Macklem nfsvno_getfs(&fs, isdgram); 22839ec7b004SRick Macklem vput(vp); 22849ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 22859ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO); 22869ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_rtmax); 22879ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_rtpref); 22889ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_rtmult); 22899ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_wtmax); 22909ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_wtpref); 22919ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_wtmult); 22929ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_dtpref); 22939ec7b004SRick Macklem txdr_hyper(fs.fs_maxfilesize, tl); 22949ec7b004SRick Macklem tl += 2; 22959ec7b004SRick Macklem txdr_nfsv3time(&fs.fs_timedelta, tl); 22969ec7b004SRick Macklem tl += 2; 22979ec7b004SRick Macklem *tl = txdr_unsigned(fs.fs_properties); 2298a9285ae5SZack Kirsch 2299a9285ae5SZack Kirsch out: 2300a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 23019ec7b004SRick Macklem return (0); 23029ec7b004SRick Macklem } 23039ec7b004SRick Macklem 23049ec7b004SRick Macklem /* 23059ec7b004SRick Macklem * nfs pathconf service 23069ec7b004SRick Macklem */ 2307b9cc3262SRyan Moeller int 23089ec7b004SRick Macklem nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram, 2309af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 23109ec7b004SRick Macklem { 23119ec7b004SRick Macklem struct nfsv3_pathconf *pc; 23129ec7b004SRick Macklem int getret = 1; 2313b1288166SJohn Baldwin long linkmax, namemax, chownres, notrunc; 23149ec7b004SRick Macklem struct nfsvattr at; 2315af444b18SEdward Tomasz Napierala struct thread *p = curthread; 23169ec7b004SRick Macklem 23179ec7b004SRick Macklem if (nd->nd_repstat) { 23189ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 2319a9285ae5SZack Kirsch goto out; 23209ec7b004SRick Macklem } 23219ec7b004SRick Macklem nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax, 23229ec7b004SRick Macklem nd->nd_cred, p); 23239ec7b004SRick Macklem if (!nd->nd_repstat) 23249ec7b004SRick Macklem nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax, 23259ec7b004SRick Macklem nd->nd_cred, p); 23269ec7b004SRick Macklem if (!nd->nd_repstat) 23279ec7b004SRick Macklem nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED, 23289ec7b004SRick Macklem &chownres, nd->nd_cred, p); 23299ec7b004SRick Macklem if (!nd->nd_repstat) 23309ec7b004SRick Macklem nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc, 23319ec7b004SRick Macklem nd->nd_cred, p); 233290d2dfabSRick Macklem getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); 23339ec7b004SRick Macklem vput(vp); 23349ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 23359ec7b004SRick Macklem if (!nd->nd_repstat) { 23369ec7b004SRick Macklem NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); 23379ec7b004SRick Macklem pc->pc_linkmax = txdr_unsigned(linkmax); 23389ec7b004SRick Macklem pc->pc_namemax = txdr_unsigned(namemax); 23399ec7b004SRick Macklem pc->pc_notrunc = txdr_unsigned(notrunc); 23409ec7b004SRick Macklem pc->pc_chownrestricted = txdr_unsigned(chownres); 23419ec7b004SRick Macklem 23429ec7b004SRick Macklem /* 23439ec7b004SRick Macklem * These should probably be supported by VOP_PATHCONF(), but 23449ec7b004SRick Macklem * until msdosfs is exportable (why would you want to?), the 23459ec7b004SRick Macklem * Unix defaults should be ok. 23469ec7b004SRick Macklem */ 23479ec7b004SRick Macklem pc->pc_caseinsensitive = newnfs_false; 23489ec7b004SRick Macklem pc->pc_casepreserving = newnfs_true; 23499ec7b004SRick Macklem } 2350a9285ae5SZack Kirsch 2351a9285ae5SZack Kirsch out: 2352a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 23539ec7b004SRick Macklem return (0); 23549ec7b004SRick Macklem } 23559ec7b004SRick Macklem 23569ec7b004SRick Macklem /* 23579ec7b004SRick Macklem * nfsv4 lock service 23589ec7b004SRick Macklem */ 2359b9cc3262SRyan Moeller int 23609ec7b004SRick Macklem nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram, 2361af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 23629ec7b004SRick Macklem { 23639ec7b004SRick Macklem u_int32_t *tl; 23649ec7b004SRick Macklem int i; 23659ec7b004SRick Macklem struct nfsstate *stp = NULL; 23669ec7b004SRick Macklem struct nfslock *lop; 23679ec7b004SRick Macklem struct nfslockconflict cf; 23689ec7b004SRick Macklem int error = 0; 23699ec7b004SRick Macklem u_short flags = NFSLCK_LOCK, lflags; 23709ec7b004SRick Macklem u_int64_t offset, len; 23719ec7b004SRick Macklem nfsv4stateid_t stateid; 23729ec7b004SRick Macklem nfsquad_t clientid; 2373af444b18SEdward Tomasz Napierala struct thread *p = curthread; 23749ec7b004SRick Macklem 23759ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 23769ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 23779ec7b004SRick Macklem switch (i) { 23789ec7b004SRick Macklem case NFSV4LOCKT_READW: 23799ec7b004SRick Macklem flags |= NFSLCK_BLOCKING; 23809ec7b004SRick Macklem case NFSV4LOCKT_READ: 23819ec7b004SRick Macklem lflags = NFSLCK_READ; 23829ec7b004SRick Macklem break; 23839ec7b004SRick Macklem case NFSV4LOCKT_WRITEW: 23849ec7b004SRick Macklem flags |= NFSLCK_BLOCKING; 23859ec7b004SRick Macklem case NFSV4LOCKT_WRITE: 23869ec7b004SRick Macklem lflags = NFSLCK_WRITE; 23879ec7b004SRick Macklem break; 23889ec7b004SRick Macklem default: 23899ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 23909ec7b004SRick Macklem goto nfsmout; 239174b8d63dSPedro F. Giffuni } 23929ec7b004SRick Macklem if (*tl++ == newnfs_true) 23939ec7b004SRick Macklem flags |= NFSLCK_RECLAIM; 23949ec7b004SRick Macklem offset = fxdr_hyper(tl); 23959ec7b004SRick Macklem tl += 2; 23969ec7b004SRick Macklem len = fxdr_hyper(tl); 23979ec7b004SRick Macklem tl += 2; 23989ec7b004SRick Macklem if (*tl == newnfs_true) 23999ec7b004SRick Macklem flags |= NFSLCK_OPENTOLOCK; 24009ec7b004SRick Macklem if (flags & NFSLCK_OPENTOLOCK) { 24019ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID); 24029ec7b004SRick Macklem i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED))); 24032a45247cSRick Macklem if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 24042a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 24052a45247cSRick Macklem goto nfsmout; 24062a45247cSRick Macklem } 2407222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate) + i, 24089ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 24099ec7b004SRick Macklem stp->ls_ownerlen = i; 24109ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 24119ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(int, *tl++); 24129ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 24139ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 24149ec7b004SRick Macklem NFSX_STATEIDOTHER); 24159ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 241690d2dfabSRick Macklem 241790d2dfabSRick Macklem /* 241890d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set 241990d2dfabSRick Macklem * the stateid to the current stateid, if it is set. 242090d2dfabSRick Macklem */ 242190d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 && 242290d2dfabSRick Macklem stp->ls_stateid.seqid == 1 && 242390d2dfabSRick Macklem stp->ls_stateid.other[0] == 0 && 242490d2dfabSRick Macklem stp->ls_stateid.other[1] == 0 && 242590d2dfabSRick Macklem stp->ls_stateid.other[2] == 0) { 242690d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 242790d2dfabSRick Macklem stp->ls_stateid = nd->nd_curstateid; 242890d2dfabSRick Macklem stp->ls_stateid.seqid = 0; 242990d2dfabSRick Macklem } else { 243090d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 243190d2dfabSRick Macklem goto nfsmout; 243290d2dfabSRick Macklem } 243390d2dfabSRick Macklem } 243490d2dfabSRick Macklem 24359ec7b004SRick Macklem stp->ls_opentolockseq = fxdr_unsigned(int, *tl++); 24369ec7b004SRick Macklem clientid.lval[0] = *tl++; 24379ec7b004SRick Macklem clientid.lval[1] = *tl++; 2438c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2439c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2440c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2441c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2442c59e4cc3SRick Macklem printf("EEK3 multiple clids\n"); 24439ec7b004SRick Macklem } else { 2444c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2445c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 24469ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 24479ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 24489ec7b004SRick Macklem } 24499ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 24509ec7b004SRick Macklem if (error) 24519ec7b004SRick Macklem goto nfsmout; 24529ec7b004SRick Macklem } else { 24539ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 2454222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate), 24559ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 24569ec7b004SRick Macklem stp->ls_ownerlen = 0; 24579ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 24589ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 24599ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 24609ec7b004SRick Macklem NFSX_STATEIDOTHER); 24619ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 246290d2dfabSRick Macklem 246390d2dfabSRick Macklem /* 246490d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set 246590d2dfabSRick Macklem * the stateid to the current stateid, if it is set. 246690d2dfabSRick Macklem */ 246790d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 && 246890d2dfabSRick Macklem stp->ls_stateid.seqid == 1 && 246990d2dfabSRick Macklem stp->ls_stateid.other[0] == 0 && 247090d2dfabSRick Macklem stp->ls_stateid.other[1] == 0 && 247190d2dfabSRick Macklem stp->ls_stateid.other[2] == 0) { 247290d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 247390d2dfabSRick Macklem stp->ls_stateid = nd->nd_curstateid; 247490d2dfabSRick Macklem stp->ls_stateid.seqid = 0; 247590d2dfabSRick Macklem } else { 247690d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 247790d2dfabSRick Macklem goto nfsmout; 247890d2dfabSRick Macklem } 247990d2dfabSRick Macklem } 248090d2dfabSRick Macklem 24819ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(int, *tl); 24829ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 24839ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 2484c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2485c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2486c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2487c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2488c59e4cc3SRick Macklem printf("EEK4 multiple clids\n"); 24899ec7b004SRick Macklem } else { 2490c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2491c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 24929ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 24939ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 24949ec7b004SRick Macklem } 24959ec7b004SRick Macklem } 2496222daa42SConrad Meyer lop = malloc(sizeof (struct nfslock), 24979ec7b004SRick Macklem M_NFSDLOCK, M_WAITOK); 24989ec7b004SRick Macklem lop->lo_first = offset; 24999ec7b004SRick Macklem if (len == NFS64BITSSET) { 25009ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 25019ec7b004SRick Macklem } else { 25029ec7b004SRick Macklem lop->lo_end = offset + len; 25039ec7b004SRick Macklem if (lop->lo_end <= lop->lo_first) 25049ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 25059ec7b004SRick Macklem } 25069ec7b004SRick Macklem lop->lo_flags = lflags; 25079ec7b004SRick Macklem stp->ls_flags = flags; 25089ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 25099ec7b004SRick Macklem 25109ec7b004SRick Macklem /* 25119ec7b004SRick Macklem * Do basic access checking. 25129ec7b004SRick Macklem */ 25135d3fe02cSRick Macklem if (!nd->nd_repstat && vp->v_type != VREG) { 25145d3fe02cSRick Macklem if (vp->v_type == VDIR) 25159ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 25169ec7b004SRick Macklem else 25179ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 25189ec7b004SRick Macklem } 25199ec7b004SRick Macklem if (!nd->nd_repstat) { 25209ec7b004SRick Macklem if (lflags & NFSLCK_WRITE) { 25218da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 25229ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 25238da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 25249ec7b004SRick Macklem } else { 25258da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, 25269ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 25278da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 25289ec7b004SRick Macklem if (nd->nd_repstat) 25298da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 25309ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 25318da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 25329ec7b004SRick Macklem } 25339ec7b004SRick Macklem } 25349ec7b004SRick Macklem 25359ec7b004SRick Macklem /* 25369ec7b004SRick Macklem * We call nfsrv_lockctrl() even if nd_repstat set, so that the 25379ec7b004SRick Macklem * seqid# gets updated. nfsrv_lockctrl() will return the value 25389ec7b004SRick Macklem * of nd_repstat, if it gets that far. 25399ec7b004SRick Macklem */ 25409ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 25419ec7b004SRick Macklem &stateid, exp, nd, p); 25429ec7b004SRick Macklem if (lop) 2543222daa42SConrad Meyer free(lop, M_NFSDLOCK); 25449ec7b004SRick Macklem if (stp) 2545222daa42SConrad Meyer free(stp, M_NFSDSTATE); 25469ec7b004SRick Macklem if (!nd->nd_repstat) { 254790d2dfabSRick Macklem /* For NFSv4.1, set the Current StateID. */ 254890d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 254990d2dfabSRick Macklem nd->nd_curstateid = stateid; 255090d2dfabSRick Macklem nd->nd_flag |= ND_CURSTATEID; 255190d2dfabSRick Macklem } 25529ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 25539ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 25549ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 25559ec7b004SRick Macklem } else if (nd->nd_repstat == NFSERR_DENIED) { 25569ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 25579ec7b004SRick Macklem txdr_hyper(cf.cl_first, tl); 25589ec7b004SRick Macklem tl += 2; 25599ec7b004SRick Macklem if (cf.cl_end == NFS64BITSSET) 25609ec7b004SRick Macklem len = NFS64BITSSET; 25619ec7b004SRick Macklem else 25629ec7b004SRick Macklem len = cf.cl_end - cf.cl_first; 25639ec7b004SRick Macklem txdr_hyper(len, tl); 25649ec7b004SRick Macklem tl += 2; 25659ec7b004SRick Macklem if (cf.cl_flags == NFSLCK_WRITE) 25669ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 25679ec7b004SRick Macklem else 25689ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 25699ec7b004SRick Macklem *tl++ = stateid.other[0]; 25709ec7b004SRick Macklem *tl = stateid.other[1]; 25719ec7b004SRick Macklem (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 25729ec7b004SRick Macklem } 25739ec7b004SRick Macklem vput(vp); 2574a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 25759ec7b004SRick Macklem return (0); 25769ec7b004SRick Macklem nfsmout: 25779ec7b004SRick Macklem vput(vp); 25789ec7b004SRick Macklem if (stp) 2579222daa42SConrad Meyer free(stp, M_NFSDSTATE); 2580a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 25819ec7b004SRick Macklem return (error); 25829ec7b004SRick Macklem } 25839ec7b004SRick Macklem 25849ec7b004SRick Macklem /* 25859ec7b004SRick Macklem * nfsv4 lock test service 25869ec7b004SRick Macklem */ 2587b9cc3262SRyan Moeller int 25889ec7b004SRick Macklem nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram, 2589af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 25909ec7b004SRick Macklem { 25919ec7b004SRick Macklem u_int32_t *tl; 25929ec7b004SRick Macklem int i; 25939ec7b004SRick Macklem struct nfsstate *stp = NULL; 25949ec7b004SRick Macklem struct nfslock lo, *lop = &lo; 25959ec7b004SRick Macklem struct nfslockconflict cf; 25969ec7b004SRick Macklem int error = 0; 25979ec7b004SRick Macklem nfsv4stateid_t stateid; 25989ec7b004SRick Macklem nfsquad_t clientid; 25999ec7b004SRick Macklem u_int64_t len; 2600af444b18SEdward Tomasz Napierala struct thread *p = curthread; 26019ec7b004SRick Macklem 26029ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 26039ec7b004SRick Macklem i = fxdr_unsigned(int, *(tl + 7)); 26042a45247cSRick Macklem if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 26052a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 26062a45247cSRick Macklem goto nfsmout; 26072a45247cSRick Macklem } 2608222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate) + i, 26099ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 26109ec7b004SRick Macklem stp->ls_ownerlen = i; 26119ec7b004SRick Macklem stp->ls_op = NULL; 26129ec7b004SRick Macklem stp->ls_flags = NFSLCK_TEST; 26139ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 26149ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 26159ec7b004SRick Macklem switch (i) { 26169ec7b004SRick Macklem case NFSV4LOCKT_READW: 26179ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 26189ec7b004SRick Macklem case NFSV4LOCKT_READ: 26199ec7b004SRick Macklem lo.lo_flags = NFSLCK_READ; 26209ec7b004SRick Macklem break; 26219ec7b004SRick Macklem case NFSV4LOCKT_WRITEW: 26229ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 26239ec7b004SRick Macklem case NFSV4LOCKT_WRITE: 26249ec7b004SRick Macklem lo.lo_flags = NFSLCK_WRITE; 26259ec7b004SRick Macklem break; 26269ec7b004SRick Macklem default: 26279ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 26289ec7b004SRick Macklem goto nfsmout; 262974b8d63dSPedro F. Giffuni } 26309ec7b004SRick Macklem lo.lo_first = fxdr_hyper(tl); 26319ec7b004SRick Macklem tl += 2; 26329ec7b004SRick Macklem len = fxdr_hyper(tl); 26339ec7b004SRick Macklem if (len == NFS64BITSSET) { 26349ec7b004SRick Macklem lo.lo_end = NFS64BITSSET; 26359ec7b004SRick Macklem } else { 26369ec7b004SRick Macklem lo.lo_end = lo.lo_first + len; 26379ec7b004SRick Macklem if (lo.lo_end <= lo.lo_first) 26389ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 26399ec7b004SRick Macklem } 26409ec7b004SRick Macklem tl += 2; 26419ec7b004SRick Macklem clientid.lval[0] = *tl++; 26429ec7b004SRick Macklem clientid.lval[1] = *tl; 2643c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2644c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2645c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2646c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2647c59e4cc3SRick Macklem printf("EEK5 multiple clids\n"); 26489ec7b004SRick Macklem } else { 2649c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2650c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 26519ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 26529ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 26539ec7b004SRick Macklem } 26549ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 26559ec7b004SRick Macklem if (error) 26569ec7b004SRick Macklem goto nfsmout; 26575d3fe02cSRick Macklem if (!nd->nd_repstat && vp->v_type != VREG) { 26585d3fe02cSRick Macklem if (vp->v_type == VDIR) 26599ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 26609ec7b004SRick Macklem else 26619ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 26629ec7b004SRick Macklem } 26639ec7b004SRick Macklem if (!nd->nd_repstat) 26649ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 26659ec7b004SRick Macklem &stateid, exp, nd, p); 26669ec7b004SRick Macklem if (nd->nd_repstat) { 26679ec7b004SRick Macklem if (nd->nd_repstat == NFSERR_DENIED) { 26689ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 26699ec7b004SRick Macklem txdr_hyper(cf.cl_first, tl); 26709ec7b004SRick Macklem tl += 2; 26719ec7b004SRick Macklem if (cf.cl_end == NFS64BITSSET) 26729ec7b004SRick Macklem len = NFS64BITSSET; 26739ec7b004SRick Macklem else 26749ec7b004SRick Macklem len = cf.cl_end - cf.cl_first; 26759ec7b004SRick Macklem txdr_hyper(len, tl); 26769ec7b004SRick Macklem tl += 2; 26779ec7b004SRick Macklem if (cf.cl_flags == NFSLCK_WRITE) 26789ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 26799ec7b004SRick Macklem else 26809ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 26819ec7b004SRick Macklem *tl++ = stp->ls_stateid.other[0]; 26829ec7b004SRick Macklem *tl = stp->ls_stateid.other[1]; 26839ec7b004SRick Macklem (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 26849ec7b004SRick Macklem } 26859ec7b004SRick Macklem } 26869ec7b004SRick Macklem vput(vp); 26875ecc225fSConrad Meyer if (stp) 2688222daa42SConrad Meyer free(stp, M_NFSDSTATE); 2689a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 26909ec7b004SRick Macklem return (0); 26919ec7b004SRick Macklem nfsmout: 26929ec7b004SRick Macklem vput(vp); 26939ec7b004SRick Macklem if (stp) 2694222daa42SConrad Meyer free(stp, M_NFSDSTATE); 2695a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 26969ec7b004SRick Macklem return (error); 26979ec7b004SRick Macklem } 26989ec7b004SRick Macklem 26999ec7b004SRick Macklem /* 27009ec7b004SRick Macklem * nfsv4 unlock service 27019ec7b004SRick Macklem */ 2702b9cc3262SRyan Moeller int 27039ec7b004SRick Macklem nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram, 2704af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 27059ec7b004SRick Macklem { 27069ec7b004SRick Macklem u_int32_t *tl; 27079ec7b004SRick Macklem int i; 27089ec7b004SRick Macklem struct nfsstate *stp; 27099ec7b004SRick Macklem struct nfslock *lop; 27109ec7b004SRick Macklem int error = 0; 27119ec7b004SRick Macklem nfsv4stateid_t stateid; 27129ec7b004SRick Macklem nfsquad_t clientid; 27139ec7b004SRick Macklem u_int64_t len; 2714af444b18SEdward Tomasz Napierala struct thread *p = curthread; 27159ec7b004SRick Macklem 27169ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID); 2717222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate), 27189ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 2719222daa42SConrad Meyer lop = malloc(sizeof (struct nfslock), 27209ec7b004SRick Macklem M_NFSDLOCK, M_WAITOK); 27219ec7b004SRick Macklem stp->ls_flags = NFSLCK_UNLOCK; 27229ec7b004SRick Macklem lop->lo_flags = NFSLCK_UNLOCK; 27239ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 27249ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 27259ec7b004SRick Macklem switch (i) { 27269ec7b004SRick Macklem case NFSV4LOCKT_READW: 27279ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 27289ec7b004SRick Macklem case NFSV4LOCKT_READ: 27299ec7b004SRick Macklem break; 27309ec7b004SRick Macklem case NFSV4LOCKT_WRITEW: 27319ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 27329ec7b004SRick Macklem case NFSV4LOCKT_WRITE: 27339ec7b004SRick Macklem break; 27349ec7b004SRick Macklem default: 27359ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 27362a45247cSRick Macklem free(stp, M_NFSDSTATE); 27372a45247cSRick Macklem free(lop, M_NFSDLOCK); 27389ec7b004SRick Macklem goto nfsmout; 273974b8d63dSPedro F. Giffuni } 27409ec7b004SRick Macklem stp->ls_ownerlen = 0; 27419ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 27429ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(int, *tl++); 27439ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 27449ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 27459ec7b004SRick Macklem NFSX_STATEIDOTHER); 27469ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 274790d2dfabSRick Macklem 274890d2dfabSRick Macklem /* 274990d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 275090d2dfabSRick Macklem * stateid to the current stateid, if it is set. 275190d2dfabSRick Macklem */ 275290d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 275390d2dfabSRick Macklem stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 275490d2dfabSRick Macklem stp->ls_stateid.other[2] == 0) { 275590d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 275690d2dfabSRick Macklem stp->ls_stateid = nd->nd_curstateid; 275790d2dfabSRick Macklem stp->ls_stateid.seqid = 0; 275890d2dfabSRick Macklem } else { 275990d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 27600bb42627SEric van Gyzen free(stp, M_NFSDSTATE); 27610bb42627SEric van Gyzen free(lop, M_NFSDLOCK); 276290d2dfabSRick Macklem goto nfsmout; 276390d2dfabSRick Macklem } 276490d2dfabSRick Macklem } 276590d2dfabSRick Macklem 27669ec7b004SRick Macklem lop->lo_first = fxdr_hyper(tl); 27679ec7b004SRick Macklem tl += 2; 27689ec7b004SRick Macklem len = fxdr_hyper(tl); 27699ec7b004SRick Macklem if (len == NFS64BITSSET) { 27709ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 27719ec7b004SRick Macklem } else { 27729ec7b004SRick Macklem lop->lo_end = lop->lo_first + len; 27739ec7b004SRick Macklem if (lop->lo_end <= lop->lo_first) 27749ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 27759ec7b004SRick Macklem } 27769ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 27779ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 2778c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2779c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2780c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2781c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2782c59e4cc3SRick Macklem printf("EEK6 multiple clids\n"); 27839ec7b004SRick Macklem } else { 2784c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2785c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 27869ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 27879ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 27889ec7b004SRick Macklem } 27895d3fe02cSRick Macklem if (!nd->nd_repstat && vp->v_type != VREG) { 27905d3fe02cSRick Macklem if (vp->v_type == VDIR) 27919ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 27929ec7b004SRick Macklem else 27939ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 27949ec7b004SRick Macklem } 27959ec7b004SRick Macklem /* 27969ec7b004SRick Macklem * Call nfsrv_lockctrl() even if nd_repstat is set, so that the 27979ec7b004SRick Macklem * seqid# gets incremented. nfsrv_lockctrl() will return the 27989ec7b004SRick Macklem * value of nd_repstat, if it gets that far. 27999ec7b004SRick Macklem */ 28009ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 28019ec7b004SRick Macklem &stateid, exp, nd, p); 28029ec7b004SRick Macklem if (stp) 2803222daa42SConrad Meyer free(stp, M_NFSDSTATE); 28049ec7b004SRick Macklem if (lop) 2805222daa42SConrad Meyer free(lop, M_NFSDLOCK); 28069ec7b004SRick Macklem if (!nd->nd_repstat) { 28079ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 28089ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 28099ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 28109ec7b004SRick Macklem } 28119ec7b004SRick Macklem nfsmout: 28129ec7b004SRick Macklem vput(vp); 2813a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 28149ec7b004SRick Macklem return (error); 28159ec7b004SRick Macklem } 28169ec7b004SRick Macklem 28179ec7b004SRick Macklem /* 28189ec7b004SRick Macklem * nfsv4 open service 28199ec7b004SRick Macklem */ 2820b9cc3262SRyan Moeller int 28219ec7b004SRick Macklem nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram, 2822af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp) 28239ec7b004SRick Macklem { 28249ec7b004SRick Macklem u_int32_t *tl; 2825c59e4cc3SRick Macklem int i, retext; 28269ec7b004SRick Macklem struct nfsstate *stp = NULL; 2827b0b7d978SRick Macklem int error = 0, create, claim, exclusive_flag = 0, override; 28289ec7b004SRick Macklem u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask; 28299ec7b004SRick Macklem int how = NFSCREATE_UNCHECKED; 2830086f6e0cSRick Macklem int32_t cverf[2], tverf[2] = { 0, 0 }; 28319ec7b004SRick Macklem vnode_t vp = NULL, dirp = NULL; 28329ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 28339ec7b004SRick Macklem struct nameidata named; 28349ec7b004SRick Macklem nfsv4stateid_t stateid, delegstateid; 28359ec7b004SRick Macklem nfsattrbit_t attrbits; 28369ec7b004SRick Macklem nfsquad_t clientid; 28379ec7b004SRick Macklem char *bufp = NULL; 28389ec7b004SRick Macklem u_long *hashp; 28399ec7b004SRick Macklem NFSACL_T *aclp = NULL; 2840af444b18SEdward Tomasz Napierala struct thread *p = curthread; 2841dcfa3ee4SRick Macklem bool done_namei; 28429ec7b004SRick Macklem 28439ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 2844c3e22f83SRick Macklem aclp = acl_alloc(M_WAITOK); 28459ec7b004SRick Macklem aclp->acl_cnt = 0; 28469ec7b004SRick Macklem #endif 28479ec7b004SRick Macklem NFSZERO_ATTRBIT(&attrbits); 2848dcfa3ee4SRick Macklem done_namei = false; 28499ec7b004SRick Macklem named.ni_cnd.cn_nameiop = 0; 28509ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 28519ec7b004SRick Macklem i = fxdr_unsigned(int, *(tl + 5)); 28522a45247cSRick Macklem if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 28532a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 2854a9285ae5SZack Kirsch goto nfsmout; 28552a45247cSRick Macklem } 2856222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate) + i, 28579ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 28589ec7b004SRick Macklem stp->ls_ownerlen = i; 28599ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 28609ec7b004SRick Macklem stp->ls_flags = NFSLCK_OPEN; 28619ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 28629ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 28639ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 2864c59e4cc3SRick Macklem retext = 0; 2865c59e4cc3SRick Macklem if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG | 2866c59e4cc3SRick Macklem NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) { 2867c59e4cc3SRick Macklem retext = 1; 2868c59e4cc3SRick Macklem /* For now, ignore these. */ 2869c59e4cc3SRick Macklem i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG); 2870c59e4cc3SRick Macklem switch (i & NFSV4OPEN_WANTDELEGMASK) { 2871c59e4cc3SRick Macklem case NFSV4OPEN_WANTANYDELEG: 2872c59e4cc3SRick Macklem stp->ls_flags |= (NFSLCK_WANTRDELEG | 2873c59e4cc3SRick Macklem NFSLCK_WANTWDELEG); 2874c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2875c59e4cc3SRick Macklem break; 2876c59e4cc3SRick Macklem case NFSV4OPEN_WANTREADDELEG: 2877c59e4cc3SRick Macklem stp->ls_flags |= NFSLCK_WANTRDELEG; 2878c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2879c59e4cc3SRick Macklem break; 2880c59e4cc3SRick Macklem case NFSV4OPEN_WANTWRITEDELEG: 2881c59e4cc3SRick Macklem stp->ls_flags |= NFSLCK_WANTWDELEG; 2882c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2883c59e4cc3SRick Macklem break; 2884c59e4cc3SRick Macklem case NFSV4OPEN_WANTNODELEG: 2885c59e4cc3SRick Macklem stp->ls_flags |= NFSLCK_WANTNODELEG; 2886c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2887c59e4cc3SRick Macklem break; 2888c59e4cc3SRick Macklem case NFSV4OPEN_WANTCANCEL: 2889c59e4cc3SRick Macklem printf("NFSv4: ignore Open WantCancel\n"); 2890c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2891c59e4cc3SRick Macklem break; 2892c59e4cc3SRick Macklem default: 2893c59e4cc3SRick Macklem /* nd_repstat will be set to NFSERR_INVAL below. */ 2894c59e4cc3SRick Macklem break; 289574b8d63dSPedro F. Giffuni } 2896c59e4cc3SRick Macklem } 28979ec7b004SRick Macklem switch (i) { 28989ec7b004SRick Macklem case NFSV4OPEN_ACCESSREAD: 28999ec7b004SRick Macklem stp->ls_flags |= NFSLCK_READACCESS; 29009ec7b004SRick Macklem break; 29019ec7b004SRick Macklem case NFSV4OPEN_ACCESSWRITE: 29029ec7b004SRick Macklem stp->ls_flags |= NFSLCK_WRITEACCESS; 29039ec7b004SRick Macklem break; 29049ec7b004SRick Macklem case NFSV4OPEN_ACCESSBOTH: 29059ec7b004SRick Macklem stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 29069ec7b004SRick Macklem break; 29079ec7b004SRick Macklem default: 29089ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 290974b8d63dSPedro F. Giffuni } 29109ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 29119ec7b004SRick Macklem switch (i) { 29129ec7b004SRick Macklem case NFSV4OPEN_DENYNONE: 29139ec7b004SRick Macklem break; 29149ec7b004SRick Macklem case NFSV4OPEN_DENYREAD: 29159ec7b004SRick Macklem stp->ls_flags |= NFSLCK_READDENY; 29169ec7b004SRick Macklem break; 29179ec7b004SRick Macklem case NFSV4OPEN_DENYWRITE: 29189ec7b004SRick Macklem stp->ls_flags |= NFSLCK_WRITEDENY; 29199ec7b004SRick Macklem break; 29209ec7b004SRick Macklem case NFSV4OPEN_DENYBOTH: 29219ec7b004SRick Macklem stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 29229ec7b004SRick Macklem break; 29239ec7b004SRick Macklem default: 29249ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 292574b8d63dSPedro F. Giffuni } 29269ec7b004SRick Macklem clientid.lval[0] = *tl++; 29279ec7b004SRick Macklem clientid.lval[1] = *tl; 2928c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2929c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2930c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2931c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2932c59e4cc3SRick Macklem printf("EEK7 multiple clids\n"); 29339ec7b004SRick Macklem } else { 2934c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2935c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 29369ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 29379ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 29389ec7b004SRick Macklem } 29399ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2940a9285ae5SZack Kirsch if (error) 2941a9285ae5SZack Kirsch goto nfsmout; 29429ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 29439ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 29449ec7b004SRick Macklem create = fxdr_unsigned(int, *tl); 29459ec7b004SRick Macklem if (!nd->nd_repstat) 294690d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL); 29479ec7b004SRick Macklem if (create == NFSV4OPEN_CREATE) { 29489ec7b004SRick Macklem nva.na_type = VREG; 29499ec7b004SRick Macklem nva.na_mode = 0; 29509ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 29519ec7b004SRick Macklem how = fxdr_unsigned(int, *tl); 29529ec7b004SRick Macklem switch (how) { 29539ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 29549ec7b004SRick Macklem case NFSCREATE_GUARDED: 2955d8a5961fSMarcelo Araujo error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p); 2956a9285ae5SZack Kirsch if (error) 2957a9285ae5SZack Kirsch goto nfsmout; 29589ec7b004SRick Macklem /* 29599ec7b004SRick Macklem * If the na_gid being set is the same as that of 29609ec7b004SRick Macklem * the directory it is going in, clear it, since 29619ec7b004SRick Macklem * that is what will be set by default. This allows 29629ec7b004SRick Macklem * a user that isn't in that group to do the create. 29639ec7b004SRick Macklem */ 29649ec7b004SRick Macklem if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) && 29659ec7b004SRick Macklem nva.na_gid == dirfor.na_gid) 29669ec7b004SRick Macklem NFSVNO_UNSET(&nva, gid); 29679ec7b004SRick Macklem if (!nd->nd_repstat) 29689ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 29699ec7b004SRick Macklem break; 29709ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 29719ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2972086f6e0cSRick Macklem cverf[0] = *tl++; 2973086f6e0cSRick Macklem cverf[1] = *tl; 29749ec7b004SRick Macklem break; 2975c59e4cc3SRick Macklem case NFSCREATE_EXCLUSIVE41: 2976c59e4cc3SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2977c59e4cc3SRick Macklem cverf[0] = *tl++; 2978c59e4cc3SRick Macklem cverf[1] = *tl; 2979b4645807SRick Macklem error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p); 2980c59e4cc3SRick Macklem if (error != 0) 2981c59e4cc3SRick Macklem goto nfsmout; 2982c59e4cc3SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, 2983c59e4cc3SRick Macklem NFSATTRBIT_TIMEACCESSSET)) 2984c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_INVAL; 2985c59e4cc3SRick Macklem /* 2986c59e4cc3SRick Macklem * If the na_gid being set is the same as that of 2987c59e4cc3SRick Macklem * the directory it is going in, clear it, since 2988c59e4cc3SRick Macklem * that is what will be set by default. This allows 2989c59e4cc3SRick Macklem * a user that isn't in that group to do the create. 2990c59e4cc3SRick Macklem */ 2991c59e4cc3SRick Macklem if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) && 2992c59e4cc3SRick Macklem nva.na_gid == dirfor.na_gid) 2993c59e4cc3SRick Macklem NFSVNO_UNSET(&nva, gid); 2994c59e4cc3SRick Macklem if (nd->nd_repstat == 0) 2995c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2996c59e4cc3SRick Macklem break; 29979ec7b004SRick Macklem default: 29989ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 2999a9285ae5SZack Kirsch goto nfsmout; 300074b8d63dSPedro F. Giffuni } 30019ec7b004SRick Macklem } else if (create != NFSV4OPEN_NOCREATE) { 30029ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 3003a9285ae5SZack Kirsch goto nfsmout; 30049ec7b004SRick Macklem } 30059ec7b004SRick Macklem 30069ec7b004SRick Macklem /* 30079ec7b004SRick Macklem * Now, handle the claim, which usually includes looking up a 30089ec7b004SRick Macklem * name in the directory referenced by dp. The exception is 30099ec7b004SRick Macklem * NFSV4OPEN_CLAIMPREVIOUS. 30109ec7b004SRick Macklem */ 30119ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 30129ec7b004SRick Macklem claim = fxdr_unsigned(int, *tl); 301354c3aa02SRick Macklem if (claim == NFSV4OPEN_CLAIMDELEGATECUR || claim == 301454c3aa02SRick Macklem NFSV4OPEN_CLAIMDELEGATECURFH) { 30159ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 30169ec7b004SRick Macklem stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 30179ec7b004SRick Macklem NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 30189ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGCUR; 3019d80a903aSRick Macklem } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV || claim == 3020d80a903aSRick Macklem NFSV4OPEN_CLAIMDELEGATEPREVFH) { 30219ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGPREV; 30229ec7b004SRick Macklem } 30239ec7b004SRick Macklem if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR 30249ec7b004SRick Macklem || claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 30259ec7b004SRick Macklem if (!nd->nd_repstat && create == NFSV4OPEN_CREATE && 30269ec7b004SRick Macklem claim != NFSV4OPEN_CLAIMNULL) 30279ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 30289ec7b004SRick Macklem if (nd->nd_repstat) { 30299ec7b004SRick Macklem nd->nd_repstat = nfsrv_opencheck(clientid, 30309ec7b004SRick Macklem &stateid, stp, NULL, nd, p, nd->nd_repstat); 3031a9285ae5SZack Kirsch goto nfsmout; 30329ec7b004SRick Macklem } 30339ec7b004SRick Macklem if (create == NFSV4OPEN_CREATE) 30349ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 303565127e98SMateusz Guzik LOCKPARENT | LOCKLEAF | NOCACHE); 30369ec7b004SRick Macklem else 30379ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 303865127e98SMateusz Guzik LOCKLEAF); 30399ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 30409ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 30419ec7b004SRick Macklem if (error) { 30429ec7b004SRick Macklem vrele(dp); 30439ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 30449ec7b004SRick Macklem acl_free(aclp); 30459ec7b004SRick Macklem #endif 3046222daa42SConrad Meyer free(stp, M_NFSDSTATE); 30479ec7b004SRick Macklem nfsvno_relpathbuf(&named); 3048a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 30499ec7b004SRick Macklem return (error); 30509ec7b004SRick Macklem } 30519ec7b004SRick Macklem if (!nd->nd_repstat) { 30529ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, 3053ef7d2c1fSMateusz Guzik &dirp); 30549ec7b004SRick Macklem } else { 30559ec7b004SRick Macklem vrele(dp); 30569ec7b004SRick Macklem nfsvno_relpathbuf(&named); 30579ec7b004SRick Macklem } 30589ec7b004SRick Macklem if (create == NFSV4OPEN_CREATE) { 30599ec7b004SRick Macklem switch (how) { 30609ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 3061ded5f295SRick Macklem if (nd->nd_repstat == 0 && named.ni_vp != NULL) { 30629ec7b004SRick Macklem /* 30639ec7b004SRick Macklem * Clear the setable attribute bits, except 30649ec7b004SRick Macklem * for Size, if it is being truncated. 30659ec7b004SRick Macklem */ 30669ec7b004SRick Macklem NFSZERO_ATTRBIT(&attrbits); 30679ec7b004SRick Macklem if (NFSVNO_ISSETSIZE(&nva)) 30689ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, 30699ec7b004SRick Macklem NFSATTRBIT_SIZE); 30709ec7b004SRick Macklem } 30719ec7b004SRick Macklem break; 30729ec7b004SRick Macklem case NFSCREATE_GUARDED: 3073ded5f295SRick Macklem if (nd->nd_repstat == 0 && named.ni_vp != NULL) { 30749ec7b004SRick Macklem nd->nd_repstat = EEXIST; 3075ded5f295SRick Macklem done_namei = true; 3076ded5f295SRick Macklem } 30779ec7b004SRick Macklem break; 30789ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 30799ec7b004SRick Macklem exclusive_flag = 1; 3080ded5f295SRick Macklem if (nd->nd_repstat == 0 && named.ni_vp == NULL) 30819ec7b004SRick Macklem nva.na_mode = 0; 3082c59e4cc3SRick Macklem break; 3083c59e4cc3SRick Macklem case NFSCREATE_EXCLUSIVE41: 3084c59e4cc3SRick Macklem exclusive_flag = 1; 3085c59e4cc3SRick Macklem break; 308674b8d63dSPedro F. Giffuni } 30879ec7b004SRick Macklem } 30889ec7b004SRick Macklem nfsvno_open(nd, &named, clientid, &stateid, stp, 30899ec7b004SRick Macklem &exclusive_flag, &nva, cverf, create, aclp, &attrbits, 3090dcfa3ee4SRick Macklem nd->nd_cred, done_namei, exp, &vp); 3091c59e4cc3SRick Macklem } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim == 3092d80a903aSRick Macklem NFSV4OPEN_CLAIMFH || claim == NFSV4OPEN_CLAIMDELEGATECURFH || 3093d80a903aSRick Macklem claim == NFSV4OPEN_CLAIMDELEGATEPREVFH) { 3094c59e4cc3SRick Macklem if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 30959ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 30969ec7b004SRick Macklem i = fxdr_unsigned(int, *tl); 30979ec7b004SRick Macklem switch (i) { 30989ec7b004SRick Macklem case NFSV4OPEN_DELEGATEREAD: 30999ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGREAD; 31009ec7b004SRick Macklem break; 31019ec7b004SRick Macklem case NFSV4OPEN_DELEGATEWRITE: 31029ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGWRITE; 31039ec7b004SRick Macklem case NFSV4OPEN_DELEGATENONE: 31049ec7b004SRick Macklem break; 31059ec7b004SRick Macklem default: 31069ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 3107a9285ae5SZack Kirsch goto nfsmout; 310874b8d63dSPedro F. Giffuni } 31099ec7b004SRick Macklem stp->ls_flags |= NFSLCK_RECLAIM; 3110c59e4cc3SRick Macklem } else { 3111c59e4cc3SRick Macklem if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE) 3112c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_INVAL; 3113c59e4cc3SRick Macklem } 31149ec7b004SRick Macklem vp = dp; 311598f234f3SZack Kirsch NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 3116abd80ddbSMateusz Guzik if (!VN_IS_DOOMED(vp)) 3117629fa50eSRick Macklem nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, 3118629fa50eSRick Macklem stp, vp, nd, p, nd->nd_repstat); 3119629fa50eSRick Macklem else 3120629fa50eSRick Macklem nd->nd_repstat = NFSERR_PERM; 31219ec7b004SRick Macklem } else { 31229ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 3123a9285ae5SZack Kirsch goto nfsmout; 31249ec7b004SRick Macklem } 31259ec7b004SRick Macklem 31269ec7b004SRick Macklem /* 31279ec7b004SRick Macklem * Do basic access checking. 31289ec7b004SRick Macklem */ 31295d3fe02cSRick Macklem if (!nd->nd_repstat && vp->v_type != VREG) { 3130de67b496SRick Macklem /* 3131de67b496SRick Macklem * The IETF working group decided that this is the correct 3132de67b496SRick Macklem * error return for all non-regular files. 3133de67b496SRick Macklem */ 3134d8a5961fSMarcelo Araujo nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK; 31359ec7b004SRick Macklem } 3136b0b7d978SRick Macklem 3137b0b7d978SRick Macklem /* 3138b0b7d978SRick Macklem * If the Open is being done for a file that already exists, apply 3139b0b7d978SRick Macklem * normal permission checking including for the file owner, if 3140b0b7d978SRick Macklem * vfs.nfsd.v4openaccess is set. 3141b0b7d978SRick Macklem * Previously, the owner was always allowed to open the file to 3142b0b7d978SRick Macklem * be consistent with the NFS tradition of always allowing the 3143b0b7d978SRick Macklem * owner of the file to write to the file regardless of permissions. 3144b0b7d978SRick Macklem * It now appears that the Linux client expects the owner 3145b0b7d978SRick Macklem * permissions to be checked for opens that are not creating the 3146b0b7d978SRick Macklem * file. I believe the correct approach is to use the Access 3147b0b7d978SRick Macklem * operation's results to be consistent with NFSv3, but that is 3148b0b7d978SRick Macklem * not what the current Linux client appears to be doing. 3149b0b7d978SRick Macklem * Since both the Linux and OpenSolaris NFSv4 servers do this check, 3150e2fe58d6SRick Macklem * I have enabled it by default. Since Linux does not apply this 3151e2fe58d6SRick Macklem * check for claim_delegate_cur, this code does the same. 3152b0b7d978SRick Macklem * If this semantic change causes a problem, it can be disabled by 3153b0b7d978SRick Macklem * setting the sysctl vfs.nfsd.v4openaccess to 0 to re-enable the 3154b0b7d978SRick Macklem * previous semantics. 3155b0b7d978SRick Macklem */ 3156e2fe58d6SRick Macklem if (nfsrv_openaccess && create == NFSV4OPEN_NOCREATE && 3157e2fe58d6SRick Macklem (stp->ls_flags & NFSLCK_DELEGCUR) == 0) 3158b0b7d978SRick Macklem override = NFSACCCHK_NOOVERRIDE; 3159b0b7d978SRick Macklem else 3160b0b7d978SRick Macklem override = NFSACCCHK_ALLOWOWNER; 31619ec7b004SRick Macklem if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS)) 31628da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, 3163b0b7d978SRick Macklem exp, p, override, NFSACCCHK_VPISLOCKED, NULL); 31649ec7b004SRick Macklem if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) { 31658da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, 3166b0b7d978SRick Macklem exp, p, override, NFSACCCHK_VPISLOCKED, NULL); 31679ec7b004SRick Macklem if (nd->nd_repstat) 31688da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 3169b0b7d978SRick Macklem nd->nd_cred, exp, p, override, 31708da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 31719ec7b004SRick Macklem } 31729ec7b004SRick Macklem 3173086f6e0cSRick Macklem if (!nd->nd_repstat) { 317490d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 3175086f6e0cSRick Macklem if (!nd->nd_repstat) { 3176086f6e0cSRick Macklem tverf[0] = nva.na_atime.tv_sec; 3177086f6e0cSRick Macklem tverf[1] = nva.na_atime.tv_nsec; 3178086f6e0cSRick Macklem } 3179086f6e0cSRick Macklem } 3180086f6e0cSRick Macklem if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] || 3181086f6e0cSRick Macklem cverf[1] != tverf[1])) 31829ec7b004SRick Macklem nd->nd_repstat = EEXIST; 31839ec7b004SRick Macklem /* 31849ec7b004SRick Macklem * Do the open locking/delegation stuff. 31859ec7b004SRick Macklem */ 31869ec7b004SRick Macklem if (!nd->nd_repstat) 31879ec7b004SRick Macklem nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid, 31889ec7b004SRick Macklem &delegstateid, &rflags, exp, p, nva.na_filerev); 31899ec7b004SRick Macklem 31909ec7b004SRick Macklem /* 31919ec7b004SRick Macklem * vp must be unlocked before the call to nfsvno_getattr(dirp,...) 31929ec7b004SRick Macklem * below, to avoid a deadlock with the lookup in nfsvno_namei() above. 31939ec7b004SRick Macklem * (ie: Leave the NFSVOPUNLOCK() about here.) 31949ec7b004SRick Macklem */ 31959ec7b004SRick Macklem if (vp) 3196b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 31979ec7b004SRick Macklem if (stp) 3198222daa42SConrad Meyer free(stp, M_NFSDSTATE); 31999ec7b004SRick Macklem if (!nd->nd_repstat && dirp) 320090d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 32019ec7b004SRick Macklem if (!nd->nd_repstat) { 320290d2dfabSRick Macklem /* For NFSv4.1, set the Current StateID. */ 320390d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 320490d2dfabSRick Macklem nd->nd_curstateid = stateid; 320590d2dfabSRick Macklem nd->nd_flag |= ND_CURSTATEID; 320690d2dfabSRick Macklem } 32079ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 32089ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 32099ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 32109ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 32119ec7b004SRick Macklem if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 32129ec7b004SRick Macklem *tl++ = newnfs_true; 32139ec7b004SRick Macklem *tl++ = 0; 32149ec7b004SRick Macklem *tl++ = 0; 32159ec7b004SRick Macklem *tl++ = 0; 32169ec7b004SRick Macklem *tl++ = 0; 32179ec7b004SRick Macklem } else { 32189ec7b004SRick Macklem *tl++ = newnfs_false; /* Since dirp is not locked */ 32199ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 32209ec7b004SRick Macklem tl += 2; 32219ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 32229ec7b004SRick Macklem tl += 2; 32239ec7b004SRick Macklem } 32249ec7b004SRick Macklem *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS); 32259ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &attrbits); 32269ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 32279ec7b004SRick Macklem if (rflags & NFSV4OPEN_READDELEGATE) 32289ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD); 32299ec7b004SRick Macklem else if (rflags & NFSV4OPEN_WRITEDELEGATE) 32309ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE); 3231c59e4cc3SRick Macklem else if (retext != 0) { 3232c59e4cc3SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT); 32335d54f186SRick Macklem if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) { 32345d54f186SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 32355d54f186SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 32365d54f186SRick Macklem } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) { 32375d54f186SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 32385d54f186SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE); 32395d54f186SRick Macklem } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) { 3240c59e4cc3SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3241c59e4cc3SRick Macklem *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION); 3242c59e4cc3SRick Macklem *tl = newnfs_false; 3243c59e4cc3SRick Macklem } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) { 3244c59e4cc3SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3245c59e4cc3SRick Macklem *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE); 3246c59e4cc3SRick Macklem *tl = newnfs_false; 3247c59e4cc3SRick Macklem } else { 3248c59e4cc3SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3249c59e4cc3SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 3250c59e4cc3SRick Macklem } 3251c59e4cc3SRick Macklem } else 32529ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE); 32539ec7b004SRick Macklem if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) { 32549ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED); 32559ec7b004SRick Macklem *tl++ = txdr_unsigned(delegstateid.seqid); 32569ec7b004SRick Macklem NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl, 32579ec7b004SRick Macklem NFSX_STATEIDOTHER); 32589ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 32599ec7b004SRick Macklem if (rflags & NFSV4OPEN_RECALL) 32609ec7b004SRick Macklem *tl = newnfs_true; 32619ec7b004SRick Macklem else 32629ec7b004SRick Macklem *tl = newnfs_false; 32639ec7b004SRick Macklem if (rflags & NFSV4OPEN_WRITEDELEGATE) { 32649ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 32659ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE); 32669ec7b004SRick Macklem txdr_hyper(nva.na_size, tl); 32679ec7b004SRick Macklem } 32689ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 32699ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE); 32709ec7b004SRick Macklem *tl++ = txdr_unsigned(0x0); 32719ec7b004SRick Macklem acemask = NFSV4ACE_ALLFILESMASK; 32729ec7b004SRick Macklem if (nva.na_mode & S_IRUSR) 32739ec7b004SRick Macklem acemask |= NFSV4ACE_READMASK; 32749ec7b004SRick Macklem if (nva.na_mode & S_IWUSR) 32759ec7b004SRick Macklem acemask |= NFSV4ACE_WRITEMASK; 32769ec7b004SRick Macklem if (nva.na_mode & S_IXUSR) 32779ec7b004SRick Macklem acemask |= NFSV4ACE_EXECUTEMASK; 32789ec7b004SRick Macklem *tl = txdr_unsigned(acemask); 32799ec7b004SRick Macklem (void) nfsm_strtom(nd, "OWNER@", 6); 32809ec7b004SRick Macklem } 32819ec7b004SRick Macklem *vpp = vp; 32829ec7b004SRick Macklem } else if (vp) { 32839ec7b004SRick Macklem vrele(vp); 32849ec7b004SRick Macklem } 32859ec7b004SRick Macklem if (dirp) 32869ec7b004SRick Macklem vrele(dirp); 32879ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 32889ec7b004SRick Macklem acl_free(aclp); 32899ec7b004SRick Macklem #endif 3290a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 32919ec7b004SRick Macklem return (0); 32929ec7b004SRick Macklem nfsmout: 32939ec7b004SRick Macklem vrele(dp); 32949ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 32959ec7b004SRick Macklem acl_free(aclp); 32969ec7b004SRick Macklem #endif 32979ec7b004SRick Macklem if (stp) 3298222daa42SConrad Meyer free(stp, M_NFSDSTATE); 3299a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 33009ec7b004SRick Macklem return (error); 33019ec7b004SRick Macklem } 33029ec7b004SRick Macklem 33039ec7b004SRick Macklem /* 33049ec7b004SRick Macklem * nfsv4 close service 33059ec7b004SRick Macklem */ 3306b9cc3262SRyan Moeller int 33079ec7b004SRick Macklem nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram, 3308af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 33099ec7b004SRick Macklem { 33109ec7b004SRick Macklem u_int32_t *tl; 33119ec7b004SRick Macklem struct nfsstate st, *stp = &st; 331290d2dfabSRick Macklem int error = 0, writeacc; 33139ec7b004SRick Macklem nfsv4stateid_t stateid; 33149ec7b004SRick Macklem nfsquad_t clientid; 331590d2dfabSRick Macklem struct nfsvattr na; 3316af444b18SEdward Tomasz Napierala struct thread *p = curthread; 33179ec7b004SRick Macklem 33189ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 33199ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 33209ec7b004SRick Macklem stp->ls_ownerlen = 0; 33219ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 33229ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 33239ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 33249ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 33259ec7b004SRick Macklem NFSX_STATEIDOTHER); 332690d2dfabSRick Macklem 332790d2dfabSRick Macklem /* 332890d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 332990d2dfabSRick Macklem * stateid to the current stateid, if it is set. 333090d2dfabSRick Macklem */ 333190d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 333290d2dfabSRick Macklem stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 333390d2dfabSRick Macklem stp->ls_stateid.other[2] == 0) { 333490d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) 333590d2dfabSRick Macklem stp->ls_stateid = nd->nd_curstateid; 333690d2dfabSRick Macklem else { 333790d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 333890d2dfabSRick Macklem goto nfsmout; 333990d2dfabSRick Macklem } 334090d2dfabSRick Macklem } 334190d2dfabSRick Macklem 33429ec7b004SRick Macklem stp->ls_flags = NFSLCK_CLOSE; 33439ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 33449ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 3345c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3346c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3347c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3348c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3349c59e4cc3SRick Macklem printf("EEK8 multiple clids\n"); 33509ec7b004SRick Macklem } else { 3351c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3352c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 33539ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 33549ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 33559ec7b004SRick Macklem } 335690d2dfabSRick Macklem nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, 335790d2dfabSRick Macklem &writeacc); 335890d2dfabSRick Macklem /* For pNFS, update the attributes. */ 335990d2dfabSRick Macklem if (writeacc != 0 || nfsrv_pnfsatime != 0) 336090d2dfabSRick Macklem nfsrv_updatemdsattr(vp, &na, p); 33619ec7b004SRick Macklem vput(vp); 33629ec7b004SRick Macklem if (!nd->nd_repstat) { 336390d2dfabSRick Macklem /* 336490d2dfabSRick Macklem * If the stateid that has been closed is the current stateid, 336590d2dfabSRick Macklem * unset it. 336690d2dfabSRick Macklem */ 336790d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0 && 336890d2dfabSRick Macklem stateid.other[0] == nd->nd_curstateid.other[0] && 336990d2dfabSRick Macklem stateid.other[1] == nd->nd_curstateid.other[1] && 337090d2dfabSRick Macklem stateid.other[2] == nd->nd_curstateid.other[2]) 337190d2dfabSRick Macklem nd->nd_flag &= ~ND_CURSTATEID; 33729ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 33739ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 33749ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 33759ec7b004SRick Macklem } 3376a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 33779ec7b004SRick Macklem return (0); 33789ec7b004SRick Macklem nfsmout: 33799ec7b004SRick Macklem vput(vp); 3380a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 33819ec7b004SRick Macklem return (error); 33829ec7b004SRick Macklem } 33839ec7b004SRick Macklem 33849ec7b004SRick Macklem /* 33859ec7b004SRick Macklem * nfsv4 delegpurge service 33869ec7b004SRick Macklem */ 3387b9cc3262SRyan Moeller int 33889ec7b004SRick Macklem nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram, 3389af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 33909ec7b004SRick Macklem { 33919ec7b004SRick Macklem u_int32_t *tl; 33929ec7b004SRick Macklem int error = 0; 33939ec7b004SRick Macklem nfsquad_t clientid; 3394af444b18SEdward Tomasz Napierala struct thread *p = curthread; 33959ec7b004SRick Macklem 3396984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 3397a9285ae5SZack Kirsch goto nfsmout; 33989ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 33999ec7b004SRick Macklem clientid.lval[0] = *tl++; 34009ec7b004SRick Macklem clientid.lval[1] = *tl; 3401c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3402c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3403c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3404c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3405c59e4cc3SRick Macklem printf("EEK9 multiple clids\n"); 34069ec7b004SRick Macklem } else { 3407c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3408c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 34099ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 34109ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 34119ec7b004SRick Macklem } 3412c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL, 341390d2dfabSRick Macklem NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL); 34149ec7b004SRick Macklem nfsmout: 3415a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 34169ec7b004SRick Macklem return (error); 34179ec7b004SRick Macklem } 34189ec7b004SRick Macklem 34199ec7b004SRick Macklem /* 34209ec7b004SRick Macklem * nfsv4 delegreturn service 34219ec7b004SRick Macklem */ 3422b9cc3262SRyan Moeller int 34239ec7b004SRick Macklem nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram, 3424af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 34259ec7b004SRick Macklem { 34269ec7b004SRick Macklem u_int32_t *tl; 342790d2dfabSRick Macklem int error = 0, writeacc; 34289ec7b004SRick Macklem nfsv4stateid_t stateid; 34299ec7b004SRick Macklem nfsquad_t clientid; 343090d2dfabSRick Macklem struct nfsvattr na; 3431af444b18SEdward Tomasz Napierala struct thread *p = curthread; 34329ec7b004SRick Macklem 34339ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 34349ec7b004SRick Macklem stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 34359ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER); 34369ec7b004SRick Macklem clientid.lval[0] = stateid.other[0]; 34379ec7b004SRick Macklem clientid.lval[1] = stateid.other[1]; 3438c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3439c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3440c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3441c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3442c59e4cc3SRick Macklem printf("EEK10 multiple clids\n"); 34439ec7b004SRick Macklem } else { 3444c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3445c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 34469ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 34479ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 34489ec7b004SRick Macklem } 3449c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp, 345090d2dfabSRick Macklem NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc); 345190d2dfabSRick Macklem /* For pNFS, update the attributes. */ 345290d2dfabSRick Macklem if (writeacc != 0 || nfsrv_pnfsatime != 0) 345390d2dfabSRick Macklem nfsrv_updatemdsattr(vp, &na, p); 34549ec7b004SRick Macklem nfsmout: 34559ec7b004SRick Macklem vput(vp); 3456a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 34579ec7b004SRick Macklem return (error); 34589ec7b004SRick Macklem } 34599ec7b004SRick Macklem 34609ec7b004SRick Macklem /* 34619ec7b004SRick Macklem * nfsv4 get file handle service 34629ec7b004SRick Macklem */ 3463b9cc3262SRyan Moeller int 34649ec7b004SRick Macklem nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram, 3465af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 34669ec7b004SRick Macklem { 34679ec7b004SRick Macklem fhandle_t fh; 3468af444b18SEdward Tomasz Napierala struct thread *p = curthread; 34699ec7b004SRick Macklem 34709ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 34719ec7b004SRick Macklem vput(vp); 34729ec7b004SRick Macklem if (!nd->nd_repstat) 3473695d87baSRick Macklem (void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 0); 3474a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 34759ec7b004SRick Macklem return (0); 34769ec7b004SRick Macklem } 34779ec7b004SRick Macklem 34789ec7b004SRick Macklem /* 34799ec7b004SRick Macklem * nfsv4 open confirm service 34809ec7b004SRick Macklem */ 3481b9cc3262SRyan Moeller int 34829ec7b004SRick Macklem nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram, 3483af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 34849ec7b004SRick Macklem { 34859ec7b004SRick Macklem u_int32_t *tl; 34869ec7b004SRick Macklem struct nfsstate st, *stp = &st; 34879ec7b004SRick Macklem int error = 0; 34889ec7b004SRick Macklem nfsv4stateid_t stateid; 34899ec7b004SRick Macklem nfsquad_t clientid; 3490af444b18SEdward Tomasz Napierala struct thread *p = curthread; 34919ec7b004SRick Macklem 3492c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3493c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3494c59e4cc3SRick Macklem goto nfsmout; 3495c59e4cc3SRick Macklem } 34969ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 34979ec7b004SRick Macklem stp->ls_ownerlen = 0; 34989ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 34999ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 35009ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 35019ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 35029ec7b004SRick Macklem NFSX_STATEIDOTHER); 35039ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 35049ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl); 35059ec7b004SRick Macklem stp->ls_flags = NFSLCK_CONFIRM; 35069ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 35079ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 3508c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3509c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3510c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3511c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3512c59e4cc3SRick Macklem printf("EEK11 multiple clids\n"); 35139ec7b004SRick Macklem } else { 3514c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3515c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 35169ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 35179ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 35189ec7b004SRick Macklem } 351990d2dfabSRick Macklem nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, 352090d2dfabSRick Macklem NULL); 35219ec7b004SRick Macklem if (!nd->nd_repstat) { 35229ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 35239ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 35249ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 35259ec7b004SRick Macklem } 35269ec7b004SRick Macklem nfsmout: 35279ec7b004SRick Macklem vput(vp); 3528a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 35299ec7b004SRick Macklem return (error); 35309ec7b004SRick Macklem } 35319ec7b004SRick Macklem 35329ec7b004SRick Macklem /* 35339ec7b004SRick Macklem * nfsv4 open downgrade service 35349ec7b004SRick Macklem */ 3535b9cc3262SRyan Moeller int 35369ec7b004SRick Macklem nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram, 3537af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 35389ec7b004SRick Macklem { 35399ec7b004SRick Macklem u_int32_t *tl; 35409ec7b004SRick Macklem int i; 35419ec7b004SRick Macklem struct nfsstate st, *stp = &st; 35429ec7b004SRick Macklem int error = 0; 35439ec7b004SRick Macklem nfsv4stateid_t stateid; 35449ec7b004SRick Macklem nfsquad_t clientid; 3545af444b18SEdward Tomasz Napierala struct thread *p = curthread; 35469ec7b004SRick Macklem 3547d8a5961fSMarcelo Araujo /* opendowngrade can only work on a file object.*/ 3548d8a5961fSMarcelo Araujo if (vp->v_type != VREG) { 3549d8a5961fSMarcelo Araujo error = NFSERR_INVAL; 3550d8a5961fSMarcelo Araujo goto nfsmout; 3551d8a5961fSMarcelo Araujo } 35529ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 35539ec7b004SRick Macklem stp->ls_ownerlen = 0; 35549ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 35559ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 35569ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 35579ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 35589ec7b004SRick Macklem NFSX_STATEIDOTHER); 35599ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 356090d2dfabSRick Macklem 356190d2dfabSRick Macklem /* 356290d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 356390d2dfabSRick Macklem * stateid to the current stateid, if it is set. 356490d2dfabSRick Macklem */ 356590d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 356690d2dfabSRick Macklem stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 356790d2dfabSRick Macklem stp->ls_stateid.other[2] == 0) { 356890d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) 356990d2dfabSRick Macklem stp->ls_stateid = nd->nd_curstateid; 357090d2dfabSRick Macklem else { 357190d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 357290d2dfabSRick Macklem goto nfsmout; 357390d2dfabSRick Macklem } 357490d2dfabSRick Macklem } 357590d2dfabSRick Macklem 35769ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 35779ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 35786269d663SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 35796269d663SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 35809ec7b004SRick Macklem switch (i) { 35819ec7b004SRick Macklem case NFSV4OPEN_ACCESSREAD: 35829ec7b004SRick Macklem stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE); 35839ec7b004SRick Macklem break; 35849ec7b004SRick Macklem case NFSV4OPEN_ACCESSWRITE: 35859ec7b004SRick Macklem stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); 35869ec7b004SRick Macklem break; 35879ec7b004SRick Macklem case NFSV4OPEN_ACCESSBOTH: 35889ec7b004SRick Macklem stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS | 35899ec7b004SRick Macklem NFSLCK_DOWNGRADE); 35909ec7b004SRick Macklem break; 35919ec7b004SRick Macklem default: 35926269d663SRick Macklem nd->nd_repstat = NFSERR_INVAL; 359374b8d63dSPedro F. Giffuni } 35949ec7b004SRick Macklem i = fxdr_unsigned(int, *tl); 35959ec7b004SRick Macklem switch (i) { 35969ec7b004SRick Macklem case NFSV4OPEN_DENYNONE: 35979ec7b004SRick Macklem break; 35989ec7b004SRick Macklem case NFSV4OPEN_DENYREAD: 35999ec7b004SRick Macklem stp->ls_flags |= NFSLCK_READDENY; 36009ec7b004SRick Macklem break; 36019ec7b004SRick Macklem case NFSV4OPEN_DENYWRITE: 36029ec7b004SRick Macklem stp->ls_flags |= NFSLCK_WRITEDENY; 36039ec7b004SRick Macklem break; 36049ec7b004SRick Macklem case NFSV4OPEN_DENYBOTH: 36059ec7b004SRick Macklem stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 36069ec7b004SRick Macklem break; 36079ec7b004SRick Macklem default: 36086269d663SRick Macklem nd->nd_repstat = NFSERR_INVAL; 360974b8d63dSPedro F. Giffuni } 36109ec7b004SRick Macklem 36119ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 36129ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 3613c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3614c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3615c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3616c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3617c59e4cc3SRick Macklem printf("EEK12 multiple clids\n"); 36189ec7b004SRick Macklem } else { 3619c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3620c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 36219ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 36229ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 36239ec7b004SRick Macklem } 36249ec7b004SRick Macklem if (!nd->nd_repstat) 36259ec7b004SRick Macklem nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, 362690d2dfabSRick Macklem nd, p, NULL); 36279ec7b004SRick Macklem if (!nd->nd_repstat) { 362890d2dfabSRick Macklem /* For NFSv4.1, set the Current StateID. */ 362990d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 363090d2dfabSRick Macklem nd->nd_curstateid = stateid; 363190d2dfabSRick Macklem nd->nd_flag |= ND_CURSTATEID; 363290d2dfabSRick Macklem } 36339ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 36349ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 36359ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 36369ec7b004SRick Macklem } 36379ec7b004SRick Macklem nfsmout: 36389ec7b004SRick Macklem vput(vp); 3639a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 36409ec7b004SRick Macklem return (error); 36419ec7b004SRick Macklem } 36429ec7b004SRick Macklem 36439ec7b004SRick Macklem /* 36449ec7b004SRick Macklem * nfsv4 renew lease service 36459ec7b004SRick Macklem */ 3646b9cc3262SRyan Moeller int 36479ec7b004SRick Macklem nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram, 3648af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 36499ec7b004SRick Macklem { 36509ec7b004SRick Macklem u_int32_t *tl; 36519ec7b004SRick Macklem int error = 0; 36529ec7b004SRick Macklem nfsquad_t clientid; 3653af444b18SEdward Tomasz Napierala struct thread *p = curthread; 36549ec7b004SRick Macklem 3655c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3656c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3657c59e4cc3SRick Macklem goto nfsmout; 3658c59e4cc3SRick Macklem } 3659984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 3660a9285ae5SZack Kirsch goto nfsmout; 36619ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 36629ec7b004SRick Macklem clientid.lval[0] = *tl++; 36639ec7b004SRick Macklem clientid.lval[1] = *tl; 3664c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3665c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3666c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3667c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3668c59e4cc3SRick Macklem printf("EEK13 multiple clids\n"); 36699ec7b004SRick Macklem } else { 3670c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3671c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 36729ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 36739ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 36749ec7b004SRick Macklem } 36759ec7b004SRick Macklem nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW), 3676c59e4cc3SRick Macklem NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p); 36779ec7b004SRick Macklem nfsmout: 3678a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 36799ec7b004SRick Macklem return (error); 36809ec7b004SRick Macklem } 36819ec7b004SRick Macklem 36829ec7b004SRick Macklem /* 36839ec7b004SRick Macklem * nfsv4 security info service 36849ec7b004SRick Macklem */ 3685b9cc3262SRyan Moeller int 36869ec7b004SRick Macklem nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram, 3687af444b18SEdward Tomasz Napierala vnode_t dp, struct nfsexstuff *exp) 36889ec7b004SRick Macklem { 36899ec7b004SRick Macklem u_int32_t *tl; 36909ec7b004SRick Macklem int len; 36919ec7b004SRick Macklem struct nameidata named; 36929ec7b004SRick Macklem vnode_t dirp = NULL, vp; 36939ec7b004SRick Macklem struct nfsrvfh fh; 36949ec7b004SRick Macklem struct nfsexstuff retnes; 36959ec7b004SRick Macklem u_int32_t *sizp; 3696947bd247SRick Macklem int error = 0, i; 3697947bd247SRick Macklem uint64_t savflag; 36989ec7b004SRick Macklem char *bufp; 36999ec7b004SRick Macklem u_long *hashp; 3700af444b18SEdward Tomasz Napierala struct thread *p = curthread; 37019ec7b004SRick Macklem 37029ec7b004SRick Macklem /* 37039ec7b004SRick Macklem * All this just to get the export flags for the name. 37049ec7b004SRick Macklem */ 37059ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 370665127e98SMateusz Guzik LOCKLEAF); 37079ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 37089ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 37099ec7b004SRick Macklem if (error) { 37109ec7b004SRick Macklem vput(dp); 37119ec7b004SRick Macklem nfsvno_relpathbuf(&named); 3712a9285ae5SZack Kirsch goto out; 37139ec7b004SRick Macklem } 37149ec7b004SRick Macklem if (!nd->nd_repstat) { 3715ef7d2c1fSMateusz Guzik nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp); 37169ec7b004SRick Macklem } else { 37179ec7b004SRick Macklem vput(dp); 37189ec7b004SRick Macklem nfsvno_relpathbuf(&named); 37199ec7b004SRick Macklem } 37209ec7b004SRick Macklem if (dirp) 37219ec7b004SRick Macklem vrele(dirp); 37229ec7b004SRick Macklem if (nd->nd_repstat) 3723a9285ae5SZack Kirsch goto out; 37249ec7b004SRick Macklem nfsvno_relpathbuf(&named); 37259ec7b004SRick Macklem fh.nfsrvfh_len = NFSX_MYFH; 37269ec7b004SRick Macklem vp = named.ni_vp; 37279ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 37289ec7b004SRick Macklem vput(vp); 37299ec7b004SRick Macklem savflag = nd->nd_flag; 37309ec7b004SRick Macklem if (!nd->nd_repstat) { 3731a5df139eSRick Macklem /* 3732a5df139eSRick Macklem * Pretend the next op is Secinfo, so that no wrongsec 3733a5df139eSRick Macklem * test will be done. 3734a5df139eSRick Macklem */ 3735a5df139eSRick Macklem nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, 3736a5df139eSRick Macklem NFSV4OP_SECINFO); 37379ec7b004SRick Macklem if (vp) 37389ec7b004SRick Macklem vput(vp); 37399ec7b004SRick Macklem } 37409ec7b004SRick Macklem nd->nd_flag = savflag; 37419ec7b004SRick Macklem if (nd->nd_repstat) 3742a9285ae5SZack Kirsch goto out; 37439ec7b004SRick Macklem 37449ec7b004SRick Macklem /* 37459ec7b004SRick Macklem * Finally have the export flags for name, so we can create 37469ec7b004SRick Macklem * the security info. 37479ec7b004SRick Macklem */ 37489ec7b004SRick Macklem len = 0; 37499ec7b004SRick Macklem NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED); 375056e9d8e3SRick Macklem 375156e9d8e3SRick Macklem /* If nes_numsecflavor == 0, all are allowed. */ 375256e9d8e3SRick Macklem if (retnes.nes_numsecflavor == 0) { 375356e9d8e3SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 375456e9d8e3SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_UNIX); 375556e9d8e3SRick Macklem *tl = txdr_unsigned(RPCAUTH_GSS); 375656e9d8e3SRick Macklem nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 375756e9d8e3SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 375856e9d8e3SRick Macklem NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 375956e9d8e3SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 376056e9d8e3SRick Macklem *tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE); 376156e9d8e3SRick Macklem *tl = txdr_unsigned(RPCAUTH_GSS); 376256e9d8e3SRick Macklem nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 376356e9d8e3SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 376456e9d8e3SRick Macklem NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 376556e9d8e3SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 376656e9d8e3SRick Macklem *tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 376756e9d8e3SRick Macklem *tl = txdr_unsigned(RPCAUTH_GSS); 376856e9d8e3SRick Macklem nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 376956e9d8e3SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 377056e9d8e3SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 377156e9d8e3SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 377256e9d8e3SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 377356e9d8e3SRick Macklem len = 4; 377456e9d8e3SRick Macklem } 377598ad4453SRick Macklem for (i = 0; i < retnes.nes_numsecflavor; i++) { 377698ad4453SRick Macklem if (retnes.nes_secflavors[i] == AUTH_SYS) { 37779ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 37789ec7b004SRick Macklem *tl = txdr_unsigned(RPCAUTH_UNIX); 37799ec7b004SRick Macklem len++; 378098ad4453SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 37819ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 37829ec7b004SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_GSS); 37839ec7b004SRick Macklem (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 37849ec7b004SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 37859ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 37869ec7b004SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 378798ad4453SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 37889ec7b004SRick Macklem len++; 378998ad4453SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 379098ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 379198ad4453SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_GSS); 379298ad4453SRick Macklem (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 379398ad4453SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 379498ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 379598ad4453SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 379698ad4453SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 379798ad4453SRick Macklem len++; 379898ad4453SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 379998ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 380098ad4453SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_GSS); 380198ad4453SRick Macklem (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 380298ad4453SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 380398ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 380498ad4453SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 380598ad4453SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 380698ad4453SRick Macklem len++; 380798ad4453SRick Macklem } 38089ec7b004SRick Macklem } 38099ec7b004SRick Macklem *sizp = txdr_unsigned(len); 3810a9285ae5SZack Kirsch 3811a9285ae5SZack Kirsch out: 3812a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 3813a9285ae5SZack Kirsch return (error); 38149ec7b004SRick Macklem } 38159ec7b004SRick Macklem 38169ec7b004SRick Macklem /* 3817947bd247SRick Macklem * nfsv4 security info no name service 3818947bd247SRick Macklem */ 3819947bd247SRick Macklem int 3820947bd247SRick Macklem nfsrvd_secinfononame(struct nfsrv_descript *nd, int isdgram, 3821947bd247SRick Macklem vnode_t dp, struct nfsexstuff *exp) 3822947bd247SRick Macklem { 3823947bd247SRick Macklem uint32_t *tl, *sizp; 3824947bd247SRick Macklem struct nameidata named; 3825947bd247SRick Macklem vnode_t dirp = NULL, vp; 3826947bd247SRick Macklem struct nfsrvfh fh; 3827947bd247SRick Macklem struct nfsexstuff retnes; 3828947bd247SRick Macklem int error = 0, fhstyle, i, len; 3829947bd247SRick Macklem uint64_t savflag; 3830947bd247SRick Macklem char *bufp; 3831947bd247SRick Macklem u_long *hashp; 3832947bd247SRick Macklem struct thread *p = curthread; 3833947bd247SRick Macklem 3834947bd247SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3835947bd247SRick Macklem fhstyle = fxdr_unsigned(int, *tl); 3836947bd247SRick Macklem switch (fhstyle) { 3837947bd247SRick Macklem case NFSSECINFONONAME_PARENT: 383847d75c29SRick Macklem if (dp->v_type != VDIR) { 383947d75c29SRick Macklem vput(dp); 384047d75c29SRick Macklem nd->nd_repstat = NFSERR_NOTDIR; 384147d75c29SRick Macklem goto nfsmout; 384247d75c29SRick Macklem } 3843947bd247SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 384465127e98SMateusz Guzik LOCKLEAF); 3845947bd247SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 3846947bd247SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 3847947bd247SRick Macklem if (error != 0) { 3848947bd247SRick Macklem vput(dp); 3849947bd247SRick Macklem nfsvno_relpathbuf(&named); 3850947bd247SRick Macklem goto nfsmout; 3851947bd247SRick Macklem } 3852947bd247SRick Macklem if (nd->nd_repstat == 0) 3853ef7d2c1fSMateusz Guzik nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp); 3854947bd247SRick Macklem else 3855947bd247SRick Macklem vput(dp); 3856947bd247SRick Macklem if (dirp != NULL) 3857947bd247SRick Macklem vrele(dirp); 3858947bd247SRick Macklem nfsvno_relpathbuf(&named); 3859947bd247SRick Macklem vp = named.ni_vp; 3860947bd247SRick Macklem break; 3861947bd247SRick Macklem case NFSSECINFONONAME_CURFH: 3862947bd247SRick Macklem vp = dp; 3863947bd247SRick Macklem break; 3864947bd247SRick Macklem default: 3865947bd247SRick Macklem nd->nd_repstat = NFSERR_INVAL; 3866947bd247SRick Macklem vput(dp); 3867947bd247SRick Macklem } 3868947bd247SRick Macklem if (nd->nd_repstat != 0) 3869947bd247SRick Macklem goto nfsmout; 3870947bd247SRick Macklem fh.nfsrvfh_len = NFSX_MYFH; 3871947bd247SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 3872947bd247SRick Macklem vput(vp); 3873947bd247SRick Macklem savflag = nd->nd_flag; 3874947bd247SRick Macklem if (nd->nd_repstat == 0) { 3875a5df139eSRick Macklem /* 3876a5df139eSRick Macklem * Pretend the next op is Secinfo, so that no wrongsec 3877a5df139eSRick Macklem * test will be done. 3878a5df139eSRick Macklem */ 3879a5df139eSRick Macklem nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, 3880a5df139eSRick Macklem NFSV4OP_SECINFO); 3881947bd247SRick Macklem if (vp != NULL) 3882947bd247SRick Macklem vput(vp); 3883947bd247SRick Macklem } 3884947bd247SRick Macklem nd->nd_flag = savflag; 3885947bd247SRick Macklem if (nd->nd_repstat != 0) 3886947bd247SRick Macklem goto nfsmout; 3887947bd247SRick Macklem 3888947bd247SRick Macklem /* 3889947bd247SRick Macklem * Finally have the export flags for fh/parent, so we can create 3890947bd247SRick Macklem * the security info. 3891947bd247SRick Macklem */ 3892947bd247SRick Macklem len = 0; 3893947bd247SRick Macklem NFSM_BUILD(sizp, uint32_t *, NFSX_UNSIGNED); 389456e9d8e3SRick Macklem 389556e9d8e3SRick Macklem /* If nes_numsecflavor == 0, all are allowed. */ 389656e9d8e3SRick Macklem if (retnes.nes_numsecflavor == 0) { 389756e9d8e3SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 389856e9d8e3SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_UNIX); 389956e9d8e3SRick Macklem *tl = txdr_unsigned(RPCAUTH_GSS); 390056e9d8e3SRick Macklem nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 390156e9d8e3SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 390256e9d8e3SRick Macklem NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 390356e9d8e3SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 390456e9d8e3SRick Macklem *tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE); 390556e9d8e3SRick Macklem *tl = txdr_unsigned(RPCAUTH_GSS); 390656e9d8e3SRick Macklem nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 390756e9d8e3SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 390856e9d8e3SRick Macklem NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 390956e9d8e3SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 391056e9d8e3SRick Macklem *tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 391156e9d8e3SRick Macklem *tl = txdr_unsigned(RPCAUTH_GSS); 391256e9d8e3SRick Macklem nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 391356e9d8e3SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 391456e9d8e3SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 391556e9d8e3SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 391656e9d8e3SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 391756e9d8e3SRick Macklem len = 4; 391856e9d8e3SRick Macklem } 3919947bd247SRick Macklem for (i = 0; i < retnes.nes_numsecflavor; i++) { 3920947bd247SRick Macklem if (retnes.nes_secflavors[i] == AUTH_SYS) { 3921947bd247SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3922947bd247SRick Macklem *tl = txdr_unsigned(RPCAUTH_UNIX); 3923947bd247SRick Macklem len++; 3924947bd247SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 3925947bd247SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3926947bd247SRick Macklem *tl = txdr_unsigned(RPCAUTH_GSS); 3927947bd247SRick Macklem nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3928947bd247SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 3929947bd247SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3930947bd247SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3931947bd247SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3932947bd247SRick Macklem len++; 3933947bd247SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 3934947bd247SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3935947bd247SRick Macklem *tl = txdr_unsigned(RPCAUTH_GSS); 3936947bd247SRick Macklem nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3937947bd247SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 3938947bd247SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3939947bd247SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3940947bd247SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3941947bd247SRick Macklem len++; 3942947bd247SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 3943947bd247SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3944947bd247SRick Macklem *tl = txdr_unsigned(RPCAUTH_GSS); 3945947bd247SRick Macklem nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3946947bd247SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 3947947bd247SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3948947bd247SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3949947bd247SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3950947bd247SRick Macklem len++; 3951947bd247SRick Macklem } 3952947bd247SRick Macklem } 3953947bd247SRick Macklem *sizp = txdr_unsigned(len); 3954947bd247SRick Macklem 3955947bd247SRick Macklem nfsmout: 3956947bd247SRick Macklem NFSEXITCODE2(error, nd); 3957947bd247SRick Macklem return (error); 3958947bd247SRick Macklem } 3959947bd247SRick Macklem 3960947bd247SRick Macklem /* 39619ec7b004SRick Macklem * nfsv4 set client id service 39629ec7b004SRick Macklem */ 3963b9cc3262SRyan Moeller int 39649ec7b004SRick Macklem nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, 3965af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 39669ec7b004SRick Macklem { 39679ec7b004SRick Macklem u_int32_t *tl; 39689ec7b004SRick Macklem int i; 39699ec7b004SRick Macklem int error = 0, idlen; 39709ec7b004SRick Macklem struct nfsclient *clp = NULL; 3971ed2f1001SRick Macklem #ifdef INET 3972ed2f1001SRick Macklem struct sockaddr_in *rin; 3973ed2f1001SRick Macklem #endif 3974ed2f1001SRick Macklem #ifdef INET6 3975ed2f1001SRick Macklem struct sockaddr_in6 *rin6; 3976ed2f1001SRick Macklem #endif 3977ed2f1001SRick Macklem #if defined(INET) || defined(INET6) 3978ed2f1001SRick Macklem u_char *ucp, *ucp2; 3979ed2f1001SRick Macklem #endif 3980ed2f1001SRick Macklem u_char *verf, *addrbuf; 39819ec7b004SRick Macklem nfsquad_t clientid, confirm; 3982af444b18SEdward Tomasz Napierala struct thread *p = curthread; 39839ec7b004SRick Macklem 3984c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3985c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3986c59e4cc3SRick Macklem goto nfsmout; 3987c59e4cc3SRick Macklem } 3988984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 3989a9285ae5SZack Kirsch goto out; 39909ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 39919ec7b004SRick Macklem verf = (u_char *)tl; 39929ec7b004SRick Macklem tl += (NFSX_VERF / NFSX_UNSIGNED); 39939ec7b004SRick Macklem i = fxdr_unsigned(int, *tl); 39949ec7b004SRick Macklem if (i > NFSV4_OPAQUELIMIT || i <= 0) { 39959ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 3996a9285ae5SZack Kirsch goto nfsmout; 39979ec7b004SRick Macklem } 39989ec7b004SRick Macklem idlen = i; 39999ec7b004SRick Macklem if (nd->nd_flag & ND_GSS) 40009ec7b004SRick Macklem i += nd->nd_princlen; 40011f54e596SRick Macklem clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 40021f54e596SRick Macklem M_ZERO); 40031f54e596SRick Macklem clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 40041f54e596SRick Macklem nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 40059ec7b004SRick Macklem NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 4006ed2f1001SRick Macklem /* Allocated large enough for an AF_INET or AF_INET6 socket. */ 4007ed2f1001SRick Macklem clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, 4008b97b91b5SConrad Meyer M_WAITOK | M_ZERO); 40099ec7b004SRick Macklem clp->lc_req.nr_cred = NULL; 40109ec7b004SRick Macklem NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 40119ec7b004SRick Macklem clp->lc_idlen = idlen; 40129ec7b004SRick Macklem error = nfsrv_mtostr(nd, clp->lc_id, idlen); 40139ec7b004SRick Macklem if (error) 40149ec7b004SRick Macklem goto nfsmout; 40159ec7b004SRick Macklem if (nd->nd_flag & ND_GSS) { 40169ec7b004SRick Macklem clp->lc_flags = LCL_GSS; 40179ec7b004SRick Macklem if (nd->nd_flag & ND_GSSINTEGRITY) 40189ec7b004SRick Macklem clp->lc_flags |= LCL_GSSINTEGRITY; 40199ec7b004SRick Macklem else if (nd->nd_flag & ND_GSSPRIVACY) 40209ec7b004SRick Macklem clp->lc_flags |= LCL_GSSPRIVACY; 40219ec7b004SRick Macklem } else { 40229ec7b004SRick Macklem clp->lc_flags = 0; 40239ec7b004SRick Macklem } 40249ec7b004SRick Macklem if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) { 40259ec7b004SRick Macklem clp->lc_flags |= LCL_NAME; 40269ec7b004SRick Macklem clp->lc_namelen = nd->nd_princlen; 40279ec7b004SRick Macklem clp->lc_name = &clp->lc_id[idlen]; 40289ec7b004SRick Macklem NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 40299ec7b004SRick Macklem } else { 40309ec7b004SRick Macklem clp->lc_uid = nd->nd_cred->cr_uid; 40319ec7b004SRick Macklem clp->lc_gid = nd->nd_cred->cr_gid; 40329ec7b004SRick Macklem } 40336e4b6ff8SRick Macklem 40346e4b6ff8SRick Macklem /* If the client is using TLS, do so for the callback connection. */ 40356e4b6ff8SRick Macklem if (nd->nd_flag & ND_TLS) 40366e4b6ff8SRick Macklem clp->lc_flags |= LCL_TLSCB; 40376e4b6ff8SRick Macklem 40389ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 40399ec7b004SRick Macklem clp->lc_program = fxdr_unsigned(u_int32_t, *tl); 40409ec7b004SRick Macklem error = nfsrv_getclientipaddr(nd, clp); 40419ec7b004SRick Macklem if (error) 40429ec7b004SRick Macklem goto nfsmout; 40439ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 40449ec7b004SRick Macklem clp->lc_callback = fxdr_unsigned(u_int32_t, *tl); 40459ec7b004SRick Macklem 40469ec7b004SRick Macklem /* 40479ec7b004SRick Macklem * nfsrv_setclient() does the actual work of adding it to the 40489ec7b004SRick Macklem * client list. If there is no error, the structure has been 40499ec7b004SRick Macklem * linked into the client list and clp should no longer be used 40509ec7b004SRick Macklem * here. When an error is returned, it has not been linked in, 40519ec7b004SRick Macklem * so it should be free'd. 40529ec7b004SRick Macklem */ 40539ec7b004SRick Macklem nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 40549ec7b004SRick Macklem if (nd->nd_repstat == NFSERR_CLIDINUSE) { 4055ed2f1001SRick Macklem /* 4056ed2f1001SRick Macklem * 8 is the maximum length of the port# string. 4057ed2f1001SRick Macklem */ 4058ed2f1001SRick Macklem addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK); 4059ed2f1001SRick Macklem switch (clp->lc_req.nr_nam->sa_family) { 4060ed2f1001SRick Macklem #ifdef INET 4061ed2f1001SRick Macklem case AF_INET: 40629ec7b004SRick Macklem if (clp->lc_flags & LCL_TCPCALLBACK) 40639ec7b004SRick Macklem (void) nfsm_strtom(nd, "tcp", 3); 40649ec7b004SRick Macklem else 40659ec7b004SRick Macklem (void) nfsm_strtom(nd, "udp", 3); 4066ed2f1001SRick Macklem rin = (struct sockaddr_in *)clp->lc_req.nr_nam; 4067ed2f1001SRick Macklem ucp = (u_char *)&rin->sin_addr.s_addr; 4068ed2f1001SRick Macklem ucp2 = (u_char *)&rin->sin_port; 40699ec7b004SRick Macklem sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff, 40709ec7b004SRick Macklem ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff, 40719ec7b004SRick Macklem ucp2[0] & 0xff, ucp2[1] & 0xff); 4072ed2f1001SRick Macklem break; 4073ed2f1001SRick Macklem #endif 4074ed2f1001SRick Macklem #ifdef INET6 4075ed2f1001SRick Macklem case AF_INET6: 4076ed2f1001SRick Macklem if (clp->lc_flags & LCL_TCPCALLBACK) 4077ed2f1001SRick Macklem (void) nfsm_strtom(nd, "tcp6", 4); 4078ed2f1001SRick Macklem else 4079ed2f1001SRick Macklem (void) nfsm_strtom(nd, "udp6", 4); 4080ed2f1001SRick Macklem rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam; 4081ed2f1001SRick Macklem ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf, 4082ed2f1001SRick Macklem INET6_ADDRSTRLEN); 4083ed2f1001SRick Macklem if (ucp != NULL) 4084ed2f1001SRick Macklem i = strlen(ucp); 4085ed2f1001SRick Macklem else 4086ed2f1001SRick Macklem i = 0; 4087ed2f1001SRick Macklem ucp2 = (u_char *)&rin6->sin6_port; 4088ed2f1001SRick Macklem sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff, 4089ed2f1001SRick Macklem ucp2[1] & 0xff); 4090ed2f1001SRick Macklem break; 4091ed2f1001SRick Macklem #endif 4092ed2f1001SRick Macklem } 40939ec7b004SRick Macklem (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf)); 4094ed2f1001SRick Macklem free(addrbuf, M_TEMP); 40959ec7b004SRick Macklem } 40969ec7b004SRick Macklem if (clp) { 4097b97b91b5SConrad Meyer free(clp->lc_req.nr_nam, M_SONAME); 40989ec7b004SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 40991f54e596SRick Macklem free(clp->lc_stateid, M_NFSDCLIENT); 41001f54e596SRick Macklem free(clp, M_NFSDCLIENT); 41019ec7b004SRick Macklem } 41029ec7b004SRick Macklem if (!nd->nd_repstat) { 41039ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); 41049ec7b004SRick Macklem *tl++ = clientid.lval[0]; 41059ec7b004SRick Macklem *tl++ = clientid.lval[1]; 41069ec7b004SRick Macklem *tl++ = confirm.lval[0]; 41079ec7b004SRick Macklem *tl = confirm.lval[1]; 41089ec7b004SRick Macklem } 4109a9285ae5SZack Kirsch 4110a9285ae5SZack Kirsch out: 4111a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 41129ec7b004SRick Macklem return (0); 41139ec7b004SRick Macklem nfsmout: 41149ec7b004SRick Macklem if (clp) { 4115b97b91b5SConrad Meyer free(clp->lc_req.nr_nam, M_SONAME); 41169ec7b004SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 41171f54e596SRick Macklem free(clp->lc_stateid, M_NFSDCLIENT); 41181f54e596SRick Macklem free(clp, M_NFSDCLIENT); 41199ec7b004SRick Macklem } 4120a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 41219ec7b004SRick Macklem return (error); 41229ec7b004SRick Macklem } 41239ec7b004SRick Macklem 41249ec7b004SRick Macklem /* 41259ec7b004SRick Macklem * nfsv4 set client id confirm service 41269ec7b004SRick Macklem */ 4127b9cc3262SRyan Moeller int 41289ec7b004SRick Macklem nfsrvd_setclientidcfrm(struct nfsrv_descript *nd, 4129af444b18SEdward Tomasz Napierala __unused int isdgram, __unused vnode_t vp, 41309ec7b004SRick Macklem __unused struct nfsexstuff *exp) 41319ec7b004SRick Macklem { 41329ec7b004SRick Macklem u_int32_t *tl; 41339ec7b004SRick Macklem int error = 0; 41349ec7b004SRick Macklem nfsquad_t clientid, confirm; 4135af444b18SEdward Tomasz Napierala struct thread *p = curthread; 41369ec7b004SRick Macklem 4137c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 4138c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 4139c59e4cc3SRick Macklem goto nfsmout; 4140c59e4cc3SRick Macklem } 4141984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4142a9285ae5SZack Kirsch goto nfsmout; 41439ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER); 41449ec7b004SRick Macklem clientid.lval[0] = *tl++; 41459ec7b004SRick Macklem clientid.lval[1] = *tl++; 41469ec7b004SRick Macklem confirm.lval[0] = *tl++; 41479ec7b004SRick Macklem confirm.lval[1] = *tl; 41489ec7b004SRick Macklem 41499ec7b004SRick Macklem /* 41509ec7b004SRick Macklem * nfsrv_getclient() searches the client list for a match and 41519ec7b004SRick Macklem * returns the appropriate NFSERR status. 41529ec7b004SRick Macklem */ 41539ec7b004SRick Macklem nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW), 4154c59e4cc3SRick Macklem NULL, NULL, confirm, 0, nd, p); 41559ec7b004SRick Macklem nfsmout: 4156a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 41579ec7b004SRick Macklem return (error); 41589ec7b004SRick Macklem } 41599ec7b004SRick Macklem 41609ec7b004SRick Macklem /* 41619ec7b004SRick Macklem * nfsv4 verify service 41629ec7b004SRick Macklem */ 4163b9cc3262SRyan Moeller int 41649ec7b004SRick Macklem nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, 4165af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 41669ec7b004SRick Macklem { 41679ec7b004SRick Macklem int error = 0, ret, fhsize = NFSX_MYFH; 41689ec7b004SRick Macklem struct nfsvattr nva; 41692f304845SKonstantin Belousov struct statfs *sf; 41709ec7b004SRick Macklem struct nfsfsinfo fs; 41719ec7b004SRick Macklem fhandle_t fh; 4172af444b18SEdward Tomasz Napierala struct thread *p = curthread; 41739ec7b004SRick Macklem 41742f304845SKonstantin Belousov sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 417590d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 41769ec7b004SRick Macklem if (!nd->nd_repstat) 41772f304845SKonstantin Belousov nd->nd_repstat = nfsvno_statfs(vp, sf); 41789ec7b004SRick Macklem if (!nd->nd_repstat) 41799ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 41809ec7b004SRick Macklem if (!nd->nd_repstat) { 41819ec7b004SRick Macklem nfsvno_getfs(&fs, isdgram); 41829ec7b004SRick Macklem error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL, 41832f304845SKonstantin Belousov sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred); 41849ec7b004SRick Macklem if (!error) { 41859ec7b004SRick Macklem if (nd->nd_procnum == NFSV4OP_NVERIFY) { 41869ec7b004SRick Macklem if (ret == 0) 41879ec7b004SRick Macklem nd->nd_repstat = NFSERR_SAME; 41889ec7b004SRick Macklem else if (ret != NFSERR_NOTSAME) 41899ec7b004SRick Macklem nd->nd_repstat = ret; 41909ec7b004SRick Macklem } else if (ret) 41919ec7b004SRick Macklem nd->nd_repstat = ret; 41929ec7b004SRick Macklem } 41939ec7b004SRick Macklem } 41949ec7b004SRick Macklem vput(vp); 41952f304845SKonstantin Belousov free(sf, M_STATFS); 4196a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 41979ec7b004SRick Macklem return (error); 41989ec7b004SRick Macklem } 41999ec7b004SRick Macklem 42009ec7b004SRick Macklem /* 42019ec7b004SRick Macklem * nfs openattr rpc 42029ec7b004SRick Macklem */ 4203b9cc3262SRyan Moeller int 42049ec7b004SRick Macklem nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram, 42059ec7b004SRick Macklem vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp, 4206af444b18SEdward Tomasz Napierala __unused struct nfsexstuff *exp) 42079ec7b004SRick Macklem { 42089ec7b004SRick Macklem u_int32_t *tl; 42098014c971SRick Macklem int error = 0, createdir __unused; 42109ec7b004SRick Macklem 42119ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 42129ec7b004SRick Macklem createdir = fxdr_unsigned(int, *tl); 42139ec7b004SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 42149ec7b004SRick Macklem nfsmout: 42159ec7b004SRick Macklem vrele(dp); 4216a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 42179ec7b004SRick Macklem return (error); 42189ec7b004SRick Macklem } 42199ec7b004SRick Macklem 42209ec7b004SRick Macklem /* 42219ec7b004SRick Macklem * nfsv4 release lock owner service 42229ec7b004SRick Macklem */ 4223b9cc3262SRyan Moeller int 42249ec7b004SRick Macklem nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram, 4225af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 42269ec7b004SRick Macklem { 42279ec7b004SRick Macklem u_int32_t *tl; 42289ec7b004SRick Macklem struct nfsstate *stp = NULL; 42299ec7b004SRick Macklem int error = 0, len; 42309ec7b004SRick Macklem nfsquad_t clientid; 4231af444b18SEdward Tomasz Napierala struct thread *p = curthread; 42329ec7b004SRick Macklem 4233c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 4234c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 4235c59e4cc3SRick Macklem goto nfsmout; 4236c59e4cc3SRick Macklem } 4237984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4238a9285ae5SZack Kirsch goto nfsmout; 42399ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 42409ec7b004SRick Macklem len = fxdr_unsigned(int, *(tl + 2)); 42412a45247cSRick Macklem if (len <= 0 || len > NFSV4_OPAQUELIMIT) { 42422a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 4243a9285ae5SZack Kirsch goto nfsmout; 42442a45247cSRick Macklem } 4245222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate) + len, 42469ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 42479ec7b004SRick Macklem stp->ls_ownerlen = len; 42489ec7b004SRick Macklem stp->ls_op = NULL; 42499ec7b004SRick Macklem stp->ls_flags = NFSLCK_RELEASE; 42509ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 42519ec7b004SRick Macklem clientid.lval[0] = *tl++; 42529ec7b004SRick Macklem clientid.lval[1] = *tl; 4253c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 4254c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 4255c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 4256c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 4257c59e4cc3SRick Macklem printf("EEK14 multiple clids\n"); 42589ec7b004SRick Macklem } else { 4259c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 4260c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 42619ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 42629ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 42639ec7b004SRick Macklem } 42649ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, len); 42659ec7b004SRick Macklem if (error) 42669ec7b004SRick Macklem goto nfsmout; 42679ec7b004SRick Macklem nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p); 4268222daa42SConrad Meyer free(stp, M_NFSDSTATE); 4269a9285ae5SZack Kirsch 4270a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 42719ec7b004SRick Macklem return (0); 42729ec7b004SRick Macklem nfsmout: 42739ec7b004SRick Macklem if (stp) 4274222daa42SConrad Meyer free(stp, M_NFSDSTATE); 4275a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 42769ec7b004SRick Macklem return (error); 42779ec7b004SRick Macklem } 4278c59e4cc3SRick Macklem 4279c59e4cc3SRick Macklem /* 4280c59e4cc3SRick Macklem * nfsv4 exchange_id service 4281c59e4cc3SRick Macklem */ 4282b9cc3262SRyan Moeller int 4283c59e4cc3SRick Macklem nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram, 4284af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4285c59e4cc3SRick Macklem { 4286c59e4cc3SRick Macklem uint32_t *tl; 4287c59e4cc3SRick Macklem int error = 0, i, idlen; 4288c59e4cc3SRick Macklem struct nfsclient *clp = NULL; 4289c59e4cc3SRick Macklem nfsquad_t clientid, confirm; 4290c59e4cc3SRick Macklem uint8_t *verf; 4291c59e4cc3SRick Macklem uint32_t sp4type, v41flags; 4292c59e4cc3SRick Macklem struct timespec verstime; 4293ff2f1f69SRick Macklem nfsopbit_t mustops, allowops; 4294ed2f1001SRick Macklem #ifdef INET 4295ed2f1001SRick Macklem struct sockaddr_in *sin, *rin; 4296ed2f1001SRick Macklem #endif 4297ed2f1001SRick Macklem #ifdef INET6 4298ed2f1001SRick Macklem struct sockaddr_in6 *sin6, *rin6; 4299ed2f1001SRick Macklem #endif 4300af444b18SEdward Tomasz Napierala struct thread *p = curthread; 4301272c4a4dSAlexander Motin char *s; 4302c59e4cc3SRick Macklem 4303984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4304c59e4cc3SRick Macklem goto nfsmout; 4305c59e4cc3SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 4306c59e4cc3SRick Macklem verf = (uint8_t *)tl; 4307c59e4cc3SRick Macklem tl += (NFSX_VERF / NFSX_UNSIGNED); 4308c59e4cc3SRick Macklem i = fxdr_unsigned(int, *tl); 4309c59e4cc3SRick Macklem if (i > NFSV4_OPAQUELIMIT || i <= 0) { 4310c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 4311c59e4cc3SRick Macklem goto nfsmout; 4312c59e4cc3SRick Macklem } 4313c59e4cc3SRick Macklem idlen = i; 4314c59e4cc3SRick Macklem if (nd->nd_flag & ND_GSS) 4315c59e4cc3SRick Macklem i += nd->nd_princlen; 43161f54e596SRick Macklem clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 43171f54e596SRick Macklem M_ZERO); 43181f54e596SRick Macklem clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 43191f54e596SRick Macklem nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 4320c59e4cc3SRick Macklem NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 4321ed2f1001SRick Macklem /* Allocated large enough for an AF_INET or AF_INET6 socket. */ 4322ed2f1001SRick Macklem clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, 4323b97b91b5SConrad Meyer M_WAITOK | M_ZERO); 4324ed2f1001SRick Macklem switch (nd->nd_nam->sa_family) { 4325ed2f1001SRick Macklem #ifdef INET 4326ed2f1001SRick Macklem case AF_INET: 4327ed2f1001SRick Macklem rin = (struct sockaddr_in *)clp->lc_req.nr_nam; 4328ed2f1001SRick Macklem sin = (struct sockaddr_in *)nd->nd_nam; 4329ed2f1001SRick Macklem rin->sin_family = AF_INET; 4330ed2f1001SRick Macklem rin->sin_len = sizeof(struct sockaddr_in); 4331ed2f1001SRick Macklem rin->sin_port = 0; 4332ed2f1001SRick Macklem rin->sin_addr.s_addr = sin->sin_addr.s_addr; 4333ed2f1001SRick Macklem break; 4334ed2f1001SRick Macklem #endif 4335ed2f1001SRick Macklem #ifdef INET6 4336ed2f1001SRick Macklem case AF_INET6: 4337ed2f1001SRick Macklem rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam; 4338ed2f1001SRick Macklem sin6 = (struct sockaddr_in6 *)nd->nd_nam; 4339ed2f1001SRick Macklem rin6->sin6_family = AF_INET6; 4340ed2f1001SRick Macklem rin6->sin6_len = sizeof(struct sockaddr_in6); 4341ed2f1001SRick Macklem rin6->sin6_port = 0; 4342ed2f1001SRick Macklem rin6->sin6_addr = sin6->sin6_addr; 4343ed2f1001SRick Macklem break; 4344ed2f1001SRick Macklem #endif 4345ed2f1001SRick Macklem } 4346c59e4cc3SRick Macklem clp->lc_req.nr_cred = NULL; 4347c59e4cc3SRick Macklem NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 4348c59e4cc3SRick Macklem clp->lc_idlen = idlen; 4349c59e4cc3SRick Macklem error = nfsrv_mtostr(nd, clp->lc_id, idlen); 4350c59e4cc3SRick Macklem if (error != 0) 4351c59e4cc3SRick Macklem goto nfsmout; 4352c59e4cc3SRick Macklem if ((nd->nd_flag & ND_GSS) != 0) { 4353c59e4cc3SRick Macklem clp->lc_flags = LCL_GSS | LCL_NFSV41; 4354c59e4cc3SRick Macklem if ((nd->nd_flag & ND_GSSINTEGRITY) != 0) 4355c59e4cc3SRick Macklem clp->lc_flags |= LCL_GSSINTEGRITY; 4356c59e4cc3SRick Macklem else if ((nd->nd_flag & ND_GSSPRIVACY) != 0) 4357c59e4cc3SRick Macklem clp->lc_flags |= LCL_GSSPRIVACY; 4358c59e4cc3SRick Macklem } else 4359c59e4cc3SRick Macklem clp->lc_flags = LCL_NFSV41; 4360c057a378SRick Macklem if ((nd->nd_flag & ND_NFSV42) != 0) 4361c057a378SRick Macklem clp->lc_flags |= LCL_NFSV42; 4362c59e4cc3SRick Macklem if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) { 4363c59e4cc3SRick Macklem clp->lc_flags |= LCL_NAME; 4364c59e4cc3SRick Macklem clp->lc_namelen = nd->nd_princlen; 4365c59e4cc3SRick Macklem clp->lc_name = &clp->lc_id[idlen]; 4366c59e4cc3SRick Macklem NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 4367c59e4cc3SRick Macklem } else { 4368c59e4cc3SRick Macklem clp->lc_uid = nd->nd_cred->cr_uid; 4369c59e4cc3SRick Macklem clp->lc_gid = nd->nd_cred->cr_gid; 4370c59e4cc3SRick Macklem } 4371c59e4cc3SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4372c59e4cc3SRick Macklem v41flags = fxdr_unsigned(uint32_t, *tl++); 4373c59e4cc3SRick Macklem if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR | 4374c59e4cc3SRick Macklem NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS | 4375c59e4cc3SRick Macklem NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) { 4376c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_INVAL; 4377c59e4cc3SRick Macklem goto nfsmout; 4378c59e4cc3SRick Macklem } 4379c59e4cc3SRick Macklem if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0) 4380c59e4cc3SRick Macklem confirm.lval[1] = 1; 4381c59e4cc3SRick Macklem else 4382c59e4cc3SRick Macklem confirm.lval[1] = 0; 438390d2dfabSRick Macklem if (nfsrv_devidcnt == 0) 438490d2dfabSRick Macklem v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS; 438590d2dfabSRick Macklem else 438690d2dfabSRick Macklem v41flags = NFSV4EXCH_USEPNFSMDS; 4387c59e4cc3SRick Macklem sp4type = fxdr_unsigned(uint32_t, *tl); 4388ff2f1f69SRick Macklem if (sp4type == NFSV4EXCH_SP4MACHCRED) { 4389ff2f1f69SRick Macklem if ((nd->nd_flag & (ND_GSSINTEGRITY | ND_GSSPRIVACY)) == 0 || 4390ff2f1f69SRick Macklem nd->nd_princlen == 0) 4391ff2f1f69SRick Macklem nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); 4392ff2f1f69SRick Macklem if (nd->nd_repstat == 0) 4393ff2f1f69SRick Macklem nd->nd_repstat = nfsrv_getopbits(nd, &mustops, NULL); 4394ff2f1f69SRick Macklem if (nd->nd_repstat == 0) 4395ff2f1f69SRick Macklem nd->nd_repstat = nfsrv_getopbits(nd, &allowops, NULL); 4396ff2f1f69SRick Macklem if (nd->nd_repstat != 0) 4397ff2f1f69SRick Macklem goto nfsmout; 4398ff2f1f69SRick Macklem NFSOPBIT_CLRNOTMUST(&mustops); 4399ff2f1f69SRick Macklem NFSSET_OPBIT(&clp->lc_mustops, &mustops); 4400ff2f1f69SRick Macklem NFSOPBIT_CLRNOTALLOWED(&allowops); 4401ff2f1f69SRick Macklem NFSSET_OPBIT(&clp->lc_allowops, &allowops); 4402ff2f1f69SRick Macklem clp->lc_flags |= LCL_MACHCRED; 4403ff2f1f69SRick Macklem } else if (sp4type != NFSV4EXCH_SP4NONE) { 4404c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 4405c59e4cc3SRick Macklem goto nfsmout; 4406c59e4cc3SRick Macklem } 4407c59e4cc3SRick Macklem 4408c59e4cc3SRick Macklem /* 4409c59e4cc3SRick Macklem * nfsrv_setclient() does the actual work of adding it to the 4410c59e4cc3SRick Macklem * client list. If there is no error, the structure has been 4411c59e4cc3SRick Macklem * linked into the client list and clp should no longer be used 4412c59e4cc3SRick Macklem * here. When an error is returned, it has not been linked in, 4413c59e4cc3SRick Macklem * so it should be free'd. 4414c59e4cc3SRick Macklem */ 4415c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 4416c59e4cc3SRick Macklem if (clp != NULL) { 4417b97b91b5SConrad Meyer free(clp->lc_req.nr_nam, M_SONAME); 4418c59e4cc3SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 44191f54e596SRick Macklem free(clp->lc_stateid, M_NFSDCLIENT); 4420c59e4cc3SRick Macklem free(clp, M_NFSDCLIENT); 4421c59e4cc3SRick Macklem } 4422c59e4cc3SRick Macklem if (nd->nd_repstat == 0) { 4423c59e4cc3SRick Macklem if (confirm.lval[1] != 0) 4424c59e4cc3SRick Macklem v41flags |= NFSV4EXCH_CONFIRMEDR; 4425ff2f1f69SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED); 4426c59e4cc3SRick Macklem *tl++ = clientid.lval[0]; /* ClientID */ 4427c59e4cc3SRick Macklem *tl++ = clientid.lval[1]; 4428c59e4cc3SRick Macklem *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */ 4429c59e4cc3SRick Macklem *tl++ = txdr_unsigned(v41flags); /* Exch flags */ 4430ff2f1f69SRick Macklem *tl = txdr_unsigned(sp4type); /* No SSV */ 4431ff2f1f69SRick Macklem if (sp4type == NFSV4EXCH_SP4MACHCRED) { 4432ff2f1f69SRick Macklem nfsrv_putopbit(nd, &mustops); 4433ff2f1f69SRick Macklem nfsrv_putopbit(nd, &allowops); 4434ff2f1f69SRick Macklem } 4435ff2f1f69SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_HYPER); 4436272c4a4dSAlexander Motin txdr_hyper(nfsrv_owner_minor, tl); /* Owner Minor */ 4437272c4a4dSAlexander Motin if (nfsrv_owner_major[0] != 0) 4438272c4a4dSAlexander Motin s = nfsrv_owner_major; 4439272c4a4dSAlexander Motin else 4440272c4a4dSAlexander Motin s = nd->nd_cred->cr_prison->pr_hostuuid; 4441272c4a4dSAlexander Motin nfsm_strtom(nd, s, strlen(s)); /* Owner Major */ 4442272c4a4dSAlexander Motin if (nfsrv_scope[0] != 0) 4443272c4a4dSAlexander Motin s = nfsrv_scope; 4444272c4a4dSAlexander Motin else 4445272c4a4dSAlexander Motin s = nd->nd_cred->cr_prison->pr_hostuuid; 4446272c4a4dSAlexander Motin nfsm_strtom(nd, s, strlen(s) ); /* Scope */ 44478932a483SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4448c59e4cc3SRick Macklem *tl = txdr_unsigned(1); 4449c59e4cc3SRick Macklem (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 4450c59e4cc3SRick Macklem (void)nfsm_strtom(nd, version, strlen(version)); 4451c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 4452c59e4cc3SRick Macklem verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 4453c59e4cc3SRick Macklem verstime.tv_nsec = 0; 4454c59e4cc3SRick Macklem txdr_nfsv4time(&verstime, tl); 4455c59e4cc3SRick Macklem } 4456c59e4cc3SRick Macklem NFSEXITCODE2(0, nd); 4457c59e4cc3SRick Macklem return (0); 4458c59e4cc3SRick Macklem nfsmout: 4459c59e4cc3SRick Macklem if (clp != NULL) { 4460b97b91b5SConrad Meyer free(clp->lc_req.nr_nam, M_SONAME); 4461c59e4cc3SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 44621f54e596SRick Macklem free(clp->lc_stateid, M_NFSDCLIENT); 4463c59e4cc3SRick Macklem free(clp, M_NFSDCLIENT); 4464c59e4cc3SRick Macklem } 4465c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4466c59e4cc3SRick Macklem return (error); 4467c59e4cc3SRick Macklem } 4468c59e4cc3SRick Macklem 4469c59e4cc3SRick Macklem /* 4470c59e4cc3SRick Macklem * nfsv4 create session service 4471c59e4cc3SRick Macklem */ 4472b9cc3262SRyan Moeller int 4473c59e4cc3SRick Macklem nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram, 4474af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4475c59e4cc3SRick Macklem { 4476c59e4cc3SRick Macklem uint32_t *tl; 4477c59e4cc3SRick Macklem int error = 0; 4478c59e4cc3SRick Macklem nfsquad_t clientid, confirm; 4479c59e4cc3SRick Macklem struct nfsdsession *sep = NULL; 4480c59e4cc3SRick Macklem uint32_t rdmacnt; 4481af444b18SEdward Tomasz Napierala struct thread *p = curthread; 4482ee29e6f3SRick Macklem static bool do_printf = true; 4483c59e4cc3SRick Macklem 4484984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4485c59e4cc3SRick Macklem goto nfsmout; 4486c59e4cc3SRick Macklem sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession), 4487c59e4cc3SRick Macklem M_NFSDSESSION, M_WAITOK | M_ZERO); 4488c59e4cc3SRick Macklem sep->sess_refcnt = 1; 4489c59e4cc3SRick Macklem mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF); 4490c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 4491c59e4cc3SRick Macklem clientid.lval[0] = *tl++; 4492c59e4cc3SRick Macklem clientid.lval[1] = *tl++; 4493c59e4cc3SRick Macklem confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++); 4494c59e4cc3SRick Macklem sep->sess_crflags = fxdr_unsigned(uint32_t, *tl); 4495c59e4cc3SRick Macklem /* Persistent sessions and RDMA are not supported. */ 4496c59e4cc3SRick Macklem sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN; 4497c59e4cc3SRick Macklem 4498c59e4cc3SRick Macklem /* Fore channel attributes. */ 4499c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4500c59e4cc3SRick Macklem tl++; /* Header pad always 0. */ 4501c59e4cc3SRick Macklem sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++); 450290d2dfabSRick Macklem if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) { 450390d2dfabSRick Macklem sep->sess_maxreq = sb_max_adj - NFS_MAXXDR; 4504ee29e6f3SRick Macklem if (do_printf) 450590d2dfabSRick Macklem printf("Consider increasing kern.ipc.maxsockbuf\n"); 4506ee29e6f3SRick Macklem do_printf = false; 450790d2dfabSRick Macklem } 4508c59e4cc3SRick Macklem sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++); 450990d2dfabSRick Macklem if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) { 451090d2dfabSRick Macklem sep->sess_maxresp = sb_max_adj - NFS_MAXXDR; 4511ee29e6f3SRick Macklem if (do_printf) 451290d2dfabSRick Macklem printf("Consider increasing kern.ipc.maxsockbuf\n"); 4513ee29e6f3SRick Macklem do_printf = false; 451490d2dfabSRick Macklem } 4515c59e4cc3SRick Macklem sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++); 4516c59e4cc3SRick Macklem sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++); 4517c59e4cc3SRick Macklem sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++); 4518c59e4cc3SRick Macklem if (sep->sess_maxslots > NFSV4_SLOTS) 4519c59e4cc3SRick Macklem sep->sess_maxslots = NFSV4_SLOTS; 4520c59e4cc3SRick Macklem rdmacnt = fxdr_unsigned(uint32_t, *tl); 4521c59e4cc3SRick Macklem if (rdmacnt > 1) { 4522c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 4523c59e4cc3SRick Macklem goto nfsmout; 4524c59e4cc3SRick Macklem } else if (rdmacnt == 1) 4525c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4526c59e4cc3SRick Macklem 4527c59e4cc3SRick Macklem /* Back channel attributes. */ 4528c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4529c59e4cc3SRick Macklem tl++; /* Header pad always 0. */ 4530c59e4cc3SRick Macklem sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++); 4531c59e4cc3SRick Macklem sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++); 4532c59e4cc3SRick Macklem sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++); 4533c59e4cc3SRick Macklem sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++); 4534c59e4cc3SRick Macklem sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++); 4535c59e4cc3SRick Macklem rdmacnt = fxdr_unsigned(uint32_t, *tl); 4536c59e4cc3SRick Macklem if (rdmacnt > 1) { 4537c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 4538c59e4cc3SRick Macklem goto nfsmout; 4539c59e4cc3SRick Macklem } else if (rdmacnt == 1) 4540c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4541c59e4cc3SRick Macklem 4542c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4543c59e4cc3SRick Macklem sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl); 4544c59e4cc3SRick Macklem 4545c59e4cc3SRick Macklem /* 4546c59e4cc3SRick Macklem * nfsrv_getclient() searches the client list for a match and 4547c59e4cc3SRick Macklem * returns the appropriate NFSERR status. 4548c59e4cc3SRick Macklem */ 4549c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW, 4550c59e4cc3SRick Macklem NULL, sep, confirm, sep->sess_cbprogram, nd, p); 4551c59e4cc3SRick Macklem if (nd->nd_repstat == 0) { 4552c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4553c59e4cc3SRick Macklem NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID); 4554c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED); 4555c59e4cc3SRick Macklem *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */ 4556c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_crflags); 4557c59e4cc3SRick Macklem 4558c59e4cc3SRick Macklem /* Fore channel attributes. */ 4559c59e4cc3SRick Macklem *tl++ = 0; 4560c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxreq); 4561c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxresp); 4562c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxrespcached); 4563c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxops); 4564c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxslots); 4565c59e4cc3SRick Macklem *tl++ = txdr_unsigned(1); 4566c59e4cc3SRick Macklem *tl++ = txdr_unsigned(0); /* No RDMA. */ 4567c59e4cc3SRick Macklem 4568c59e4cc3SRick Macklem /* Back channel attributes. */ 4569c59e4cc3SRick Macklem *tl++ = 0; 4570c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbmaxreq); 4571c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbmaxresp); 4572c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached); 4573c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbmaxops); 4574c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots); 4575c59e4cc3SRick Macklem *tl++ = txdr_unsigned(1); 4576c59e4cc3SRick Macklem *tl = txdr_unsigned(0); /* No RDMA. */ 4577c59e4cc3SRick Macklem } 4578c59e4cc3SRick Macklem nfsmout: 4579c59e4cc3SRick Macklem if (nd->nd_repstat != 0 && sep != NULL) 4580c59e4cc3SRick Macklem free(sep, M_NFSDSESSION); 4581c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4582c59e4cc3SRick Macklem return (error); 4583c59e4cc3SRick Macklem } 4584c59e4cc3SRick Macklem 4585c59e4cc3SRick Macklem /* 4586c59e4cc3SRick Macklem * nfsv4 sequence service 4587c59e4cc3SRick Macklem */ 4588b9cc3262SRyan Moeller int 4589c59e4cc3SRick Macklem nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram, 4590af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4591c59e4cc3SRick Macklem { 4592c59e4cc3SRick Macklem uint32_t *tl; 4593c59e4cc3SRick Macklem uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid; 4594c59e4cc3SRick Macklem int cache_this, error = 0; 4595af444b18SEdward Tomasz Napierala struct thread *p = curthread; 4596c59e4cc3SRick Macklem 4597984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4598c59e4cc3SRick Macklem goto nfsmout; 4599c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID); 4600c59e4cc3SRick Macklem NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID); 4601c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 4602c59e4cc3SRick Macklem sequenceid = fxdr_unsigned(uint32_t, *tl++); 4603c59e4cc3SRick Macklem nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++); 4604c59e4cc3SRick Macklem highest_slotid = fxdr_unsigned(uint32_t, *tl++); 4605c59e4cc3SRick Macklem if (*tl == newnfs_true) 4606c59e4cc3SRick Macklem cache_this = 1; 4607c59e4cc3SRick Macklem else 4608c59e4cc3SRick Macklem cache_this = 0; 4609c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid, 4610c59e4cc3SRick Macklem &target_highest_slotid, cache_this, &sflags, p); 4611db0ac6deSCy Schubert if (nd->nd_repstat != NFSERR_BADSLOT) 4612db0ac6deSCy Schubert nd->nd_flag |= ND_HASSEQUENCE; 4613c59e4cc3SRick Macklem if (nd->nd_repstat == 0) { 4614c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4615c59e4cc3SRick Macklem NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID); 4616c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 4617c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sequenceid); 4618c59e4cc3SRick Macklem *tl++ = txdr_unsigned(nd->nd_slotid); 4619c59e4cc3SRick Macklem *tl++ = txdr_unsigned(highest_slotid); 4620c59e4cc3SRick Macklem *tl++ = txdr_unsigned(target_highest_slotid); 4621c59e4cc3SRick Macklem *tl = txdr_unsigned(sflags); 4622c59e4cc3SRick Macklem } 4623c59e4cc3SRick Macklem nfsmout: 4624c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4625c59e4cc3SRick Macklem return (error); 4626c59e4cc3SRick Macklem } 4627c59e4cc3SRick Macklem 4628c59e4cc3SRick Macklem /* 4629c59e4cc3SRick Macklem * nfsv4 reclaim complete service 4630c59e4cc3SRick Macklem */ 4631b9cc3262SRyan Moeller int 4632c59e4cc3SRick Macklem nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram, 4633af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4634c59e4cc3SRick Macklem { 4635c59e4cc3SRick Macklem uint32_t *tl; 4636a3e709cdSRick Macklem int error = 0, onefs; 4637c59e4cc3SRick Macklem 4638c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4639a3e709cdSRick Macklem /* 4640a3e709cdSRick Macklem * I believe that a ReclaimComplete with rca_one_fs == TRUE is only 4641a3e709cdSRick Macklem * to be used after a file system has been transferred to a different 4642a3e709cdSRick Macklem * file server. However, RFC5661 is somewhat vague w.r.t. this and 4643a3e709cdSRick Macklem * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs 4644a3e709cdSRick Macklem * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE. 4645a3e709cdSRick Macklem * Therefore, just ignore the rca_one_fs == TRUE operation and return 4646a3e709cdSRick Macklem * NFS_OK without doing anything. 4647a3e709cdSRick Macklem */ 4648a3e709cdSRick Macklem onefs = 0; 4649c59e4cc3SRick Macklem if (*tl == newnfs_true) 4650a3e709cdSRick Macklem onefs = 1; 4651a3e709cdSRick Macklem nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs); 4652c59e4cc3SRick Macklem nfsmout: 4653c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4654c59e4cc3SRick Macklem return (error); 4655c59e4cc3SRick Macklem } 4656c59e4cc3SRick Macklem 4657c59e4cc3SRick Macklem /* 4658c59e4cc3SRick Macklem * nfsv4 destroy clientid service 4659c59e4cc3SRick Macklem */ 4660b9cc3262SRyan Moeller int 4661c59e4cc3SRick Macklem nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram, 4662af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4663c59e4cc3SRick Macklem { 4664c59e4cc3SRick Macklem uint32_t *tl; 4665c59e4cc3SRick Macklem nfsquad_t clientid; 4666c59e4cc3SRick Macklem int error = 0; 4667af444b18SEdward Tomasz Napierala struct thread *p = curthread; 4668c59e4cc3SRick Macklem 4669984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4670c59e4cc3SRick Macklem goto nfsmout; 4671c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4672c59e4cc3SRick Macklem clientid.lval[0] = *tl++; 4673c59e4cc3SRick Macklem clientid.lval[1] = *tl; 4674ff2f1f69SRick Macklem nd->nd_repstat = nfsrv_destroyclient(nd, clientid, p); 4675c59e4cc3SRick Macklem nfsmout: 4676c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4677c59e4cc3SRick Macklem return (error); 4678c59e4cc3SRick Macklem } 4679c59e4cc3SRick Macklem 4680c59e4cc3SRick Macklem /* 46819442a64eSRick Macklem * nfsv4 bind connection to session service 46829442a64eSRick Macklem */ 4683b9cc3262SRyan Moeller int 46849442a64eSRick Macklem nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram, 4685af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 46869442a64eSRick Macklem { 46879442a64eSRick Macklem uint32_t *tl; 46889442a64eSRick Macklem uint8_t sessid[NFSX_V4SESSIONID]; 46899442a64eSRick Macklem int error = 0, foreaft; 46909442a64eSRick Macklem 4691984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 46929442a64eSRick Macklem goto nfsmout; 46939442a64eSRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED); 46949442a64eSRick Macklem NFSBCOPY(tl, sessid, NFSX_V4SESSIONID); 46959442a64eSRick Macklem tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); 46969442a64eSRick Macklem foreaft = fxdr_unsigned(int, *tl++); 46979442a64eSRick Macklem if (*tl == newnfs_true) { 46989442a64eSRick Macklem /* RDMA is not supported. */ 46999442a64eSRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 47009442a64eSRick Macklem goto nfsmout; 47019442a64eSRick Macklem } 47029442a64eSRick Macklem 47039442a64eSRick Macklem nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft); 47049442a64eSRick Macklem if (nd->nd_repstat == 0) { 47059442a64eSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 * 47069442a64eSRick Macklem NFSX_UNSIGNED); 47079442a64eSRick Macklem NFSBCOPY(sessid, tl, NFSX_V4SESSIONID); 47089442a64eSRick Macklem tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); 47099442a64eSRick Macklem *tl++ = txdr_unsigned(foreaft); 47109442a64eSRick Macklem *tl = newnfs_false; 47119442a64eSRick Macklem } 47129442a64eSRick Macklem nfsmout: 47139442a64eSRick Macklem NFSEXITCODE2(error, nd); 47149442a64eSRick Macklem return (error); 47159442a64eSRick Macklem } 47169442a64eSRick Macklem 47179442a64eSRick Macklem /* 4718c59e4cc3SRick Macklem * nfsv4 destroy session service 4719c59e4cc3SRick Macklem */ 4720b9cc3262SRyan Moeller int 4721c59e4cc3SRick Macklem nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram, 4722af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4723c59e4cc3SRick Macklem { 4724c59e4cc3SRick Macklem uint8_t *cp, sessid[NFSX_V4SESSIONID]; 4725c59e4cc3SRick Macklem int error = 0; 4726c59e4cc3SRick Macklem 4727984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4728c59e4cc3SRick Macklem goto nfsmout; 4729c59e4cc3SRick Macklem NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID); 4730c59e4cc3SRick Macklem NFSBCOPY(cp, sessid, NFSX_V4SESSIONID); 4731c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_destroysession(nd, sessid); 4732c59e4cc3SRick Macklem nfsmout: 4733c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4734c59e4cc3SRick Macklem return (error); 4735c59e4cc3SRick Macklem } 4736c59e4cc3SRick Macklem 4737c59e4cc3SRick Macklem /* 4738c59e4cc3SRick Macklem * nfsv4 free stateid service 4739c59e4cc3SRick Macklem */ 4740b9cc3262SRyan Moeller int 4741c59e4cc3SRick Macklem nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram, 4742af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4743c59e4cc3SRick Macklem { 4744c59e4cc3SRick Macklem uint32_t *tl; 4745c59e4cc3SRick Macklem nfsv4stateid_t stateid; 4746c59e4cc3SRick Macklem int error = 0; 4747af444b18SEdward Tomasz Napierala struct thread *p = curthread; 4748c59e4cc3SRick Macklem 4749c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 4750c59e4cc3SRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4751c59e4cc3SRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 475290d2dfabSRick Macklem 475390d2dfabSRick Macklem /* 475490d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 475590d2dfabSRick Macklem * stateid to the current stateid, if it is set. 475690d2dfabSRick Macklem */ 475790d2dfabSRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 475890d2dfabSRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 475990d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 476090d2dfabSRick Macklem stateid = nd->nd_curstateid; 476190d2dfabSRick Macklem stateid.seqid = 0; 476290d2dfabSRick Macklem } else { 476390d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 476490d2dfabSRick Macklem goto nfsmout; 476590d2dfabSRick Macklem } 476690d2dfabSRick Macklem } 476790d2dfabSRick Macklem 4768c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p); 476990d2dfabSRick Macklem 477090d2dfabSRick Macklem /* If the current stateid has been free'd, unset it. */ 477190d2dfabSRick Macklem if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 && 477290d2dfabSRick Macklem stateid.other[0] == nd->nd_curstateid.other[0] && 477390d2dfabSRick Macklem stateid.other[1] == nd->nd_curstateid.other[1] && 477490d2dfabSRick Macklem stateid.other[2] == nd->nd_curstateid.other[2]) 477590d2dfabSRick Macklem nd->nd_flag &= ~ND_CURSTATEID; 477690d2dfabSRick Macklem nfsmout: 477790d2dfabSRick Macklem NFSEXITCODE2(error, nd); 477890d2dfabSRick Macklem return (error); 477990d2dfabSRick Macklem } 478090d2dfabSRick Macklem 478190d2dfabSRick Macklem /* 478290d2dfabSRick Macklem * nfsv4 layoutget service 478390d2dfabSRick Macklem */ 4784b9cc3262SRyan Moeller int 478590d2dfabSRick Macklem nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram, 4786af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 478790d2dfabSRick Macklem { 478890d2dfabSRick Macklem uint32_t *tl; 478990d2dfabSRick Macklem nfsv4stateid_t stateid; 479090d2dfabSRick Macklem int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose; 479190d2dfabSRick Macklem uint64_t offset, len, minlen; 479290d2dfabSRick Macklem char *layp; 4793af444b18SEdward Tomasz Napierala struct thread *p = curthread; 479490d2dfabSRick Macklem 479590d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 479690d2dfabSRick Macklem NFSX_STATEID); 479790d2dfabSRick Macklem tl++; /* Signal layout available. Ignore for now. */ 479890d2dfabSRick Macklem layouttype = fxdr_unsigned(int, *tl++); 479990d2dfabSRick Macklem iomode = fxdr_unsigned(int, *tl++); 480090d2dfabSRick Macklem offset = fxdr_hyper(tl); tl += 2; 480190d2dfabSRick Macklem len = fxdr_hyper(tl); tl += 2; 480290d2dfabSRick Macklem minlen = fxdr_hyper(tl); tl += 2; 480390d2dfabSRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 480490d2dfabSRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 480590d2dfabSRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 480690d2dfabSRick Macklem maxcnt = fxdr_unsigned(int, *tl); 480790d2dfabSRick Macklem NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n", 480890d2dfabSRick Macklem layouttype, iomode, (uintmax_t)offset, (uintmax_t)len, 480990d2dfabSRick Macklem (uintmax_t)minlen); 481090d2dfabSRick Macklem if (len < minlen || 481190d2dfabSRick Macklem (minlen != UINT64_MAX && offset + minlen < offset) || 481290d2dfabSRick Macklem (len != UINT64_MAX && offset + len < offset)) { 481390d2dfabSRick Macklem nd->nd_repstat = NFSERR_INVAL; 481490d2dfabSRick Macklem goto nfsmout; 481590d2dfabSRick Macklem } 481690d2dfabSRick Macklem 481790d2dfabSRick Macklem /* 481890d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 481990d2dfabSRick Macklem * stateid to the current stateid, if it is set. 482090d2dfabSRick Macklem */ 482190d2dfabSRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 482290d2dfabSRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 482390d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 482490d2dfabSRick Macklem stateid = nd->nd_curstateid; 482590d2dfabSRick Macklem stateid.seqid = 0; 482690d2dfabSRick Macklem } else { 482790d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 482890d2dfabSRick Macklem goto nfsmout; 482990d2dfabSRick Macklem } 483090d2dfabSRick Macklem } 483190d2dfabSRick Macklem 483290d2dfabSRick Macklem layp = NULL; 483390d2dfabSRick Macklem if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1) 483490d2dfabSRick Macklem layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK); 483590d2dfabSRick Macklem else if (layouttype == NFSLAYOUT_FLEXFILE) 483690d2dfabSRick Macklem layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP, 483790d2dfabSRick Macklem M_WAITOK); 483890d2dfabSRick Macklem else 483990d2dfabSRick Macklem nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE; 484090d2dfabSRick Macklem if (layp != NULL) 484190d2dfabSRick Macklem nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype, 484290d2dfabSRick Macklem &iomode, &offset, &len, minlen, &stateid, maxcnt, 484390d2dfabSRick Macklem &retonclose, &layoutlen, layp, nd->nd_cred, p); 484490d2dfabSRick Macklem NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat, 484590d2dfabSRick Macklem layoutlen); 484690d2dfabSRick Macklem if (nd->nd_repstat == 0) { 484790d2dfabSRick Macklem /* For NFSv4.1, set the Current StateID. */ 484890d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 484990d2dfabSRick Macklem nd->nd_curstateid = stateid; 485090d2dfabSRick Macklem nd->nd_flag |= ND_CURSTATEID; 485190d2dfabSRick Macklem } 485290d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID + 485390d2dfabSRick Macklem 2 * NFSX_HYPER); 485490d2dfabSRick Macklem *tl++ = txdr_unsigned(retonclose); 485590d2dfabSRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 485690d2dfabSRick Macklem NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER); 485790d2dfabSRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 485890d2dfabSRick Macklem *tl++ = txdr_unsigned(1); /* Only returns one layout. */ 485990d2dfabSRick Macklem txdr_hyper(offset, tl); tl += 2; 486090d2dfabSRick Macklem txdr_hyper(len, tl); tl += 2; 486190d2dfabSRick Macklem *tl++ = txdr_unsigned(iomode); 486290d2dfabSRick Macklem *tl = txdr_unsigned(layouttype); 486390d2dfabSRick Macklem nfsm_strtom(nd, layp, layoutlen); 486490d2dfabSRick Macklem } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) { 486590d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 486690d2dfabSRick Macklem *tl = newnfs_false; 486790d2dfabSRick Macklem } 486890d2dfabSRick Macklem free(layp, M_TEMP); 486990d2dfabSRick Macklem nfsmout: 487090d2dfabSRick Macklem vput(vp); 487190d2dfabSRick Macklem NFSEXITCODE2(error, nd); 487290d2dfabSRick Macklem return (error); 487390d2dfabSRick Macklem } 487490d2dfabSRick Macklem 487590d2dfabSRick Macklem /* 487690d2dfabSRick Macklem * nfsv4 layoutcommit service 487790d2dfabSRick Macklem */ 4878b9cc3262SRyan Moeller int 487990d2dfabSRick Macklem nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram, 4880af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 488190d2dfabSRick Macklem { 488290d2dfabSRick Macklem uint32_t *tl; 488390d2dfabSRick Macklem nfsv4stateid_t stateid; 488490d2dfabSRick Macklem int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim; 488590d2dfabSRick Macklem int hasnewsize; 4886f808cf72SRick Macklem uint64_t offset, len, newoff = 0, newsize; 488790d2dfabSRick Macklem struct timespec newmtime; 488890d2dfabSRick Macklem char *layp; 4889af444b18SEdward Tomasz Napierala struct thread *p = curthread; 489090d2dfabSRick Macklem 489190d2dfabSRick Macklem layp = NULL; 489290d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER + 489390d2dfabSRick Macklem NFSX_STATEID); 489490d2dfabSRick Macklem offset = fxdr_hyper(tl); tl += 2; 489590d2dfabSRick Macklem len = fxdr_hyper(tl); tl += 2; 489690d2dfabSRick Macklem reclaim = fxdr_unsigned(int, *tl++); 489790d2dfabSRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 489890d2dfabSRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 489990d2dfabSRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 490090d2dfabSRick Macklem /* 490190d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 490290d2dfabSRick Macklem * stateid to the current stateid, if it is set. 490390d2dfabSRick Macklem */ 490490d2dfabSRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 490590d2dfabSRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 490690d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 490790d2dfabSRick Macklem stateid = nd->nd_curstateid; 490890d2dfabSRick Macklem stateid.seqid = 0; 490990d2dfabSRick Macklem } else { 491090d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 491190d2dfabSRick Macklem goto nfsmout; 491290d2dfabSRick Macklem } 491390d2dfabSRick Macklem } 491490d2dfabSRick Macklem 491590d2dfabSRick Macklem hasnewoff = fxdr_unsigned(int, *tl); 491690d2dfabSRick Macklem if (hasnewoff != 0) { 491790d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 491890d2dfabSRick Macklem newoff = fxdr_hyper(tl); tl += 2; 491990d2dfabSRick Macklem } else 492090d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 492190d2dfabSRick Macklem hasnewmtime = fxdr_unsigned(int, *tl); 492290d2dfabSRick Macklem if (hasnewmtime != 0) { 492390d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED); 492490d2dfabSRick Macklem fxdr_nfsv4time(tl, &newmtime); 492590d2dfabSRick Macklem tl += (NFSX_V4TIME / NFSX_UNSIGNED); 492690d2dfabSRick Macklem } else 492790d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 492890d2dfabSRick Macklem layouttype = fxdr_unsigned(int, *tl++); 492990d2dfabSRick Macklem maxcnt = fxdr_unsigned(int, *tl); 493090d2dfabSRick Macklem if (maxcnt > 0) { 493190d2dfabSRick Macklem layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK); 493290d2dfabSRick Macklem error = nfsrv_mtostr(nd, layp, maxcnt); 493390d2dfabSRick Macklem if (error != 0) 493490d2dfabSRick Macklem goto nfsmout; 493590d2dfabSRick Macklem } 493690d2dfabSRick Macklem nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff, 493790d2dfabSRick Macklem newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid, 493890d2dfabSRick Macklem maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p); 493990d2dfabSRick Macklem NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat); 494090d2dfabSRick Macklem if (nd->nd_repstat == 0) { 494190d2dfabSRick Macklem if (hasnewsize != 0) { 494290d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); 494390d2dfabSRick Macklem *tl++ = newnfs_true; 494490d2dfabSRick Macklem txdr_hyper(newsize, tl); 494590d2dfabSRick Macklem } else { 494690d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 494790d2dfabSRick Macklem *tl = newnfs_false; 494890d2dfabSRick Macklem } 494990d2dfabSRick Macklem } 495090d2dfabSRick Macklem nfsmout: 495190d2dfabSRick Macklem free(layp, M_TEMP); 495290d2dfabSRick Macklem vput(vp); 495390d2dfabSRick Macklem NFSEXITCODE2(error, nd); 495490d2dfabSRick Macklem return (error); 495590d2dfabSRick Macklem } 495690d2dfabSRick Macklem 495790d2dfabSRick Macklem /* 495890d2dfabSRick Macklem * nfsv4 layoutreturn service 495990d2dfabSRick Macklem */ 4960b9cc3262SRyan Moeller int 496190d2dfabSRick Macklem nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram, 4962af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 496390d2dfabSRick Macklem { 496490d2dfabSRick Macklem uint32_t *tl, *layp; 496590d2dfabSRick Macklem nfsv4stateid_t stateid; 496690d2dfabSRick Macklem int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim; 496790d2dfabSRick Macklem uint64_t offset, len; 4968af444b18SEdward Tomasz Napierala struct thread *p = curthread; 496990d2dfabSRick Macklem 497090d2dfabSRick Macklem layp = NULL; 497190d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 497290d2dfabSRick Macklem reclaim = *tl++; 497390d2dfabSRick Macklem layouttype = fxdr_unsigned(int, *tl++); 497490d2dfabSRick Macklem iomode = fxdr_unsigned(int, *tl++); 497590d2dfabSRick Macklem kind = fxdr_unsigned(int, *tl); 497690d2dfabSRick Macklem NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim, 497790d2dfabSRick Macklem layouttype, iomode, kind); 497890d2dfabSRick Macklem if (kind == NFSV4LAYOUTRET_FILE) { 497990d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 498090d2dfabSRick Macklem NFSX_UNSIGNED); 498190d2dfabSRick Macklem offset = fxdr_hyper(tl); tl += 2; 498290d2dfabSRick Macklem len = fxdr_hyper(tl); tl += 2; 498390d2dfabSRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 498490d2dfabSRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 498590d2dfabSRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 498690d2dfabSRick Macklem 498790d2dfabSRick Macklem /* 498890d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set 498990d2dfabSRick Macklem * the stateid to the current stateid, if it is set. 499090d2dfabSRick Macklem */ 499190d2dfabSRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 499290d2dfabSRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 499390d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 499490d2dfabSRick Macklem stateid = nd->nd_curstateid; 499590d2dfabSRick Macklem stateid.seqid = 0; 499690d2dfabSRick Macklem } else { 499790d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 499890d2dfabSRick Macklem goto nfsmout; 499990d2dfabSRick Macklem } 500090d2dfabSRick Macklem } 500190d2dfabSRick Macklem 500290d2dfabSRick Macklem maxcnt = fxdr_unsigned(int, *tl); 5003bdd57cbbSRick Macklem /* 5004bdd57cbbSRick Macklem * There is no fixed upper bound defined in the RFCs, 5005bdd57cbbSRick Macklem * but 128Kbytes should be more than sufficient. 5006bdd57cbbSRick Macklem */ 5007bdd57cbbSRick Macklem if (maxcnt < 0 || maxcnt > 131072) 5008bdd57cbbSRick Macklem maxcnt = 0; 500990d2dfabSRick Macklem if (maxcnt > 0) { 501090d2dfabSRick Macklem layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK); 501190d2dfabSRick Macklem error = nfsrv_mtostr(nd, (char *)layp, maxcnt); 501290d2dfabSRick Macklem if (error != 0) 501390d2dfabSRick Macklem goto nfsmout; 501490d2dfabSRick Macklem } 501590d2dfabSRick Macklem } else { 501690d2dfabSRick Macklem if (reclaim == newnfs_true) { 501790d2dfabSRick Macklem nd->nd_repstat = NFSERR_INVAL; 501890d2dfabSRick Macklem goto nfsmout; 501990d2dfabSRick Macklem } 502090d2dfabSRick Macklem offset = len = 0; 502190d2dfabSRick Macklem maxcnt = 0; 502290d2dfabSRick Macklem } 502390d2dfabSRick Macklem nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode, 502490d2dfabSRick Macklem offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd, 502590d2dfabSRick Macklem nd->nd_cred, p); 502690d2dfabSRick Macklem NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat, 502790d2dfabSRick Macklem fnd); 502890d2dfabSRick Macklem if (nd->nd_repstat == 0) { 502990d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 503090d2dfabSRick Macklem if (fnd != 0) { 503190d2dfabSRick Macklem *tl = newnfs_true; 503290d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_STATEID); 503390d2dfabSRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 503490d2dfabSRick Macklem NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER); 503590d2dfabSRick Macklem } else 503690d2dfabSRick Macklem *tl = newnfs_false; 503790d2dfabSRick Macklem } 503890d2dfabSRick Macklem nfsmout: 503990d2dfabSRick Macklem free(layp, M_TEMP); 504090d2dfabSRick Macklem vput(vp); 504190d2dfabSRick Macklem NFSEXITCODE2(error, nd); 504290d2dfabSRick Macklem return (error); 504390d2dfabSRick Macklem } 504490d2dfabSRick Macklem 504590d2dfabSRick Macklem /* 5046c057a378SRick Macklem * nfsv4 layout error service 5047c057a378SRick Macklem */ 5048b9cc3262SRyan Moeller int 5049c057a378SRick Macklem nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram, 5050c057a378SRick Macklem vnode_t vp, struct nfsexstuff *exp) 5051c057a378SRick Macklem { 5052c057a378SRick Macklem uint32_t *tl; 5053c057a378SRick Macklem nfsv4stateid_t stateid; 5054c057a378SRick Macklem int cnt, error = 0, i, stat; 5055c057a378SRick Macklem int opnum __unused; 5056c057a378SRick Macklem char devid[NFSX_V4DEVICEID]; 5057c057a378SRick Macklem uint64_t offset, len; 5058c057a378SRick Macklem 5059c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 5060c057a378SRick Macklem NFSX_UNSIGNED); 5061c057a378SRick Macklem offset = fxdr_hyper(tl); tl += 2; 5062c057a378SRick Macklem len = fxdr_hyper(tl); tl += 2; 5063c057a378SRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5064c057a378SRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 5065c057a378SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 5066c057a378SRick Macklem cnt = fxdr_unsigned(int, *tl); 5067c057a378SRick Macklem NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset, 5068c057a378SRick Macklem (uintmax_t)len, cnt); 5069c057a378SRick Macklem /* 5070c057a378SRick Macklem * For the special stateid of other all 0s and seqid == 1, set 5071c057a378SRick Macklem * the stateid to the current stateid, if it is set. 5072c057a378SRick Macklem */ 5073c057a378SRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 5074c057a378SRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 5075c057a378SRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 5076c057a378SRick Macklem stateid = nd->nd_curstateid; 5077c057a378SRick Macklem stateid.seqid = 0; 5078c057a378SRick Macklem } else { 5079c057a378SRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 5080c057a378SRick Macklem goto nfsmout; 5081c057a378SRick Macklem } 5082c057a378SRick Macklem } 5083c057a378SRick Macklem 5084c057a378SRick Macklem /* 5085c057a378SRick Macklem * Ignore offset, len and stateid for now. 5086c057a378SRick Macklem */ 5087c057a378SRick Macklem for (i = 0; i < cnt; i++) { 5088c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 * 5089c057a378SRick Macklem NFSX_UNSIGNED); 5090c057a378SRick Macklem NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 5091c057a378SRick Macklem tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5092c057a378SRick Macklem stat = fxdr_unsigned(int, *tl++); 5093c057a378SRick Macklem opnum = fxdr_unsigned(int, *tl); 5094c057a378SRick Macklem NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat); 5095c057a378SRick Macklem /* 5096a7e014eeSRick Macklem * Except for NFSERR_ACCES, NFSERR_STALE and NFSERR_NOSPC 5097a7e014eeSRick Macklem * errors, disable the mirror. 5098c057a378SRick Macklem */ 5099a7e014eeSRick Macklem if (stat != NFSERR_ACCES && stat != NFSERR_STALE && 5100a7e014eeSRick Macklem stat != NFSERR_NOSPC) 5101c057a378SRick Macklem nfsrv_delds(devid, curthread); 5102f8dc0630SRick Macklem 5103f8dc0630SRick Macklem /* For NFSERR_NOSPC, mark all deviceids and layouts. */ 5104f8dc0630SRick Macklem if (stat == NFSERR_NOSPC) 5105f8dc0630SRick Macklem nfsrv_marknospc(devid, true); 5106c057a378SRick Macklem } 5107c057a378SRick Macklem nfsmout: 5108c057a378SRick Macklem vput(vp); 5109c057a378SRick Macklem NFSEXITCODE2(error, nd); 5110c057a378SRick Macklem return (error); 5111c057a378SRick Macklem } 5112c057a378SRick Macklem 5113c057a378SRick Macklem /* 5114c057a378SRick Macklem * nfsv4 layout stats service 5115c057a378SRick Macklem */ 5116b9cc3262SRyan Moeller int 5117c057a378SRick Macklem nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram, 5118c057a378SRick Macklem vnode_t vp, struct nfsexstuff *exp) 5119c057a378SRick Macklem { 5120c057a378SRick Macklem uint32_t *tl; 5121c057a378SRick Macklem nfsv4stateid_t stateid; 5122c057a378SRick Macklem int cnt, error = 0; 5123c057a378SRick Macklem int layouttype __unused; 5124c057a378SRick Macklem char devid[NFSX_V4DEVICEID] __unused; 5125638b90a1SRick Macklem uint64_t offset __unused, len __unused, readcount __unused; 5126638b90a1SRick Macklem uint64_t readbytes __unused, writecount __unused, writebytes __unused; 5127c057a378SRick Macklem 5128c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID + 5129c057a378SRick Macklem NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED); 5130c057a378SRick Macklem offset = fxdr_hyper(tl); tl += 2; 5131c057a378SRick Macklem len = fxdr_hyper(tl); tl += 2; 5132c057a378SRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5133c057a378SRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 5134c057a378SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 5135c057a378SRick Macklem readcount = fxdr_hyper(tl); tl += 2; 5136c057a378SRick Macklem readbytes = fxdr_hyper(tl); tl += 2; 5137c057a378SRick Macklem writecount = fxdr_hyper(tl); tl += 2; 5138c057a378SRick Macklem writebytes = fxdr_hyper(tl); tl += 2; 5139c057a378SRick Macklem NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 5140c057a378SRick Macklem tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5141c057a378SRick Macklem layouttype = fxdr_unsigned(int, *tl++); 5142c057a378SRick Macklem cnt = fxdr_unsigned(int, *tl); 5143c057a378SRick Macklem error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1); 5144c057a378SRick Macklem if (error != 0) 5145c057a378SRick Macklem goto nfsmout; 5146c057a378SRick Macklem NFSD_DEBUG(4, "layoutstats cnt=%d\n", cnt); 5147c057a378SRick Macklem /* 5148c057a378SRick Macklem * For the special stateid of other all 0s and seqid == 1, set 5149c057a378SRick Macklem * the stateid to the current stateid, if it is set. 5150c057a378SRick Macklem */ 5151c057a378SRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 5152c057a378SRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 5153c057a378SRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 5154c057a378SRick Macklem stateid = nd->nd_curstateid; 5155c057a378SRick Macklem stateid.seqid = 0; 5156c057a378SRick Macklem } else { 5157c057a378SRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 5158c057a378SRick Macklem goto nfsmout; 5159c057a378SRick Macklem } 5160c057a378SRick Macklem } 5161c057a378SRick Macklem 5162c057a378SRick Macklem /* 5163c057a378SRick Macklem * No use for the stats for now. 5164c057a378SRick Macklem */ 5165c057a378SRick Macklem nfsmout: 5166c057a378SRick Macklem vput(vp); 5167c057a378SRick Macklem NFSEXITCODE2(error, nd); 5168c057a378SRick Macklem return (error); 5169c057a378SRick Macklem } 5170c057a378SRick Macklem 5171c057a378SRick Macklem /* 5172c057a378SRick Macklem * nfsv4 io_advise service 5173c057a378SRick Macklem */ 5174b9cc3262SRyan Moeller int 5175c057a378SRick Macklem nfsrvd_ioadvise(struct nfsrv_descript *nd, __unused int isdgram, 5176c057a378SRick Macklem vnode_t vp, struct nfsexstuff *exp) 5177c057a378SRick Macklem { 5178c057a378SRick Macklem uint32_t *tl; 5179c057a378SRick Macklem nfsv4stateid_t stateid; 5180c057a378SRick Macklem nfsattrbit_t hints; 5181c057a378SRick Macklem int error = 0, ret; 5182c057a378SRick Macklem off_t offset, len; 5183c057a378SRick Macklem 5184c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); 5185c057a378SRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5186c057a378SRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 5187c057a378SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 5188c057a378SRick Macklem offset = fxdr_hyper(tl); tl += 2; 5189c057a378SRick Macklem len = fxdr_hyper(tl); 5190c057a378SRick Macklem error = nfsrv_getattrbits(nd, &hints, NULL, NULL); 5191c057a378SRick Macklem if (error != 0) 5192c057a378SRick Macklem goto nfsmout; 5193c057a378SRick Macklem /* 5194c057a378SRick Macklem * For the special stateid of other all 0s and seqid == 1, set 5195c057a378SRick Macklem * the stateid to the current stateid, if it is set. 5196c057a378SRick Macklem */ 5197c057a378SRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 5198c057a378SRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 5199c057a378SRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 5200c057a378SRick Macklem stateid = nd->nd_curstateid; 5201c057a378SRick Macklem stateid.seqid = 0; 5202c057a378SRick Macklem } else { 5203c057a378SRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 5204c057a378SRick Macklem goto nfsmout; 5205c057a378SRick Macklem } 5206c057a378SRick Macklem } 5207c057a378SRick Macklem 5208c057a378SRick Macklem if (offset < 0) { 5209c057a378SRick Macklem nd->nd_repstat = NFSERR_INVAL; 5210c057a378SRick Macklem goto nfsmout; 5211c057a378SRick Macklem } 5212c057a378SRick Macklem if (len < 0) 5213c057a378SRick Macklem len = 0; 5214c057a378SRick Macklem if (vp->v_type != VREG) { 5215c057a378SRick Macklem if (vp->v_type == VDIR) 5216c057a378SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 5217c057a378SRick Macklem else 5218c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGTYPE; 5219c057a378SRick Macklem goto nfsmout; 5220c057a378SRick Macklem } 5221c057a378SRick Macklem 5222c057a378SRick Macklem /* 5223c057a378SRick Macklem * For now, we can only handle WILLNEED and DONTNEED and don't use 5224c057a378SRick Macklem * the stateid. 5225c057a378SRick Macklem */ 5226c057a378SRick Macklem if ((NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED) && 5227c057a378SRick Macklem !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED)) || 5228c057a378SRick Macklem (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED) && 5229c057a378SRick Macklem !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED))) { 5230b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 5231c057a378SRick Macklem if (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED)) { 5232c057a378SRick Macklem ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_WILLNEED); 5233c057a378SRick Macklem NFSZERO_ATTRBIT(&hints); 5234c057a378SRick Macklem if (ret == 0) 5235c057a378SRick Macklem NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED); 5236c057a378SRick Macklem else 5237c057a378SRick Macklem NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 5238c057a378SRick Macklem } else { 5239c057a378SRick Macklem ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_DONTNEED); 5240c057a378SRick Macklem NFSZERO_ATTRBIT(&hints); 5241c057a378SRick Macklem if (ret == 0) 5242c057a378SRick Macklem NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED); 5243c057a378SRick Macklem else 5244c057a378SRick Macklem NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 5245c057a378SRick Macklem } 5246c057a378SRick Macklem vrele(vp); 5247c057a378SRick Macklem } else { 5248c057a378SRick Macklem NFSZERO_ATTRBIT(&hints); 5249c057a378SRick Macklem NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 5250c057a378SRick Macklem vput(vp); 5251c057a378SRick Macklem } 5252c057a378SRick Macklem nfsrv_putattrbit(nd, &hints); 5253c057a378SRick Macklem NFSEXITCODE2(error, nd); 5254c057a378SRick Macklem return (error); 5255c057a378SRick Macklem nfsmout: 5256c057a378SRick Macklem vput(vp); 5257c057a378SRick Macklem NFSEXITCODE2(error, nd); 5258c057a378SRick Macklem return (error); 5259c057a378SRick Macklem } 5260c057a378SRick Macklem 5261c057a378SRick Macklem /* 526290d2dfabSRick Macklem * nfsv4 getdeviceinfo service 526390d2dfabSRick Macklem */ 5264b9cc3262SRyan Moeller int 526590d2dfabSRick Macklem nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram, 5266af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 526790d2dfabSRick Macklem { 526890d2dfabSRick Macklem uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP]; 526990d2dfabSRick Macklem int cnt, devaddrlen, error = 0, i, layouttype; 527090d2dfabSRick Macklem char devid[NFSX_V4DEVICEID], *devaddr; 527190d2dfabSRick Macklem time_t dev_time; 527290d2dfabSRick Macklem 527390d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID); 527490d2dfabSRick Macklem NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 527590d2dfabSRick Macklem tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 527690d2dfabSRick Macklem layouttype = fxdr_unsigned(int, *tl++); 527790d2dfabSRick Macklem maxcnt = fxdr_unsigned(uint32_t, *tl++); 527890d2dfabSRick Macklem cnt = fxdr_unsigned(int, *tl); 527990d2dfabSRick Macklem NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype, 528090d2dfabSRick Macklem maxcnt, cnt); 528190d2dfabSRick Macklem if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) { 528290d2dfabSRick Macklem nd->nd_repstat = NFSERR_INVAL; 528390d2dfabSRick Macklem goto nfsmout; 528490d2dfabSRick Macklem } 528590d2dfabSRick Macklem if (cnt > 0) { 528690d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED); 528790d2dfabSRick Macklem for (i = 0; i < cnt; i++) 528890d2dfabSRick Macklem notify[i] = fxdr_unsigned(uint32_t, *tl++); 528990d2dfabSRick Macklem } 529090d2dfabSRick Macklem for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++) 529190d2dfabSRick Macklem notify[i] = 0; 529290d2dfabSRick Macklem 529390d2dfabSRick Macklem /* 529490d2dfabSRick Macklem * Check that the device id is not stale. Device ids are recreated 529590d2dfabSRick Macklem * each time the nfsd threads are restarted. 529690d2dfabSRick Macklem */ 529790d2dfabSRick Macklem NFSBCOPY(devid, &dev_time, sizeof(dev_time)); 529890d2dfabSRick Macklem if (dev_time != nfsdev_time) { 529990d2dfabSRick Macklem nd->nd_repstat = NFSERR_NOENT; 530090d2dfabSRick Macklem goto nfsmout; 530190d2dfabSRick Macklem } 530290d2dfabSRick Macklem 530390d2dfabSRick Macklem /* Look for the device id. */ 530490d2dfabSRick Macklem nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt, 530590d2dfabSRick Macklem notify, &devaddrlen, &devaddr); 530690d2dfabSRick Macklem NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat); 530790d2dfabSRick Macklem if (nd->nd_repstat == 0) { 530890d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 530990d2dfabSRick Macklem *tl = txdr_unsigned(layouttype); 531090d2dfabSRick Macklem nfsm_strtom(nd, devaddr, devaddrlen); 531190d2dfabSRick Macklem cnt = 0; 531290d2dfabSRick Macklem for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) { 531390d2dfabSRick Macklem if (notify[i] != 0) 531490d2dfabSRick Macklem cnt = i + 1; 531590d2dfabSRick Macklem } 531690d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED); 531790d2dfabSRick Macklem *tl++ = txdr_unsigned(cnt); 531890d2dfabSRick Macklem for (i = 0; i < cnt; i++) 531990d2dfabSRick Macklem *tl++ = txdr_unsigned(notify[i]); 532090d2dfabSRick Macklem } else if (nd->nd_repstat == NFSERR_TOOSMALL) { 532190d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 532290d2dfabSRick Macklem *tl = txdr_unsigned(maxcnt); 532390d2dfabSRick Macklem } 5324c59e4cc3SRick Macklem nfsmout: 5325c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 5326c59e4cc3SRick Macklem return (error); 5327c59e4cc3SRick Macklem } 5328c59e4cc3SRick Macklem 5329c59e4cc3SRick Macklem /* 53305d4835e4SRick Macklem * nfsv4 test stateid service 53315d4835e4SRick Macklem */ 5332b9cc3262SRyan Moeller int 53335d4835e4SRick Macklem nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram, 5334af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 53355d4835e4SRick Macklem { 53365d4835e4SRick Macklem uint32_t *tl; 53375d4835e4SRick Macklem nfsv4stateid_t *stateidp = NULL, *tstateidp; 53385d4835e4SRick Macklem int cnt, error = 0, i, ret; 5339af444b18SEdward Tomasz Napierala struct thread *p = curthread; 53405d4835e4SRick Macklem 53415d4835e4SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 53425d4835e4SRick Macklem cnt = fxdr_unsigned(int, *tl); 53435d4835e4SRick Macklem if (cnt <= 0 || cnt > 1024) { 53445d4835e4SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 53455d4835e4SRick Macklem goto nfsmout; 53465d4835e4SRick Macklem } 53475d4835e4SRick Macklem stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK); 53485d4835e4SRick Macklem tstateidp = stateidp; 53495d4835e4SRick Macklem for (i = 0; i < cnt; i++) { 53505d4835e4SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 53515d4835e4SRick Macklem tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 53525d4835e4SRick Macklem NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER); 53535d4835e4SRick Macklem tstateidp++; 53545d4835e4SRick Macklem } 53555d4835e4SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 53565d4835e4SRick Macklem *tl = txdr_unsigned(cnt); 53575d4835e4SRick Macklem tstateidp = stateidp; 53585d4835e4SRick Macklem for (i = 0; i < cnt; i++) { 53595d4835e4SRick Macklem ret = nfsrv_teststateid(nd, tstateidp, p); 53605d4835e4SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 53615d4835e4SRick Macklem *tl = txdr_unsigned(ret); 53625d4835e4SRick Macklem tstateidp++; 53635d4835e4SRick Macklem } 53645d4835e4SRick Macklem nfsmout: 53655d4835e4SRick Macklem free(stateidp, M_TEMP); 53665d4835e4SRick Macklem NFSEXITCODE2(error, nd); 53675d4835e4SRick Macklem return (error); 53685d4835e4SRick Macklem } 53695d4835e4SRick Macklem 53705d4835e4SRick Macklem /* 5371c057a378SRick Macklem * nfs allocate service 5372c057a378SRick Macklem */ 5373b9cc3262SRyan Moeller int 5374c057a378SRick Macklem nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram, 5375c057a378SRick Macklem vnode_t vp, struct nfsexstuff *exp) 5376c057a378SRick Macklem { 5377c057a378SRick Macklem uint32_t *tl; 5378c057a378SRick Macklem struct nfsvattr forat; 5379c057a378SRick Macklem int error = 0, forat_ret = 1, gotproxystateid; 5380c057a378SRick Macklem off_t off, len; 5381c057a378SRick Macklem struct nfsstate st, *stp = &st; 5382c057a378SRick Macklem struct nfslock lo, *lop = &lo; 5383c057a378SRick Macklem nfsv4stateid_t stateid; 5384c057a378SRick Macklem nfsquad_t clientid; 5385c057a378SRick Macklem nfsattrbit_t attrbits; 5386c057a378SRick Macklem 5387dfe887b7SRick Macklem if (!nfsrv_doallocate) { 5388dfe887b7SRick Macklem /* 5389dfe887b7SRick Macklem * If any exported file system, such as a ZFS one, cannot 5390dfe887b7SRick Macklem * do VOP_ALLOCATE(), this operation cannot be supported 5391dfe887b7SRick Macklem * for NFSv4.2. This cannot be done 'per filesystem', but 5392dfe887b7SRick Macklem * must be for the entire nfsd NFSv4.2 service. 5393dfe887b7SRick Macklem */ 5394dfe887b7SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 5395dfe887b7SRick Macklem goto nfsmout; 5396dfe887b7SRick Macklem } 5397c057a378SRick Macklem gotproxystateid = 0; 5398c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); 5399c057a378SRick Macklem stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 5400c057a378SRick Macklem lop->lo_flags = NFSLCK_WRITE; 5401c057a378SRick Macklem stp->ls_ownerlen = 0; 5402c057a378SRick Macklem stp->ls_op = NULL; 5403c057a378SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 5404c057a378SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 5405c057a378SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 5406c057a378SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 5407c057a378SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 5408c057a378SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 5409c057a378SRick Macklem clientid.qval = nd->nd_clientid.qval; 5410c057a378SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 5411c057a378SRick Macklem printf("EEK2 multiple clids\n"); 5412c057a378SRick Macklem } else { 5413c057a378SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 5414c057a378SRick Macklem printf("EEK! no clientid from session\n"); 5415c057a378SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 5416c057a378SRick Macklem nd->nd_clientid.qval = clientid.qval; 5417c057a378SRick Macklem } 5418c057a378SRick Macklem stp->ls_stateid.other[2] = *tl++; 5419c057a378SRick Macklem /* 5420c057a378SRick Macklem * Don't allow this to be done for a DS. 5421c057a378SRick Macklem */ 5422c057a378SRick Macklem if ((nd->nd_flag & ND_DSSERVER) != 0) 5423c057a378SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 5424c057a378SRick Macklem /* However, allow the proxy stateid. */ 5425c057a378SRick Macklem if (stp->ls_stateid.seqid == 0xffffffff && 5426c057a378SRick Macklem stp->ls_stateid.other[0] == 0x55555555 && 5427c057a378SRick Macklem stp->ls_stateid.other[1] == 0x55555555 && 5428c057a378SRick Macklem stp->ls_stateid.other[2] == 0x55555555) 5429c057a378SRick Macklem gotproxystateid = 1; 5430c057a378SRick Macklem off = fxdr_hyper(tl); tl += 2; 5431c057a378SRick Macklem lop->lo_first = off; 5432c057a378SRick Macklem len = fxdr_hyper(tl); 543306afb53bSRick Macklem lop->lo_end = lop->lo_first + len; 5434c057a378SRick Macklem /* 543506afb53bSRick Macklem * Sanity check the offset and length. 543606afb53bSRick Macklem * off and len are off_t (signed int64_t) whereas 543706afb53bSRick Macklem * lo_first and lo_end are uint64_t and, as such, 543806afb53bSRick Macklem * if off >= 0 && len > 0, lo_end cannot overflow 543906afb53bSRick Macklem * unless off_t is changed to something other than 544006afb53bSRick Macklem * int64_t. Check lo_end < lo_first in case that 544106afb53bSRick Macklem * is someday the case. 5442c057a378SRick Macklem */ 544306afb53bSRick Macklem if (nd->nd_repstat == 0 && (len <= 0 || off < 0 || lop->lo_end > 544406afb53bSRick Macklem OFF_MAX || lop->lo_end < lop->lo_first)) 5445c057a378SRick Macklem nd->nd_repstat = NFSERR_INVAL; 5446c057a378SRick Macklem 54475d3fe02cSRick Macklem if (nd->nd_repstat == 0 && vp->v_type != VREG) 5448c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGTYPE; 5449c057a378SRick Macklem NFSZERO_ATTRBIT(&attrbits); 5450c057a378SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5451c057a378SRick Macklem forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits); 5452c057a378SRick Macklem if (nd->nd_repstat == 0) 5453c057a378SRick Macklem nd->nd_repstat = forat_ret; 5454c057a378SRick Macklem if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid || 5455c057a378SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) 5456c057a378SRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, 5457c057a378SRick Macklem curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5458c057a378SRick Macklem NULL); 5459c057a378SRick Macklem if (nd->nd_repstat == 0 && gotproxystateid == 0) 5460c057a378SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 5461c057a378SRick Macklem &stateid, exp, nd, curthread); 5462c057a378SRick Macklem 5463dfe887b7SRick Macklem NFSD_DEBUG(4, "nfsrvd_allocate: off=%jd len=%jd stat=%d\n", 5464dfe887b7SRick Macklem (intmax_t)off, (intmax_t)len, nd->nd_repstat); 5465c057a378SRick Macklem if (nd->nd_repstat == 0) 5466c057a378SRick Macklem nd->nd_repstat = nfsvno_allocate(vp, off, len, nd->nd_cred, 5467c057a378SRick Macklem curthread); 5468dfe887b7SRick Macklem NFSD_DEBUG(4, "nfsrvd_allocate: aft nfsvno_allocate=%d\n", 5469dfe887b7SRick Macklem nd->nd_repstat); 5470c057a378SRick Macklem vput(vp); 5471c057a378SRick Macklem NFSEXITCODE2(0, nd); 5472c057a378SRick Macklem return (0); 5473c057a378SRick Macklem nfsmout: 5474c057a378SRick Macklem vput(vp); 5475c057a378SRick Macklem NFSEXITCODE2(error, nd); 5476c057a378SRick Macklem return (error); 5477c057a378SRick Macklem } 5478c057a378SRick Macklem 5479c057a378SRick Macklem /* 5480bb958dcfSRick Macklem * nfs deallocate service 5481bb958dcfSRick Macklem */ 5482bb958dcfSRick Macklem int 5483bb958dcfSRick Macklem nfsrvd_deallocate(struct nfsrv_descript *nd, __unused int isdgram, 5484bb958dcfSRick Macklem vnode_t vp, struct nfsexstuff *exp) 5485bb958dcfSRick Macklem { 5486bb958dcfSRick Macklem uint32_t *tl; 5487bb958dcfSRick Macklem struct nfsvattr forat; 5488bb958dcfSRick Macklem int error = 0, forat_ret = 1, gotproxystateid; 5489bb958dcfSRick Macklem off_t off, len; 5490bb958dcfSRick Macklem struct nfsstate st, *stp = &st; 5491bb958dcfSRick Macklem struct nfslock lo, *lop = &lo; 5492bb958dcfSRick Macklem nfsv4stateid_t stateid; 5493bb958dcfSRick Macklem nfsquad_t clientid; 5494bb958dcfSRick Macklem nfsattrbit_t attrbits; 5495bb958dcfSRick Macklem 5496bb958dcfSRick Macklem gotproxystateid = 0; 5497bb958dcfSRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); 5498bb958dcfSRick Macklem stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 5499bb958dcfSRick Macklem lop->lo_flags = NFSLCK_WRITE; 5500bb958dcfSRick Macklem stp->ls_ownerlen = 0; 5501bb958dcfSRick Macklem stp->ls_op = NULL; 5502bb958dcfSRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 5503bb958dcfSRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 5504bb958dcfSRick Macklem clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 5505bb958dcfSRick Macklem clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 5506bb958dcfSRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 5507bb958dcfSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 5508bb958dcfSRick Macklem clientid.qval = nd->nd_clientid.qval; 5509bb958dcfSRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 5510bb958dcfSRick Macklem printf("EEK2 multiple clids\n"); 5511bb958dcfSRick Macklem } else { 5512bb958dcfSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 5513bb958dcfSRick Macklem printf("EEK! no clientid from session\n"); 5514bb958dcfSRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 5515bb958dcfSRick Macklem nd->nd_clientid.qval = clientid.qval; 5516bb958dcfSRick Macklem } 5517bb958dcfSRick Macklem stp->ls_stateid.other[2] = *tl++; 5518bb958dcfSRick Macklem /* 5519bb958dcfSRick Macklem * Don't allow this to be done for a DS. 5520bb958dcfSRick Macklem */ 5521bb958dcfSRick Macklem if ((nd->nd_flag & ND_DSSERVER) != 0) 5522bb958dcfSRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 5523bb958dcfSRick Macklem /* However, allow the proxy stateid. */ 5524bb958dcfSRick Macklem if (stp->ls_stateid.seqid == 0xffffffff && 5525bb958dcfSRick Macklem stp->ls_stateid.other[0] == 0x55555555 && 5526bb958dcfSRick Macklem stp->ls_stateid.other[1] == 0x55555555 && 5527bb958dcfSRick Macklem stp->ls_stateid.other[2] == 0x55555555) 5528bb958dcfSRick Macklem gotproxystateid = 1; 5529bb958dcfSRick Macklem off = fxdr_hyper(tl); tl += 2; 5530bb958dcfSRick Macklem lop->lo_first = off; 5531bb958dcfSRick Macklem len = fxdr_hyper(tl); 5532bb958dcfSRick Macklem if (len < 0) 5533bb958dcfSRick Macklem len = OFF_MAX; 5534bb958dcfSRick Macklem NFSD_DEBUG(4, "dealloc: off=%jd len=%jd\n", (intmax_t)off, 5535bb958dcfSRick Macklem (intmax_t)len); 5536bb958dcfSRick Macklem lop->lo_end = lop->lo_first + len; 5537bb958dcfSRick Macklem /* 5538bb958dcfSRick Macklem * Sanity check the offset and length. 5539bb958dcfSRick Macklem * off and len are off_t (signed int64_t) whereas 5540bb958dcfSRick Macklem * lo_first and lo_end are uint64_t and, as such, 5541bb958dcfSRick Macklem * if off >= 0 && len > 0, lo_end cannot overflow 5542bb958dcfSRick Macklem * unless off_t is changed to something other than 5543bb958dcfSRick Macklem * int64_t. Check lo_end < lo_first in case that 5544bb958dcfSRick Macklem * is someday the case. 5545bb958dcfSRick Macklem * The error to return is not specified by RFC 7862 so I 5546bb958dcfSRick Macklem * made this compatible with the Linux knfsd. 5547bb958dcfSRick Macklem */ 5548bb958dcfSRick Macklem if (nd->nd_repstat == 0) { 5549bb958dcfSRick Macklem if (off < 0 || lop->lo_end > NFSRV_MAXFILESIZE) 5550bb958dcfSRick Macklem nd->nd_repstat = NFSERR_FBIG; 5551bb958dcfSRick Macklem else if (len == 0 || lop->lo_end < lop->lo_first) 5552bb958dcfSRick Macklem nd->nd_repstat = NFSERR_INVAL; 5553bb958dcfSRick Macklem } 5554bb958dcfSRick Macklem 55555d3fe02cSRick Macklem if (nd->nd_repstat == 0 && vp->v_type != VREG) 5556bb958dcfSRick Macklem nd->nd_repstat = NFSERR_WRONGTYPE; 5557bb958dcfSRick Macklem NFSZERO_ATTRBIT(&attrbits); 5558bb958dcfSRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5559bb958dcfSRick Macklem forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits); 5560bb958dcfSRick Macklem if (nd->nd_repstat == 0) 5561bb958dcfSRick Macklem nd->nd_repstat = forat_ret; 5562bb958dcfSRick Macklem if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid || 5563bb958dcfSRick Macklem NFSVNO_EXSTRICTACCESS(exp))) 5564bb958dcfSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, 5565bb958dcfSRick Macklem curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5566bb958dcfSRick Macklem NULL); 5567bb958dcfSRick Macklem if (nd->nd_repstat == 0 && gotproxystateid == 0) 5568bb958dcfSRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 5569bb958dcfSRick Macklem &stateid, exp, nd, curthread); 5570bb958dcfSRick Macklem 5571bb958dcfSRick Macklem if (nd->nd_repstat == 0) 5572bb958dcfSRick Macklem nd->nd_repstat = nfsvno_deallocate(vp, off, len, nd->nd_cred, 5573bb958dcfSRick Macklem curthread); 5574bb958dcfSRick Macklem vput(vp); 5575bb958dcfSRick Macklem NFSD_DEBUG(4, "eo deallocate=%d\n", nd->nd_repstat); 5576bb958dcfSRick Macklem NFSEXITCODE2(0, nd); 5577bb958dcfSRick Macklem return (0); 5578bb958dcfSRick Macklem nfsmout: 5579bb958dcfSRick Macklem vput(vp); 5580bb958dcfSRick Macklem NFSEXITCODE2(error, nd); 5581bb958dcfSRick Macklem return (error); 5582bb958dcfSRick Macklem } 5583bb958dcfSRick Macklem 5584bb958dcfSRick Macklem /* 5585c057a378SRick Macklem * nfs copy service 5586c057a378SRick Macklem */ 5587b9cc3262SRyan Moeller int 5588c057a378SRick Macklem nfsrvd_copy_file_range(struct nfsrv_descript *nd, __unused int isdgram, 5589c057a378SRick Macklem vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp) 5590c057a378SRick Macklem { 5591c057a378SRick Macklem uint32_t *tl; 5592c057a378SRick Macklem struct nfsvattr at; 5593c057a378SRick Macklem int cnt, error = 0, ret; 5594c057a378SRick Macklem off_t inoff, outoff; 5595c057a378SRick Macklem uint64_t len; 5596f1c8811dSRick Macklem size_t xfer; 5597c057a378SRick Macklem struct nfsstate inst, outst, *instp = &inst, *outstp = &outst; 5598c057a378SRick Macklem struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo; 5599c057a378SRick Macklem nfsquad_t clientid; 5600c057a378SRick Macklem nfsv4stateid_t stateid; 5601c057a378SRick Macklem nfsattrbit_t attrbits; 5602c057a378SRick Macklem void *rl_rcookie, *rl_wcookie; 5603c057a378SRick Macklem 5604c057a378SRick Macklem rl_rcookie = rl_wcookie = NULL; 5605748f56c5SRick Macklem if (nfsrv_maxcopyrange == 0 || nfsrv_devidcnt > 0) { 5606c057a378SRick Macklem /* 5607c057a378SRick Macklem * For a pNFS server, reply NFSERR_NOTSUPP so that the client 5608c057a378SRick Macklem * will do the copy via I/O on the DS(s). 5609748f56c5SRick Macklem * If vfs.nfsd.maxcopyrange set to 0, disable Copy. 5610c057a378SRick Macklem */ 5611c057a378SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 5612c057a378SRick Macklem goto nfsmout; 5613c057a378SRick Macklem } 5614c057a378SRick Macklem if (vp == tovp) { 5615c057a378SRick Macklem /* Copying a byte range within the same file is not allowed. */ 5616c057a378SRick Macklem nd->nd_repstat = NFSERR_INVAL; 5617c057a378SRick Macklem goto nfsmout; 5618c057a378SRick Macklem } 5619c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER + 5620c057a378SRick Macklem 3 * NFSX_UNSIGNED); 5621c057a378SRick Macklem instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS); 5622c057a378SRick Macklem inlop->lo_flags = NFSLCK_READ; 5623c057a378SRick Macklem instp->ls_ownerlen = 0; 5624c057a378SRick Macklem instp->ls_op = NULL; 5625c057a378SRick Macklem instp->ls_uid = nd->nd_cred->cr_uid; 5626c057a378SRick Macklem instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5627c057a378SRick Macklem clientid.lval[0] = instp->ls_stateid.other[0] = *tl++; 5628c057a378SRick Macklem clientid.lval[1] = instp->ls_stateid.other[1] = *tl++; 5629c057a378SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) 5630c057a378SRick Macklem clientid.qval = nd->nd_clientid.qval; 5631c057a378SRick Macklem instp->ls_stateid.other[2] = *tl++; 5632c057a378SRick Macklem outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 5633c057a378SRick Macklem outlop->lo_flags = NFSLCK_WRITE; 5634c057a378SRick Macklem outstp->ls_ownerlen = 0; 5635c057a378SRick Macklem outstp->ls_op = NULL; 5636c057a378SRick Macklem outstp->ls_uid = nd->nd_cred->cr_uid; 5637c057a378SRick Macklem outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5638c057a378SRick Macklem outstp->ls_stateid.other[0] = *tl++; 5639c057a378SRick Macklem outstp->ls_stateid.other[1] = *tl++; 5640c057a378SRick Macklem outstp->ls_stateid.other[2] = *tl++; 5641c057a378SRick Macklem inoff = fxdr_hyper(tl); tl += 2; 5642c057a378SRick Macklem inlop->lo_first = inoff; 5643c057a378SRick Macklem outoff = fxdr_hyper(tl); tl += 2; 5644c057a378SRick Macklem outlop->lo_first = outoff; 5645c057a378SRick Macklem len = fxdr_hyper(tl); tl += 2; 5646c057a378SRick Macklem if (len == 0) { 5647c057a378SRick Macklem /* len == 0 means to EOF. */ 5648c057a378SRick Macklem inlop->lo_end = OFF_MAX; 5649c057a378SRick Macklem outlop->lo_end = OFF_MAX; 5650c057a378SRick Macklem } else { 5651c057a378SRick Macklem inlop->lo_end = inlop->lo_first + len; 5652c057a378SRick Macklem outlop->lo_end = outlop->lo_first + len; 5653c057a378SRick Macklem } 5654c057a378SRick Macklem 5655c057a378SRick Macklem /* 5656c057a378SRick Macklem * At this time only consecutive, synchronous copy is supported, 5657c057a378SRick Macklem * so ca_consecutive and ca_synchronous can be ignored. 5658c057a378SRick Macklem */ 5659c057a378SRick Macklem tl += 2; 5660c057a378SRick Macklem 5661c057a378SRick Macklem cnt = fxdr_unsigned(int, *tl); 5662c057a378SRick Macklem if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0) 5663c057a378SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 5664c057a378SRick Macklem if (nd->nd_repstat == 0 && (inoff > OFF_MAX || outoff > OFF_MAX || 5665c057a378SRick Macklem inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX || 5666c057a378SRick Macklem inlop->lo_end < inlop->lo_first || outlop->lo_end < 5667c057a378SRick Macklem outlop->lo_first)) 5668c057a378SRick Macklem nd->nd_repstat = NFSERR_INVAL; 5669c057a378SRick Macklem 56705d3fe02cSRick Macklem if (nd->nd_repstat == 0 && vp->v_type != VREG) 5671c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGTYPE; 5672c057a378SRick Macklem 5673c057a378SRick Macklem /* Check permissions for the input file. */ 5674c057a378SRick Macklem NFSZERO_ATTRBIT(&attrbits); 5675c057a378SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5676c057a378SRick Macklem ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits); 5677c057a378SRick Macklem if (nd->nd_repstat == 0) 5678c057a378SRick Macklem nd->nd_repstat = ret; 5679c057a378SRick Macklem if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 5680c057a378SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) 5681c057a378SRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, 5682c057a378SRick Macklem curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5683c057a378SRick Macklem NULL); 5684c057a378SRick Macklem if (nd->nd_repstat == 0) 5685c057a378SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL, 5686c057a378SRick Macklem clientid, &stateid, exp, nd, curthread); 5687b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 5688c057a378SRick Macklem if (nd->nd_repstat != 0) 5689c057a378SRick Macklem goto out; 5690c057a378SRick Macklem 5691c057a378SRick Macklem error = NFSVOPLOCK(tovp, LK_SHARED); 5692c057a378SRick Macklem if (error != 0) 5693c057a378SRick Macklem goto out; 56945d3fe02cSRick Macklem if (tovp->v_type != VREG) 5695c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGTYPE; 5696c057a378SRick Macklem 5697c057a378SRick Macklem /* For the output file, we only need the Owner attribute. */ 5698c057a378SRick Macklem ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits); 5699c057a378SRick Macklem if (nd->nd_repstat == 0) 5700c057a378SRick Macklem nd->nd_repstat = ret; 5701c057a378SRick Macklem if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 5702c057a378SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) 5703c057a378SRick Macklem nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp, 5704c057a378SRick Macklem curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5705c057a378SRick Macklem NULL); 5706c057a378SRick Macklem if (nd->nd_repstat == 0) 5707c057a378SRick Macklem nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL, 5708c057a378SRick Macklem clientid, &stateid, toexp, nd, curthread); 5709b249ce48SMateusz Guzik NFSVOPUNLOCK(tovp); 5710c057a378SRick Macklem 5711c057a378SRick Macklem /* Range lock the byte ranges for both invp and outvp. */ 5712c057a378SRick Macklem if (nd->nd_repstat == 0) { 5713c057a378SRick Macklem for (;;) { 5714c057a378SRick Macklem if (len == 0) { 5715c057a378SRick Macklem rl_wcookie = vn_rangelock_wlock(tovp, outoff, 5716c057a378SRick Macklem OFF_MAX); 5717c057a378SRick Macklem rl_rcookie = vn_rangelock_tryrlock(vp, inoff, 5718c057a378SRick Macklem OFF_MAX); 5719c057a378SRick Macklem } else { 5720c057a378SRick Macklem rl_wcookie = vn_rangelock_wlock(tovp, outoff, 5721c057a378SRick Macklem outoff + len); 5722c057a378SRick Macklem rl_rcookie = vn_rangelock_tryrlock(vp, inoff, 5723c057a378SRick Macklem inoff + len); 5724c057a378SRick Macklem } 5725c057a378SRick Macklem if (rl_rcookie != NULL) 5726c057a378SRick Macklem break; 5727c057a378SRick Macklem vn_rangelock_unlock(tovp, rl_wcookie); 5728c057a378SRick Macklem if (len == 0) 5729c057a378SRick Macklem rl_rcookie = vn_rangelock_rlock(vp, inoff, 5730c057a378SRick Macklem OFF_MAX); 5731c057a378SRick Macklem else 5732c057a378SRick Macklem rl_rcookie = vn_rangelock_rlock(vp, inoff, 5733c057a378SRick Macklem inoff + len); 5734c057a378SRick Macklem vn_rangelock_unlock(vp, rl_rcookie); 5735c057a378SRick Macklem } 5736c057a378SRick Macklem 5737c057a378SRick Macklem error = NFSVOPLOCK(vp, LK_SHARED); 5738c057a378SRick Macklem if (error == 0) { 5739c057a378SRick Macklem ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL); 5740c057a378SRick Macklem if (ret == 0) { 5741c057a378SRick Macklem /* 5742c057a378SRick Macklem * Since invp is range locked, na_size should 5743c057a378SRick Macklem * not change. 5744c057a378SRick Macklem */ 5745c057a378SRick Macklem if (len == 0 && at.na_size > inoff) { 5746c057a378SRick Macklem /* 5747c057a378SRick Macklem * If len == 0, set it based on invp's 5748c057a378SRick Macklem * size. If offset is past EOF, just 5749c057a378SRick Macklem * leave len == 0. 5750c057a378SRick Macklem */ 5751c057a378SRick Macklem len = at.na_size - inoff; 5752c057a378SRick Macklem } else if (nfsrv_linux42server == 0 && 5753c057a378SRick Macklem inoff + len > at.na_size) { 5754c057a378SRick Macklem /* 5755c057a378SRick Macklem * RFC-7862 says that NFSERR_INVAL must 5756c057a378SRick Macklem * be returned when inoff + len exceeds 5757c057a378SRick Macklem * the file size, however the NFSv4.2 5758c057a378SRick Macklem * Linux client likes to do this, so 5759c057a378SRick Macklem * only check if nfsrv_linux42server 5760c057a378SRick Macklem * is not set. 5761c057a378SRick Macklem */ 5762c057a378SRick Macklem nd->nd_repstat = NFSERR_INVAL; 5763c057a378SRick Macklem } 5764c057a378SRick Macklem } 5765b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 5766c057a378SRick Macklem if (ret != 0 && nd->nd_repstat == 0) 5767c057a378SRick Macklem nd->nd_repstat = ret; 5768c057a378SRick Macklem } else if (nd->nd_repstat == 0) 5769c057a378SRick Macklem nd->nd_repstat = error; 5770c057a378SRick Macklem } 5771c057a378SRick Macklem 5772748f56c5SRick Macklem /* 5773748f56c5SRick Macklem * Do the actual copy to an upper limit of vfs.nfsd.maxcopyrange. 5774748f56c5SRick Macklem * This size limit can be set to limit the time a copy RPC will 5775748f56c5SRick Macklem * take. 5776748f56c5SRick Macklem */ 5777748f56c5SRick Macklem if (len > nfsrv_maxcopyrange) 5778748f56c5SRick Macklem xfer = nfsrv_maxcopyrange; 5779748f56c5SRick Macklem else 5780f1c8811dSRick Macklem xfer = len; 5781f1c8811dSRick Macklem if (nd->nd_repstat == 0) { 5782103b2075SRick Macklem nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff, 5783f1c8811dSRick Macklem &xfer, COPY_FILE_RANGE_TIMEO1SEC, nd->nd_cred, nd->nd_cred, 5784103b2075SRick Macklem NULL); 5785f1c8811dSRick Macklem if (nd->nd_repstat == 0) 5786f1c8811dSRick Macklem len = xfer; 5787f1c8811dSRick Macklem } 5788c057a378SRick Macklem 5789c057a378SRick Macklem /* Unlock the ranges. */ 5790c057a378SRick Macklem if (rl_rcookie != NULL) 5791c057a378SRick Macklem vn_rangelock_unlock(vp, rl_rcookie); 5792c057a378SRick Macklem if (rl_wcookie != NULL) 5793c057a378SRick Macklem vn_rangelock_unlock(tovp, rl_wcookie); 5794c057a378SRick Macklem 5795c057a378SRick Macklem if (nd->nd_repstat == 0) { 5796c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER + 5797c057a378SRick Macklem NFSX_VERF); 5798c057a378SRick Macklem *tl++ = txdr_unsigned(0); /* No callback ids. */ 5799c057a378SRick Macklem txdr_hyper(len, tl); tl += 2; 5800c057a378SRick Macklem *tl++ = txdr_unsigned(NFSWRITE_UNSTABLE); 5801c057a378SRick Macklem *tl++ = txdr_unsigned(nfsboottime.tv_sec); 5802c057a378SRick Macklem *tl++ = txdr_unsigned(nfsboottime.tv_usec); 5803c057a378SRick Macklem *tl++ = newnfs_true; 5804c057a378SRick Macklem *tl = newnfs_true; 5805c057a378SRick Macklem } 5806c057a378SRick Macklem out: 5807c057a378SRick Macklem vrele(vp); 5808c057a378SRick Macklem vrele(tovp); 5809c057a378SRick Macklem NFSEXITCODE2(error, nd); 5810c057a378SRick Macklem return (error); 5811c057a378SRick Macklem nfsmout: 5812c057a378SRick Macklem vput(vp); 5813c057a378SRick Macklem vrele(tovp); 5814c057a378SRick Macklem NFSEXITCODE2(error, nd); 5815c057a378SRick Macklem return (error); 5816c057a378SRick Macklem } 5817c057a378SRick Macklem 5818c057a378SRick Macklem /* 5819c057a378SRick Macklem * nfs seek service 5820c057a378SRick Macklem */ 5821b9cc3262SRyan Moeller int 5822c057a378SRick Macklem nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram, 5823c057a378SRick Macklem vnode_t vp, struct nfsexstuff *exp) 5824c057a378SRick Macklem { 5825c057a378SRick Macklem uint32_t *tl; 5826c057a378SRick Macklem struct nfsvattr at; 5827c057a378SRick Macklem int content, error = 0; 5828c057a378SRick Macklem off_t off; 5829c057a378SRick Macklem u_long cmd; 5830c057a378SRick Macklem nfsattrbit_t attrbits; 5831c057a378SRick Macklem bool eof; 5832c057a378SRick Macklem 5833c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED); 5834c057a378SRick Macklem /* Ignore the stateid for now. */ 5835c057a378SRick Macklem tl += (NFSX_STATEID / NFSX_UNSIGNED); 5836c057a378SRick Macklem off = fxdr_hyper(tl); tl += 2; 5837c057a378SRick Macklem content = fxdr_unsigned(int, *tl); 5838c057a378SRick Macklem if (content == NFSV4CONTENT_DATA) 5839c057a378SRick Macklem cmd = FIOSEEKDATA; 5840c057a378SRick Macklem else if (content == NFSV4CONTENT_HOLE) 5841c057a378SRick Macklem cmd = FIOSEEKHOLE; 5842c057a378SRick Macklem else 5843c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 58445d3fe02cSRick Macklem if (nd->nd_repstat == 0 && vp->v_type == VDIR) 5845c057a378SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 58465d3fe02cSRick Macklem if (nd->nd_repstat == 0 && vp->v_type != VREG) 5847c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGTYPE; 5848c057a378SRick Macklem if (nd->nd_repstat == 0 && off < 0) 5849c057a378SRick Macklem nd->nd_repstat = NFSERR_NXIO; 5850c057a378SRick Macklem if (nd->nd_repstat == 0) { 5851c057a378SRick Macklem /* Check permissions for the input file. */ 5852c057a378SRick Macklem NFSZERO_ATTRBIT(&attrbits); 5853c057a378SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5854c057a378SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1, 5855c057a378SRick Macklem &attrbits); 5856c057a378SRick Macklem } 5857c057a378SRick Macklem if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 5858c057a378SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) 5859c057a378SRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, 5860c057a378SRick Macklem curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5861c057a378SRick Macklem NULL); 5862c057a378SRick Macklem if (nd->nd_repstat != 0) 5863c057a378SRick Macklem goto nfsmout; 5864c057a378SRick Macklem 5865c057a378SRick Macklem /* nfsvno_seek() unlocks and vrele()s the vp. */ 5866c057a378SRick Macklem nd->nd_repstat = nfsvno_seek(nd, vp, cmd, &off, content, &eof, 5867c057a378SRick Macklem nd->nd_cred, curthread); 5868c057a378SRick Macklem if (nd->nd_repstat == 0 && eof && content == NFSV4CONTENT_DATA && 5869c057a378SRick Macklem nfsrv_linux42server != 0) 5870c057a378SRick Macklem nd->nd_repstat = NFSERR_NXIO; 5871c057a378SRick Macklem if (nd->nd_repstat == 0) { 5872c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); 5873c057a378SRick Macklem if (eof) 5874c057a378SRick Macklem *tl++ = newnfs_true; 5875c057a378SRick Macklem else 5876c057a378SRick Macklem *tl++ = newnfs_false; 5877c057a378SRick Macklem txdr_hyper(off, tl); 5878c057a378SRick Macklem } 5879c057a378SRick Macklem NFSEXITCODE2(error, nd); 5880c057a378SRick Macklem return (error); 5881c057a378SRick Macklem nfsmout: 5882c057a378SRick Macklem vput(vp); 5883c057a378SRick Macklem NFSEXITCODE2(error, nd); 5884c057a378SRick Macklem return (error); 5885c057a378SRick Macklem } 5886c057a378SRick Macklem 5887c057a378SRick Macklem /* 5888c057a378SRick Macklem * nfs get extended attribute service 5889c057a378SRick Macklem */ 5890b9cc3262SRyan Moeller int 5891c057a378SRick Macklem nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram, 5892c057a378SRick Macklem vnode_t vp, __unused struct nfsexstuff *exp) 5893c057a378SRick Macklem { 5894c057a378SRick Macklem uint32_t *tl; 5895ae070589SRick Macklem struct mbuf *mp = NULL, *mpend = NULL; 5896c057a378SRick Macklem int error, len; 5897c057a378SRick Macklem char *name; 5898c057a378SRick Macklem struct thread *p = curthread; 5899cb889ce6SRick Macklem uint16_t off; 5900c057a378SRick Macklem 5901c057a378SRick Macklem error = 0; 5902c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5903c057a378SRick Macklem len = fxdr_unsigned(int, *tl); 5904c057a378SRick Macklem if (len <= 0) { 5905c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 5906c057a378SRick Macklem goto nfsmout; 5907c057a378SRick Macklem } 5908c057a378SRick Macklem if (len > EXTATTR_MAXNAMELEN) { 5909c057a378SRick Macklem nd->nd_repstat = NFSERR_NOXATTR; 5910c057a378SRick Macklem goto nfsmout; 5911c057a378SRick Macklem } 5912c057a378SRick Macklem name = malloc(len + 1, M_TEMP, M_WAITOK); 5913c057a378SRick Macklem nd->nd_repstat = nfsrv_mtostr(nd, name, len); 5914c057a378SRick Macklem if (nd->nd_repstat == 0) 5915cb889ce6SRick Macklem nd->nd_repstat = nfsvno_getxattr(vp, name, 5916cb889ce6SRick Macklem nd->nd_maxresp, nd->nd_cred, nd->nd_flag, 5917cb889ce6SRick Macklem nd->nd_maxextsiz, p, &mp, &mpend, &len); 5918c057a378SRick Macklem if (nd->nd_repstat == ENOATTR) 5919c057a378SRick Macklem nd->nd_repstat = NFSERR_NOXATTR; 5920c057a378SRick Macklem else if (nd->nd_repstat == EOPNOTSUPP) 5921c057a378SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 5922c057a378SRick Macklem if (nd->nd_repstat == 0) { 5923c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5924c057a378SRick Macklem *tl = txdr_unsigned(len); 5925fb8ed4c5SRick Macklem if (len > 0) { 59269f6624d3SRick Macklem nd->nd_mb->m_next = mp; 5927c057a378SRick Macklem nd->nd_mb = mpend; 5928cb889ce6SRick Macklem if ((mpend->m_flags & M_EXTPG) != 0) { 5929cb889ce6SRick Macklem nd->nd_flag |= ND_EXTPG; 5930cb889ce6SRick Macklem nd->nd_bextpg = mpend->m_epg_npgs - 1; 5931cb889ce6SRick Macklem nd->nd_bpos = (char *)(void *) 5932cb889ce6SRick Macklem PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]); 5933cb889ce6SRick Macklem off = (nd->nd_bextpg == 0) ? 5934cb889ce6SRick Macklem mpend->m_epg_1st_off : 0; 5935cb889ce6SRick Macklem nd->nd_bpos += off + mpend->m_epg_last_len; 5936cb889ce6SRick Macklem nd->nd_bextpgsiz = PAGE_SIZE - 5937cb889ce6SRick Macklem mpend->m_epg_last_len - off; 5938cb889ce6SRick Macklem } else 5939cb889ce6SRick Macklem nd->nd_bpos = mtod(mpend, char *) + 5940cb889ce6SRick Macklem mpend->m_len; 5941c057a378SRick Macklem } 5942fb8ed4c5SRick Macklem } 5943c057a378SRick Macklem free(name, M_TEMP); 5944c057a378SRick Macklem 5945c057a378SRick Macklem nfsmout: 5946c057a378SRick Macklem if (nd->nd_repstat == 0) 5947c057a378SRick Macklem nd->nd_repstat = error; 5948c057a378SRick Macklem vput(vp); 5949c057a378SRick Macklem NFSEXITCODE2(0, nd); 5950c057a378SRick Macklem return (0); 5951c057a378SRick Macklem } 5952c057a378SRick Macklem 5953c057a378SRick Macklem /* 5954c057a378SRick Macklem * nfs set extended attribute service 5955c057a378SRick Macklem */ 5956b9cc3262SRyan Moeller int 5957c057a378SRick Macklem nfsrvd_setxattr(struct nfsrv_descript *nd, __unused int isdgram, 5958c057a378SRick Macklem vnode_t vp, __unused struct nfsexstuff *exp) 5959c057a378SRick Macklem { 5960c057a378SRick Macklem uint32_t *tl; 5961c057a378SRick Macklem struct nfsvattr ova, nva; 5962c057a378SRick Macklem nfsattrbit_t attrbits; 5963c057a378SRick Macklem int error, len, opt; 5964c057a378SRick Macklem char *name; 5965c057a378SRick Macklem size_t siz; 5966c057a378SRick Macklem struct thread *p = curthread; 5967c057a378SRick Macklem 5968c057a378SRick Macklem error = 0; 5969c057a378SRick Macklem name = NULL; 5970c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5971c057a378SRick Macklem opt = fxdr_unsigned(int, *tl++); 5972c057a378SRick Macklem len = fxdr_unsigned(int, *tl); 5973c057a378SRick Macklem if (len <= 0) { 5974c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 5975c057a378SRick Macklem goto nfsmout; 5976c057a378SRick Macklem } 5977c057a378SRick Macklem if (len > EXTATTR_MAXNAMELEN) { 5978c057a378SRick Macklem nd->nd_repstat = NFSERR_NOXATTR; 5979c057a378SRick Macklem goto nfsmout; 5980c057a378SRick Macklem } 5981c057a378SRick Macklem name = malloc(len + 1, M_TEMP, M_WAITOK); 5982c057a378SRick Macklem error = nfsrv_mtostr(nd, name, len); 5983c057a378SRick Macklem if (error != 0) 5984c057a378SRick Macklem goto nfsmout; 5985c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5986c057a378SRick Macklem len = fxdr_unsigned(int, *tl); 5987fb8ed4c5SRick Macklem if (len < 0 || len > IOSIZE_MAX) { 5988c057a378SRick Macklem nd->nd_repstat = NFSERR_XATTR2BIG; 5989c057a378SRick Macklem goto nfsmout; 5990c057a378SRick Macklem } 5991c057a378SRick Macklem switch (opt) { 5992c057a378SRick Macklem case NFSV4SXATTR_CREATE: 5993c057a378SRick Macklem error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL, 5994c057a378SRick Macklem &siz, nd->nd_cred, p); 5995c057a378SRick Macklem if (error != ENOATTR) 5996c057a378SRick Macklem nd->nd_repstat = NFSERR_EXIST; 5997c057a378SRick Macklem error = 0; 5998c057a378SRick Macklem break; 5999c057a378SRick Macklem case NFSV4SXATTR_REPLACE: 6000c057a378SRick Macklem error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL, 6001c057a378SRick Macklem &siz, nd->nd_cred, p); 6002c057a378SRick Macklem if (error != 0) 6003c057a378SRick Macklem nd->nd_repstat = NFSERR_NOXATTR; 6004c057a378SRick Macklem break; 6005c057a378SRick Macklem case NFSV4SXATTR_EITHER: 6006c057a378SRick Macklem break; 6007c057a378SRick Macklem default: 6008c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 6009c057a378SRick Macklem } 6010c057a378SRick Macklem if (nd->nd_repstat != 0) 6011c057a378SRick Macklem goto nfsmout; 6012c057a378SRick Macklem 6013c057a378SRick Macklem /* Now, do the Set Extended attribute, with Change before and after. */ 6014c057a378SRick Macklem NFSZERO_ATTRBIT(&attrbits); 6015c057a378SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 6016c057a378SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits); 6017c057a378SRick Macklem if (nd->nd_repstat == 0) { 6018c057a378SRick Macklem nd->nd_repstat = nfsvno_setxattr(vp, name, len, nd->nd_md, 6019c057a378SRick Macklem nd->nd_dpos, nd->nd_cred, p); 6020c057a378SRick Macklem if (nd->nd_repstat == ENXIO) 6021c057a378SRick Macklem nd->nd_repstat = NFSERR_XATTR2BIG; 6022c057a378SRick Macklem } 6023fb8ed4c5SRick Macklem if (nd->nd_repstat == 0 && len > 0) 6024c057a378SRick Macklem nd->nd_repstat = nfsm_advance(nd, NFSM_RNDUP(len), -1); 6025c057a378SRick Macklem if (nd->nd_repstat == 0) 6026c057a378SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); 6027c057a378SRick Macklem if (nd->nd_repstat == 0) { 6028c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); 6029c057a378SRick Macklem *tl++ = newnfs_true; 6030c057a378SRick Macklem txdr_hyper(ova.na_filerev, tl); tl += 2; 6031c057a378SRick Macklem txdr_hyper(nva.na_filerev, tl); 6032c057a378SRick Macklem } 6033c057a378SRick Macklem 6034c057a378SRick Macklem nfsmout: 6035c057a378SRick Macklem free(name, M_TEMP); 6036c057a378SRick Macklem if (nd->nd_repstat == 0) 6037c057a378SRick Macklem nd->nd_repstat = error; 6038c057a378SRick Macklem vput(vp); 6039c057a378SRick Macklem NFSEXITCODE2(0, nd); 6040c057a378SRick Macklem return (0); 6041c057a378SRick Macklem } 6042c057a378SRick Macklem 6043c057a378SRick Macklem /* 6044c057a378SRick Macklem * nfs remove extended attribute service 6045c057a378SRick Macklem */ 6046b9cc3262SRyan Moeller int 6047c057a378SRick Macklem nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int isdgram, 6048c057a378SRick Macklem vnode_t vp, __unused struct nfsexstuff *exp) 6049c057a378SRick Macklem { 6050c057a378SRick Macklem uint32_t *tl; 6051c057a378SRick Macklem struct nfsvattr ova, nva; 6052c057a378SRick Macklem nfsattrbit_t attrbits; 6053c057a378SRick Macklem int error, len; 6054c057a378SRick Macklem char *name; 6055c057a378SRick Macklem struct thread *p = curthread; 6056c057a378SRick Macklem 6057c057a378SRick Macklem error = 0; 6058c057a378SRick Macklem name = NULL; 6059c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 6060c057a378SRick Macklem len = fxdr_unsigned(int, *tl); 6061c057a378SRick Macklem if (len <= 0) { 6062c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 6063c057a378SRick Macklem goto nfsmout; 6064c057a378SRick Macklem } 6065c057a378SRick Macklem if (len > EXTATTR_MAXNAMELEN) { 6066c057a378SRick Macklem nd->nd_repstat = NFSERR_NOXATTR; 6067c057a378SRick Macklem goto nfsmout; 6068c057a378SRick Macklem } 6069c057a378SRick Macklem name = malloc(len + 1, M_TEMP, M_WAITOK); 6070c057a378SRick Macklem error = nfsrv_mtostr(nd, name, len); 6071c057a378SRick Macklem if (error != 0) 6072c057a378SRick Macklem goto nfsmout; 6073c057a378SRick Macklem 6074c057a378SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) == 0) { 6075c057a378SRick Macklem printf("EEK! nfsrvd_rmxattr: no implied clientid\n"); 6076c057a378SRick Macklem error = NFSERR_NOXATTR; 6077c057a378SRick Macklem goto nfsmout; 6078c057a378SRick Macklem } 6079c057a378SRick Macklem /* 6080c057a378SRick Macklem * Now, do the Remove Extended attribute, with Change before and 6081c057a378SRick Macklem * after. 6082c057a378SRick Macklem */ 6083c057a378SRick Macklem NFSZERO_ATTRBIT(&attrbits); 6084c057a378SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 6085c057a378SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits); 6086c057a378SRick Macklem if (nd->nd_repstat == 0) { 6087c057a378SRick Macklem nd->nd_repstat = nfsvno_rmxattr(nd, vp, name, nd->nd_cred, p); 6088c057a378SRick Macklem if (nd->nd_repstat == ENOATTR) 6089c057a378SRick Macklem nd->nd_repstat = NFSERR_NOXATTR; 6090c057a378SRick Macklem } 6091c057a378SRick Macklem if (nd->nd_repstat == 0) 6092c057a378SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); 6093c057a378SRick Macklem if (nd->nd_repstat == 0) { 60940bda1dddSRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); 60950bda1dddSRick Macklem *tl++ = newnfs_true; 6096c057a378SRick Macklem txdr_hyper(ova.na_filerev, tl); tl += 2; 6097c057a378SRick Macklem txdr_hyper(nva.na_filerev, tl); 6098c057a378SRick Macklem } 6099c057a378SRick Macklem 6100c057a378SRick Macklem nfsmout: 6101c057a378SRick Macklem free(name, M_TEMP); 6102c057a378SRick Macklem if (nd->nd_repstat == 0) 6103c057a378SRick Macklem nd->nd_repstat = error; 6104c057a378SRick Macklem vput(vp); 6105c057a378SRick Macklem NFSEXITCODE2(0, nd); 6106c057a378SRick Macklem return (0); 6107c057a378SRick Macklem } 6108c057a378SRick Macklem 6109c057a378SRick Macklem /* 6110c057a378SRick Macklem * nfs list extended attribute service 6111c057a378SRick Macklem */ 6112b9cc3262SRyan Moeller int 6113c057a378SRick Macklem nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram, 6114c057a378SRick Macklem vnode_t vp, __unused struct nfsexstuff *exp) 6115c057a378SRick Macklem { 6116c057a378SRick Macklem uint32_t cnt, *tl, len, len2, i, pos, retlen; 6117c057a378SRick Macklem int error; 6118c057a378SRick Macklem uint64_t cookie, cookie2; 6119c057a378SRick Macklem u_char *buf; 6120c057a378SRick Macklem bool eof; 6121c057a378SRick Macklem struct thread *p = curthread; 6122c057a378SRick Macklem 6123c057a378SRick Macklem error = 0; 6124c057a378SRick Macklem buf = NULL; 6125c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 6126c057a378SRick Macklem /* 6127c057a378SRick Macklem * The cookie doesn't need to be in net byte order, but FreeBSD 6128c057a378SRick Macklem * does so to make it more readable in packet traces. 6129c057a378SRick Macklem */ 6130c057a378SRick Macklem cookie = fxdr_hyper(tl); tl += 2; 6131c057a378SRick Macklem len = fxdr_unsigned(uint32_t, *tl); 6132c057a378SRick Macklem if (len == 0 || cookie >= IOSIZE_MAX) { 6133c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 6134c057a378SRick Macklem goto nfsmout; 6135c057a378SRick Macklem } 6136c057a378SRick Macklem if (len > nd->nd_maxresp - NFS_MAXXDR) 6137c057a378SRick Macklem len = nd->nd_maxresp - NFS_MAXXDR; 6138c057a378SRick Macklem len2 = len; 6139c057a378SRick Macklem nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf, 6140c057a378SRick Macklem &len, &eof); 6141c057a378SRick Macklem if (nd->nd_repstat == EOPNOTSUPP) 6142c057a378SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 6143c057a378SRick Macklem if (nd->nd_repstat == 0) { 6144c057a378SRick Macklem cookie2 = cookie + len; 6145c057a378SRick Macklem if (cookie2 < cookie) 6146c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 6147c057a378SRick Macklem } 61485b430a13SRick Macklem retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED; 61495b430a13SRick Macklem if (nd->nd_repstat == 0 && len2 < retlen) 61505b430a13SRick Macklem nd->nd_repstat = NFSERR_TOOSMALL; 6151c057a378SRick Macklem if (nd->nd_repstat == 0) { 6152c057a378SRick Macklem /* Now copy the entries out. */ 61535b430a13SRick Macklem if (len == 0) { 6154c057a378SRick Macklem /* The cookie was at eof. */ 6155c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * 6156c057a378SRick Macklem NFSX_UNSIGNED); 6157c057a378SRick Macklem txdr_hyper(cookie2, tl); tl += 2; 6158c057a378SRick Macklem *tl++ = txdr_unsigned(0); 6159c057a378SRick Macklem *tl = newnfs_true; 6160c057a378SRick Macklem goto nfsmout; 6161c057a378SRick Macklem } 6162c057a378SRick Macklem 6163c057a378SRick Macklem /* Sanity check the cookie. */ 6164c057a378SRick Macklem for (pos = 0; pos < len; pos += (i + 1)) { 6165c057a378SRick Macklem if (pos == cookie) 6166c057a378SRick Macklem break; 6167c057a378SRick Macklem i = buf[pos]; 6168c057a378SRick Macklem } 6169c057a378SRick Macklem if (pos != cookie) { 6170c057a378SRick Macklem nd->nd_repstat = NFSERR_INVAL; 6171c057a378SRick Macklem goto nfsmout; 6172c057a378SRick Macklem } 6173c057a378SRick Macklem 6174c057a378SRick Macklem /* Loop around copying the entrie(s) out. */ 6175c057a378SRick Macklem cnt = 0; 6176c057a378SRick Macklem len -= cookie; 6177c057a378SRick Macklem i = buf[pos]; 6178c057a378SRick Macklem while (i < len && len2 >= retlen + NFSM_RNDUP(i) + 6179c057a378SRick Macklem NFSX_UNSIGNED) { 6180c057a378SRick Macklem if (cnt == 0) { 6181c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 6182c057a378SRick Macklem NFSX_UNSIGNED); 6183c057a378SRick Macklem txdr_hyper(cookie2, tl); tl += 2; 6184c057a378SRick Macklem } 6185c057a378SRick Macklem retlen += nfsm_strtom(nd, &buf[pos + 1], i); 6186c057a378SRick Macklem len -= (i + 1); 6187c057a378SRick Macklem pos += (i + 1); 6188c057a378SRick Macklem i = buf[pos]; 6189c057a378SRick Macklem cnt++; 6190c057a378SRick Macklem } 6191c057a378SRick Macklem /* 6192c057a378SRick Macklem * eof is set true/false by nfsvno_listxattr(), but if we 6193c057a378SRick Macklem * can't copy all entries returned by nfsvno_listxattr(), 6194c057a378SRick Macklem * we are not at eof. 6195c057a378SRick Macklem */ 6196c057a378SRick Macklem if (len > 0) 6197c057a378SRick Macklem eof = false; 6198c057a378SRick Macklem if (cnt > 0) { 6199c057a378SRick Macklem /* *tl is set above. */ 6200c057a378SRick Macklem *tl = txdr_unsigned(cnt); 6201c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 6202c057a378SRick Macklem if (eof) 6203c057a378SRick Macklem *tl = newnfs_true; 6204c057a378SRick Macklem else 6205c057a378SRick Macklem *tl = newnfs_false; 6206c057a378SRick Macklem } else 6207c057a378SRick Macklem nd->nd_repstat = NFSERR_TOOSMALL; 6208c057a378SRick Macklem } 6209c057a378SRick Macklem 6210c057a378SRick Macklem nfsmout: 6211c057a378SRick Macklem free(buf, M_TEMP); 6212c057a378SRick Macklem if (nd->nd_repstat == 0) 6213c057a378SRick Macklem nd->nd_repstat = error; 6214c057a378SRick Macklem vput(vp); 6215c057a378SRick Macklem NFSEXITCODE2(0, nd); 6216c057a378SRick Macklem return (0); 6217c057a378SRick Macklem } 6218c057a378SRick Macklem 6219c057a378SRick Macklem /* 6220c59e4cc3SRick Macklem * nfsv4 service not supported 6221c59e4cc3SRick Macklem */ 6222b9cc3262SRyan Moeller int 6223c59e4cc3SRick Macklem nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram, 6224af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 6225c59e4cc3SRick Macklem { 6226c59e4cc3SRick Macklem 6227c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 6228c59e4cc3SRick Macklem NFSEXITCODE2(0, nd); 6229c59e4cc3SRick Macklem return (0); 6230c59e4cc3SRick Macklem } 6231