19ec7b004SRick Macklem /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 49ec7b004SRick Macklem * Copyright (c) 1989, 1993 59ec7b004SRick Macklem * The Regents of the University of California. All rights reserved. 69ec7b004SRick Macklem * 79ec7b004SRick Macklem * This code is derived from software contributed to Berkeley by 89ec7b004SRick Macklem * Rick Macklem at The University of Guelph. 99ec7b004SRick Macklem * 109ec7b004SRick Macklem * Redistribution and use in source and binary forms, with or without 119ec7b004SRick Macklem * modification, are permitted provided that the following conditions 129ec7b004SRick Macklem * are met: 139ec7b004SRick Macklem * 1. Redistributions of source code must retain the above copyright 149ec7b004SRick Macklem * notice, this list of conditions and the following disclaimer. 159ec7b004SRick Macklem * 2. Redistributions in binary form must reproduce the above copyright 169ec7b004SRick Macklem * notice, this list of conditions and the following disclaimer in the 179ec7b004SRick Macklem * documentation and/or other materials provided with the distribution. 18fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 199ec7b004SRick Macklem * may be used to endorse or promote products derived from this software 209ec7b004SRick Macklem * without specific prior written permission. 219ec7b004SRick Macklem * 229ec7b004SRick Macklem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 239ec7b004SRick Macklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 249ec7b004SRick Macklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 259ec7b004SRick Macklem * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 269ec7b004SRick Macklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 279ec7b004SRick Macklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 289ec7b004SRick Macklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 299ec7b004SRick Macklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 309ec7b004SRick Macklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 319ec7b004SRick Macklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 329ec7b004SRick Macklem * SUCH DAMAGE. 339ec7b004SRick Macklem * 349ec7b004SRick Macklem */ 359ec7b004SRick Macklem 369ec7b004SRick Macklem #include <sys/cdefs.h> 379ec7b004SRick Macklem __FBSDID("$FreeBSD$"); 389ec7b004SRick Macklem 39ed2f1001SRick Macklem #include "opt_inet.h" 40ed2f1001SRick Macklem #include "opt_inet6.h" 419ec7b004SRick Macklem /* 429ec7b004SRick Macklem * nfs version 2, 3 and 4 server calls to vnode ops 439ec7b004SRick Macklem * - these routines generally have 3 phases 449ec7b004SRick Macklem * 1 - break down and validate rpc request in mbuf list 459ec7b004SRick Macklem * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX() 469ec7b004SRick Macklem * function in nfsd_port.c 479ec7b004SRick Macklem * 3 - build the rpc reply in an mbuf list 489ec7b004SRick Macklem * For nfsv4, these functions are called for each Op within the Compound RPC. 499ec7b004SRick Macklem */ 509ec7b004SRick Macklem 519ec7b004SRick Macklem #include <fs/nfs/nfsport.h> 52c057a378SRick Macklem #include <sys/extattr.h> 53c057a378SRick Macklem #include <sys/filio.h> 549ec7b004SRick Macklem 559ec7b004SRick Macklem /* Global vars */ 569ec7b004SRick Macklem extern u_int32_t newnfs_false, newnfs_true; 579ec7b004SRick Macklem extern enum vtype nv34tov_type[8]; 589ec7b004SRick Macklem extern struct timeval nfsboottime; 5907c0c166SRick Macklem extern int nfsrv_enable_crossmntpt; 601f54e596SRick Macklem extern int nfsrv_statehashsize; 6190d2dfabSRick Macklem extern int nfsrv_layouthashsize; 6290d2dfabSRick Macklem extern time_t nfsdev_time; 6390d2dfabSRick Macklem extern volatile int nfsrv_devidcnt; 6490d2dfabSRick Macklem extern int nfsd_debuglevel; 6590d2dfabSRick Macklem extern u_long sb_max_adj; 6690d2dfabSRick Macklem extern int nfsrv_pnfsatime; 6790d2dfabSRick Macklem extern int nfsrv_maxpnfsmirror; 68c057a378SRick Macklem extern int nfs_maxcopyrange; 699ec7b004SRick Macklem 70e4558aacSXin LI static int nfs_async = 0; 71e4558aacSXin LI SYSCTL_DECL(_vfs_nfsd); 72e4558aacSXin LI SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0, 73e4558aacSXin LI "Tell client that writes were synced even though they were not"); 7490d2dfabSRick Macklem extern int nfsrv_doflexfile; 7590d2dfabSRick Macklem SYSCTL_INT(_vfs_nfsd, OID_AUTO, default_flexfile, CTLFLAG_RW, 7690d2dfabSRick Macklem &nfsrv_doflexfile, 0, "Make Flex File Layout the default for pNFS"); 77c057a378SRick Macklem static int nfsrv_linux42server = 1; 78c057a378SRick Macklem SYSCTL_INT(_vfs_nfsd, OID_AUTO, linux42server, CTLFLAG_RW, 79c057a378SRick Macklem &nfsrv_linux42server, 0, 80c057a378SRick Macklem "Enable Linux style NFSv4.2 server (non-RFC compliant)"); 81b0b7d978SRick Macklem static bool nfsrv_openaccess = true; 82b0b7d978SRick Macklem SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, v4openaccess, CTLFLAG_RW, 83b0b7d978SRick Macklem &nfsrv_openaccess, 0, 84b0b7d978SRick Macklem "Enable Linux style NFSv4 Open access check"); 85e4558aacSXin LI 869ec7b004SRick Macklem /* 879ec7b004SRick Macklem * This list defines the GSS mechanisms supported. 889ec7b004SRick Macklem * (Don't ask me how you get these strings from the RFC stuff like 899ec7b004SRick Macklem * iso(1), org(3)... but someone did it, so I don't need to know.) 909ec7b004SRick Macklem */ 919ec7b004SRick Macklem static struct nfsgss_mechlist nfsgss_mechlist[] = { 929ec7b004SRick Macklem { 9, "\052\206\110\206\367\022\001\002\002", 11 }, 939ec7b004SRick Macklem { 0, "", 0 }, 949ec7b004SRick Macklem }; 959ec7b004SRick Macklem 969ec7b004SRick Macklem /* local functions */ 979ec7b004SRick Macklem static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 989ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 999ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 1009ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, 1019ec7b004SRick Macklem NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 1029ec7b004SRick Macklem int pathlen); 1039ec7b004SRick Macklem static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 1049ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 1059ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 1069ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 1079ec7b004SRick Macklem NFSPROC_T *p, struct nfsexstuff *exp); 1089ec7b004SRick Macklem 1099ec7b004SRick Macklem /* 1109ec7b004SRick Macklem * nfs access service (not a part of NFS V2) 1119ec7b004SRick Macklem */ 112b9cc3262SRyan Moeller int 1139ec7b004SRick Macklem nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram, 114af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 1159ec7b004SRick Macklem { 1169ec7b004SRick Macklem u_int32_t *tl; 1179ec7b004SRick Macklem int getret, error = 0; 1189ec7b004SRick Macklem struct nfsvattr nva; 1199ec7b004SRick Macklem u_int32_t testmode, nfsmode, supported = 0; 1208da45f2cSRick Macklem accmode_t deletebit; 121af444b18SEdward Tomasz Napierala struct thread *p = curthread; 1229ec7b004SRick Macklem 1239ec7b004SRick Macklem if (nd->nd_repstat) { 1249ec7b004SRick Macklem nfsrv_postopattr(nd, 1, &nva); 125a9285ae5SZack Kirsch goto out; 1269ec7b004SRick Macklem } 1279ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1289ec7b004SRick Macklem nfsmode = fxdr_unsigned(u_int32_t, *tl); 1299ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && 1309ec7b004SRick Macklem (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP | 1319ec7b004SRick Macklem NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE | 132c057a378SRick Macklem NFSACCESS_EXECUTE | NFSACCESS_XAREAD | NFSACCESS_XAWRITE | 133c057a378SRick Macklem NFSACCESS_XALIST))) { 1349ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 1359ec7b004SRick Macklem vput(vp); 136a9285ae5SZack Kirsch goto out; 1379ec7b004SRick Macklem } 1389ec7b004SRick Macklem if (nfsmode & NFSACCESS_READ) { 1399ec7b004SRick Macklem supported |= NFSACCESS_READ; 1408da45f2cSRick Macklem if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, 1418da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1429ec7b004SRick Macklem nfsmode &= ~NFSACCESS_READ; 1439ec7b004SRick Macklem } 1449ec7b004SRick Macklem if (nfsmode & NFSACCESS_MODIFY) { 1459ec7b004SRick Macklem supported |= NFSACCESS_MODIFY; 1468da45f2cSRick Macklem if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, 1478da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1489ec7b004SRick Macklem nfsmode &= ~NFSACCESS_MODIFY; 1499ec7b004SRick Macklem } 1509ec7b004SRick Macklem if (nfsmode & NFSACCESS_EXTEND) { 1519ec7b004SRick Macklem supported |= NFSACCESS_EXTEND; 1528da45f2cSRick Macklem if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p, 1538da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1549ec7b004SRick Macklem nfsmode &= ~NFSACCESS_EXTEND; 1559ec7b004SRick Macklem } 156c057a378SRick Macklem if (nfsmode & NFSACCESS_XAREAD) { 157c057a378SRick Macklem supported |= NFSACCESS_XAREAD; 158c057a378SRick Macklem if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, 159c057a378SRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 160c057a378SRick Macklem nfsmode &= ~NFSACCESS_XAREAD; 161c057a378SRick Macklem } 162c057a378SRick Macklem if (nfsmode & NFSACCESS_XAWRITE) { 163c057a378SRick Macklem supported |= NFSACCESS_XAWRITE; 164c057a378SRick Macklem if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, 165c057a378SRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 166c057a378SRick Macklem nfsmode &= ~NFSACCESS_XAWRITE; 167c057a378SRick Macklem } 168c057a378SRick Macklem if (nfsmode & NFSACCESS_XALIST) { 169c057a378SRick Macklem supported |= NFSACCESS_XALIST; 170c057a378SRick Macklem if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, 171c057a378SRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 172c057a378SRick Macklem nfsmode &= ~NFSACCESS_XALIST; 173c057a378SRick Macklem } 1749ec7b004SRick Macklem if (nfsmode & NFSACCESS_DELETE) { 1759ec7b004SRick Macklem supported |= NFSACCESS_DELETE; 1768da45f2cSRick Macklem if (vp->v_type == VDIR) 1778da45f2cSRick Macklem deletebit = VDELETE_CHILD; 1788da45f2cSRick Macklem else 1798da45f2cSRick Macklem deletebit = VDELETE; 1808da45f2cSRick Macklem if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p, 1818da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1829ec7b004SRick Macklem nfsmode &= ~NFSACCESS_DELETE; 1839ec7b004SRick Macklem } 1849ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 1859ec7b004SRick Macklem testmode = NFSACCESS_LOOKUP; 1869ec7b004SRick Macklem else 1879ec7b004SRick Macklem testmode = NFSACCESS_EXECUTE; 1889ec7b004SRick Macklem if (nfsmode & testmode) { 1899ec7b004SRick Macklem supported |= (nfsmode & testmode); 1908da45f2cSRick Macklem if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p, 1918da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1929ec7b004SRick Macklem nfsmode &= ~testmode; 1939ec7b004SRick Macklem } 1949ec7b004SRick Macklem nfsmode &= supported; 1959ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 19690d2dfabSRick Macklem getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 1979ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 1989ec7b004SRick Macklem } 1999ec7b004SRick Macklem vput(vp); 2009ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 2019ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2029ec7b004SRick Macklem *tl++ = txdr_unsigned(supported); 2039ec7b004SRick Macklem } else 2049ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2059ec7b004SRick Macklem *tl = txdr_unsigned(nfsmode); 206a9285ae5SZack Kirsch 207a9285ae5SZack Kirsch out: 208a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 2099ec7b004SRick Macklem return (0); 2109ec7b004SRick Macklem nfsmout: 2119ec7b004SRick Macklem vput(vp); 212a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 2139ec7b004SRick Macklem return (error); 2149ec7b004SRick Macklem } 2159ec7b004SRick Macklem 2169ec7b004SRick Macklem /* 2179ec7b004SRick Macklem * nfs getattr service 2189ec7b004SRick Macklem */ 219b9cc3262SRyan Moeller int 2209ec7b004SRick Macklem nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram, 221af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 2229ec7b004SRick Macklem { 2239ec7b004SRick Macklem struct nfsvattr nva; 2249ec7b004SRick Macklem fhandle_t fh; 225a09001a8SRick Macklem int at_root = 0, error = 0, supports_nfsv4acls; 2269ec7b004SRick Macklem struct nfsreferral *refp; 22753f476caSRick Macklem nfsattrbit_t attrbits, tmpbits; 22807c0c166SRick Macklem struct mount *mp; 22907c0c166SRick Macklem struct vnode *tvp = NULL; 23007c0c166SRick Macklem struct vattr va; 23107c0c166SRick Macklem uint64_t mounted_on_fileno = 0; 23253f476caSRick Macklem accmode_t accmode; 233af444b18SEdward Tomasz Napierala struct thread *p = curthread; 2349ec7b004SRick Macklem 2359ec7b004SRick Macklem if (nd->nd_repstat) 236a9285ae5SZack Kirsch goto out; 2379ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 2389ec7b004SRick Macklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 2399ec7b004SRick Macklem if (error) { 2409ec7b004SRick Macklem vput(vp); 241a9285ae5SZack Kirsch goto out; 2429ec7b004SRick Macklem } 2439ec7b004SRick Macklem 2449ec7b004SRick Macklem /* 2459ec7b004SRick Macklem * Check for a referral. 2469ec7b004SRick Macklem */ 2479ec7b004SRick Macklem refp = nfsv4root_getreferral(vp, NULL, 0); 2489ec7b004SRick Macklem if (refp != NULL) { 2499ec7b004SRick Macklem (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1, 2509ec7b004SRick Macklem &nd->nd_repstat); 2519ec7b004SRick Macklem vput(vp); 252a9285ae5SZack Kirsch goto out; 2539ec7b004SRick Macklem } 25453f476caSRick Macklem if (nd->nd_repstat == 0) { 25553f476caSRick Macklem accmode = 0; 25653f476caSRick Macklem NFSSET_ATTRBIT(&tmpbits, &attrbits); 257d8a5961fSMarcelo Araujo 258d8a5961fSMarcelo Araujo /* 259d8a5961fSMarcelo Araujo * GETATTR with write-only attr time_access_set and time_modify_set 260d8a5961fSMarcelo Araujo * should return NFS4ERR_INVAL. 261d8a5961fSMarcelo Araujo */ 262d8a5961fSMarcelo Araujo if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) || 263d8a5961fSMarcelo Araujo NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){ 264d8a5961fSMarcelo Araujo error = NFSERR_INVAL; 265d8a5961fSMarcelo Araujo vput(vp); 266d8a5961fSMarcelo Araujo goto out; 267d8a5961fSMarcelo Araujo } 26853f476caSRick Macklem if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) { 26953f476caSRick Macklem NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL); 27053f476caSRick Macklem accmode |= VREAD_ACL; 27153f476caSRick Macklem } 27253f476caSRick Macklem if (NFSNONZERO_ATTRBIT(&tmpbits)) 27353f476caSRick Macklem accmode |= VREAD_ATTRIBUTES; 27453f476caSRick Macklem if (accmode != 0) 27553f476caSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, accmode, 2768da45f2cSRick Macklem nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, 2778da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 2789ec7b004SRick Macklem } 27953f476caSRick Macklem } 2809ec7b004SRick Macklem if (!nd->nd_repstat) 28190d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); 2829ec7b004SRick Macklem if (!nd->nd_repstat) { 2839ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 2849ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE)) 2859ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 2869ec7b004SRick Macklem if (!nd->nd_repstat) 2879ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkgetattr(nd, vp, 28890d2dfabSRick Macklem &nva, &attrbits, p); 28907c0c166SRick Macklem if (nd->nd_repstat == 0) { 290a09001a8SRick Macklem supports_nfsv4acls = nfs_supportsnfsv4acls(vp); 29107c0c166SRick Macklem mp = vp->v_mount; 29207c0c166SRick Macklem if (nfsrv_enable_crossmntpt != 0 && 29307c0c166SRick Macklem vp->v_type == VDIR && 29407c0c166SRick Macklem (vp->v_vflag & VV_ROOT) != 0 && 29507c0c166SRick Macklem vp != rootvnode) { 29607c0c166SRick Macklem tvp = mp->mnt_vnodecovered; 29707c0c166SRick Macklem VREF(tvp); 29807c0c166SRick Macklem at_root = 1; 29907c0c166SRick Macklem } else 30007c0c166SRick Macklem at_root = 0; 30107c0c166SRick Macklem vfs_ref(mp); 302b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 30307c0c166SRick Macklem if (at_root != 0) { 30407c0c166SRick Macklem if ((nd->nd_repstat = 30598f234f3SZack Kirsch NFSVOPLOCK(tvp, LK_SHARED)) == 0) { 30607c0c166SRick Macklem nd->nd_repstat = VOP_GETATTR( 30707c0c166SRick Macklem tvp, &va, nd->nd_cred); 30807c0c166SRick Macklem vput(tvp); 30907c0c166SRick Macklem } else 31007c0c166SRick Macklem vrele(tvp); 31107c0c166SRick Macklem if (nd->nd_repstat == 0) 31207c0c166SRick Macklem mounted_on_fileno = (uint64_t) 31307c0c166SRick Macklem va.va_fileid; 31407c0c166SRick Macklem else 31507c0c166SRick Macklem at_root = 0; 31607c0c166SRick Macklem } 31707c0c166SRick Macklem if (nd->nd_repstat == 0) 31807c0c166SRick Macklem nd->nd_repstat = vfs_busy(mp, 0); 31907c0c166SRick Macklem vfs_rel(mp); 32007c0c166SRick Macklem if (nd->nd_repstat == 0) { 32107c0c166SRick Macklem (void)nfsvno_fillattr(nd, mp, vp, &nva, 32207c0c166SRick Macklem &fh, 0, &attrbits, nd->nd_cred, p, 323a09001a8SRick Macklem isdgram, 1, supports_nfsv4acls, 324a09001a8SRick Macklem at_root, mounted_on_fileno); 32507c0c166SRick Macklem vfs_unbusy(mp); 32607c0c166SRick Macklem } 3279ec7b004SRick Macklem vrele(vp); 32807c0c166SRick Macklem } else 32907c0c166SRick Macklem vput(vp); 3309ec7b004SRick Macklem } else { 3319ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 3329ec7b004SRick Macklem vput(vp); 3339ec7b004SRick Macklem } 3349ec7b004SRick Macklem } else { 3359ec7b004SRick Macklem vput(vp); 3369ec7b004SRick Macklem } 337a9285ae5SZack Kirsch 338a9285ae5SZack Kirsch out: 339a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 340a9285ae5SZack Kirsch return (error); 3419ec7b004SRick Macklem } 3429ec7b004SRick Macklem 3439ec7b004SRick Macklem /* 3449ec7b004SRick Macklem * nfs setattr service 3459ec7b004SRick Macklem */ 346b9cc3262SRyan Moeller int 3479ec7b004SRick Macklem nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram, 348af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 3499ec7b004SRick Macklem { 3509ec7b004SRick Macklem struct nfsvattr nva, nva2; 3519ec7b004SRick Macklem u_int32_t *tl; 3529ec7b004SRick Macklem int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0; 35390d2dfabSRick Macklem int gotproxystateid; 3549ec7b004SRick Macklem struct timespec guard = { 0, 0 }; 3559ec7b004SRick Macklem nfsattrbit_t attrbits, retbits; 3569ec7b004SRick Macklem nfsv4stateid_t stateid; 3579ec7b004SRick Macklem NFSACL_T *aclp = NULL; 358af444b18SEdward Tomasz Napierala struct thread *p = curthread; 3599ec7b004SRick Macklem 3609ec7b004SRick Macklem if (nd->nd_repstat) { 3619ec7b004SRick Macklem nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 362a9285ae5SZack Kirsch goto out; 3639ec7b004SRick Macklem } 3649ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 365c3e22f83SRick Macklem aclp = acl_alloc(M_WAITOK); 3669ec7b004SRick Macklem aclp->acl_cnt = 0; 3679ec7b004SRick Macklem #endif 36890d2dfabSRick Macklem gotproxystateid = 0; 3699ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 3709ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 3719ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3729ec7b004SRick Macklem stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 37390d2dfabSRick Macklem stateid.other[0] = *tl++; 37490d2dfabSRick Macklem stateid.other[1] = *tl++; 37590d2dfabSRick Macklem stateid.other[2] = *tl; 37690d2dfabSRick Macklem if (stateid.other[0] == 0x55555555 && 37790d2dfabSRick Macklem stateid.other[1] == 0x55555555 && 37890d2dfabSRick Macklem stateid.other[2] == 0x55555555 && 37990d2dfabSRick Macklem stateid.seqid == 0xffffffff) 38090d2dfabSRick Macklem gotproxystateid = 1; 3819ec7b004SRick Macklem } 382d8a5961fSMarcelo Araujo error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p); 3839ec7b004SRick Macklem if (error) 3849ec7b004SRick Macklem goto nfsmout; 38590d2dfabSRick Macklem 38690d2dfabSRick Macklem /* For NFSv4, only va_uid is used from nva2. */ 38790d2dfabSRick Macklem NFSZERO_ATTRBIT(&retbits); 38890d2dfabSRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER); 38990d2dfabSRick Macklem preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits); 3909ec7b004SRick Macklem if (!nd->nd_repstat) 3919ec7b004SRick Macklem nd->nd_repstat = preat_ret; 39290d2dfabSRick Macklem 39390d2dfabSRick Macklem NFSZERO_ATTRBIT(&retbits); 3949ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 3959ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3969ec7b004SRick Macklem gcheck = fxdr_unsigned(int, *tl); 3979ec7b004SRick Macklem if (gcheck) { 3989ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3999ec7b004SRick Macklem fxdr_nfsv3time(tl, &guard); 4009ec7b004SRick Macklem } 4019ec7b004SRick Macklem if (!nd->nd_repstat && gcheck && 4029ec7b004SRick Macklem (nva2.na_ctime.tv_sec != guard.tv_sec || 4039ec7b004SRick Macklem nva2.na_ctime.tv_nsec != guard.tv_nsec)) 4049ec7b004SRick Macklem nd->nd_repstat = NFSERR_NOT_SYNC; 4059ec7b004SRick Macklem if (nd->nd_repstat) { 4069ec7b004SRick Macklem vput(vp); 4079ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 4089ec7b004SRick Macklem acl_free(aclp); 4099ec7b004SRick Macklem #endif 4109ec7b004SRick Macklem nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 411a9285ae5SZack Kirsch goto out; 4129ec7b004SRick Macklem } 4139ec7b004SRick Macklem } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) 4149ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 4159ec7b004SRick Macklem 4169ec7b004SRick Macklem /* 4179ec7b004SRick Macklem * Now that we have all the fields, lets do it. 4189ec7b004SRick Macklem * If the size is being changed write access is required, otherwise 4199ec7b004SRick Macklem * just check for a read only file system. 4209ec7b004SRick Macklem */ 4219ec7b004SRick Macklem if (!nd->nd_repstat) { 4229ec7b004SRick Macklem if (NFSVNO_NOTSETSIZE(&nva)) { 4239ec7b004SRick Macklem if (NFSVNO_EXRDONLY(exp) || 424eea79fdeSAlan Somers (vfs_flags(vp->v_mount) & MNT_RDONLY)) 4259ec7b004SRick Macklem nd->nd_repstat = EROFS; 4269ec7b004SRick Macklem } else { 4279ec7b004SRick Macklem if (vnode_vtype(vp) != VREG) 4289ec7b004SRick Macklem nd->nd_repstat = EINVAL; 4299ec7b004SRick Macklem else if (nva2.na_uid != nd->nd_cred->cr_uid || 4309ec7b004SRick Macklem NFSVNO_EXSTRICTACCESS(exp)) 4319ec7b004SRick Macklem nd->nd_repstat = nfsvno_accchk(vp, 4328da45f2cSRick Macklem VWRITE, nd->nd_cred, exp, p, 4338da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, 4348da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 4359ec7b004SRick Macklem } 4369ec7b004SRick Macklem } 43790d2dfabSRick Macklem /* 43890d2dfabSRick Macklem * Proxy operations from the MDS are allowed via the all 0s special 43990d2dfabSRick Macklem * stateid. 44090d2dfabSRick Macklem */ 44190d2dfabSRick Macklem if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0 && 44290d2dfabSRick Macklem gotproxystateid == 0) 4439ec7b004SRick Macklem nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid, 4449ec7b004SRick Macklem &nva, &attrbits, exp, p); 4459ec7b004SRick Macklem 4469ec7b004SRick Macklem if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 4479ec7b004SRick Macklem /* 4489ec7b004SRick Macklem * For V4, try setting the attrbutes in sets, so that the 4499ec7b004SRick Macklem * reply bitmap will be correct for an error case. 4509ec7b004SRick Macklem */ 4519ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) || 4529ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) { 4539ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 4549ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid); 4559ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid); 4569ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 4579ec7b004SRick Macklem exp); 4589ec7b004SRick Macklem if (!nd->nd_repstat) { 4599ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER)) 4609ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER); 4619ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) 4629ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP); 4639ec7b004SRick Macklem } 4649ec7b004SRick Macklem } 4659ec7b004SRick Macklem if (!nd->nd_repstat && 4669ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) { 4679ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 4689ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, size, nva.na_size); 4699ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 4709ec7b004SRick Macklem exp); 4719ec7b004SRick Macklem if (!nd->nd_repstat) 4729ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE); 4739ec7b004SRick Macklem } 4749ec7b004SRick Macklem if (!nd->nd_repstat && 4759ec7b004SRick Macklem (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) || 4769ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) { 4779ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 4789ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime); 4799ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime); 4809ec7b004SRick Macklem if (nva.na_vaflags & VA_UTIMES_NULL) { 4819ec7b004SRick Macklem nva2.na_vaflags |= VA_UTIMES_NULL; 4829ec7b004SRick Macklem NFSVNO_SETACTIVE(&nva2, vaflags); 4839ec7b004SRick Macklem } 4849ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 4859ec7b004SRick Macklem exp); 4869ec7b004SRick Macklem if (!nd->nd_repstat) { 4879ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET)) 4889ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET); 4899ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET)) 4909ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET); 4919ec7b004SRick Macklem } 4929ec7b004SRick Macklem } 4939ec7b004SRick Macklem if (!nd->nd_repstat && 494dd02d9d6SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE)) { 495dd02d9d6SRick Macklem NFSVNO_ATTRINIT(&nva2); 496dd02d9d6SRick Macklem NFSVNO_SETATTRVAL(&nva2, btime, nva.na_btime); 497dd02d9d6SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 498dd02d9d6SRick Macklem exp); 499dd02d9d6SRick Macklem if (!nd->nd_repstat) 500dd02d9d6SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMECREATE); 501dd02d9d6SRick Macklem } 502dd02d9d6SRick Macklem if (!nd->nd_repstat && 503b4372164SRick Macklem (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE) || 504b4372164SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))) { 5059ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 5069ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode); 5079ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 5089ec7b004SRick Macklem exp); 509b4372164SRick Macklem if (!nd->nd_repstat) { 510b4372164SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) 5119ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE); 512b4372164SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED)) 513b4372164SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODESETMASKED); 514b4372164SRick Macklem } 5159ec7b004SRick Macklem } 5169ec7b004SRick Macklem 5179ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 5189ec7b004SRick Macklem if (!nd->nd_repstat && aclp->acl_cnt > 0 && 5199ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) { 5209ec7b004SRick Macklem nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p); 5219ec7b004SRick Macklem if (!nd->nd_repstat) 5229ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL); 5239ec7b004SRick Macklem } 5249ec7b004SRick Macklem #endif 5259ec7b004SRick Macklem } else if (!nd->nd_repstat) { 5269ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p, 5279ec7b004SRick Macklem exp); 5289ec7b004SRick Macklem } 5299ec7b004SRick Macklem if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) { 53090d2dfabSRick Macklem postat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 5319ec7b004SRick Macklem if (!nd->nd_repstat) 5329ec7b004SRick Macklem nd->nd_repstat = postat_ret; 5339ec7b004SRick Macklem } 5349ec7b004SRick Macklem vput(vp); 5359ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 5369ec7b004SRick Macklem acl_free(aclp); 5379ec7b004SRick Macklem #endif 5389ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 5399ec7b004SRick Macklem nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 5409ec7b004SRick Macklem else if (nd->nd_flag & ND_NFSV4) 5419ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &retbits); 5429ec7b004SRick Macklem else if (!nd->nd_repstat) 5439ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 544a9285ae5SZack Kirsch 545a9285ae5SZack Kirsch out: 546a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 5479ec7b004SRick Macklem return (0); 5489ec7b004SRick Macklem nfsmout: 5499ec7b004SRick Macklem vput(vp); 5509ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 5519ec7b004SRick Macklem acl_free(aclp); 5529ec7b004SRick Macklem #endif 5539ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 5549ec7b004SRick Macklem /* 5559ec7b004SRick Macklem * For all nd_repstat, the V4 reply includes a bitmap, 5569ec7b004SRick Macklem * even NFSERR_BADXDR, which is what this will end up 5579ec7b004SRick Macklem * returning. 5589ec7b004SRick Macklem */ 5599ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &retbits); 5609ec7b004SRick Macklem } 561a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 5629ec7b004SRick Macklem return (error); 5639ec7b004SRick Macklem } 5649ec7b004SRick Macklem 5659ec7b004SRick Macklem /* 5669ec7b004SRick Macklem * nfs lookup rpc 5679ec7b004SRick Macklem * (Also performs lookup parent for v4) 5689ec7b004SRick Macklem */ 569b9cc3262SRyan Moeller int 5709ec7b004SRick Macklem nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram, 571af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 5729ec7b004SRick Macklem { 5739ec7b004SRick Macklem struct nameidata named; 5749ec7b004SRick Macklem vnode_t vp, dirp = NULL; 575a9285ae5SZack Kirsch int error = 0, dattr_ret = 1; 5769ec7b004SRick Macklem struct nfsvattr nva, dattr; 5779ec7b004SRick Macklem char *bufp; 5789ec7b004SRick Macklem u_long *hashp; 579af444b18SEdward Tomasz Napierala struct thread *p = curthread; 5809ec7b004SRick Macklem 5819ec7b004SRick Macklem if (nd->nd_repstat) { 5829ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 583a9285ae5SZack Kirsch goto out; 5849ec7b004SRick Macklem } 5859ec7b004SRick Macklem 5869ec7b004SRick Macklem /* 5879ec7b004SRick Macklem * For some reason, if dp is a symlink, the error 5889ec7b004SRick Macklem * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR. 5899ec7b004SRick Macklem */ 5909ec7b004SRick Macklem if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) { 5919ec7b004SRick Macklem nd->nd_repstat = NFSERR_SYMLINK; 5929ec7b004SRick Macklem vrele(dp); 593a9285ae5SZack Kirsch goto out; 5949ec7b004SRick Macklem } 5959ec7b004SRick Macklem 5969ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 5979ec7b004SRick Macklem LOCKLEAF | SAVESTART); 5989ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 5999ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 6009ec7b004SRick Macklem if (error) { 6019ec7b004SRick Macklem vrele(dp); 6029ec7b004SRick Macklem nfsvno_relpathbuf(&named); 603a9285ae5SZack Kirsch goto out; 6049ec7b004SRick Macklem } 6059ec7b004SRick Macklem if (!nd->nd_repstat) { 6069ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 6079ec7b004SRick Macklem } else { 6089ec7b004SRick Macklem vrele(dp); 6099ec7b004SRick Macklem nfsvno_relpathbuf(&named); 6109ec7b004SRick Macklem } 6119ec7b004SRick Macklem if (nd->nd_repstat) { 6129ec7b004SRick Macklem if (dirp) { 6139ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 61490d2dfabSRick Macklem dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 61590d2dfabSRick Macklem 0, NULL); 6169ec7b004SRick Macklem vrele(dirp); 6179ec7b004SRick Macklem } 6189ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 6199ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 620a9285ae5SZack Kirsch goto out; 6219ec7b004SRick Macklem } 6229ec7b004SRick Macklem if (named.ni_startdir) 6239ec7b004SRick Macklem vrele(named.ni_startdir); 6249ec7b004SRick Macklem nfsvno_relpathbuf(&named); 6259ec7b004SRick Macklem vp = named.ni_vp; 62637b88c2dSRick Macklem if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) && 62737b88c2dSRick Macklem vp->v_type != VDIR && vp->v_type != VLNK) 62837b88c2dSRick Macklem /* 62937b88c2dSRick Macklem * Only allow lookup of VDIR and VLNK for traversal of 63037b88c2dSRick Macklem * non-exported volumes during NFSv4 mounting. 63137b88c2dSRick Macklem */ 63237b88c2dSRick Macklem nd->nd_repstat = ENOENT; 63337b88c2dSRick Macklem if (nd->nd_repstat == 0) 6349ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 6359ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 63690d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 63781f78d99SRick Macklem if (vpp != NULL && nd->nd_repstat == 0) 6389ec7b004SRick Macklem *vpp = vp; 63981f78d99SRick Macklem else 6409ec7b004SRick Macklem vput(vp); 6419ec7b004SRick Macklem if (dirp) { 6429ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 64390d2dfabSRick Macklem dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0, 64490d2dfabSRick Macklem NULL); 6459ec7b004SRick Macklem vrele(dirp); 6469ec7b004SRick Macklem } 6479ec7b004SRick Macklem if (nd->nd_repstat) { 6489ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 6499ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 650a9285ae5SZack Kirsch goto out; 6519ec7b004SRick Macklem } 6529ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 6539ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 6549ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 6559ec7b004SRick Macklem } else if (nd->nd_flag & ND_NFSV3) { 6569ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 6579ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 6589ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 6599ec7b004SRick Macklem } 660a9285ae5SZack Kirsch 661a9285ae5SZack Kirsch out: 662a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 663a9285ae5SZack Kirsch return (error); 6649ec7b004SRick Macklem } 6659ec7b004SRick Macklem 6669ec7b004SRick Macklem /* 6679ec7b004SRick Macklem * nfs readlink service 6689ec7b004SRick Macklem */ 669b9cc3262SRyan Moeller int 6709ec7b004SRick Macklem nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram, 671af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 6729ec7b004SRick Macklem { 6739ec7b004SRick Macklem u_int32_t *tl; 674ae070589SRick Macklem struct mbuf *mp = NULL, *mpend = NULL; 6759ec7b004SRick Macklem int getret = 1, len; 6769ec7b004SRick Macklem struct nfsvattr nva; 677af444b18SEdward Tomasz Napierala struct thread *p = curthread; 678cb889ce6SRick Macklem uint16_t off; 6799ec7b004SRick Macklem 6809ec7b004SRick Macklem if (nd->nd_repstat) { 6819ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 682a9285ae5SZack Kirsch goto out; 6839ec7b004SRick Macklem } 6849ec7b004SRick Macklem if (vnode_vtype(vp) != VLNK) { 6859ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) 6869ec7b004SRick Macklem nd->nd_repstat = ENXIO; 6879ec7b004SRick Macklem else 6889ec7b004SRick Macklem nd->nd_repstat = EINVAL; 6899ec7b004SRick Macklem } 690cb889ce6SRick Macklem if (nd->nd_repstat == 0) { 691cb889ce6SRick Macklem if ((nd->nd_flag & ND_EXTPG) != 0) 692cb889ce6SRick Macklem nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, 693cb889ce6SRick Macklem nd->nd_maxextsiz, p, &mp, &mpend, &len); 694cb889ce6SRick Macklem else 695cb889ce6SRick Macklem nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, 696cb889ce6SRick Macklem 0, p, &mp, &mpend, &len); 697cb889ce6SRick Macklem } 6989ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 69990d2dfabSRick Macklem getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 7009ec7b004SRick Macklem vput(vp); 7019ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 7029ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 7039ec7b004SRick Macklem if (nd->nd_repstat) 704a9285ae5SZack Kirsch goto out; 7059ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 7069ec7b004SRick Macklem *tl = txdr_unsigned(len); 70718a48314SRick Macklem if (mp != NULL) { 7089f6624d3SRick Macklem nd->nd_mb->m_next = mp; 7099ec7b004SRick Macklem nd->nd_mb = mpend; 710cb889ce6SRick Macklem if ((mpend->m_flags & M_EXTPG) != 0) { 711cb889ce6SRick Macklem nd->nd_bextpg = mpend->m_epg_npgs - 1; 712cb889ce6SRick Macklem nd->nd_bpos = (char *)(void *) 713cb889ce6SRick Macklem PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]); 714cb889ce6SRick Macklem off = (nd->nd_bextpg == 0) ? mpend->m_epg_1st_off : 0; 715cb889ce6SRick Macklem nd->nd_bpos += off + mpend->m_epg_last_len; 716cb889ce6SRick Macklem nd->nd_bextpgsiz = PAGE_SIZE - mpend->m_epg_last_len - 717cb889ce6SRick Macklem off; 718cb889ce6SRick Macklem } else 719cb889ce6SRick Macklem nd->nd_bpos = mtod(mpend, char *) + mpend->m_len; 72018a48314SRick Macklem } 721a9285ae5SZack Kirsch 722a9285ae5SZack Kirsch out: 723a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 7249ec7b004SRick Macklem return (0); 7259ec7b004SRick Macklem } 7269ec7b004SRick Macklem 7279ec7b004SRick Macklem /* 7289ec7b004SRick Macklem * nfs read service 7299ec7b004SRick Macklem */ 730b9cc3262SRyan Moeller int 7319ec7b004SRick Macklem nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram, 732af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 7339ec7b004SRick Macklem { 7349ec7b004SRick Macklem u_int32_t *tl; 73590d2dfabSRick Macklem int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0; 736ae070589SRick Macklem struct mbuf *m2, *m3; 7379ec7b004SRick Macklem struct nfsvattr nva; 7389ec7b004SRick Macklem off_t off = 0x0; 7399ec7b004SRick Macklem struct nfsstate st, *stp = &st; 7409ec7b004SRick Macklem struct nfslock lo, *lop = &lo; 7419ec7b004SRick Macklem nfsv4stateid_t stateid; 7429ec7b004SRick Macklem nfsquad_t clientid; 743af444b18SEdward Tomasz Napierala struct thread *p = curthread; 744cb889ce6SRick Macklem uint16_t poff; 7459ec7b004SRick Macklem 7469ec7b004SRick Macklem if (nd->nd_repstat) { 7479ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 748a9285ae5SZack Kirsch goto out; 7499ec7b004SRick Macklem } 7509ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 7519ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 7529ec7b004SRick Macklem off = (off_t)fxdr_unsigned(u_int32_t, *tl++); 7539ec7b004SRick Macklem reqlen = fxdr_unsigned(int, *tl); 7549ec7b004SRick Macklem } else if (nd->nd_flag & ND_NFSV3) { 7559ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 7569ec7b004SRick Macklem off = fxdr_hyper(tl); 7579ec7b004SRick Macklem tl += 2; 7589ec7b004SRick Macklem reqlen = fxdr_unsigned(int, *tl); 7599ec7b004SRick Macklem } else { 7609ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED); 7619ec7b004SRick Macklem reqlen = fxdr_unsigned(int, *(tl + 6)); 7629ec7b004SRick Macklem } 7639ec7b004SRick Macklem if (reqlen > NFS_SRVMAXDATA(nd)) { 7649ec7b004SRick Macklem reqlen = NFS_SRVMAXDATA(nd); 7659ec7b004SRick Macklem } else if (reqlen < 0) { 7669ec7b004SRick Macklem error = EBADRPC; 7679ec7b004SRick Macklem goto nfsmout; 7689ec7b004SRick Macklem } 76990d2dfabSRick Macklem gotproxystateid = 0; 7709ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 7719ec7b004SRick Macklem stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS); 7729ec7b004SRick Macklem lop->lo_flags = NFSLCK_READ; 7739ec7b004SRick Macklem stp->ls_ownerlen = 0; 7749ec7b004SRick Macklem stp->ls_op = NULL; 7759ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 7769ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 7779ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 7789ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 779c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 780c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 781c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 782c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 783c59e4cc3SRick Macklem printf("EEK1 multiple clids\n"); 7849ec7b004SRick Macklem } else { 785c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 786c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 7879ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 7889ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 7899ec7b004SRick Macklem } 7909ec7b004SRick Macklem stp->ls_stateid.other[2] = *tl++; 79190d2dfabSRick Macklem /* 79290d2dfabSRick Macklem * Don't allow the client to use a special stateid for a DS op. 79390d2dfabSRick Macklem */ 79490d2dfabSRick Macklem if ((nd->nd_flag & ND_DSSERVER) != 0 && 79590d2dfabSRick Macklem ((stp->ls_stateid.other[0] == 0x0 && 79690d2dfabSRick Macklem stp->ls_stateid.other[1] == 0x0 && 79790d2dfabSRick Macklem stp->ls_stateid.other[2] == 0x0) || 79890d2dfabSRick Macklem (stp->ls_stateid.other[0] == 0xffffffff && 79990d2dfabSRick Macklem stp->ls_stateid.other[1] == 0xffffffff && 80090d2dfabSRick Macklem stp->ls_stateid.other[2] == 0xffffffff) || 80190d2dfabSRick Macklem stp->ls_stateid.seqid != 0)) 80290d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 80390d2dfabSRick Macklem /* However, allow the proxy stateid. */ 80490d2dfabSRick Macklem if (stp->ls_stateid.seqid == 0xffffffff && 80590d2dfabSRick Macklem stp->ls_stateid.other[0] == 0x55555555 && 80690d2dfabSRick Macklem stp->ls_stateid.other[1] == 0x55555555 && 80790d2dfabSRick Macklem stp->ls_stateid.other[2] == 0x55555555) 80890d2dfabSRick Macklem gotproxystateid = 1; 8099ec7b004SRick Macklem off = fxdr_hyper(tl); 8109ec7b004SRick Macklem lop->lo_first = off; 8119ec7b004SRick Macklem tl += 2; 8129ec7b004SRick Macklem lop->lo_end = off + reqlen; 8139ec7b004SRick Macklem /* 8149ec7b004SRick Macklem * Paranoia, just in case it wraps around. 8159ec7b004SRick Macklem */ 8169ec7b004SRick Macklem if (lop->lo_end < off) 8179ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 8189ec7b004SRick Macklem } 8199ec7b004SRick Macklem if (vnode_vtype(vp) != VREG) { 8209ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 8219ec7b004SRick Macklem nd->nd_repstat = EINVAL; 8229ec7b004SRick Macklem else 8239ec7b004SRick Macklem nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR : 8249ec7b004SRick Macklem EINVAL; 8259ec7b004SRick Macklem } 82690d2dfabSRick Macklem getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 8279ec7b004SRick Macklem if (!nd->nd_repstat) 8289ec7b004SRick Macklem nd->nd_repstat = getret; 8299ec7b004SRick Macklem if (!nd->nd_repstat && 8309ec7b004SRick Macklem (nva.na_uid != nd->nd_cred->cr_uid || 8319ec7b004SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) { 8328da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, 8339ec7b004SRick Macklem nd->nd_cred, exp, p, 8348da45f2cSRick Macklem NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 8359ec7b004SRick Macklem if (nd->nd_repstat) 8368da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 8378da45f2cSRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 8388da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 8399ec7b004SRick Macklem } 84090d2dfabSRick Macklem /* 84190d2dfabSRick Macklem * DS reads are marked by ND_DSSERVER or use the proxy special 84290d2dfabSRick Macklem * stateid. 84390d2dfabSRick Macklem */ 84490d2dfabSRick Macklem if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) == 84590d2dfabSRick Macklem ND_NFSV4 && gotproxystateid == 0) 8469ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 8479ec7b004SRick Macklem &stateid, exp, nd, p); 8489ec7b004SRick Macklem if (nd->nd_repstat) { 8499ec7b004SRick Macklem vput(vp); 8509ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 8519ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 852a9285ae5SZack Kirsch goto out; 8539ec7b004SRick Macklem } 8549ec7b004SRick Macklem if (off >= nva.na_size) { 8559ec7b004SRick Macklem cnt = 0; 8569ec7b004SRick Macklem eof = 1; 8579ec7b004SRick Macklem } else if (reqlen == 0) 8589ec7b004SRick Macklem cnt = 0; 85906521fbbSZack Kirsch else if ((off + reqlen) >= nva.na_size) { 8609ec7b004SRick Macklem cnt = nva.na_size - off; 86106521fbbSZack Kirsch eof = 1; 86206521fbbSZack Kirsch } else 8639ec7b004SRick Macklem cnt = reqlen; 8649ec7b004SRick Macklem m3 = NULL; 8659ec7b004SRick Macklem if (cnt > 0) { 866cb889ce6SRick Macklem /* 867cb889ce6SRick Macklem * If cnt > MCLBYTES and the reply will not be saved, use 868cb889ce6SRick Macklem * ext_pgs mbufs for TLS. 869cb889ce6SRick Macklem * For NFSv4.0, we do not know for sure if the reply will 870cb889ce6SRick Macklem * be saved, so do not use ext_pgs mbufs for NFSv4.0. 871cb889ce6SRick Macklem * Always use ext_pgs mbufs if ND_EXTPG is set. 872cb889ce6SRick Macklem */ 873cb889ce6SRick Macklem if ((nd->nd_flag & ND_EXTPG) != 0 || (cnt > MCLBYTES && 874cb889ce6SRick Macklem (nd->nd_flag & (ND_TLS | ND_SAVEREPLY)) == ND_TLS && 875cb889ce6SRick Macklem (nd->nd_flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4)) 876cb889ce6SRick Macklem nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, 877cb889ce6SRick Macklem nd->nd_maxextsiz, p, &m3, &m2); 878cb889ce6SRick Macklem else 879cb889ce6SRick Macklem nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, 880cb889ce6SRick Macklem 0, p, &m3, &m2); 8819ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV4)) { 88290d2dfabSRick Macklem getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 8839ec7b004SRick Macklem if (!nd->nd_repstat) 8849ec7b004SRick Macklem nd->nd_repstat = getret; 8859ec7b004SRick Macklem } 8869ec7b004SRick Macklem if (nd->nd_repstat) { 8879ec7b004SRick Macklem vput(vp); 8889ec7b004SRick Macklem if (m3) 8899f6624d3SRick Macklem m_freem(m3); 8909ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 8919ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 892a9285ae5SZack Kirsch goto out; 8939ec7b004SRick Macklem } 8949ec7b004SRick Macklem } 8959ec7b004SRick Macklem vput(vp); 8969ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 8979ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 8989ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 8999ec7b004SRick Macklem } else { 9009ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 9019ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 9029ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 9039ec7b004SRick Macklem *tl++ = txdr_unsigned(cnt); 9049ec7b004SRick Macklem } else 9059ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 90606521fbbSZack Kirsch if (eof) 9079ec7b004SRick Macklem *tl++ = newnfs_true; 9089ec7b004SRick Macklem else 9099ec7b004SRick Macklem *tl++ = newnfs_false; 9109ec7b004SRick Macklem } 9119ec7b004SRick Macklem *tl = txdr_unsigned(cnt); 9129ec7b004SRick Macklem if (m3) { 9139f6624d3SRick Macklem nd->nd_mb->m_next = m3; 9149ec7b004SRick Macklem nd->nd_mb = m2; 915cb889ce6SRick Macklem if ((m2->m_flags & M_EXTPG) != 0) { 916cb889ce6SRick Macklem nd->nd_flag |= ND_EXTPG; 917cb889ce6SRick Macklem nd->nd_bextpg = m2->m_epg_npgs - 1; 918cb889ce6SRick Macklem nd->nd_bpos = (char *)(void *) 919cb889ce6SRick Macklem PHYS_TO_DMAP(m2->m_epg_pa[nd->nd_bextpg]); 920cb889ce6SRick Macklem poff = (nd->nd_bextpg == 0) ? m2->m_epg_1st_off : 0; 921cb889ce6SRick Macklem nd->nd_bpos += poff + m2->m_epg_last_len; 922cb889ce6SRick Macklem nd->nd_bextpgsiz = PAGE_SIZE - m2->m_epg_last_len - 923cb889ce6SRick Macklem poff; 924cb889ce6SRick Macklem } else 925cb889ce6SRick Macklem nd->nd_bpos = mtod(m2, char *) + m2->m_len; 9269ec7b004SRick Macklem } 927a9285ae5SZack Kirsch 928a9285ae5SZack Kirsch out: 929a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 9309ec7b004SRick Macklem return (0); 9319ec7b004SRick Macklem nfsmout: 9329ec7b004SRick Macklem vput(vp); 933a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 9349ec7b004SRick Macklem return (error); 9359ec7b004SRick Macklem } 9369ec7b004SRick Macklem 9379ec7b004SRick Macklem /* 9389ec7b004SRick Macklem * nfs write service 9399ec7b004SRick Macklem */ 940b9cc3262SRyan Moeller int 9419ec7b004SRick Macklem nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram, 942af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 9439ec7b004SRick Macklem { 9449ec7b004SRick Macklem u_int32_t *tl; 9459ec7b004SRick Macklem struct nfsvattr nva, forat; 9469ec7b004SRick Macklem int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1; 94790d2dfabSRick Macklem int gotproxystateid, stable = NFSWRITE_FILESYNC; 9489ec7b004SRick Macklem off_t off; 9499ec7b004SRick Macklem struct nfsstate st, *stp = &st; 9509ec7b004SRick Macklem struct nfslock lo, *lop = &lo; 9519ec7b004SRick Macklem nfsv4stateid_t stateid; 9529ec7b004SRick Macklem nfsquad_t clientid; 95390d2dfabSRick Macklem nfsattrbit_t attrbits; 954af444b18SEdward Tomasz Napierala struct thread *p = curthread; 9559ec7b004SRick Macklem 9569ec7b004SRick Macklem if (nd->nd_repstat) { 9579ec7b004SRick Macklem nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 958a9285ae5SZack Kirsch goto out; 9599ec7b004SRick Macklem } 96090d2dfabSRick Macklem gotproxystateid = 0; 9619ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 9629ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 9639ec7b004SRick Macklem off = (off_t)fxdr_unsigned(u_int32_t, *++tl); 9649ec7b004SRick Macklem tl += 2; 9659ec7b004SRick Macklem retlen = len = fxdr_unsigned(int32_t, *tl); 9669ec7b004SRick Macklem } else if (nd->nd_flag & ND_NFSV3) { 9679ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 9689ec7b004SRick Macklem off = fxdr_hyper(tl); 9699ec7b004SRick Macklem tl += 3; 9709ec7b004SRick Macklem stable = fxdr_unsigned(int, *tl++); 9719ec7b004SRick Macklem retlen = len = fxdr_unsigned(int32_t, *tl); 9729ec7b004SRick Macklem } else { 9739ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED); 9749ec7b004SRick Macklem stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 9759ec7b004SRick Macklem lop->lo_flags = NFSLCK_WRITE; 9769ec7b004SRick Macklem stp->ls_ownerlen = 0; 9779ec7b004SRick Macklem stp->ls_op = NULL; 9789ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 9799ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 9809ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 9819ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 982c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 983c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 984c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 985c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 986c59e4cc3SRick Macklem printf("EEK2 multiple clids\n"); 9879ec7b004SRick Macklem } else { 988c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 989c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 9909ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 9919ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 9929ec7b004SRick Macklem } 9939ec7b004SRick Macklem stp->ls_stateid.other[2] = *tl++; 99490d2dfabSRick Macklem /* 99590d2dfabSRick Macklem * Don't allow the client to use a special stateid for a DS op. 99690d2dfabSRick Macklem */ 99790d2dfabSRick Macklem if ((nd->nd_flag & ND_DSSERVER) != 0 && 99890d2dfabSRick Macklem ((stp->ls_stateid.other[0] == 0x0 && 99990d2dfabSRick Macklem stp->ls_stateid.other[1] == 0x0 && 100090d2dfabSRick Macklem stp->ls_stateid.other[2] == 0x0) || 100190d2dfabSRick Macklem (stp->ls_stateid.other[0] == 0xffffffff && 100290d2dfabSRick Macklem stp->ls_stateid.other[1] == 0xffffffff && 100390d2dfabSRick Macklem stp->ls_stateid.other[2] == 0xffffffff) || 100490d2dfabSRick Macklem stp->ls_stateid.seqid != 0)) 100590d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 100690d2dfabSRick Macklem /* However, allow the proxy stateid. */ 100790d2dfabSRick Macklem if (stp->ls_stateid.seqid == 0xffffffff && 100890d2dfabSRick Macklem stp->ls_stateid.other[0] == 0x55555555 && 100990d2dfabSRick Macklem stp->ls_stateid.other[1] == 0x55555555 && 101090d2dfabSRick Macklem stp->ls_stateid.other[2] == 0x55555555) 101190d2dfabSRick Macklem gotproxystateid = 1; 10129ec7b004SRick Macklem off = fxdr_hyper(tl); 10139ec7b004SRick Macklem lop->lo_first = off; 10149ec7b004SRick Macklem tl += 2; 10159ec7b004SRick Macklem stable = fxdr_unsigned(int, *tl++); 10169ec7b004SRick Macklem retlen = len = fxdr_unsigned(int32_t, *tl); 10179ec7b004SRick Macklem lop->lo_end = off + len; 10189ec7b004SRick Macklem /* 10199ec7b004SRick Macklem * Paranoia, just in case it wraps around, which shouldn't 10209ec7b004SRick Macklem * ever happen anyhow. 10219ec7b004SRick Macklem */ 10229ec7b004SRick Macklem if (lop->lo_end < lop->lo_first) 10239ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 10249ec7b004SRick Macklem } 10259ec7b004SRick Macklem 102666e80f77SRick Macklem if (retlen > NFS_SRVMAXIO || retlen < 0) 10279ec7b004SRick Macklem nd->nd_repstat = EIO; 10289ec7b004SRick Macklem if (vnode_vtype(vp) != VREG && !nd->nd_repstat) { 10299ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 10309ec7b004SRick Macklem nd->nd_repstat = EINVAL; 10319ec7b004SRick Macklem else 10329ec7b004SRick Macklem nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR : 10339ec7b004SRick Macklem EINVAL; 10349ec7b004SRick Macklem } 103590d2dfabSRick Macklem NFSZERO_ATTRBIT(&attrbits); 103690d2dfabSRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 103790d2dfabSRick Macklem forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits); 10389ec7b004SRick Macklem if (!nd->nd_repstat) 10399ec7b004SRick Macklem nd->nd_repstat = forat_ret; 10409ec7b004SRick Macklem if (!nd->nd_repstat && 10419ec7b004SRick Macklem (forat.na_uid != nd->nd_cred->cr_uid || 10429ec7b004SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) 10438da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 10449ec7b004SRick Macklem nd->nd_cred, exp, p, 10458da45f2cSRick Macklem NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 104690d2dfabSRick Macklem /* 104790d2dfabSRick Macklem * DS reads are marked by ND_DSSERVER or use the proxy special 104890d2dfabSRick Macklem * stateid. 104990d2dfabSRick Macklem */ 105090d2dfabSRick Macklem if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) == 105190d2dfabSRick Macklem ND_NFSV4 && gotproxystateid == 0) 10529ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 10539ec7b004SRick Macklem &stateid, exp, nd, p); 10549ec7b004SRick Macklem if (nd->nd_repstat) { 10559ec7b004SRick Macklem vput(vp); 10569ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 10579ec7b004SRick Macklem nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 1058a9285ae5SZack Kirsch goto out; 10599ec7b004SRick Macklem } 10609ec7b004SRick Macklem 10619ec7b004SRick Macklem /* 10629ec7b004SRick Macklem * For NFS Version 2, it is not obvious what a write of zero length 10639ec7b004SRick Macklem * should do, but I might as well be consistent with Version 3, 10649ec7b004SRick Macklem * which is to return ok so long as there are no permission problems. 10659ec7b004SRick Macklem */ 10669ec7b004SRick Macklem if (retlen > 0) { 1067c057a378SRick Macklem nd->nd_repstat = nfsvno_write(vp, off, retlen, &stable, 10689ec7b004SRick Macklem nd->nd_md, nd->nd_dpos, nd->nd_cred, p); 10699ec7b004SRick Macklem error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1); 10709ec7b004SRick Macklem if (error) 1071ce8d06feSRick Macklem goto nfsmout; 10729ec7b004SRick Macklem } 10739ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) 10749ec7b004SRick Macklem aftat_ret = 0; 10759ec7b004SRick Macklem else 107690d2dfabSRick Macklem aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 10779ec7b004SRick Macklem vput(vp); 10789ec7b004SRick Macklem if (!nd->nd_repstat) 10799ec7b004SRick Macklem nd->nd_repstat = aftat_ret; 10809ec7b004SRick Macklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 10819ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 10829ec7b004SRick Macklem nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 10839ec7b004SRick Macklem if (nd->nd_repstat) 1084a9285ae5SZack Kirsch goto out; 10859ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 10869ec7b004SRick Macklem *tl++ = txdr_unsigned(retlen); 1087e4558aacSXin LI /* 1088e4558aacSXin LI * If nfs_async is set, then pretend the write was FILESYNC. 1089e4558aacSXin LI * Warning: Doing this violates RFC1813 and runs a risk 1090e4558aacSXin LI * of data written by a client being lost when the server 1091e4558aacSXin LI * crashes/reboots. 1092e4558aacSXin LI */ 1093e4558aacSXin LI if (stable == NFSWRITE_UNSTABLE && nfs_async == 0) 10949ec7b004SRick Macklem *tl++ = txdr_unsigned(stable); 10959ec7b004SRick Macklem else 10969ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSWRITE_FILESYNC); 10979ec7b004SRick Macklem /* 10989ec7b004SRick Macklem * Actually, there is no need to txdr these fields, 10999ec7b004SRick Macklem * but it may make the values more human readable, 11009ec7b004SRick Macklem * for debugging purposes. 11019ec7b004SRick Macklem */ 11029ec7b004SRick Macklem *tl++ = txdr_unsigned(nfsboottime.tv_sec); 11039ec7b004SRick Macklem *tl = txdr_unsigned(nfsboottime.tv_usec); 11049ec7b004SRick Macklem } else if (!nd->nd_repstat) 11059ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 1106a9285ae5SZack Kirsch 1107a9285ae5SZack Kirsch out: 1108a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 11099ec7b004SRick Macklem return (0); 11109ec7b004SRick Macklem nfsmout: 11119ec7b004SRick Macklem vput(vp); 1112a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 11139ec7b004SRick Macklem return (error); 11149ec7b004SRick Macklem } 11159ec7b004SRick Macklem 11169ec7b004SRick Macklem /* 11179ec7b004SRick Macklem * nfs create service (creates regular files for V2 and V3. Spec. files for V2.) 11189ec7b004SRick Macklem * now does a truncate to 0 length via. setattr if it already exists 11199ec7b004SRick Macklem * The core creation routine has been extracted out into nfsrv_creatsub(), 11209ec7b004SRick Macklem * so it can also be used by nfsrv_open() for V4. 11219ec7b004SRick Macklem */ 1122b9cc3262SRyan Moeller int 11239ec7b004SRick Macklem nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram, 1124af444b18SEdward Tomasz Napierala vnode_t dp, struct nfsexstuff *exp) 11259ec7b004SRick Macklem { 11269ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 11279ec7b004SRick Macklem struct nfsv2_sattr *sp; 11289ec7b004SRick Macklem struct nameidata named; 11299ec7b004SRick Macklem u_int32_t *tl; 11309ec7b004SRick Macklem int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1; 11319ec7b004SRick Macklem int how = NFSCREATE_UNCHECKED, exclusive_flag = 0; 11329ec7b004SRick Macklem NFSDEV_T rdev = 0; 11339ec7b004SRick Macklem vnode_t vp = NULL, dirp = NULL; 11349ec7b004SRick Macklem fhandle_t fh; 11359ec7b004SRick Macklem char *bufp; 11369ec7b004SRick Macklem u_long *hashp; 11379ec7b004SRick Macklem enum vtype vtyp; 1138086f6e0cSRick Macklem int32_t cverf[2], tverf[2] = { 0, 0 }; 1139af444b18SEdward Tomasz Napierala struct thread *p = curthread; 11409ec7b004SRick Macklem 11419ec7b004SRick Macklem if (nd->nd_repstat) { 11429ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1143a9285ae5SZack Kirsch goto out; 11449ec7b004SRick Macklem } 11459ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 11466c21f6edSKonstantin Belousov LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE); 11479ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 11489ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1149a9285ae5SZack Kirsch if (error) 1150a9285ae5SZack Kirsch goto nfsmout; 11519ec7b004SRick Macklem if (!nd->nd_repstat) { 11529ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 11539ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 11549ec7b004SRick Macklem NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 11559ec7b004SRick Macklem vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode)); 11569ec7b004SRick Macklem if (vtyp == VNON) 11579ec7b004SRick Macklem vtyp = VREG; 11589ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, type, vtyp); 11599ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, mode, 11609ec7b004SRick Macklem nfstov_mode(sp->sa_mode)); 11619ec7b004SRick Macklem switch (nva.na_type) { 11629ec7b004SRick Macklem case VREG: 11639ec7b004SRick Macklem tsize = fxdr_unsigned(int32_t, sp->sa_size); 11649ec7b004SRick Macklem if (tsize != -1) 11659ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, size, 11669ec7b004SRick Macklem (u_quad_t)tsize); 11679ec7b004SRick Macklem break; 11689ec7b004SRick Macklem case VCHR: 11699ec7b004SRick Macklem case VBLK: 11709ec7b004SRick Macklem case VFIFO: 11719ec7b004SRick Macklem rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size); 11729ec7b004SRick Macklem break; 11739ec7b004SRick Macklem default: 11749ec7b004SRick Macklem break; 117574b8d63dSPedro F. Giffuni } 11769ec7b004SRick Macklem } else { 11779ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 11789ec7b004SRick Macklem how = fxdr_unsigned(int, *tl); 11799ec7b004SRick Macklem switch (how) { 11809ec7b004SRick Macklem case NFSCREATE_GUARDED: 11819ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 1182d8a5961fSMarcelo Araujo error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p); 11839ec7b004SRick Macklem if (error) 11849ec7b004SRick Macklem goto nfsmout; 11859ec7b004SRick Macklem break; 11869ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 1187086f6e0cSRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 1188086f6e0cSRick Macklem cverf[0] = *tl++; 1189086f6e0cSRick Macklem cverf[1] = *tl; 11909ec7b004SRick Macklem exclusive_flag = 1; 11919ec7b004SRick Macklem break; 119274b8d63dSPedro F. Giffuni } 11939ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, type, VREG); 11949ec7b004SRick Macklem } 11959ec7b004SRick Macklem } 11969ec7b004SRick Macklem if (nd->nd_repstat) { 11979ec7b004SRick Macklem nfsvno_relpathbuf(&named); 11989ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 119990d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1, 120090d2dfabSRick Macklem NULL); 12019ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 12029ec7b004SRick Macklem &diraft); 12039ec7b004SRick Macklem } 12049ec7b004SRick Macklem vput(dp); 1205a9285ae5SZack Kirsch goto out; 12069ec7b004SRick Macklem } 12079ec7b004SRick Macklem 12089ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 12099ec7b004SRick Macklem if (dirp) { 12109ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 12119ec7b004SRick Macklem vrele(dirp); 12129ec7b004SRick Macklem dirp = NULL; 12139ec7b004SRick Macklem } else { 121490d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 121590d2dfabSRick Macklem NULL); 12169ec7b004SRick Macklem } 12179ec7b004SRick Macklem } 12189ec7b004SRick Macklem if (nd->nd_repstat) { 12199ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 12209ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 12219ec7b004SRick Macklem &diraft); 12229ec7b004SRick Macklem if (dirp) 12239ec7b004SRick Macklem vrele(dirp); 1224a9285ae5SZack Kirsch goto out; 12259ec7b004SRick Macklem } 12269ec7b004SRick Macklem 12279ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) { 12289ec7b004SRick Macklem switch (how) { 12299ec7b004SRick Macklem case NFSCREATE_GUARDED: 12309ec7b004SRick Macklem if (named.ni_vp) 12319ec7b004SRick Macklem nd->nd_repstat = EEXIST; 12329ec7b004SRick Macklem break; 12339ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 12349ec7b004SRick Macklem break; 12359ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 12369ec7b004SRick Macklem if (named.ni_vp == NULL) 12379ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, mode, 0); 12389ec7b004SRick Macklem break; 123974b8d63dSPedro F. Giffuni } 12409ec7b004SRick Macklem } 12419ec7b004SRick Macklem 12429ec7b004SRick Macklem /* 12439ec7b004SRick Macklem * Iff doesn't exist, create it 12449ec7b004SRick Macklem * otherwise just truncate to 0 length 12459ec7b004SRick Macklem * should I set the mode too ? 12469ec7b004SRick Macklem */ 12479ec7b004SRick Macklem nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva, 1248127152feSEdward Tomasz Napierala &exclusive_flag, cverf, rdev, exp); 12499ec7b004SRick Macklem 12509ec7b004SRick Macklem if (!nd->nd_repstat) { 12519ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 12529ec7b004SRick Macklem if (!nd->nd_repstat) 125390d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, 125490d2dfabSRick Macklem NULL); 12559ec7b004SRick Macklem vput(vp); 1256086f6e0cSRick Macklem if (!nd->nd_repstat) { 1257086f6e0cSRick Macklem tverf[0] = nva.na_atime.tv_sec; 1258086f6e0cSRick Macklem tverf[1] = nva.na_atime.tv_nsec; 1259086f6e0cSRick Macklem } 12609ec7b004SRick Macklem } 12619ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 12629ec7b004SRick Macklem if (!nd->nd_repstat) { 12639ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 12649ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 12659ec7b004SRick Macklem } 12669ec7b004SRick Macklem } else { 1267086f6e0cSRick Macklem if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0] 1268086f6e0cSRick Macklem || cverf[1] != tverf[1])) 12699ec7b004SRick Macklem nd->nd_repstat = EEXIST; 127090d2dfabSRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 12719ec7b004SRick Macklem vrele(dirp); 12729ec7b004SRick Macklem if (!nd->nd_repstat) { 12739ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1); 12749ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 12759ec7b004SRick Macklem } 12769ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 12779ec7b004SRick Macklem } 1278a9285ae5SZack Kirsch 1279a9285ae5SZack Kirsch out: 1280a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 12819ec7b004SRick Macklem return (0); 12829ec7b004SRick Macklem nfsmout: 12839ec7b004SRick Macklem vput(dp); 12849ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1285a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 12869ec7b004SRick Macklem return (error); 12879ec7b004SRick Macklem } 12889ec7b004SRick Macklem 12899ec7b004SRick Macklem /* 12909ec7b004SRick Macklem * nfs v3 mknod service (and v4 create) 12919ec7b004SRick Macklem */ 1292b9cc3262SRyan Moeller int 12939ec7b004SRick Macklem nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram, 1294af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 12959ec7b004SRick Macklem { 12969ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 12979ec7b004SRick Macklem u_int32_t *tl; 12989ec7b004SRick Macklem struct nameidata named; 12999ec7b004SRick Macklem int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 13009ec7b004SRick Macklem u_int32_t major, minor; 13019ec7b004SRick Macklem enum vtype vtyp = VNON; 13029ec7b004SRick Macklem nfstype nfs4type = NFNON; 13039ec7b004SRick Macklem vnode_t vp, dirp = NULL; 13049ec7b004SRick Macklem nfsattrbit_t attrbits; 13059ec7b004SRick Macklem char *bufp = NULL, *pathcp = NULL; 13069ec7b004SRick Macklem u_long *hashp, cnflags; 13079ec7b004SRick Macklem NFSACL_T *aclp = NULL; 1308af444b18SEdward Tomasz Napierala struct thread *p = curthread; 13099ec7b004SRick Macklem 13109ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 13119ec7b004SRick Macklem cnflags = (LOCKPARENT | SAVESTART); 13129ec7b004SRick Macklem if (nd->nd_repstat) { 13139ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1314a9285ae5SZack Kirsch goto out; 13159ec7b004SRick Macklem } 13169ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 1317c3e22f83SRick Macklem aclp = acl_alloc(M_WAITOK); 13189ec7b004SRick Macklem aclp->acl_cnt = 0; 13199ec7b004SRick Macklem #endif 13209ec7b004SRick Macklem 13219ec7b004SRick Macklem /* 13229ec7b004SRick Macklem * For V4, the creation stuff is here, Yuck! 13239ec7b004SRick Macklem */ 13249ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 13259ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 13269ec7b004SRick Macklem vtyp = nfsv34tov_type(*tl); 13279ec7b004SRick Macklem nfs4type = fxdr_unsigned(nfstype, *tl); 13289ec7b004SRick Macklem switch (nfs4type) { 13299ec7b004SRick Macklem case NFLNK: 13309ec7b004SRick Macklem error = nfsvno_getsymlink(nd, &nva, p, &pathcp, 13319ec7b004SRick Macklem &pathlen); 1332a9285ae5SZack Kirsch if (error) 1333a9285ae5SZack Kirsch goto nfsmout; 13349ec7b004SRick Macklem break; 13359ec7b004SRick Macklem case NFCHR: 13369ec7b004SRick Macklem case NFBLK: 13379ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 13389ec7b004SRick Macklem major = fxdr_unsigned(u_int32_t, *tl++); 13399ec7b004SRick Macklem minor = fxdr_unsigned(u_int32_t, *tl); 13409ec7b004SRick Macklem nva.na_rdev = NFSMAKEDEV(major, minor); 13419ec7b004SRick Macklem break; 13429ec7b004SRick Macklem case NFSOCK: 13439ec7b004SRick Macklem case NFFIFO: 13449ec7b004SRick Macklem break; 13459ec7b004SRick Macklem case NFDIR: 1346f61786cbSRick Macklem cnflags = (LOCKPARENT | SAVENAME); 13479ec7b004SRick Macklem break; 13489ec7b004SRick Macklem default: 13499ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADTYPE; 13509ec7b004SRick Macklem vrele(dp); 13519ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 13529ec7b004SRick Macklem acl_free(aclp); 13539ec7b004SRick Macklem #endif 1354a9285ae5SZack Kirsch goto out; 1355a9285ae5SZack Kirsch } 13569ec7b004SRick Macklem } 13576c21f6edSKonstantin Belousov NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE); 13589ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 13599ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1360a9285ae5SZack Kirsch if (error) 1361a9285ae5SZack Kirsch goto nfsmout; 13629ec7b004SRick Macklem if (!nd->nd_repstat) { 13639ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 13649ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 13659ec7b004SRick Macklem vtyp = nfsv34tov_type(*tl); 13669ec7b004SRick Macklem } 1367d8a5961fSMarcelo Araujo error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p); 1368a9285ae5SZack Kirsch if (error) 1369a9285ae5SZack Kirsch goto nfsmout; 13709ec7b004SRick Macklem nva.na_type = vtyp; 13719ec7b004SRick Macklem if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) && 13729ec7b004SRick Macklem (vtyp == VCHR || vtyp == VBLK)) { 13739ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 13749ec7b004SRick Macklem major = fxdr_unsigned(u_int32_t, *tl++); 13759ec7b004SRick Macklem minor = fxdr_unsigned(u_int32_t, *tl); 13769ec7b004SRick Macklem nva.na_rdev = NFSMAKEDEV(major, minor); 13779ec7b004SRick Macklem } 13789ec7b004SRick Macklem } 13799ec7b004SRick Macklem 138090d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL); 13819ec7b004SRick Macklem if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 13829ec7b004SRick Macklem if (!dirfor_ret && NFSVNO_ISSETGID(&nva) && 13839ec7b004SRick Macklem dirfor.na_gid == nva.na_gid) 13849ec7b004SRick Macklem NFSVNO_UNSET(&nva, gid); 13859ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 13869ec7b004SRick Macklem } 13879ec7b004SRick Macklem if (nd->nd_repstat) { 13889ec7b004SRick Macklem vrele(dp); 13899ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 13909ec7b004SRick Macklem acl_free(aclp); 13919ec7b004SRick Macklem #endif 13929ec7b004SRick Macklem nfsvno_relpathbuf(&named); 13939ec7b004SRick Macklem if (pathcp) 1394222daa42SConrad Meyer free(pathcp, M_TEMP); 13959ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 13969ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 13979ec7b004SRick Macklem &diraft); 1398a9285ae5SZack Kirsch goto out; 13999ec7b004SRick Macklem } 14009ec7b004SRick Macklem 14019ec7b004SRick Macklem /* 14029ec7b004SRick Macklem * Yuck! For V4, mkdir and link are here and some V4 clients don't fill 14039ec7b004SRick Macklem * in va_mode, so we'll have to set a default here. 14049ec7b004SRick Macklem */ 14059ec7b004SRick Macklem if (NFSVNO_NOTSETMODE(&nva)) { 14069ec7b004SRick Macklem if (vtyp == VLNK) 14079ec7b004SRick Macklem nva.na_mode = 0755; 14089ec7b004SRick Macklem else 14099ec7b004SRick Macklem nva.na_mode = 0400; 14109ec7b004SRick Macklem } 14119ec7b004SRick Macklem 14129ec7b004SRick Macklem if (vtyp == VDIR) 14139ec7b004SRick Macklem named.ni_cnd.cn_flags |= WILLBEDIR; 14149ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 14159ec7b004SRick Macklem if (nd->nd_repstat) { 14169ec7b004SRick Macklem if (dirp) { 14179ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 141890d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, 141990d2dfabSRick Macklem p, 0, NULL); 14209ec7b004SRick Macklem vrele(dirp); 14219ec7b004SRick Macklem } 14229ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 14239ec7b004SRick Macklem acl_free(aclp); 14249ec7b004SRick Macklem #endif 14259ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 14269ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 14279ec7b004SRick Macklem &diraft); 1428a9285ae5SZack Kirsch goto out; 14299ec7b004SRick Macklem } 14309ec7b004SRick Macklem if (dirp) 143190d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); 14329ec7b004SRick Macklem 14339ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) { 14349ec7b004SRick Macklem if (vtyp == VDIR) { 14359ec7b004SRick Macklem nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, 14369ec7b004SRick Macklem &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p, 14379ec7b004SRick Macklem exp); 14389ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 14399ec7b004SRick Macklem acl_free(aclp); 14409ec7b004SRick Macklem #endif 1441a9285ae5SZack Kirsch goto out; 14429ec7b004SRick Macklem } else if (vtyp == VLNK) { 14439ec7b004SRick Macklem nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 14449ec7b004SRick Macklem &dirfor, &diraft, &diraft_ret, &attrbits, 14459ec7b004SRick Macklem aclp, p, exp, pathcp, pathlen); 14469ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 14479ec7b004SRick Macklem acl_free(aclp); 14489ec7b004SRick Macklem #endif 1449222daa42SConrad Meyer free(pathcp, M_TEMP); 1450a9285ae5SZack Kirsch goto out; 14519ec7b004SRick Macklem } 14529ec7b004SRick Macklem } 14539ec7b004SRick Macklem 14549ec7b004SRick Macklem nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p); 14559ec7b004SRick Macklem if (!nd->nd_repstat) { 14569ec7b004SRick Macklem vp = named.ni_vp; 14579ec7b004SRick Macklem nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp); 14589ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 14599ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat) 146090d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, 146190d2dfabSRick Macklem NULL); 146281f78d99SRick Macklem if (vpp != NULL && nd->nd_repstat == 0) { 1463b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 14649ec7b004SRick Macklem *vpp = vp; 146581f78d99SRick Macklem } else 14669ec7b004SRick Macklem vput(vp); 14679ec7b004SRick Macklem } 14689ec7b004SRick Macklem 146990d2dfabSRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 14709ec7b004SRick Macklem vrele(dirp); 14719ec7b004SRick Macklem if (!nd->nd_repstat) { 14729ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 14739ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 14749ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 14759ec7b004SRick Macklem } else { 14769ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 14779ec7b004SRick Macklem *tl++ = newnfs_false; 14789ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 14799ec7b004SRick Macklem tl += 2; 14809ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 14819ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &attrbits); 14829ec7b004SRick Macklem } 14839ec7b004SRick Macklem } 14849ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 14859ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 14869ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 14879ec7b004SRick Macklem acl_free(aclp); 14889ec7b004SRick Macklem #endif 1489a9285ae5SZack Kirsch 1490a9285ae5SZack Kirsch out: 1491a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 14929ec7b004SRick Macklem return (0); 14939ec7b004SRick Macklem nfsmout: 14949ec7b004SRick Macklem vrele(dp); 14959ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 14969ec7b004SRick Macklem acl_free(aclp); 14979ec7b004SRick Macklem #endif 14989ec7b004SRick Macklem if (bufp) 14999ec7b004SRick Macklem nfsvno_relpathbuf(&named); 15009ec7b004SRick Macklem if (pathcp) 1501222daa42SConrad Meyer free(pathcp, M_TEMP); 1502a9285ae5SZack Kirsch 1503a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 15049ec7b004SRick Macklem return (error); 15059ec7b004SRick Macklem } 15069ec7b004SRick Macklem 15079ec7b004SRick Macklem /* 15089ec7b004SRick Macklem * nfs remove service 15099ec7b004SRick Macklem */ 1510b9cc3262SRyan Moeller int 15119ec7b004SRick Macklem nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram, 1512af444b18SEdward Tomasz Napierala vnode_t dp, struct nfsexstuff *exp) 15139ec7b004SRick Macklem { 15149ec7b004SRick Macklem struct nameidata named; 15159ec7b004SRick Macklem u_int32_t *tl; 1516a9285ae5SZack Kirsch int error = 0, dirfor_ret = 1, diraft_ret = 1; 15179ec7b004SRick Macklem vnode_t dirp = NULL; 15189ec7b004SRick Macklem struct nfsvattr dirfor, diraft; 15199ec7b004SRick Macklem char *bufp; 15209ec7b004SRick Macklem u_long *hashp; 1521af444b18SEdward Tomasz Napierala struct thread *p = curthread; 15229ec7b004SRick Macklem 15239ec7b004SRick Macklem if (nd->nd_repstat) { 15249ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1525a9285ae5SZack Kirsch goto out; 15269ec7b004SRick Macklem } 15279ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE, 15289ec7b004SRick Macklem LOCKPARENT | LOCKLEAF); 15299ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 15309ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 15319ec7b004SRick Macklem if (error) { 15329ec7b004SRick Macklem vput(dp); 15339ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1534a9285ae5SZack Kirsch goto out; 15359ec7b004SRick Macklem } 15369ec7b004SRick Macklem if (!nd->nd_repstat) { 15379ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 15389ec7b004SRick Macklem } else { 15399ec7b004SRick Macklem vput(dp); 15409ec7b004SRick Macklem nfsvno_relpathbuf(&named); 15419ec7b004SRick Macklem } 15429ec7b004SRick Macklem if (dirp) { 15439ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) { 154490d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 154590d2dfabSRick Macklem NULL); 15469ec7b004SRick Macklem } else { 15479ec7b004SRick Macklem vrele(dirp); 15489ec7b004SRick Macklem dirp = NULL; 15499ec7b004SRick Macklem } 15509ec7b004SRick Macklem } 15519ec7b004SRick Macklem if (!nd->nd_repstat) { 15529ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 15539ec7b004SRick Macklem if (vnode_vtype(named.ni_vp) == VDIR) 15549ec7b004SRick Macklem nd->nd_repstat = nfsvno_rmdirsub(&named, 1, 15559ec7b004SRick Macklem nd->nd_cred, p, exp); 15569ec7b004SRick Macklem else 15579ec7b004SRick Macklem nd->nd_repstat = nfsvno_removesub(&named, 1, 15589ec7b004SRick Macklem nd->nd_cred, p, exp); 15599ec7b004SRick Macklem } else if (nd->nd_procnum == NFSPROC_RMDIR) { 15609ec7b004SRick Macklem nd->nd_repstat = nfsvno_rmdirsub(&named, 0, 15619ec7b004SRick Macklem nd->nd_cred, p, exp); 15629ec7b004SRick Macklem } else { 15639ec7b004SRick Macklem nd->nd_repstat = nfsvno_removesub(&named, 0, 15649ec7b004SRick Macklem nd->nd_cred, p, exp); 15659ec7b004SRick Macklem } 15669ec7b004SRick Macklem } 15679ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) { 15689ec7b004SRick Macklem if (dirp) { 156990d2dfabSRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, 157090d2dfabSRick Macklem NULL); 15719ec7b004SRick Macklem vrele(dirp); 15729ec7b004SRick Macklem } 15739ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 15749ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 15759ec7b004SRick Macklem &diraft); 15769ec7b004SRick Macklem } else if (!nd->nd_repstat) { 15779ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 15789ec7b004SRick Macklem *tl++ = newnfs_false; 15799ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 15809ec7b004SRick Macklem tl += 2; 15819ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 15829ec7b004SRick Macklem } 15839ec7b004SRick Macklem } 1584a9285ae5SZack Kirsch 1585a9285ae5SZack Kirsch out: 1586a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1587a9285ae5SZack Kirsch return (error); 15889ec7b004SRick Macklem } 15899ec7b004SRick Macklem 15909ec7b004SRick Macklem /* 15919ec7b004SRick Macklem * nfs rename service 15929ec7b004SRick Macklem */ 1593b9cc3262SRyan Moeller int 15949ec7b004SRick Macklem nfsrvd_rename(struct nfsrv_descript *nd, int isdgram, 1595af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t todp, struct nfsexstuff *exp, struct nfsexstuff *toexp) 15969ec7b004SRick Macklem { 15979ec7b004SRick Macklem u_int32_t *tl; 1598a9285ae5SZack Kirsch int error = 0, fdirfor_ret = 1, fdiraft_ret = 1; 15999ec7b004SRick Macklem int tdirfor_ret = 1, tdiraft_ret = 1; 16009ec7b004SRick Macklem struct nameidata fromnd, tond; 16019ec7b004SRick Macklem vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL; 16029ec7b004SRick Macklem struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft; 16039ec7b004SRick Macklem struct nfsexstuff tnes; 16049ec7b004SRick Macklem struct nfsrvfh tfh; 16059ec7b004SRick Macklem char *bufp, *tbufp = NULL; 16069ec7b004SRick Macklem u_long *hashp; 16076b3dfc6aSRick Macklem fhandle_t fh; 1608af444b18SEdward Tomasz Napierala struct thread *p = curthread; 16099ec7b004SRick Macklem 16109ec7b004SRick Macklem if (nd->nd_repstat) { 16119ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 16129ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 1613a9285ae5SZack Kirsch goto out; 16149ec7b004SRick Macklem } 16159ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) 161690d2dfabSRick Macklem fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL); 16179ec7b004SRick Macklem tond.ni_cnd.cn_nameiop = 0; 16189ec7b004SRick Macklem tond.ni_startdir = NULL; 16199ec7b004SRick Macklem NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART); 16209ec7b004SRick Macklem nfsvno_setpathbuf(&fromnd, &bufp, &hashp); 16219ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen); 16229ec7b004SRick Macklem if (error) { 16239ec7b004SRick Macklem vput(dp); 16249ec7b004SRick Macklem if (todp) 16259ec7b004SRick Macklem vrele(todp); 16269ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 1627a9285ae5SZack Kirsch goto out; 16289ec7b004SRick Macklem } 162925bfde79SXin LI /* 163025bfde79SXin LI * Unlock dp in this code section, so it is unlocked before 163125bfde79SXin LI * tdp gets locked. This avoids a potential LOR if tdp is the 163225bfde79SXin LI * parent directory of dp. 163325bfde79SXin LI */ 16349ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 16359ec7b004SRick Macklem tdp = todp; 16369ec7b004SRick Macklem tnes = *toexp; 163725bfde79SXin LI if (dp != tdp) { 1638b249ce48SMateusz Guzik NFSVOPUNLOCK(dp); 163990d2dfabSRick Macklem /* Might lock tdp. */ 164090d2dfabSRick Macklem tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0, 164190d2dfabSRick Macklem NULL); 164225bfde79SXin LI } else { 164390d2dfabSRick Macklem tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1, 164490d2dfabSRick Macklem NULL); 1645b249ce48SMateusz Guzik NFSVOPUNLOCK(dp); 164625bfde79SXin LI } 16479ec7b004SRick Macklem } else { 16486b3dfc6aSRick Macklem tfh.nfsrvfh_len = 0; 16499ec7b004SRick Macklem error = nfsrv_mtofh(nd, &tfh); 16506b3dfc6aSRick Macklem if (error == 0) 16516b3dfc6aSRick Macklem error = nfsvno_getfh(dp, &fh, p); 16529ec7b004SRick Macklem if (error) { 16539ec7b004SRick Macklem vput(dp); 16549ec7b004SRick Macklem /* todp is always NULL except NFSv4 */ 16559ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 1656a9285ae5SZack Kirsch goto out; 16579ec7b004SRick Macklem } 16586b3dfc6aSRick Macklem 16596b3dfc6aSRick Macklem /* If this is the same file handle, just VREF() the vnode. */ 16606b3dfc6aSRick Macklem if (tfh.nfsrvfh_len == NFSX_MYFH && 16616b3dfc6aSRick Macklem !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) { 16626b3dfc6aSRick Macklem VREF(dp); 16636b3dfc6aSRick Macklem tdp = dp; 16646b3dfc6aSRick Macklem tnes = *exp; 166590d2dfabSRick Macklem tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1, 166690d2dfabSRick Macklem NULL); 1667b249ce48SMateusz Guzik NFSVOPUNLOCK(dp); 16686b3dfc6aSRick Macklem } else { 1669b249ce48SMateusz Guzik NFSVOPUNLOCK(dp); 16706b3dfc6aSRick Macklem nd->nd_cred->cr_uid = nd->nd_saveduid; 16716b3dfc6aSRick Macklem nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL, 16725edc9102SEdward Tomasz Napierala 0); /* Locks tdp. */ 16736b3dfc6aSRick Macklem if (tdp) { 167490d2dfabSRick Macklem tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, 167590d2dfabSRick Macklem p, 1, NULL); 1676b249ce48SMateusz Guzik NFSVOPUNLOCK(tdp); 16779ec7b004SRick Macklem } 16789ec7b004SRick Macklem } 16796b3dfc6aSRick Macklem } 16809ec7b004SRick Macklem NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART); 16819ec7b004SRick Macklem nfsvno_setpathbuf(&tond, &tbufp, &hashp); 16829ec7b004SRick Macklem if (!nd->nd_repstat) { 16839ec7b004SRick Macklem error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen); 16849ec7b004SRick Macklem if (error) { 16858974bc2fSRick Macklem if (tdp) 16869ec7b004SRick Macklem vrele(tdp); 168725bfde79SXin LI vrele(dp); 16889ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 16899ec7b004SRick Macklem nfsvno_relpathbuf(&tond); 1690a9285ae5SZack Kirsch goto out; 16919ec7b004SRick Macklem } 16929ec7b004SRick Macklem } 16939ec7b004SRick Macklem if (nd->nd_repstat) { 16949ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 16959ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 16969ec7b004SRick Macklem &fdiraft); 16979ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 16989ec7b004SRick Macklem &tdiraft); 16999ec7b004SRick Macklem } 17008974bc2fSRick Macklem if (tdp) 17019ec7b004SRick Macklem vrele(tdp); 170225bfde79SXin LI vrele(dp); 17039ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 17049ec7b004SRick Macklem nfsvno_relpathbuf(&tond); 1705a9285ae5SZack Kirsch goto out; 17069ec7b004SRick Macklem } 17079ec7b004SRick Macklem 17089ec7b004SRick Macklem /* 17099ec7b004SRick Macklem * Done parsing, now down to business. 17109ec7b004SRick Macklem */ 171125bfde79SXin LI nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp); 17129ec7b004SRick Macklem if (nd->nd_repstat) { 17139ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 17149ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 17159ec7b004SRick Macklem &fdiraft); 17169ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 17179ec7b004SRick Macklem &tdiraft); 17189ec7b004SRick Macklem } 17199ec7b004SRick Macklem if (fdirp) 17209ec7b004SRick Macklem vrele(fdirp); 17218974bc2fSRick Macklem if (tdp) 17229ec7b004SRick Macklem vrele(tdp); 17239ec7b004SRick Macklem nfsvno_relpathbuf(&tond); 1724a9285ae5SZack Kirsch goto out; 17259ec7b004SRick Macklem } 17269ec7b004SRick Macklem if (vnode_vtype(fromnd.ni_vp) == VDIR) 17279ec7b004SRick Macklem tond.ni_cnd.cn_flags |= WILLBEDIR; 17289ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp); 17299ec7b004SRick Macklem nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat, 17309ec7b004SRick Macklem nd->nd_flag, nd->nd_cred, p); 17319ec7b004SRick Macklem if (fdirp) 173290d2dfabSRick Macklem fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL); 17339ec7b004SRick Macklem if (tdirp) 173490d2dfabSRick Macklem tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL); 17359ec7b004SRick Macklem if (fdirp) 17369ec7b004SRick Macklem vrele(fdirp); 17379ec7b004SRick Macklem if (tdirp) 17389ec7b004SRick Macklem vrele(tdirp); 17399ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 17409ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 17419ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 17429ec7b004SRick Macklem } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 17439ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED); 17449ec7b004SRick Macklem *tl++ = newnfs_false; 17459ec7b004SRick Macklem txdr_hyper(fdirfor.na_filerev, tl); 17469ec7b004SRick Macklem tl += 2; 17479ec7b004SRick Macklem txdr_hyper(fdiraft.na_filerev, tl); 17489ec7b004SRick Macklem tl += 2; 17499ec7b004SRick Macklem *tl++ = newnfs_false; 17509ec7b004SRick Macklem txdr_hyper(tdirfor.na_filerev, tl); 17519ec7b004SRick Macklem tl += 2; 17529ec7b004SRick Macklem txdr_hyper(tdiraft.na_filerev, tl); 17539ec7b004SRick Macklem } 1754a9285ae5SZack Kirsch 1755a9285ae5SZack Kirsch out: 1756a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1757a9285ae5SZack Kirsch return (error); 17589ec7b004SRick Macklem } 17599ec7b004SRick Macklem 17609ec7b004SRick Macklem /* 17619ec7b004SRick Macklem * nfs link service 17629ec7b004SRick Macklem */ 1763b9cc3262SRyan Moeller int 17649ec7b004SRick Macklem nfsrvd_link(struct nfsrv_descript *nd, int isdgram, 1765af444b18SEdward Tomasz Napierala vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp) 17669ec7b004SRick Macklem { 17679ec7b004SRick Macklem struct nameidata named; 17689ec7b004SRick Macklem u_int32_t *tl; 17699ec7b004SRick Macklem int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1; 17709ec7b004SRick Macklem vnode_t dirp = NULL, dp = NULL; 17719ec7b004SRick Macklem struct nfsvattr dirfor, diraft, at; 17729ec7b004SRick Macklem struct nfsexstuff tnes; 17739ec7b004SRick Macklem struct nfsrvfh dfh; 17749ec7b004SRick Macklem char *bufp; 17759ec7b004SRick Macklem u_long *hashp; 1776af444b18SEdward Tomasz Napierala struct thread *p = curthread; 17779ec7b004SRick Macklem 17789ec7b004SRick Macklem if (nd->nd_repstat) { 17799ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 17809ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1781a9285ae5SZack Kirsch goto out; 17829ec7b004SRick Macklem } 1783b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 17849ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) { 17859ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) 17869ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 17879ec7b004SRick Macklem else 17889ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 17899ec7b004SRick Macklem if (tovp) 17909ec7b004SRick Macklem vrele(tovp); 17919ec7b004SRick Macklem } 17929ec7b004SRick Macklem if (!nd->nd_repstat) { 17939ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 17949ec7b004SRick Macklem dp = tovp; 17959ec7b004SRick Macklem tnes = *toexp; 17969ec7b004SRick Macklem } else { 17979ec7b004SRick Macklem error = nfsrv_mtofh(nd, &dfh); 17989ec7b004SRick Macklem if (error) { 17999ec7b004SRick Macklem vrele(vp); 18009ec7b004SRick Macklem /* tovp is always NULL unless NFSv4 */ 1801a9285ae5SZack Kirsch goto out; 18029ec7b004SRick Macklem } 18035edc9102SEdward Tomasz Napierala nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0); 18049ec7b004SRick Macklem if (dp) 1805b249ce48SMateusz Guzik NFSVOPUNLOCK(dp); 18069ec7b004SRick Macklem } 18079ec7b004SRick Macklem } 1808f61786cbSRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 18096c21f6edSKonstantin Belousov LOCKPARENT | SAVENAME | NOCACHE); 18109ec7b004SRick Macklem if (!nd->nd_repstat) { 18119ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 18129ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 18139ec7b004SRick Macklem if (error) { 18149ec7b004SRick Macklem vrele(vp); 18158974bc2fSRick Macklem if (dp) 18169ec7b004SRick Macklem vrele(dp); 18179ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1818a9285ae5SZack Kirsch goto out; 18199ec7b004SRick Macklem } 18209ec7b004SRick Macklem if (!nd->nd_repstat) { 18219ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes, 18229ec7b004SRick Macklem p, &dirp); 18239ec7b004SRick Macklem } else { 18249ec7b004SRick Macklem if (dp) 18259ec7b004SRick Macklem vrele(dp); 18269ec7b004SRick Macklem nfsvno_relpathbuf(&named); 18279ec7b004SRick Macklem } 18289ec7b004SRick Macklem } 18299ec7b004SRick Macklem if (dirp) { 18309ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 18319ec7b004SRick Macklem vrele(dirp); 18329ec7b004SRick Macklem dirp = NULL; 18339ec7b004SRick Macklem } else { 183490d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 183590d2dfabSRick Macklem NULL); 18369ec7b004SRick Macklem } 18379ec7b004SRick Macklem } 18389ec7b004SRick Macklem if (!nd->nd_repstat) 18399ec7b004SRick Macklem nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp); 18409ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 184190d2dfabSRick Macklem getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL); 18429ec7b004SRick Macklem if (dirp) { 184390d2dfabSRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 18449ec7b004SRick Macklem vrele(dirp); 18459ec7b004SRick Macklem } 18469ec7b004SRick Macklem vrele(vp); 18479ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 18489ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 18499ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 18509ec7b004SRick Macklem } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 18519ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 18529ec7b004SRick Macklem *tl++ = newnfs_false; 18539ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 18549ec7b004SRick Macklem tl += 2; 18559ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 18569ec7b004SRick Macklem } 1857a9285ae5SZack Kirsch 1858a9285ae5SZack Kirsch out: 1859a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1860a9285ae5SZack Kirsch return (error); 18619ec7b004SRick Macklem } 18629ec7b004SRick Macklem 18639ec7b004SRick Macklem /* 18649ec7b004SRick Macklem * nfs symbolic link service 18659ec7b004SRick Macklem */ 1866b9cc3262SRyan Moeller int 18679ec7b004SRick Macklem nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram, 1868af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 18699ec7b004SRick Macklem { 18709ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 18719ec7b004SRick Macklem struct nameidata named; 1872a9285ae5SZack Kirsch int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 18739ec7b004SRick Macklem vnode_t dirp = NULL; 18749ec7b004SRick Macklem char *bufp, *pathcp = NULL; 18759ec7b004SRick Macklem u_long *hashp; 1876af444b18SEdward Tomasz Napierala struct thread *p = curthread; 18779ec7b004SRick Macklem 18789ec7b004SRick Macklem if (nd->nd_repstat) { 18799ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1880a9285ae5SZack Kirsch goto out; 18819ec7b004SRick Macklem } 18829ec7b004SRick Macklem if (vpp) 18839ec7b004SRick Macklem *vpp = NULL; 18849ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 18859ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 18866c21f6edSKonstantin Belousov LOCKPARENT | SAVESTART | NOCACHE); 18879ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 18889ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 18899ec7b004SRick Macklem if (!error && !nd->nd_repstat) 18909ec7b004SRick Macklem error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen); 18919ec7b004SRick Macklem if (error) { 18929ec7b004SRick Macklem vrele(dp); 18939ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1894a9285ae5SZack Kirsch goto out; 18959ec7b004SRick Macklem } 18969ec7b004SRick Macklem if (!nd->nd_repstat) { 18979ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 18989ec7b004SRick Macklem } else { 18999ec7b004SRick Macklem vrele(dp); 19009ec7b004SRick Macklem nfsvno_relpathbuf(&named); 19019ec7b004SRick Macklem } 19029ec7b004SRick Macklem if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 19039ec7b004SRick Macklem vrele(dirp); 19049ec7b004SRick Macklem dirp = NULL; 19059ec7b004SRick Macklem } 19069ec7b004SRick Macklem 19079ec7b004SRick Macklem /* 19089ec7b004SRick Macklem * And call nfsrvd_symlinksub() to do the common code. It will 19099ec7b004SRick Macklem * return EBADRPC upon a parsing error, 0 otherwise. 19109ec7b004SRick Macklem */ 19119ec7b004SRick Macklem if (!nd->nd_repstat) { 19129ec7b004SRick Macklem if (dirp != NULL) 191390d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 191490d2dfabSRick Macklem NULL); 19159ec7b004SRick Macklem nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 19169ec7b004SRick Macklem &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp, 19179ec7b004SRick Macklem pathcp, pathlen); 19189ec7b004SRick Macklem } else if (dirp != NULL) { 191990d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); 19209ec7b004SRick Macklem vrele(dirp); 19219ec7b004SRick Macklem } 19229ec7b004SRick Macklem if (pathcp) 1923222daa42SConrad Meyer free(pathcp, M_TEMP); 19249ec7b004SRick Macklem 19259ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 19269ec7b004SRick Macklem if (!nd->nd_repstat) { 19279ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 19289ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 19299ec7b004SRick Macklem } 19309ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 19319ec7b004SRick Macklem } 1932a9285ae5SZack Kirsch 1933a9285ae5SZack Kirsch out: 1934a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1935a9285ae5SZack Kirsch return (error); 19369ec7b004SRick Macklem } 19379ec7b004SRick Macklem 19389ec7b004SRick Macklem /* 19399ec7b004SRick Macklem * Common code for creating a symbolic link. 19409ec7b004SRick Macklem */ 19419ec7b004SRick Macklem static void 19429ec7b004SRick Macklem nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 19439ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 19449ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 19459ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, 19469ec7b004SRick Macklem NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 19479ec7b004SRick Macklem int pathlen) 19489ec7b004SRick Macklem { 19499ec7b004SRick Macklem u_int32_t *tl; 19509ec7b004SRick Macklem 19519ec7b004SRick Macklem nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen, 19529ec7b004SRick Macklem !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp); 19539ec7b004SRick Macklem if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) { 19549ec7b004SRick Macklem nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp); 19559ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 19569ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p); 19579ec7b004SRick Macklem if (!nd->nd_repstat) 19589ec7b004SRick Macklem nd->nd_repstat = nfsvno_getattr(ndp->ni_vp, 195990d2dfabSRick Macklem nvap, nd, p, 1, NULL); 19609ec7b004SRick Macklem } 196181f78d99SRick Macklem if (vpp != NULL && nd->nd_repstat == 0) { 1962b249ce48SMateusz Guzik NFSVOPUNLOCK(ndp->ni_vp); 19639ec7b004SRick Macklem *vpp = ndp->ni_vp; 196481f78d99SRick Macklem } else 19659ec7b004SRick Macklem vput(ndp->ni_vp); 19669ec7b004SRick Macklem } 19679ec7b004SRick Macklem if (dirp) { 196890d2dfabSRick Macklem *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL); 19699ec7b004SRick Macklem vrele(dirp); 19709ec7b004SRick Macklem } 19719ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 19729ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 19739ec7b004SRick Macklem *tl++ = newnfs_false; 19749ec7b004SRick Macklem txdr_hyper(dirforp->na_filerev, tl); 19759ec7b004SRick Macklem tl += 2; 19769ec7b004SRick Macklem txdr_hyper(diraftp->na_filerev, tl); 19779ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, attrbitp); 19789ec7b004SRick Macklem } 1979a9285ae5SZack Kirsch 1980a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 19819ec7b004SRick Macklem } 19829ec7b004SRick Macklem 19839ec7b004SRick Macklem /* 19849ec7b004SRick Macklem * nfs mkdir service 19859ec7b004SRick Macklem */ 1986b9cc3262SRyan Moeller int 19879ec7b004SRick Macklem nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram, 1988af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 19899ec7b004SRick Macklem { 19909ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 19919ec7b004SRick Macklem struct nameidata named; 19929ec7b004SRick Macklem u_int32_t *tl; 1993a9285ae5SZack Kirsch int error = 0, dirfor_ret = 1, diraft_ret = 1; 19949ec7b004SRick Macklem vnode_t dirp = NULL; 19959ec7b004SRick Macklem char *bufp; 19969ec7b004SRick Macklem u_long *hashp; 1997af444b18SEdward Tomasz Napierala struct thread *p = curthread; 19989ec7b004SRick Macklem 19999ec7b004SRick Macklem if (nd->nd_repstat) { 20009ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 2001a9285ae5SZack Kirsch goto out; 20029ec7b004SRick Macklem } 2003f61786cbSRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 20046c21f6edSKonstantin Belousov LOCKPARENT | SAVENAME | NOCACHE); 20059ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 20069ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 2007a9285ae5SZack Kirsch if (error) 2008a9285ae5SZack Kirsch goto nfsmout; 20099ec7b004SRick Macklem if (!nd->nd_repstat) { 20109ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 20119ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 2012d8a5961fSMarcelo Araujo error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p); 2013a9285ae5SZack Kirsch if (error) 2014a9285ae5SZack Kirsch goto nfsmout; 20159ec7b004SRick Macklem } else { 20169ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 20179ec7b004SRick Macklem nva.na_mode = nfstov_mode(*tl++); 20189ec7b004SRick Macklem } 20199ec7b004SRick Macklem } 20209ec7b004SRick Macklem if (!nd->nd_repstat) { 20219ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 20229ec7b004SRick Macklem } else { 20239ec7b004SRick Macklem vrele(dp); 20249ec7b004SRick Macklem nfsvno_relpathbuf(&named); 20259ec7b004SRick Macklem } 20269ec7b004SRick Macklem if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 20279ec7b004SRick Macklem vrele(dirp); 20289ec7b004SRick Macklem dirp = NULL; 20299ec7b004SRick Macklem } 20309ec7b004SRick Macklem if (nd->nd_repstat) { 20319ec7b004SRick Macklem if (dirp != NULL) { 203290d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 203390d2dfabSRick Macklem NULL); 20349ec7b004SRick Macklem vrele(dirp); 20359ec7b004SRick Macklem } 20369ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 20379ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 20389ec7b004SRick Macklem &diraft); 2039a9285ae5SZack Kirsch goto out; 20409ec7b004SRick Macklem } 20419ec7b004SRick Macklem if (dirp != NULL) 204290d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); 20439ec7b004SRick Macklem 20449ec7b004SRick Macklem /* 20459ec7b004SRick Macklem * Call nfsrvd_mkdirsub() for the code common to V4 as well. 20469ec7b004SRick Macklem */ 20479ec7b004SRick Macklem nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft, 20489ec7b004SRick Macklem &diraft_ret, NULL, NULL, p, exp); 20499ec7b004SRick Macklem 20509ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 20519ec7b004SRick Macklem if (!nd->nd_repstat) { 20529ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 20539ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 20549ec7b004SRick Macklem } 20559ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 20569ec7b004SRick Macklem } else if (!nd->nd_repstat) { 20579ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 20589ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 20599ec7b004SRick Macklem } 2060a9285ae5SZack Kirsch 2061a9285ae5SZack Kirsch out: 2062a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 20639ec7b004SRick Macklem return (0); 20649ec7b004SRick Macklem nfsmout: 20659ec7b004SRick Macklem vrele(dp); 20669ec7b004SRick Macklem nfsvno_relpathbuf(&named); 2067a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 20689ec7b004SRick Macklem return (error); 20699ec7b004SRick Macklem } 20709ec7b004SRick Macklem 20719ec7b004SRick Macklem /* 20729ec7b004SRick Macklem * Code common to mkdir for V2,3 and 4. 20739ec7b004SRick Macklem */ 20749ec7b004SRick Macklem static void 20759ec7b004SRick Macklem nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 20769ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 20779ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 20789ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 20799ec7b004SRick Macklem NFSPROC_T *p, struct nfsexstuff *exp) 20809ec7b004SRick Macklem { 20819ec7b004SRick Macklem vnode_t vp; 20829ec7b004SRick Macklem u_int32_t *tl; 20839ec7b004SRick Macklem 20849ec7b004SRick Macklem NFSVNO_SETATTRVAL(nvap, type, VDIR); 20859ec7b004SRick Macklem nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid, 20869ec7b004SRick Macklem nd->nd_cred, p, exp); 20879ec7b004SRick Macklem if (!nd->nd_repstat) { 20889ec7b004SRick Macklem vp = ndp->ni_vp; 20899ec7b004SRick Macklem nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp); 20909ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 20919ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 209290d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1, 209390d2dfabSRick Macklem NULL); 20949ec7b004SRick Macklem if (vpp && !nd->nd_repstat) { 2095b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 20969ec7b004SRick Macklem *vpp = vp; 20979ec7b004SRick Macklem } else { 20989ec7b004SRick Macklem vput(vp); 20999ec7b004SRick Macklem } 21009ec7b004SRick Macklem } 21019ec7b004SRick Macklem if (dirp) { 210290d2dfabSRick Macklem *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL); 21039ec7b004SRick Macklem vrele(dirp); 21049ec7b004SRick Macklem } 21059ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 21069ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 21079ec7b004SRick Macklem *tl++ = newnfs_false; 21089ec7b004SRick Macklem txdr_hyper(dirforp->na_filerev, tl); 21099ec7b004SRick Macklem tl += 2; 21109ec7b004SRick Macklem txdr_hyper(diraftp->na_filerev, tl); 21119ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, attrbitp); 21129ec7b004SRick Macklem } 2113a9285ae5SZack Kirsch 2114a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 21159ec7b004SRick Macklem } 21169ec7b004SRick Macklem 21179ec7b004SRick Macklem /* 21189ec7b004SRick Macklem * nfs commit service 21199ec7b004SRick Macklem */ 2120b9cc3262SRyan Moeller int 21219ec7b004SRick Macklem nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram, 2122af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 21239ec7b004SRick Macklem { 21249ec7b004SRick Macklem struct nfsvattr bfor, aft; 21259ec7b004SRick Macklem u_int32_t *tl; 21269ec7b004SRick Macklem int error = 0, for_ret = 1, aft_ret = 1, cnt; 21279ec7b004SRick Macklem u_int64_t off; 2128af444b18SEdward Tomasz Napierala struct thread *p = curthread; 21299ec7b004SRick Macklem 21309ec7b004SRick Macklem if (nd->nd_repstat) { 21319ec7b004SRick Macklem nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 2132a9285ae5SZack Kirsch goto out; 21339ec7b004SRick Macklem } 2134d8a5961fSMarcelo Araujo 2135d8a5961fSMarcelo Araujo /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */ 2136d8a5961fSMarcelo Araujo if (vp->v_type != VREG) { 2137d8a5961fSMarcelo Araujo if (nd->nd_flag & ND_NFSV3) 2138d8a5961fSMarcelo Araujo error = NFSERR_NOTSUPP; 2139d8a5961fSMarcelo Araujo else 2140d8a5961fSMarcelo Araujo error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL; 2141d8a5961fSMarcelo Araujo goto nfsmout; 2142d8a5961fSMarcelo Araujo } 21439ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2144d8a5961fSMarcelo Araujo 21459ec7b004SRick Macklem /* 21469ec7b004SRick Macklem * XXX At this time VOP_FSYNC() does not accept offset and byte 21479ec7b004SRick Macklem * count parameters, so these arguments are useless (someday maybe). 21489ec7b004SRick Macklem */ 21499ec7b004SRick Macklem off = fxdr_hyper(tl); 21509ec7b004SRick Macklem tl += 2; 21519ec7b004SRick Macklem cnt = fxdr_unsigned(int, *tl); 21529ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 215390d2dfabSRick Macklem for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL); 21549ec7b004SRick Macklem nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p); 21559ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 215690d2dfabSRick Macklem aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL); 21579ec7b004SRick Macklem nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 21589ec7b004SRick Macklem } 21599ec7b004SRick Macklem vput(vp); 21609ec7b004SRick Macklem if (!nd->nd_repstat) { 21619ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 21629ec7b004SRick Macklem *tl++ = txdr_unsigned(nfsboottime.tv_sec); 21639ec7b004SRick Macklem *tl = txdr_unsigned(nfsboottime.tv_usec); 21649ec7b004SRick Macklem } 2165a9285ae5SZack Kirsch 2166a9285ae5SZack Kirsch out: 2167a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 21689ec7b004SRick Macklem return (0); 21699ec7b004SRick Macklem nfsmout: 21709ec7b004SRick Macklem vput(vp); 2171a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 21729ec7b004SRick Macklem return (error); 21739ec7b004SRick Macklem } 21749ec7b004SRick Macklem 21759ec7b004SRick Macklem /* 21769ec7b004SRick Macklem * nfs statfs service 21779ec7b004SRick Macklem */ 2178b9cc3262SRyan Moeller int 21799ec7b004SRick Macklem nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram, 2180af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 21819ec7b004SRick Macklem { 21829ec7b004SRick Macklem struct statfs *sf; 21839ec7b004SRick Macklem u_int32_t *tl; 21849ec7b004SRick Macklem int getret = 1; 21859ec7b004SRick Macklem struct nfsvattr at; 21869ec7b004SRick Macklem u_quad_t tval; 2187af444b18SEdward Tomasz Napierala struct thread *p = curthread; 21889ec7b004SRick Macklem 21892f304845SKonstantin Belousov sf = NULL; 21909ec7b004SRick Macklem if (nd->nd_repstat) { 21919ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 2192a9285ae5SZack Kirsch goto out; 21939ec7b004SRick Macklem } 21942f304845SKonstantin Belousov sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 2195dfd233edSAttilio Rao nd->nd_repstat = nfsvno_statfs(vp, sf); 219690d2dfabSRick Macklem getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); 21979ec7b004SRick Macklem vput(vp); 21989ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 21999ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 22009ec7b004SRick Macklem if (nd->nd_repstat) 2201a9285ae5SZack Kirsch goto out; 22029ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 22039ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS); 22049ec7b004SRick Macklem *tl++ = txdr_unsigned(NFS_V2MAXDATA); 22059ec7b004SRick Macklem *tl++ = txdr_unsigned(sf->f_bsize); 22069ec7b004SRick Macklem *tl++ = txdr_unsigned(sf->f_blocks); 22079ec7b004SRick Macklem *tl++ = txdr_unsigned(sf->f_bfree); 22089ec7b004SRick Macklem *tl = txdr_unsigned(sf->f_bavail); 22099ec7b004SRick Macklem } else { 22109ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS); 22119ec7b004SRick Macklem tval = (u_quad_t)sf->f_blocks; 22129ec7b004SRick Macklem tval *= (u_quad_t)sf->f_bsize; 22139ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 22149ec7b004SRick Macklem tval = (u_quad_t)sf->f_bfree; 22159ec7b004SRick Macklem tval *= (u_quad_t)sf->f_bsize; 22169ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 22179ec7b004SRick Macklem tval = (u_quad_t)sf->f_bavail; 22189ec7b004SRick Macklem tval *= (u_quad_t)sf->f_bsize; 22199ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 22209ec7b004SRick Macklem tval = (u_quad_t)sf->f_files; 22219ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 22229ec7b004SRick Macklem tval = (u_quad_t)sf->f_ffree; 22239ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 22249ec7b004SRick Macklem tval = (u_quad_t)sf->f_ffree; 22259ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 22269ec7b004SRick Macklem *tl = 0; 22279ec7b004SRick Macklem } 2228a9285ae5SZack Kirsch 2229a9285ae5SZack Kirsch out: 22302f304845SKonstantin Belousov free(sf, M_STATFS); 2231a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 22329ec7b004SRick Macklem return (0); 22339ec7b004SRick Macklem } 22349ec7b004SRick Macklem 22359ec7b004SRick Macklem /* 22369ec7b004SRick Macklem * nfs fsinfo service 22379ec7b004SRick Macklem */ 2238b9cc3262SRyan Moeller int 22399ec7b004SRick Macklem nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram, 2240af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 22419ec7b004SRick Macklem { 22429ec7b004SRick Macklem u_int32_t *tl; 22439ec7b004SRick Macklem struct nfsfsinfo fs; 22449ec7b004SRick Macklem int getret = 1; 22459ec7b004SRick Macklem struct nfsvattr at; 2246af444b18SEdward Tomasz Napierala struct thread *p = curthread; 22479ec7b004SRick Macklem 22489ec7b004SRick Macklem if (nd->nd_repstat) { 22499ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 2250a9285ae5SZack Kirsch goto out; 22519ec7b004SRick Macklem } 225290d2dfabSRick Macklem getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); 22539ec7b004SRick Macklem nfsvno_getfs(&fs, isdgram); 22549ec7b004SRick Macklem vput(vp); 22559ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 22569ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO); 22579ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_rtmax); 22589ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_rtpref); 22599ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_rtmult); 22609ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_wtmax); 22619ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_wtpref); 22629ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_wtmult); 22639ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_dtpref); 22649ec7b004SRick Macklem txdr_hyper(fs.fs_maxfilesize, tl); 22659ec7b004SRick Macklem tl += 2; 22669ec7b004SRick Macklem txdr_nfsv3time(&fs.fs_timedelta, tl); 22679ec7b004SRick Macklem tl += 2; 22689ec7b004SRick Macklem *tl = txdr_unsigned(fs.fs_properties); 2269a9285ae5SZack Kirsch 2270a9285ae5SZack Kirsch out: 2271a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 22729ec7b004SRick Macklem return (0); 22739ec7b004SRick Macklem } 22749ec7b004SRick Macklem 22759ec7b004SRick Macklem /* 22769ec7b004SRick Macklem * nfs pathconf service 22779ec7b004SRick Macklem */ 2278b9cc3262SRyan Moeller int 22799ec7b004SRick Macklem nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram, 2280af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 22819ec7b004SRick Macklem { 22829ec7b004SRick Macklem struct nfsv3_pathconf *pc; 22839ec7b004SRick Macklem int getret = 1; 2284b1288166SJohn Baldwin long linkmax, namemax, chownres, notrunc; 22859ec7b004SRick Macklem struct nfsvattr at; 2286af444b18SEdward Tomasz Napierala struct thread *p = curthread; 22879ec7b004SRick Macklem 22889ec7b004SRick Macklem if (nd->nd_repstat) { 22899ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 2290a9285ae5SZack Kirsch goto out; 22919ec7b004SRick Macklem } 22929ec7b004SRick Macklem nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax, 22939ec7b004SRick Macklem nd->nd_cred, p); 22949ec7b004SRick Macklem if (!nd->nd_repstat) 22959ec7b004SRick Macklem nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax, 22969ec7b004SRick Macklem nd->nd_cred, p); 22979ec7b004SRick Macklem if (!nd->nd_repstat) 22989ec7b004SRick Macklem nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED, 22999ec7b004SRick Macklem &chownres, nd->nd_cred, p); 23009ec7b004SRick Macklem if (!nd->nd_repstat) 23019ec7b004SRick Macklem nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc, 23029ec7b004SRick Macklem nd->nd_cred, p); 230390d2dfabSRick Macklem getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); 23049ec7b004SRick Macklem vput(vp); 23059ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 23069ec7b004SRick Macklem if (!nd->nd_repstat) { 23079ec7b004SRick Macklem NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); 23089ec7b004SRick Macklem pc->pc_linkmax = txdr_unsigned(linkmax); 23099ec7b004SRick Macklem pc->pc_namemax = txdr_unsigned(namemax); 23109ec7b004SRick Macklem pc->pc_notrunc = txdr_unsigned(notrunc); 23119ec7b004SRick Macklem pc->pc_chownrestricted = txdr_unsigned(chownres); 23129ec7b004SRick Macklem 23139ec7b004SRick Macklem /* 23149ec7b004SRick Macklem * These should probably be supported by VOP_PATHCONF(), but 23159ec7b004SRick Macklem * until msdosfs is exportable (why would you want to?), the 23169ec7b004SRick Macklem * Unix defaults should be ok. 23179ec7b004SRick Macklem */ 23189ec7b004SRick Macklem pc->pc_caseinsensitive = newnfs_false; 23199ec7b004SRick Macklem pc->pc_casepreserving = newnfs_true; 23209ec7b004SRick Macklem } 2321a9285ae5SZack Kirsch 2322a9285ae5SZack Kirsch out: 2323a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 23249ec7b004SRick Macklem return (0); 23259ec7b004SRick Macklem } 23269ec7b004SRick Macklem 23279ec7b004SRick Macklem /* 23289ec7b004SRick Macklem * nfsv4 lock service 23299ec7b004SRick Macklem */ 2330b9cc3262SRyan Moeller int 23319ec7b004SRick Macklem nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram, 2332af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 23339ec7b004SRick Macklem { 23349ec7b004SRick Macklem u_int32_t *tl; 23359ec7b004SRick Macklem int i; 23369ec7b004SRick Macklem struct nfsstate *stp = NULL; 23379ec7b004SRick Macklem struct nfslock *lop; 23389ec7b004SRick Macklem struct nfslockconflict cf; 23399ec7b004SRick Macklem int error = 0; 23409ec7b004SRick Macklem u_short flags = NFSLCK_LOCK, lflags; 23419ec7b004SRick Macklem u_int64_t offset, len; 23429ec7b004SRick Macklem nfsv4stateid_t stateid; 23439ec7b004SRick Macklem nfsquad_t clientid; 2344af444b18SEdward Tomasz Napierala struct thread *p = curthread; 23459ec7b004SRick Macklem 23469ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 23479ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 23489ec7b004SRick Macklem switch (i) { 23499ec7b004SRick Macklem case NFSV4LOCKT_READW: 23509ec7b004SRick Macklem flags |= NFSLCK_BLOCKING; 23519ec7b004SRick Macklem case NFSV4LOCKT_READ: 23529ec7b004SRick Macklem lflags = NFSLCK_READ; 23539ec7b004SRick Macklem break; 23549ec7b004SRick Macklem case NFSV4LOCKT_WRITEW: 23559ec7b004SRick Macklem flags |= NFSLCK_BLOCKING; 23569ec7b004SRick Macklem case NFSV4LOCKT_WRITE: 23579ec7b004SRick Macklem lflags = NFSLCK_WRITE; 23589ec7b004SRick Macklem break; 23599ec7b004SRick Macklem default: 23609ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 23619ec7b004SRick Macklem goto nfsmout; 236274b8d63dSPedro F. Giffuni } 23639ec7b004SRick Macklem if (*tl++ == newnfs_true) 23649ec7b004SRick Macklem flags |= NFSLCK_RECLAIM; 23659ec7b004SRick Macklem offset = fxdr_hyper(tl); 23669ec7b004SRick Macklem tl += 2; 23679ec7b004SRick Macklem len = fxdr_hyper(tl); 23689ec7b004SRick Macklem tl += 2; 23699ec7b004SRick Macklem if (*tl == newnfs_true) 23709ec7b004SRick Macklem flags |= NFSLCK_OPENTOLOCK; 23719ec7b004SRick Macklem if (flags & NFSLCK_OPENTOLOCK) { 23729ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID); 23739ec7b004SRick Macklem i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED))); 23742a45247cSRick Macklem if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 23752a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 23762a45247cSRick Macklem goto nfsmout; 23772a45247cSRick Macklem } 2378222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate) + i, 23799ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 23809ec7b004SRick Macklem stp->ls_ownerlen = i; 23819ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 23829ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(int, *tl++); 23839ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 23849ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 23859ec7b004SRick Macklem NFSX_STATEIDOTHER); 23869ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 238790d2dfabSRick Macklem 238890d2dfabSRick Macklem /* 238990d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set 239090d2dfabSRick Macklem * the stateid to the current stateid, if it is set. 239190d2dfabSRick Macklem */ 239290d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 && 239390d2dfabSRick Macklem stp->ls_stateid.seqid == 1 && 239490d2dfabSRick Macklem stp->ls_stateid.other[0] == 0 && 239590d2dfabSRick Macklem stp->ls_stateid.other[1] == 0 && 239690d2dfabSRick Macklem stp->ls_stateid.other[2] == 0) { 239790d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 239890d2dfabSRick Macklem stp->ls_stateid = nd->nd_curstateid; 239990d2dfabSRick Macklem stp->ls_stateid.seqid = 0; 240090d2dfabSRick Macklem } else { 240190d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 240290d2dfabSRick Macklem goto nfsmout; 240390d2dfabSRick Macklem } 240490d2dfabSRick Macklem } 240590d2dfabSRick Macklem 24069ec7b004SRick Macklem stp->ls_opentolockseq = fxdr_unsigned(int, *tl++); 24079ec7b004SRick Macklem clientid.lval[0] = *tl++; 24089ec7b004SRick Macklem clientid.lval[1] = *tl++; 2409c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2410c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2411c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2412c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2413c59e4cc3SRick Macklem printf("EEK3 multiple clids\n"); 24149ec7b004SRick Macklem } else { 2415c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2416c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 24179ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 24189ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 24199ec7b004SRick Macklem } 24209ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 24219ec7b004SRick Macklem if (error) 24229ec7b004SRick Macklem goto nfsmout; 24239ec7b004SRick Macklem } else { 24249ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 2425222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate), 24269ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 24279ec7b004SRick Macklem stp->ls_ownerlen = 0; 24289ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 24299ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 24309ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 24319ec7b004SRick Macklem NFSX_STATEIDOTHER); 24329ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 243390d2dfabSRick Macklem 243490d2dfabSRick Macklem /* 243590d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set 243690d2dfabSRick Macklem * the stateid to the current stateid, if it is set. 243790d2dfabSRick Macklem */ 243890d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 && 243990d2dfabSRick Macklem stp->ls_stateid.seqid == 1 && 244090d2dfabSRick Macklem stp->ls_stateid.other[0] == 0 && 244190d2dfabSRick Macklem stp->ls_stateid.other[1] == 0 && 244290d2dfabSRick Macklem stp->ls_stateid.other[2] == 0) { 244390d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 244490d2dfabSRick Macklem stp->ls_stateid = nd->nd_curstateid; 244590d2dfabSRick Macklem stp->ls_stateid.seqid = 0; 244690d2dfabSRick Macklem } else { 244790d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 244890d2dfabSRick Macklem goto nfsmout; 244990d2dfabSRick Macklem } 245090d2dfabSRick Macklem } 245190d2dfabSRick Macklem 24529ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(int, *tl); 24539ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 24549ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 2455c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2456c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2457c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2458c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2459c59e4cc3SRick Macklem printf("EEK4 multiple clids\n"); 24609ec7b004SRick Macklem } else { 2461c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2462c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 24639ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 24649ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 24659ec7b004SRick Macklem } 24669ec7b004SRick Macklem } 2467222daa42SConrad Meyer lop = malloc(sizeof (struct nfslock), 24689ec7b004SRick Macklem M_NFSDLOCK, M_WAITOK); 24699ec7b004SRick Macklem lop->lo_first = offset; 24709ec7b004SRick Macklem if (len == NFS64BITSSET) { 24719ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 24729ec7b004SRick Macklem } else { 24739ec7b004SRick Macklem lop->lo_end = offset + len; 24749ec7b004SRick Macklem if (lop->lo_end <= lop->lo_first) 24759ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 24769ec7b004SRick Macklem } 24779ec7b004SRick Macklem lop->lo_flags = lflags; 24789ec7b004SRick Macklem stp->ls_flags = flags; 24799ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 24809ec7b004SRick Macklem 24819ec7b004SRick Macklem /* 24829ec7b004SRick Macklem * Do basic access checking. 24839ec7b004SRick Macklem */ 24849ec7b004SRick Macklem if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 24859ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 24869ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 24879ec7b004SRick Macklem else 24889ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 24899ec7b004SRick Macklem } 24909ec7b004SRick Macklem if (!nd->nd_repstat) { 24919ec7b004SRick Macklem if (lflags & NFSLCK_WRITE) { 24928da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 24939ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 24948da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 24959ec7b004SRick Macklem } else { 24968da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, 24979ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 24988da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 24999ec7b004SRick Macklem if (nd->nd_repstat) 25008da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 25019ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 25028da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 25039ec7b004SRick Macklem } 25049ec7b004SRick Macklem } 25059ec7b004SRick Macklem 25069ec7b004SRick Macklem /* 25079ec7b004SRick Macklem * We call nfsrv_lockctrl() even if nd_repstat set, so that the 25089ec7b004SRick Macklem * seqid# gets updated. nfsrv_lockctrl() will return the value 25099ec7b004SRick Macklem * of nd_repstat, if it gets that far. 25109ec7b004SRick Macklem */ 25119ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 25129ec7b004SRick Macklem &stateid, exp, nd, p); 25139ec7b004SRick Macklem if (lop) 2514222daa42SConrad Meyer free(lop, M_NFSDLOCK); 25159ec7b004SRick Macklem if (stp) 2516222daa42SConrad Meyer free(stp, M_NFSDSTATE); 25179ec7b004SRick Macklem if (!nd->nd_repstat) { 251890d2dfabSRick Macklem /* For NFSv4.1, set the Current StateID. */ 251990d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 252090d2dfabSRick Macklem nd->nd_curstateid = stateid; 252190d2dfabSRick Macklem nd->nd_flag |= ND_CURSTATEID; 252290d2dfabSRick Macklem } 25239ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 25249ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 25259ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 25269ec7b004SRick Macklem } else if (nd->nd_repstat == NFSERR_DENIED) { 25279ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 25289ec7b004SRick Macklem txdr_hyper(cf.cl_first, tl); 25299ec7b004SRick Macklem tl += 2; 25309ec7b004SRick Macklem if (cf.cl_end == NFS64BITSSET) 25319ec7b004SRick Macklem len = NFS64BITSSET; 25329ec7b004SRick Macklem else 25339ec7b004SRick Macklem len = cf.cl_end - cf.cl_first; 25349ec7b004SRick Macklem txdr_hyper(len, tl); 25359ec7b004SRick Macklem tl += 2; 25369ec7b004SRick Macklem if (cf.cl_flags == NFSLCK_WRITE) 25379ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 25389ec7b004SRick Macklem else 25399ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 25409ec7b004SRick Macklem *tl++ = stateid.other[0]; 25419ec7b004SRick Macklem *tl = stateid.other[1]; 25429ec7b004SRick Macklem (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 25439ec7b004SRick Macklem } 25449ec7b004SRick Macklem vput(vp); 2545a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 25469ec7b004SRick Macklem return (0); 25479ec7b004SRick Macklem nfsmout: 25489ec7b004SRick Macklem vput(vp); 25499ec7b004SRick Macklem if (stp) 2550222daa42SConrad Meyer free(stp, M_NFSDSTATE); 2551a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 25529ec7b004SRick Macklem return (error); 25539ec7b004SRick Macklem } 25549ec7b004SRick Macklem 25559ec7b004SRick Macklem /* 25569ec7b004SRick Macklem * nfsv4 lock test service 25579ec7b004SRick Macklem */ 2558b9cc3262SRyan Moeller int 25599ec7b004SRick Macklem nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram, 2560af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 25619ec7b004SRick Macklem { 25629ec7b004SRick Macklem u_int32_t *tl; 25639ec7b004SRick Macklem int i; 25649ec7b004SRick Macklem struct nfsstate *stp = NULL; 25659ec7b004SRick Macklem struct nfslock lo, *lop = &lo; 25669ec7b004SRick Macklem struct nfslockconflict cf; 25679ec7b004SRick Macklem int error = 0; 25689ec7b004SRick Macklem nfsv4stateid_t stateid; 25699ec7b004SRick Macklem nfsquad_t clientid; 25709ec7b004SRick Macklem u_int64_t len; 2571af444b18SEdward Tomasz Napierala struct thread *p = curthread; 25729ec7b004SRick Macklem 25739ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 25749ec7b004SRick Macklem i = fxdr_unsigned(int, *(tl + 7)); 25752a45247cSRick Macklem if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 25762a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 25772a45247cSRick Macklem goto nfsmout; 25782a45247cSRick Macklem } 2579222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate) + i, 25809ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 25819ec7b004SRick Macklem stp->ls_ownerlen = i; 25829ec7b004SRick Macklem stp->ls_op = NULL; 25839ec7b004SRick Macklem stp->ls_flags = NFSLCK_TEST; 25849ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 25859ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 25869ec7b004SRick Macklem switch (i) { 25879ec7b004SRick Macklem case NFSV4LOCKT_READW: 25889ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 25899ec7b004SRick Macklem case NFSV4LOCKT_READ: 25909ec7b004SRick Macklem lo.lo_flags = NFSLCK_READ; 25919ec7b004SRick Macklem break; 25929ec7b004SRick Macklem case NFSV4LOCKT_WRITEW: 25939ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 25949ec7b004SRick Macklem case NFSV4LOCKT_WRITE: 25959ec7b004SRick Macklem lo.lo_flags = NFSLCK_WRITE; 25969ec7b004SRick Macklem break; 25979ec7b004SRick Macklem default: 25989ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 25999ec7b004SRick Macklem goto nfsmout; 260074b8d63dSPedro F. Giffuni } 26019ec7b004SRick Macklem lo.lo_first = fxdr_hyper(tl); 26029ec7b004SRick Macklem tl += 2; 26039ec7b004SRick Macklem len = fxdr_hyper(tl); 26049ec7b004SRick Macklem if (len == NFS64BITSSET) { 26059ec7b004SRick Macklem lo.lo_end = NFS64BITSSET; 26069ec7b004SRick Macklem } else { 26079ec7b004SRick Macklem lo.lo_end = lo.lo_first + len; 26089ec7b004SRick Macklem if (lo.lo_end <= lo.lo_first) 26099ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 26109ec7b004SRick Macklem } 26119ec7b004SRick Macklem tl += 2; 26129ec7b004SRick Macklem clientid.lval[0] = *tl++; 26139ec7b004SRick Macklem clientid.lval[1] = *tl; 2614c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2615c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2616c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2617c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2618c59e4cc3SRick Macklem printf("EEK5 multiple clids\n"); 26199ec7b004SRick Macklem } else { 2620c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2621c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 26229ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 26239ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 26249ec7b004SRick Macklem } 26259ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 26269ec7b004SRick Macklem if (error) 26279ec7b004SRick Macklem goto nfsmout; 26289ec7b004SRick Macklem if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 26299ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 26309ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 26319ec7b004SRick Macklem else 26329ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 26339ec7b004SRick Macklem } 26349ec7b004SRick Macklem if (!nd->nd_repstat) 26359ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 26369ec7b004SRick Macklem &stateid, exp, nd, p); 26379ec7b004SRick Macklem if (nd->nd_repstat) { 26389ec7b004SRick Macklem if (nd->nd_repstat == NFSERR_DENIED) { 26399ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 26409ec7b004SRick Macklem txdr_hyper(cf.cl_first, tl); 26419ec7b004SRick Macklem tl += 2; 26429ec7b004SRick Macklem if (cf.cl_end == NFS64BITSSET) 26439ec7b004SRick Macklem len = NFS64BITSSET; 26449ec7b004SRick Macklem else 26459ec7b004SRick Macklem len = cf.cl_end - cf.cl_first; 26469ec7b004SRick Macklem txdr_hyper(len, tl); 26479ec7b004SRick Macklem tl += 2; 26489ec7b004SRick Macklem if (cf.cl_flags == NFSLCK_WRITE) 26499ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 26509ec7b004SRick Macklem else 26519ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 26529ec7b004SRick Macklem *tl++ = stp->ls_stateid.other[0]; 26539ec7b004SRick Macklem *tl = stp->ls_stateid.other[1]; 26549ec7b004SRick Macklem (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 26559ec7b004SRick Macklem } 26569ec7b004SRick Macklem } 26579ec7b004SRick Macklem vput(vp); 26585ecc225fSConrad Meyer if (stp) 2659222daa42SConrad Meyer free(stp, M_NFSDSTATE); 2660a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 26619ec7b004SRick Macklem return (0); 26629ec7b004SRick Macklem nfsmout: 26639ec7b004SRick Macklem vput(vp); 26649ec7b004SRick Macklem if (stp) 2665222daa42SConrad Meyer free(stp, M_NFSDSTATE); 2666a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 26679ec7b004SRick Macklem return (error); 26689ec7b004SRick Macklem } 26699ec7b004SRick Macklem 26709ec7b004SRick Macklem /* 26719ec7b004SRick Macklem * nfsv4 unlock service 26729ec7b004SRick Macklem */ 2673b9cc3262SRyan Moeller int 26749ec7b004SRick Macklem nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram, 2675af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 26769ec7b004SRick Macklem { 26779ec7b004SRick Macklem u_int32_t *tl; 26789ec7b004SRick Macklem int i; 26799ec7b004SRick Macklem struct nfsstate *stp; 26809ec7b004SRick Macklem struct nfslock *lop; 26819ec7b004SRick Macklem int error = 0; 26829ec7b004SRick Macklem nfsv4stateid_t stateid; 26839ec7b004SRick Macklem nfsquad_t clientid; 26849ec7b004SRick Macklem u_int64_t len; 2685af444b18SEdward Tomasz Napierala struct thread *p = curthread; 26869ec7b004SRick Macklem 26879ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID); 2688222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate), 26899ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 2690222daa42SConrad Meyer lop = malloc(sizeof (struct nfslock), 26919ec7b004SRick Macklem M_NFSDLOCK, M_WAITOK); 26929ec7b004SRick Macklem stp->ls_flags = NFSLCK_UNLOCK; 26939ec7b004SRick Macklem lop->lo_flags = NFSLCK_UNLOCK; 26949ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 26959ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 26969ec7b004SRick Macklem switch (i) { 26979ec7b004SRick Macklem case NFSV4LOCKT_READW: 26989ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 26999ec7b004SRick Macklem case NFSV4LOCKT_READ: 27009ec7b004SRick Macklem break; 27019ec7b004SRick Macklem case NFSV4LOCKT_WRITEW: 27029ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 27039ec7b004SRick Macklem case NFSV4LOCKT_WRITE: 27049ec7b004SRick Macklem break; 27059ec7b004SRick Macklem default: 27069ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 27072a45247cSRick Macklem free(stp, M_NFSDSTATE); 27082a45247cSRick Macklem free(lop, M_NFSDLOCK); 27099ec7b004SRick Macklem goto nfsmout; 271074b8d63dSPedro F. Giffuni } 27119ec7b004SRick Macklem stp->ls_ownerlen = 0; 27129ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 27139ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(int, *tl++); 27149ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 27159ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 27169ec7b004SRick Macklem NFSX_STATEIDOTHER); 27179ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 271890d2dfabSRick Macklem 271990d2dfabSRick Macklem /* 272090d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 272190d2dfabSRick Macklem * stateid to the current stateid, if it is set. 272290d2dfabSRick Macklem */ 272390d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 272490d2dfabSRick Macklem stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 272590d2dfabSRick Macklem stp->ls_stateid.other[2] == 0) { 272690d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 272790d2dfabSRick Macklem stp->ls_stateid = nd->nd_curstateid; 272890d2dfabSRick Macklem stp->ls_stateid.seqid = 0; 272990d2dfabSRick Macklem } else { 273090d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 27310bb42627SEric van Gyzen free(stp, M_NFSDSTATE); 27320bb42627SEric van Gyzen free(lop, M_NFSDLOCK); 273390d2dfabSRick Macklem goto nfsmout; 273490d2dfabSRick Macklem } 273590d2dfabSRick Macklem } 273690d2dfabSRick Macklem 27379ec7b004SRick Macklem lop->lo_first = fxdr_hyper(tl); 27389ec7b004SRick Macklem tl += 2; 27399ec7b004SRick Macklem len = fxdr_hyper(tl); 27409ec7b004SRick Macklem if (len == NFS64BITSSET) { 27419ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 27429ec7b004SRick Macklem } else { 27439ec7b004SRick Macklem lop->lo_end = lop->lo_first + len; 27449ec7b004SRick Macklem if (lop->lo_end <= lop->lo_first) 27459ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 27469ec7b004SRick Macklem } 27479ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 27489ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 2749c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2750c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2751c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2752c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2753c59e4cc3SRick Macklem printf("EEK6 multiple clids\n"); 27549ec7b004SRick Macklem } else { 2755c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2756c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 27579ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 27589ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 27599ec7b004SRick Macklem } 27609ec7b004SRick Macklem if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 27619ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 27629ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 27639ec7b004SRick Macklem else 27649ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 27659ec7b004SRick Macklem } 27669ec7b004SRick Macklem /* 27679ec7b004SRick Macklem * Call nfsrv_lockctrl() even if nd_repstat is set, so that the 27689ec7b004SRick Macklem * seqid# gets incremented. nfsrv_lockctrl() will return the 27699ec7b004SRick Macklem * value of nd_repstat, if it gets that far. 27709ec7b004SRick Macklem */ 27719ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 27729ec7b004SRick Macklem &stateid, exp, nd, p); 27739ec7b004SRick Macklem if (stp) 2774222daa42SConrad Meyer free(stp, M_NFSDSTATE); 27759ec7b004SRick Macklem if (lop) 2776222daa42SConrad Meyer free(lop, M_NFSDLOCK); 27779ec7b004SRick Macklem if (!nd->nd_repstat) { 27789ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 27799ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 27809ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 27819ec7b004SRick Macklem } 27829ec7b004SRick Macklem nfsmout: 27839ec7b004SRick Macklem vput(vp); 2784a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 27859ec7b004SRick Macklem return (error); 27869ec7b004SRick Macklem } 27879ec7b004SRick Macklem 27889ec7b004SRick Macklem /* 27899ec7b004SRick Macklem * nfsv4 open service 27909ec7b004SRick Macklem */ 2791b9cc3262SRyan Moeller int 27929ec7b004SRick Macklem nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram, 2793af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp) 27949ec7b004SRick Macklem { 27959ec7b004SRick Macklem u_int32_t *tl; 2796c59e4cc3SRick Macklem int i, retext; 27979ec7b004SRick Macklem struct nfsstate *stp = NULL; 2798b0b7d978SRick Macklem int error = 0, create, claim, exclusive_flag = 0, override; 27999ec7b004SRick Macklem u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask; 28009ec7b004SRick Macklem int how = NFSCREATE_UNCHECKED; 2801086f6e0cSRick Macklem int32_t cverf[2], tverf[2] = { 0, 0 }; 28029ec7b004SRick Macklem vnode_t vp = NULL, dirp = NULL; 28039ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 28049ec7b004SRick Macklem struct nameidata named; 28059ec7b004SRick Macklem nfsv4stateid_t stateid, delegstateid; 28069ec7b004SRick Macklem nfsattrbit_t attrbits; 28079ec7b004SRick Macklem nfsquad_t clientid; 28089ec7b004SRick Macklem char *bufp = NULL; 28099ec7b004SRick Macklem u_long *hashp; 28109ec7b004SRick Macklem NFSACL_T *aclp = NULL; 2811af444b18SEdward Tomasz Napierala struct thread *p = curthread; 28129ec7b004SRick Macklem 28139ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 2814c3e22f83SRick Macklem aclp = acl_alloc(M_WAITOK); 28159ec7b004SRick Macklem aclp->acl_cnt = 0; 28169ec7b004SRick Macklem #endif 28179ec7b004SRick Macklem NFSZERO_ATTRBIT(&attrbits); 28189ec7b004SRick Macklem named.ni_startdir = NULL; 28199ec7b004SRick Macklem named.ni_cnd.cn_nameiop = 0; 28209ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 28219ec7b004SRick Macklem i = fxdr_unsigned(int, *(tl + 5)); 28222a45247cSRick Macklem if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 28232a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 2824a9285ae5SZack Kirsch goto nfsmout; 28252a45247cSRick Macklem } 2826222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate) + i, 28279ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 28289ec7b004SRick Macklem stp->ls_ownerlen = i; 28299ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 28309ec7b004SRick Macklem stp->ls_flags = NFSLCK_OPEN; 28319ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 28329ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 28339ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 2834c59e4cc3SRick Macklem retext = 0; 2835c59e4cc3SRick Macklem if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG | 2836c59e4cc3SRick Macklem NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) { 2837c59e4cc3SRick Macklem retext = 1; 2838c59e4cc3SRick Macklem /* For now, ignore these. */ 2839c59e4cc3SRick Macklem i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG); 2840c59e4cc3SRick Macklem switch (i & NFSV4OPEN_WANTDELEGMASK) { 2841c59e4cc3SRick Macklem case NFSV4OPEN_WANTANYDELEG: 2842c59e4cc3SRick Macklem stp->ls_flags |= (NFSLCK_WANTRDELEG | 2843c59e4cc3SRick Macklem NFSLCK_WANTWDELEG); 2844c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2845c59e4cc3SRick Macklem break; 2846c59e4cc3SRick Macklem case NFSV4OPEN_WANTREADDELEG: 2847c59e4cc3SRick Macklem stp->ls_flags |= NFSLCK_WANTRDELEG; 2848c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2849c59e4cc3SRick Macklem break; 2850c59e4cc3SRick Macklem case NFSV4OPEN_WANTWRITEDELEG: 2851c59e4cc3SRick Macklem stp->ls_flags |= NFSLCK_WANTWDELEG; 2852c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2853c59e4cc3SRick Macklem break; 2854c59e4cc3SRick Macklem case NFSV4OPEN_WANTNODELEG: 2855c59e4cc3SRick Macklem stp->ls_flags |= NFSLCK_WANTNODELEG; 2856c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2857c59e4cc3SRick Macklem break; 2858c59e4cc3SRick Macklem case NFSV4OPEN_WANTCANCEL: 2859c59e4cc3SRick Macklem printf("NFSv4: ignore Open WantCancel\n"); 2860c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2861c59e4cc3SRick Macklem break; 2862c59e4cc3SRick Macklem default: 2863c59e4cc3SRick Macklem /* nd_repstat will be set to NFSERR_INVAL below. */ 2864c59e4cc3SRick Macklem break; 286574b8d63dSPedro F. Giffuni } 2866c59e4cc3SRick Macklem } 28679ec7b004SRick Macklem switch (i) { 28689ec7b004SRick Macklem case NFSV4OPEN_ACCESSREAD: 28699ec7b004SRick Macklem stp->ls_flags |= NFSLCK_READACCESS; 28709ec7b004SRick Macklem break; 28719ec7b004SRick Macklem case NFSV4OPEN_ACCESSWRITE: 28729ec7b004SRick Macklem stp->ls_flags |= NFSLCK_WRITEACCESS; 28739ec7b004SRick Macklem break; 28749ec7b004SRick Macklem case NFSV4OPEN_ACCESSBOTH: 28759ec7b004SRick Macklem stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 28769ec7b004SRick Macklem break; 28779ec7b004SRick Macklem default: 28789ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 287974b8d63dSPedro F. Giffuni } 28809ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 28819ec7b004SRick Macklem switch (i) { 28829ec7b004SRick Macklem case NFSV4OPEN_DENYNONE: 28839ec7b004SRick Macklem break; 28849ec7b004SRick Macklem case NFSV4OPEN_DENYREAD: 28859ec7b004SRick Macklem stp->ls_flags |= NFSLCK_READDENY; 28869ec7b004SRick Macklem break; 28879ec7b004SRick Macklem case NFSV4OPEN_DENYWRITE: 28889ec7b004SRick Macklem stp->ls_flags |= NFSLCK_WRITEDENY; 28899ec7b004SRick Macklem break; 28909ec7b004SRick Macklem case NFSV4OPEN_DENYBOTH: 28919ec7b004SRick Macklem stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 28929ec7b004SRick Macklem break; 28939ec7b004SRick Macklem default: 28949ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 289574b8d63dSPedro F. Giffuni } 28969ec7b004SRick Macklem clientid.lval[0] = *tl++; 28979ec7b004SRick Macklem clientid.lval[1] = *tl; 2898c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2899c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2900c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2901c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2902c59e4cc3SRick Macklem printf("EEK7 multiple clids\n"); 29039ec7b004SRick Macklem } else { 2904c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2905c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 29069ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 29079ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 29089ec7b004SRick Macklem } 29099ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2910a9285ae5SZack Kirsch if (error) 2911a9285ae5SZack Kirsch goto nfsmout; 29129ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 29139ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 29149ec7b004SRick Macklem create = fxdr_unsigned(int, *tl); 29159ec7b004SRick Macklem if (!nd->nd_repstat) 291690d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL); 29179ec7b004SRick Macklem if (create == NFSV4OPEN_CREATE) { 29189ec7b004SRick Macklem nva.na_type = VREG; 29199ec7b004SRick Macklem nva.na_mode = 0; 29209ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 29219ec7b004SRick Macklem how = fxdr_unsigned(int, *tl); 29229ec7b004SRick Macklem switch (how) { 29239ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 29249ec7b004SRick Macklem case NFSCREATE_GUARDED: 2925d8a5961fSMarcelo Araujo error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p); 2926a9285ae5SZack Kirsch if (error) 2927a9285ae5SZack Kirsch goto nfsmout; 29289ec7b004SRick Macklem /* 29299ec7b004SRick Macklem * If the na_gid being set is the same as that of 29309ec7b004SRick Macklem * the directory it is going in, clear it, since 29319ec7b004SRick Macklem * that is what will be set by default. This allows 29329ec7b004SRick Macklem * a user that isn't in that group to do the create. 29339ec7b004SRick Macklem */ 29349ec7b004SRick Macklem if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) && 29359ec7b004SRick Macklem nva.na_gid == dirfor.na_gid) 29369ec7b004SRick Macklem NFSVNO_UNSET(&nva, gid); 29379ec7b004SRick Macklem if (!nd->nd_repstat) 29389ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 29399ec7b004SRick Macklem break; 29409ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 29419ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2942086f6e0cSRick Macklem cverf[0] = *tl++; 2943086f6e0cSRick Macklem cverf[1] = *tl; 29449ec7b004SRick Macklem break; 2945c59e4cc3SRick Macklem case NFSCREATE_EXCLUSIVE41: 2946c59e4cc3SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2947c59e4cc3SRick Macklem cverf[0] = *tl++; 2948c59e4cc3SRick Macklem cverf[1] = *tl; 2949b4645807SRick Macklem error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p); 2950c59e4cc3SRick Macklem if (error != 0) 2951c59e4cc3SRick Macklem goto nfsmout; 2952c59e4cc3SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, 2953c59e4cc3SRick Macklem NFSATTRBIT_TIMEACCESSSET)) 2954c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_INVAL; 2955c59e4cc3SRick Macklem /* 2956c59e4cc3SRick Macklem * If the na_gid being set is the same as that of 2957c59e4cc3SRick Macklem * the directory it is going in, clear it, since 2958c59e4cc3SRick Macklem * that is what will be set by default. This allows 2959c59e4cc3SRick Macklem * a user that isn't in that group to do the create. 2960c59e4cc3SRick Macklem */ 2961c59e4cc3SRick Macklem if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) && 2962c59e4cc3SRick Macklem nva.na_gid == dirfor.na_gid) 2963c59e4cc3SRick Macklem NFSVNO_UNSET(&nva, gid); 2964c59e4cc3SRick Macklem if (nd->nd_repstat == 0) 2965c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2966c59e4cc3SRick Macklem break; 29679ec7b004SRick Macklem default: 29689ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 2969a9285ae5SZack Kirsch goto nfsmout; 297074b8d63dSPedro F. Giffuni } 29719ec7b004SRick Macklem } else if (create != NFSV4OPEN_NOCREATE) { 29729ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 2973a9285ae5SZack Kirsch goto nfsmout; 29749ec7b004SRick Macklem } 29759ec7b004SRick Macklem 29769ec7b004SRick Macklem /* 29779ec7b004SRick Macklem * Now, handle the claim, which usually includes looking up a 29789ec7b004SRick Macklem * name in the directory referenced by dp. The exception is 29799ec7b004SRick Macklem * NFSV4OPEN_CLAIMPREVIOUS. 29809ec7b004SRick Macklem */ 29819ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 29829ec7b004SRick Macklem claim = fxdr_unsigned(int, *tl); 2983b3d4c70dSRick Macklem if (claim == NFSV4OPEN_CLAIMDELEGATECUR || claim == 2984b3d4c70dSRick Macklem NFSV4OPEN_CLAIMDELEGATECURFH) { 29859ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 29869ec7b004SRick Macklem stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 29879ec7b004SRick Macklem NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 29889ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGCUR; 2989d80a903aSRick Macklem } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV || claim == 2990d80a903aSRick Macklem NFSV4OPEN_CLAIMDELEGATEPREVFH) { 29919ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGPREV; 29929ec7b004SRick Macklem } 29939ec7b004SRick Macklem if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR 29949ec7b004SRick Macklem || claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 29959ec7b004SRick Macklem if (!nd->nd_repstat && create == NFSV4OPEN_CREATE && 29969ec7b004SRick Macklem claim != NFSV4OPEN_CLAIMNULL) 29979ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 29989ec7b004SRick Macklem if (nd->nd_repstat) { 29999ec7b004SRick Macklem nd->nd_repstat = nfsrv_opencheck(clientid, 30009ec7b004SRick Macklem &stateid, stp, NULL, nd, p, nd->nd_repstat); 3001a9285ae5SZack Kirsch goto nfsmout; 30029ec7b004SRick Macklem } 30039ec7b004SRick Macklem if (create == NFSV4OPEN_CREATE) 30049ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 30056c21f6edSKonstantin Belousov LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE); 30069ec7b004SRick Macklem else 30079ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 30089ec7b004SRick Macklem LOCKLEAF | SAVESTART); 30099ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 30109ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 30119ec7b004SRick Macklem if (error) { 30129ec7b004SRick Macklem vrele(dp); 30139ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 30149ec7b004SRick Macklem acl_free(aclp); 30159ec7b004SRick Macklem #endif 3016222daa42SConrad Meyer free(stp, M_NFSDSTATE); 30179ec7b004SRick Macklem nfsvno_relpathbuf(&named); 3018a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 30199ec7b004SRick Macklem return (error); 30209ec7b004SRick Macklem } 30219ec7b004SRick Macklem if (!nd->nd_repstat) { 30229ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, 30239ec7b004SRick Macklem p, &dirp); 30249ec7b004SRick Macklem } else { 30259ec7b004SRick Macklem vrele(dp); 30269ec7b004SRick Macklem nfsvno_relpathbuf(&named); 30279ec7b004SRick Macklem } 30289ec7b004SRick Macklem if (create == NFSV4OPEN_CREATE) { 30299ec7b004SRick Macklem switch (how) { 30309ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 30319ec7b004SRick Macklem if (named.ni_vp) { 30329ec7b004SRick Macklem /* 30339ec7b004SRick Macklem * Clear the setable attribute bits, except 30349ec7b004SRick Macklem * for Size, if it is being truncated. 30359ec7b004SRick Macklem */ 30369ec7b004SRick Macklem NFSZERO_ATTRBIT(&attrbits); 30379ec7b004SRick Macklem if (NFSVNO_ISSETSIZE(&nva)) 30389ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, 30399ec7b004SRick Macklem NFSATTRBIT_SIZE); 30409ec7b004SRick Macklem } 30419ec7b004SRick Macklem break; 30429ec7b004SRick Macklem case NFSCREATE_GUARDED: 30439ec7b004SRick Macklem if (named.ni_vp && !nd->nd_repstat) 30449ec7b004SRick Macklem nd->nd_repstat = EEXIST; 30459ec7b004SRick Macklem break; 30469ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 30479ec7b004SRick Macklem exclusive_flag = 1; 30489ec7b004SRick Macklem if (!named.ni_vp) 30499ec7b004SRick Macklem nva.na_mode = 0; 3050c59e4cc3SRick Macklem break; 3051c59e4cc3SRick Macklem case NFSCREATE_EXCLUSIVE41: 3052c59e4cc3SRick Macklem exclusive_flag = 1; 3053c59e4cc3SRick Macklem break; 305474b8d63dSPedro F. Giffuni } 30559ec7b004SRick Macklem } 30569ec7b004SRick Macklem nfsvno_open(nd, &named, clientid, &stateid, stp, 30579ec7b004SRick Macklem &exclusive_flag, &nva, cverf, create, aclp, &attrbits, 305801c27978SEdward Tomasz Napierala nd->nd_cred, exp, &vp); 3059c59e4cc3SRick Macklem } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim == 3060d80a903aSRick Macklem NFSV4OPEN_CLAIMFH || claim == NFSV4OPEN_CLAIMDELEGATECURFH || 3061d80a903aSRick Macklem claim == NFSV4OPEN_CLAIMDELEGATEPREVFH) { 3062c59e4cc3SRick Macklem if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 30639ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 30649ec7b004SRick Macklem i = fxdr_unsigned(int, *tl); 30659ec7b004SRick Macklem switch (i) { 30669ec7b004SRick Macklem case NFSV4OPEN_DELEGATEREAD: 30679ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGREAD; 30689ec7b004SRick Macklem break; 30699ec7b004SRick Macklem case NFSV4OPEN_DELEGATEWRITE: 30709ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGWRITE; 30719ec7b004SRick Macklem case NFSV4OPEN_DELEGATENONE: 30729ec7b004SRick Macklem break; 30739ec7b004SRick Macklem default: 30749ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 3075a9285ae5SZack Kirsch goto nfsmout; 307674b8d63dSPedro F. Giffuni } 30779ec7b004SRick Macklem stp->ls_flags |= NFSLCK_RECLAIM; 3078c59e4cc3SRick Macklem } else { 3079c59e4cc3SRick Macklem if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE) 3080c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_INVAL; 3081c59e4cc3SRick Macklem } 30829ec7b004SRick Macklem vp = dp; 308398f234f3SZack Kirsch NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 3084abd80ddbSMateusz Guzik if (!VN_IS_DOOMED(vp)) 3085629fa50eSRick Macklem nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, 3086629fa50eSRick Macklem stp, vp, nd, p, nd->nd_repstat); 3087629fa50eSRick Macklem else 3088629fa50eSRick Macklem nd->nd_repstat = NFSERR_PERM; 30899ec7b004SRick Macklem } else { 30909ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 3091a9285ae5SZack Kirsch goto nfsmout; 30929ec7b004SRick Macklem } 30939ec7b004SRick Macklem 30949ec7b004SRick Macklem /* 30959ec7b004SRick Macklem * Do basic access checking. 30969ec7b004SRick Macklem */ 30979ec7b004SRick Macklem if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 3098de67b496SRick Macklem /* 3099de67b496SRick Macklem * The IETF working group decided that this is the correct 3100de67b496SRick Macklem * error return for all non-regular files. 3101de67b496SRick Macklem */ 3102d8a5961fSMarcelo Araujo nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK; 31039ec7b004SRick Macklem } 3104b0b7d978SRick Macklem 3105b0b7d978SRick Macklem /* 3106b0b7d978SRick Macklem * If the Open is being done for a file that already exists, apply 3107b0b7d978SRick Macklem * normal permission checking including for the file owner, if 3108b0b7d978SRick Macklem * vfs.nfsd.v4openaccess is set. 3109b0b7d978SRick Macklem * Previously, the owner was always allowed to open the file to 3110b0b7d978SRick Macklem * be consistent with the NFS tradition of always allowing the 3111b0b7d978SRick Macklem * owner of the file to write to the file regardless of permissions. 3112b0b7d978SRick Macklem * It now appears that the Linux client expects the owner 3113b0b7d978SRick Macklem * permissions to be checked for opens that are not creating the 3114b0b7d978SRick Macklem * file. I believe the correct approach is to use the Access 3115b0b7d978SRick Macklem * operation's results to be consistent with NFSv3, but that is 3116b0b7d978SRick Macklem * not what the current Linux client appears to be doing. 3117b0b7d978SRick Macklem * Since both the Linux and OpenSolaris NFSv4 servers do this check, 3118b0b7d978SRick Macklem * I have enabled it by default. 3119b0b7d978SRick Macklem * If this semantic change causes a problem, it can be disabled by 3120b0b7d978SRick Macklem * setting the sysctl vfs.nfsd.v4openaccess to 0 to re-enable the 3121b0b7d978SRick Macklem * previous semantics. 3122b0b7d978SRick Macklem */ 3123b0b7d978SRick Macklem if (nfsrv_openaccess && create == NFSV4OPEN_NOCREATE) 3124b0b7d978SRick Macklem override = NFSACCCHK_NOOVERRIDE; 3125b0b7d978SRick Macklem else 3126b0b7d978SRick Macklem override = NFSACCCHK_ALLOWOWNER; 31279ec7b004SRick Macklem if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS)) 31288da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, 3129b0b7d978SRick Macklem exp, p, override, NFSACCCHK_VPISLOCKED, NULL); 31309ec7b004SRick Macklem if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) { 31318da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, 3132b0b7d978SRick Macklem exp, p, override, NFSACCCHK_VPISLOCKED, NULL); 31339ec7b004SRick Macklem if (nd->nd_repstat) 31348da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 3135b0b7d978SRick Macklem nd->nd_cred, exp, p, override, 31368da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 31379ec7b004SRick Macklem } 31389ec7b004SRick Macklem 3139086f6e0cSRick Macklem if (!nd->nd_repstat) { 314090d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 3141086f6e0cSRick Macklem if (!nd->nd_repstat) { 3142086f6e0cSRick Macklem tverf[0] = nva.na_atime.tv_sec; 3143086f6e0cSRick Macklem tverf[1] = nva.na_atime.tv_nsec; 3144086f6e0cSRick Macklem } 3145086f6e0cSRick Macklem } 3146086f6e0cSRick Macklem if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] || 3147086f6e0cSRick Macklem cverf[1] != tverf[1])) 31489ec7b004SRick Macklem nd->nd_repstat = EEXIST; 31499ec7b004SRick Macklem /* 31509ec7b004SRick Macklem * Do the open locking/delegation stuff. 31519ec7b004SRick Macklem */ 31529ec7b004SRick Macklem if (!nd->nd_repstat) 31539ec7b004SRick Macklem nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid, 31549ec7b004SRick Macklem &delegstateid, &rflags, exp, p, nva.na_filerev); 31559ec7b004SRick Macklem 31569ec7b004SRick Macklem /* 31579ec7b004SRick Macklem * vp must be unlocked before the call to nfsvno_getattr(dirp,...) 31589ec7b004SRick Macklem * below, to avoid a deadlock with the lookup in nfsvno_namei() above. 31599ec7b004SRick Macklem * (ie: Leave the NFSVOPUNLOCK() about here.) 31609ec7b004SRick Macklem */ 31619ec7b004SRick Macklem if (vp) 3162b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 31639ec7b004SRick Macklem if (stp) 3164222daa42SConrad Meyer free(stp, M_NFSDSTATE); 31659ec7b004SRick Macklem if (!nd->nd_repstat && dirp) 316690d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 31679ec7b004SRick Macklem if (!nd->nd_repstat) { 316890d2dfabSRick Macklem /* For NFSv4.1, set the Current StateID. */ 316990d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 317090d2dfabSRick Macklem nd->nd_curstateid = stateid; 317190d2dfabSRick Macklem nd->nd_flag |= ND_CURSTATEID; 317290d2dfabSRick Macklem } 31739ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 31749ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 31759ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 31769ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 31779ec7b004SRick Macklem if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 31789ec7b004SRick Macklem *tl++ = newnfs_true; 31799ec7b004SRick Macklem *tl++ = 0; 31809ec7b004SRick Macklem *tl++ = 0; 31819ec7b004SRick Macklem *tl++ = 0; 31829ec7b004SRick Macklem *tl++ = 0; 31839ec7b004SRick Macklem } else { 31849ec7b004SRick Macklem *tl++ = newnfs_false; /* Since dirp is not locked */ 31859ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 31869ec7b004SRick Macklem tl += 2; 31879ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 31889ec7b004SRick Macklem tl += 2; 31899ec7b004SRick Macklem } 31909ec7b004SRick Macklem *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS); 31919ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &attrbits); 31929ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 31939ec7b004SRick Macklem if (rflags & NFSV4OPEN_READDELEGATE) 31949ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD); 31959ec7b004SRick Macklem else if (rflags & NFSV4OPEN_WRITEDELEGATE) 31969ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE); 3197c59e4cc3SRick Macklem else if (retext != 0) { 3198c59e4cc3SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT); 31995d54f186SRick Macklem if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) { 32005d54f186SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 32015d54f186SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 32025d54f186SRick Macklem } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) { 32035d54f186SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 32045d54f186SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE); 32055d54f186SRick Macklem } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) { 3206c59e4cc3SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3207c59e4cc3SRick Macklem *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION); 3208c59e4cc3SRick Macklem *tl = newnfs_false; 3209c59e4cc3SRick Macklem } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) { 3210c59e4cc3SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3211c59e4cc3SRick Macklem *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE); 3212c59e4cc3SRick Macklem *tl = newnfs_false; 3213c59e4cc3SRick Macklem } else { 3214c59e4cc3SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3215c59e4cc3SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 3216c59e4cc3SRick Macklem } 3217c59e4cc3SRick Macklem } else 32189ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE); 32199ec7b004SRick Macklem if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) { 32209ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED); 32219ec7b004SRick Macklem *tl++ = txdr_unsigned(delegstateid.seqid); 32229ec7b004SRick Macklem NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl, 32239ec7b004SRick Macklem NFSX_STATEIDOTHER); 32249ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 32259ec7b004SRick Macklem if (rflags & NFSV4OPEN_RECALL) 32269ec7b004SRick Macklem *tl = newnfs_true; 32279ec7b004SRick Macklem else 32289ec7b004SRick Macklem *tl = newnfs_false; 32299ec7b004SRick Macklem if (rflags & NFSV4OPEN_WRITEDELEGATE) { 32309ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 32319ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE); 32329ec7b004SRick Macklem txdr_hyper(nva.na_size, tl); 32339ec7b004SRick Macklem } 32349ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 32359ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE); 32369ec7b004SRick Macklem *tl++ = txdr_unsigned(0x0); 32379ec7b004SRick Macklem acemask = NFSV4ACE_ALLFILESMASK; 32389ec7b004SRick Macklem if (nva.na_mode & S_IRUSR) 32399ec7b004SRick Macklem acemask |= NFSV4ACE_READMASK; 32409ec7b004SRick Macklem if (nva.na_mode & S_IWUSR) 32419ec7b004SRick Macklem acemask |= NFSV4ACE_WRITEMASK; 32429ec7b004SRick Macklem if (nva.na_mode & S_IXUSR) 32439ec7b004SRick Macklem acemask |= NFSV4ACE_EXECUTEMASK; 32449ec7b004SRick Macklem *tl = txdr_unsigned(acemask); 32459ec7b004SRick Macklem (void) nfsm_strtom(nd, "OWNER@", 6); 32469ec7b004SRick Macklem } 32479ec7b004SRick Macklem *vpp = vp; 32489ec7b004SRick Macklem } else if (vp) { 32499ec7b004SRick Macklem vrele(vp); 32509ec7b004SRick Macklem } 32519ec7b004SRick Macklem if (dirp) 32529ec7b004SRick Macklem vrele(dirp); 32539ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 32549ec7b004SRick Macklem acl_free(aclp); 32559ec7b004SRick Macklem #endif 3256a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 32579ec7b004SRick Macklem return (0); 32589ec7b004SRick Macklem nfsmout: 32599ec7b004SRick Macklem vrele(dp); 32609ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 32619ec7b004SRick Macklem acl_free(aclp); 32629ec7b004SRick Macklem #endif 32639ec7b004SRick Macklem if (stp) 3264222daa42SConrad Meyer free(stp, M_NFSDSTATE); 3265a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 32669ec7b004SRick Macklem return (error); 32679ec7b004SRick Macklem } 32689ec7b004SRick Macklem 32699ec7b004SRick Macklem /* 32709ec7b004SRick Macklem * nfsv4 close service 32719ec7b004SRick Macklem */ 3272b9cc3262SRyan Moeller int 32739ec7b004SRick Macklem nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram, 3274af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 32759ec7b004SRick Macklem { 32769ec7b004SRick Macklem u_int32_t *tl; 32779ec7b004SRick Macklem struct nfsstate st, *stp = &st; 327890d2dfabSRick Macklem int error = 0, writeacc; 32799ec7b004SRick Macklem nfsv4stateid_t stateid; 32809ec7b004SRick Macklem nfsquad_t clientid; 328190d2dfabSRick Macklem struct nfsvattr na; 3282af444b18SEdward Tomasz Napierala struct thread *p = curthread; 32839ec7b004SRick Macklem 32849ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 32859ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 32869ec7b004SRick Macklem stp->ls_ownerlen = 0; 32879ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 32889ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 32899ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 32909ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 32919ec7b004SRick Macklem NFSX_STATEIDOTHER); 329290d2dfabSRick Macklem 329390d2dfabSRick Macklem /* 329490d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 329590d2dfabSRick Macklem * stateid to the current stateid, if it is set. 329690d2dfabSRick Macklem */ 329790d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 329890d2dfabSRick Macklem stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 329990d2dfabSRick Macklem stp->ls_stateid.other[2] == 0) { 330090d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) 330190d2dfabSRick Macklem stp->ls_stateid = nd->nd_curstateid; 330290d2dfabSRick Macklem else { 330390d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 330490d2dfabSRick Macklem goto nfsmout; 330590d2dfabSRick Macklem } 330690d2dfabSRick Macklem } 330790d2dfabSRick Macklem 33089ec7b004SRick Macklem stp->ls_flags = NFSLCK_CLOSE; 33099ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 33109ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 3311c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3312c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3313c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3314c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3315c59e4cc3SRick Macklem printf("EEK8 multiple clids\n"); 33169ec7b004SRick Macklem } else { 3317c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3318c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 33199ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 33209ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 33219ec7b004SRick Macklem } 332290d2dfabSRick Macklem nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, 332390d2dfabSRick Macklem &writeacc); 332490d2dfabSRick Macklem /* For pNFS, update the attributes. */ 332590d2dfabSRick Macklem if (writeacc != 0 || nfsrv_pnfsatime != 0) 332690d2dfabSRick Macklem nfsrv_updatemdsattr(vp, &na, p); 33279ec7b004SRick Macklem vput(vp); 33289ec7b004SRick Macklem if (!nd->nd_repstat) { 332990d2dfabSRick Macklem /* 333090d2dfabSRick Macklem * If the stateid that has been closed is the current stateid, 333190d2dfabSRick Macklem * unset it. 333290d2dfabSRick Macklem */ 333390d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0 && 333490d2dfabSRick Macklem stateid.other[0] == nd->nd_curstateid.other[0] && 333590d2dfabSRick Macklem stateid.other[1] == nd->nd_curstateid.other[1] && 333690d2dfabSRick Macklem stateid.other[2] == nd->nd_curstateid.other[2]) 333790d2dfabSRick Macklem nd->nd_flag &= ~ND_CURSTATEID; 33389ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 33399ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 33409ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 33419ec7b004SRick Macklem } 3342a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 33439ec7b004SRick Macklem return (0); 33449ec7b004SRick Macklem nfsmout: 33459ec7b004SRick Macklem vput(vp); 3346a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 33479ec7b004SRick Macklem return (error); 33489ec7b004SRick Macklem } 33499ec7b004SRick Macklem 33509ec7b004SRick Macklem /* 33519ec7b004SRick Macklem * nfsv4 delegpurge service 33529ec7b004SRick Macklem */ 3353b9cc3262SRyan Moeller int 33549ec7b004SRick Macklem nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram, 3355af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 33569ec7b004SRick Macklem { 33579ec7b004SRick Macklem u_int32_t *tl; 33589ec7b004SRick Macklem int error = 0; 33599ec7b004SRick Macklem nfsquad_t clientid; 3360af444b18SEdward Tomasz Napierala struct thread *p = curthread; 33619ec7b004SRick Macklem 3362984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 3363a9285ae5SZack Kirsch goto nfsmout; 33649ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 33659ec7b004SRick Macklem clientid.lval[0] = *tl++; 33669ec7b004SRick Macklem clientid.lval[1] = *tl; 3367c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3368c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3369c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3370c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3371c59e4cc3SRick Macklem printf("EEK9 multiple clids\n"); 33729ec7b004SRick Macklem } else { 3373c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3374c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 33759ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 33769ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 33779ec7b004SRick Macklem } 3378c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL, 337990d2dfabSRick Macklem NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL); 33809ec7b004SRick Macklem nfsmout: 3381a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 33829ec7b004SRick Macklem return (error); 33839ec7b004SRick Macklem } 33849ec7b004SRick Macklem 33859ec7b004SRick Macklem /* 33869ec7b004SRick Macklem * nfsv4 delegreturn service 33879ec7b004SRick Macklem */ 3388b9cc3262SRyan Moeller int 33899ec7b004SRick Macklem nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram, 3390af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 33919ec7b004SRick Macklem { 33929ec7b004SRick Macklem u_int32_t *tl; 339390d2dfabSRick Macklem int error = 0, writeacc; 33949ec7b004SRick Macklem nfsv4stateid_t stateid; 33959ec7b004SRick Macklem nfsquad_t clientid; 339690d2dfabSRick Macklem struct nfsvattr na; 3397af444b18SEdward Tomasz Napierala struct thread *p = curthread; 33989ec7b004SRick Macklem 33999ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 34009ec7b004SRick Macklem stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 34019ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER); 34029ec7b004SRick Macklem clientid.lval[0] = stateid.other[0]; 34039ec7b004SRick Macklem clientid.lval[1] = stateid.other[1]; 3404c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3405c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3406c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3407c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3408c59e4cc3SRick Macklem printf("EEK10 multiple clids\n"); 34099ec7b004SRick Macklem } else { 3410c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3411c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 34129ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 34139ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 34149ec7b004SRick Macklem } 3415c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp, 341690d2dfabSRick Macklem NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc); 341790d2dfabSRick Macklem /* For pNFS, update the attributes. */ 341890d2dfabSRick Macklem if (writeacc != 0 || nfsrv_pnfsatime != 0) 341990d2dfabSRick Macklem nfsrv_updatemdsattr(vp, &na, p); 34209ec7b004SRick Macklem nfsmout: 34219ec7b004SRick Macklem vput(vp); 3422a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 34239ec7b004SRick Macklem return (error); 34249ec7b004SRick Macklem } 34259ec7b004SRick Macklem 34269ec7b004SRick Macklem /* 34279ec7b004SRick Macklem * nfsv4 get file handle service 34289ec7b004SRick Macklem */ 3429b9cc3262SRyan Moeller int 34309ec7b004SRick Macklem nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram, 3431af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 34329ec7b004SRick Macklem { 34339ec7b004SRick Macklem fhandle_t fh; 3434af444b18SEdward Tomasz Napierala struct thread *p = curthread; 34359ec7b004SRick Macklem 34369ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 34379ec7b004SRick Macklem vput(vp); 34389ec7b004SRick Macklem if (!nd->nd_repstat) 34399ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 3440a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 34419ec7b004SRick Macklem return (0); 34429ec7b004SRick Macklem } 34439ec7b004SRick Macklem 34449ec7b004SRick Macklem /* 34459ec7b004SRick Macklem * nfsv4 open confirm service 34469ec7b004SRick Macklem */ 3447b9cc3262SRyan Moeller int 34489ec7b004SRick Macklem nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram, 3449af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 34509ec7b004SRick Macklem { 34519ec7b004SRick Macklem u_int32_t *tl; 34529ec7b004SRick Macklem struct nfsstate st, *stp = &st; 34539ec7b004SRick Macklem int error = 0; 34549ec7b004SRick Macklem nfsv4stateid_t stateid; 34559ec7b004SRick Macklem nfsquad_t clientid; 3456af444b18SEdward Tomasz Napierala struct thread *p = curthread; 34579ec7b004SRick Macklem 3458c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3459c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3460c59e4cc3SRick Macklem goto nfsmout; 3461c59e4cc3SRick Macklem } 34629ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 34639ec7b004SRick Macklem stp->ls_ownerlen = 0; 34649ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 34659ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 34669ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 34679ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 34689ec7b004SRick Macklem NFSX_STATEIDOTHER); 34699ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 34709ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl); 34719ec7b004SRick Macklem stp->ls_flags = NFSLCK_CONFIRM; 34729ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 34739ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 3474c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3475c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3476c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3477c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3478c59e4cc3SRick Macklem printf("EEK11 multiple clids\n"); 34799ec7b004SRick Macklem } else { 3480c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3481c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 34829ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 34839ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 34849ec7b004SRick Macklem } 348590d2dfabSRick Macklem nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, 348690d2dfabSRick Macklem NULL); 34879ec7b004SRick Macklem if (!nd->nd_repstat) { 34889ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 34899ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 34909ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 34919ec7b004SRick Macklem } 34929ec7b004SRick Macklem nfsmout: 34939ec7b004SRick Macklem vput(vp); 3494a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 34959ec7b004SRick Macklem return (error); 34969ec7b004SRick Macklem } 34979ec7b004SRick Macklem 34989ec7b004SRick Macklem /* 34999ec7b004SRick Macklem * nfsv4 open downgrade service 35009ec7b004SRick Macklem */ 3501b9cc3262SRyan Moeller int 35029ec7b004SRick Macklem nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram, 3503af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 35049ec7b004SRick Macklem { 35059ec7b004SRick Macklem u_int32_t *tl; 35069ec7b004SRick Macklem int i; 35079ec7b004SRick Macklem struct nfsstate st, *stp = &st; 35089ec7b004SRick Macklem int error = 0; 35099ec7b004SRick Macklem nfsv4stateid_t stateid; 35109ec7b004SRick Macklem nfsquad_t clientid; 3511af444b18SEdward Tomasz Napierala struct thread *p = curthread; 35129ec7b004SRick Macklem 3513d8a5961fSMarcelo Araujo /* opendowngrade can only work on a file object.*/ 3514d8a5961fSMarcelo Araujo if (vp->v_type != VREG) { 3515d8a5961fSMarcelo Araujo error = NFSERR_INVAL; 3516d8a5961fSMarcelo Araujo goto nfsmout; 3517d8a5961fSMarcelo Araujo } 35189ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 35199ec7b004SRick Macklem stp->ls_ownerlen = 0; 35209ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 35219ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 35229ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 35239ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 35249ec7b004SRick Macklem NFSX_STATEIDOTHER); 35259ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 352690d2dfabSRick Macklem 352790d2dfabSRick Macklem /* 352890d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 352990d2dfabSRick Macklem * stateid to the current stateid, if it is set. 353090d2dfabSRick Macklem */ 353190d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 353290d2dfabSRick Macklem stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 353390d2dfabSRick Macklem stp->ls_stateid.other[2] == 0) { 353490d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) 353590d2dfabSRick Macklem stp->ls_stateid = nd->nd_curstateid; 353690d2dfabSRick Macklem else { 353790d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 353890d2dfabSRick Macklem goto nfsmout; 353990d2dfabSRick Macklem } 354090d2dfabSRick Macklem } 354190d2dfabSRick Macklem 35429ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 35439ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 35446269d663SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 35456269d663SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 35469ec7b004SRick Macklem switch (i) { 35479ec7b004SRick Macklem case NFSV4OPEN_ACCESSREAD: 35489ec7b004SRick Macklem stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE); 35499ec7b004SRick Macklem break; 35509ec7b004SRick Macklem case NFSV4OPEN_ACCESSWRITE: 35519ec7b004SRick Macklem stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); 35529ec7b004SRick Macklem break; 35539ec7b004SRick Macklem case NFSV4OPEN_ACCESSBOTH: 35549ec7b004SRick Macklem stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS | 35559ec7b004SRick Macklem NFSLCK_DOWNGRADE); 35569ec7b004SRick Macklem break; 35579ec7b004SRick Macklem default: 35586269d663SRick Macklem nd->nd_repstat = NFSERR_INVAL; 355974b8d63dSPedro F. Giffuni } 35609ec7b004SRick Macklem i = fxdr_unsigned(int, *tl); 35619ec7b004SRick Macklem switch (i) { 35629ec7b004SRick Macklem case NFSV4OPEN_DENYNONE: 35639ec7b004SRick Macklem break; 35649ec7b004SRick Macklem case NFSV4OPEN_DENYREAD: 35659ec7b004SRick Macklem stp->ls_flags |= NFSLCK_READDENY; 35669ec7b004SRick Macklem break; 35679ec7b004SRick Macklem case NFSV4OPEN_DENYWRITE: 35689ec7b004SRick Macklem stp->ls_flags |= NFSLCK_WRITEDENY; 35699ec7b004SRick Macklem break; 35709ec7b004SRick Macklem case NFSV4OPEN_DENYBOTH: 35719ec7b004SRick Macklem stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 35729ec7b004SRick Macklem break; 35739ec7b004SRick Macklem default: 35746269d663SRick Macklem nd->nd_repstat = NFSERR_INVAL; 357574b8d63dSPedro F. Giffuni } 35769ec7b004SRick Macklem 35779ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 35789ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 3579c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3580c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3581c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3582c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3583c59e4cc3SRick Macklem printf("EEK12 multiple clids\n"); 35849ec7b004SRick Macklem } else { 3585c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3586c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 35879ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 35889ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 35899ec7b004SRick Macklem } 35909ec7b004SRick Macklem if (!nd->nd_repstat) 35919ec7b004SRick Macklem nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, 359290d2dfabSRick Macklem nd, p, NULL); 35939ec7b004SRick Macklem if (!nd->nd_repstat) { 359490d2dfabSRick Macklem /* For NFSv4.1, set the Current StateID. */ 359590d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 359690d2dfabSRick Macklem nd->nd_curstateid = stateid; 359790d2dfabSRick Macklem nd->nd_flag |= ND_CURSTATEID; 359890d2dfabSRick Macklem } 35999ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 36009ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 36019ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 36029ec7b004SRick Macklem } 36039ec7b004SRick Macklem nfsmout: 36049ec7b004SRick Macklem vput(vp); 3605a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 36069ec7b004SRick Macklem return (error); 36079ec7b004SRick Macklem } 36089ec7b004SRick Macklem 36099ec7b004SRick Macklem /* 36109ec7b004SRick Macklem * nfsv4 renew lease service 36119ec7b004SRick Macklem */ 3612b9cc3262SRyan Moeller int 36139ec7b004SRick Macklem nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram, 3614af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 36159ec7b004SRick Macklem { 36169ec7b004SRick Macklem u_int32_t *tl; 36179ec7b004SRick Macklem int error = 0; 36189ec7b004SRick Macklem nfsquad_t clientid; 3619af444b18SEdward Tomasz Napierala struct thread *p = curthread; 36209ec7b004SRick Macklem 3621c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3622c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3623c59e4cc3SRick Macklem goto nfsmout; 3624c59e4cc3SRick Macklem } 3625984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 3626a9285ae5SZack Kirsch goto nfsmout; 36279ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 36289ec7b004SRick Macklem clientid.lval[0] = *tl++; 36299ec7b004SRick Macklem clientid.lval[1] = *tl; 3630c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3631c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3632c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3633c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3634c59e4cc3SRick Macklem printf("EEK13 multiple clids\n"); 36359ec7b004SRick Macklem } else { 3636c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3637c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 36389ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 36399ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 36409ec7b004SRick Macklem } 36419ec7b004SRick Macklem nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW), 3642c59e4cc3SRick Macklem NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p); 36439ec7b004SRick Macklem nfsmout: 3644a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 36459ec7b004SRick Macklem return (error); 36469ec7b004SRick Macklem } 36479ec7b004SRick Macklem 36489ec7b004SRick Macklem /* 36499ec7b004SRick Macklem * nfsv4 security info service 36509ec7b004SRick Macklem */ 3651b9cc3262SRyan Moeller int 36529ec7b004SRick Macklem nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram, 3653af444b18SEdward Tomasz Napierala vnode_t dp, struct nfsexstuff *exp) 36549ec7b004SRick Macklem { 36559ec7b004SRick Macklem u_int32_t *tl; 36569ec7b004SRick Macklem int len; 36579ec7b004SRick Macklem struct nameidata named; 36589ec7b004SRick Macklem vnode_t dirp = NULL, vp; 36599ec7b004SRick Macklem struct nfsrvfh fh; 36609ec7b004SRick Macklem struct nfsexstuff retnes; 36619ec7b004SRick Macklem u_int32_t *sizp; 3662947bd247SRick Macklem int error = 0, i; 3663947bd247SRick Macklem uint64_t savflag; 36649ec7b004SRick Macklem char *bufp; 36659ec7b004SRick Macklem u_long *hashp; 3666af444b18SEdward Tomasz Napierala struct thread *p = curthread; 36679ec7b004SRick Macklem 36689ec7b004SRick Macklem /* 36699ec7b004SRick Macklem * All this just to get the export flags for the name. 36709ec7b004SRick Macklem */ 36719ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 36729ec7b004SRick Macklem LOCKLEAF | SAVESTART); 36739ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 36749ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 36759ec7b004SRick Macklem if (error) { 36769ec7b004SRick Macklem vput(dp); 36779ec7b004SRick Macklem nfsvno_relpathbuf(&named); 3678a9285ae5SZack Kirsch goto out; 36799ec7b004SRick Macklem } 36809ec7b004SRick Macklem if (!nd->nd_repstat) { 36819ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 36829ec7b004SRick Macklem } else { 36839ec7b004SRick Macklem vput(dp); 36849ec7b004SRick Macklem nfsvno_relpathbuf(&named); 36859ec7b004SRick Macklem } 36869ec7b004SRick Macklem if (dirp) 36879ec7b004SRick Macklem vrele(dirp); 36889ec7b004SRick Macklem if (nd->nd_repstat) 3689a9285ae5SZack Kirsch goto out; 36909ec7b004SRick Macklem vrele(named.ni_startdir); 36919ec7b004SRick Macklem nfsvno_relpathbuf(&named); 36929ec7b004SRick Macklem fh.nfsrvfh_len = NFSX_MYFH; 36939ec7b004SRick Macklem vp = named.ni_vp; 36949ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 36959ec7b004SRick Macklem vput(vp); 36969ec7b004SRick Macklem savflag = nd->nd_flag; 36979ec7b004SRick Macklem if (!nd->nd_repstat) { 36985edc9102SEdward Tomasz Napierala nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0); 36999ec7b004SRick Macklem if (vp) 37009ec7b004SRick Macklem vput(vp); 37019ec7b004SRick Macklem } 37029ec7b004SRick Macklem nd->nd_flag = savflag; 37039ec7b004SRick Macklem if (nd->nd_repstat) 3704a9285ae5SZack Kirsch goto out; 37059ec7b004SRick Macklem 37069ec7b004SRick Macklem /* 37079ec7b004SRick Macklem * Finally have the export flags for name, so we can create 37089ec7b004SRick Macklem * the security info. 37099ec7b004SRick Macklem */ 37109ec7b004SRick Macklem len = 0; 37119ec7b004SRick Macklem NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED); 3712*56e9d8e3SRick Macklem 3713*56e9d8e3SRick Macklem /* If nes_numsecflavor == 0, all are allowed. */ 3714*56e9d8e3SRick Macklem if (retnes.nes_numsecflavor == 0) { 3715*56e9d8e3SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3716*56e9d8e3SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_UNIX); 3717*56e9d8e3SRick Macklem *tl = txdr_unsigned(RPCAUTH_GSS); 3718*56e9d8e3SRick Macklem nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3719*56e9d8e3SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 3720*56e9d8e3SRick Macklem NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 3721*56e9d8e3SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3722*56e9d8e3SRick Macklem *tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3723*56e9d8e3SRick Macklem *tl = txdr_unsigned(RPCAUTH_GSS); 3724*56e9d8e3SRick Macklem nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3725*56e9d8e3SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 3726*56e9d8e3SRick Macklem NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 3727*56e9d8e3SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3728*56e9d8e3SRick Macklem *tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3729*56e9d8e3SRick Macklem *tl = txdr_unsigned(RPCAUTH_GSS); 3730*56e9d8e3SRick Macklem nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3731*56e9d8e3SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 3732*56e9d8e3SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3733*56e9d8e3SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3734*56e9d8e3SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3735*56e9d8e3SRick Macklem len = 4; 3736*56e9d8e3SRick Macklem } 373798ad4453SRick Macklem for (i = 0; i < retnes.nes_numsecflavor; i++) { 373898ad4453SRick Macklem if (retnes.nes_secflavors[i] == AUTH_SYS) { 37399ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 37409ec7b004SRick Macklem *tl = txdr_unsigned(RPCAUTH_UNIX); 37419ec7b004SRick Macklem len++; 374298ad4453SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 37439ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 37449ec7b004SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_GSS); 37459ec7b004SRick Macklem (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 37469ec7b004SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 37479ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 37489ec7b004SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 374998ad4453SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 37509ec7b004SRick Macklem len++; 375198ad4453SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 375298ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 375398ad4453SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_GSS); 375498ad4453SRick Macklem (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 375598ad4453SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 375698ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 375798ad4453SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 375898ad4453SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 375998ad4453SRick Macklem len++; 376098ad4453SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 376198ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 376298ad4453SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_GSS); 376398ad4453SRick Macklem (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 376498ad4453SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 376598ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 376698ad4453SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 376798ad4453SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 376898ad4453SRick Macklem len++; 376998ad4453SRick Macklem } 37709ec7b004SRick Macklem } 37719ec7b004SRick Macklem *sizp = txdr_unsigned(len); 3772a9285ae5SZack Kirsch 3773a9285ae5SZack Kirsch out: 3774a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 3775a9285ae5SZack Kirsch return (error); 37769ec7b004SRick Macklem } 37779ec7b004SRick Macklem 37789ec7b004SRick Macklem /* 3779947bd247SRick Macklem * nfsv4 security info no name service 3780947bd247SRick Macklem */ 3781947bd247SRick Macklem int 3782947bd247SRick Macklem nfsrvd_secinfononame(struct nfsrv_descript *nd, int isdgram, 3783947bd247SRick Macklem vnode_t dp, struct nfsexstuff *exp) 3784947bd247SRick Macklem { 3785947bd247SRick Macklem uint32_t *tl, *sizp; 3786947bd247SRick Macklem struct nameidata named; 3787947bd247SRick Macklem vnode_t dirp = NULL, vp; 3788947bd247SRick Macklem struct nfsrvfh fh; 3789947bd247SRick Macklem struct nfsexstuff retnes; 3790947bd247SRick Macklem int error = 0, fhstyle, i, len; 3791947bd247SRick Macklem uint64_t savflag; 3792947bd247SRick Macklem char *bufp; 3793947bd247SRick Macklem u_long *hashp; 3794947bd247SRick Macklem struct thread *p = curthread; 3795947bd247SRick Macklem 3796947bd247SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3797947bd247SRick Macklem fhstyle = fxdr_unsigned(int, *tl); 3798947bd247SRick Macklem switch (fhstyle) { 3799947bd247SRick Macklem case NFSSECINFONONAME_PARENT: 3800947bd247SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 3801947bd247SRick Macklem LOCKLEAF | SAVESTART); 3802947bd247SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 3803947bd247SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 3804947bd247SRick Macklem if (error != 0) { 3805947bd247SRick Macklem vput(dp); 3806947bd247SRick Macklem nfsvno_relpathbuf(&named); 3807947bd247SRick Macklem goto nfsmout; 3808947bd247SRick Macklem } 3809947bd247SRick Macklem if (nd->nd_repstat == 0) 3810947bd247SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 3811947bd247SRick Macklem else 3812947bd247SRick Macklem vput(dp); 3813947bd247SRick Macklem if (dirp != NULL) 3814947bd247SRick Macklem vrele(dirp); 3815947bd247SRick Macklem vrele(named.ni_startdir); 3816947bd247SRick Macklem nfsvno_relpathbuf(&named); 3817947bd247SRick Macklem vp = named.ni_vp; 3818947bd247SRick Macklem break; 3819947bd247SRick Macklem case NFSSECINFONONAME_CURFH: 3820947bd247SRick Macklem vp = dp; 3821947bd247SRick Macklem break; 3822947bd247SRick Macklem default: 3823947bd247SRick Macklem nd->nd_repstat = NFSERR_INVAL; 3824947bd247SRick Macklem vput(dp); 3825947bd247SRick Macklem } 3826947bd247SRick Macklem if (nd->nd_repstat != 0) 3827947bd247SRick Macklem goto nfsmout; 3828947bd247SRick Macklem fh.nfsrvfh_len = NFSX_MYFH; 3829947bd247SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 3830947bd247SRick Macklem vput(vp); 3831947bd247SRick Macklem savflag = nd->nd_flag; 3832947bd247SRick Macklem if (nd->nd_repstat == 0) { 3833947bd247SRick Macklem nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0); 3834947bd247SRick Macklem if (vp != NULL) 3835947bd247SRick Macklem vput(vp); 3836947bd247SRick Macklem } 3837947bd247SRick Macklem nd->nd_flag = savflag; 3838947bd247SRick Macklem if (nd->nd_repstat != 0) 3839947bd247SRick Macklem goto nfsmout; 3840947bd247SRick Macklem 3841947bd247SRick Macklem /* 3842947bd247SRick Macklem * Finally have the export flags for fh/parent, so we can create 3843947bd247SRick Macklem * the security info. 3844947bd247SRick Macklem */ 3845947bd247SRick Macklem len = 0; 3846947bd247SRick Macklem NFSM_BUILD(sizp, uint32_t *, NFSX_UNSIGNED); 3847*56e9d8e3SRick Macklem 3848*56e9d8e3SRick Macklem /* If nes_numsecflavor == 0, all are allowed. */ 3849*56e9d8e3SRick Macklem if (retnes.nes_numsecflavor == 0) { 3850*56e9d8e3SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3851*56e9d8e3SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_UNIX); 3852*56e9d8e3SRick Macklem *tl = txdr_unsigned(RPCAUTH_GSS); 3853*56e9d8e3SRick Macklem nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3854*56e9d8e3SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 3855*56e9d8e3SRick Macklem NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 3856*56e9d8e3SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3857*56e9d8e3SRick Macklem *tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3858*56e9d8e3SRick Macklem *tl = txdr_unsigned(RPCAUTH_GSS); 3859*56e9d8e3SRick Macklem nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3860*56e9d8e3SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 3861*56e9d8e3SRick Macklem NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 3862*56e9d8e3SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3863*56e9d8e3SRick Macklem *tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3864*56e9d8e3SRick Macklem *tl = txdr_unsigned(RPCAUTH_GSS); 3865*56e9d8e3SRick Macklem nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3866*56e9d8e3SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 3867*56e9d8e3SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3868*56e9d8e3SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3869*56e9d8e3SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3870*56e9d8e3SRick Macklem len = 4; 3871*56e9d8e3SRick Macklem } 3872947bd247SRick Macklem for (i = 0; i < retnes.nes_numsecflavor; i++) { 3873947bd247SRick Macklem if (retnes.nes_secflavors[i] == AUTH_SYS) { 3874947bd247SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3875947bd247SRick Macklem *tl = txdr_unsigned(RPCAUTH_UNIX); 3876947bd247SRick Macklem len++; 3877947bd247SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 3878947bd247SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3879947bd247SRick Macklem *tl = txdr_unsigned(RPCAUTH_GSS); 3880947bd247SRick Macklem nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3881947bd247SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 3882947bd247SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3883947bd247SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3884947bd247SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3885947bd247SRick Macklem len++; 3886947bd247SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 3887947bd247SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3888947bd247SRick Macklem *tl = txdr_unsigned(RPCAUTH_GSS); 3889947bd247SRick Macklem nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3890947bd247SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 3891947bd247SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3892947bd247SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3893947bd247SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3894947bd247SRick Macklem len++; 3895947bd247SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 3896947bd247SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3897947bd247SRick Macklem *tl = txdr_unsigned(RPCAUTH_GSS); 3898947bd247SRick Macklem nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3899947bd247SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 3900947bd247SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3901947bd247SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3902947bd247SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3903947bd247SRick Macklem len++; 3904947bd247SRick Macklem } 3905947bd247SRick Macklem } 3906947bd247SRick Macklem *sizp = txdr_unsigned(len); 3907947bd247SRick Macklem 3908947bd247SRick Macklem nfsmout: 3909947bd247SRick Macklem NFSEXITCODE2(error, nd); 3910947bd247SRick Macklem return (error); 3911947bd247SRick Macklem } 3912947bd247SRick Macklem 3913947bd247SRick Macklem /* 39149ec7b004SRick Macklem * nfsv4 set client id service 39159ec7b004SRick Macklem */ 3916b9cc3262SRyan Moeller int 39179ec7b004SRick Macklem nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, 3918af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 39199ec7b004SRick Macklem { 39209ec7b004SRick Macklem u_int32_t *tl; 39219ec7b004SRick Macklem int i; 39229ec7b004SRick Macklem int error = 0, idlen; 39239ec7b004SRick Macklem struct nfsclient *clp = NULL; 3924ed2f1001SRick Macklem #ifdef INET 3925ed2f1001SRick Macklem struct sockaddr_in *rin; 3926ed2f1001SRick Macklem #endif 3927ed2f1001SRick Macklem #ifdef INET6 3928ed2f1001SRick Macklem struct sockaddr_in6 *rin6; 3929ed2f1001SRick Macklem #endif 3930ed2f1001SRick Macklem #if defined(INET) || defined(INET6) 3931ed2f1001SRick Macklem u_char *ucp, *ucp2; 3932ed2f1001SRick Macklem #endif 3933ed2f1001SRick Macklem u_char *verf, *addrbuf; 39349ec7b004SRick Macklem nfsquad_t clientid, confirm; 3935af444b18SEdward Tomasz Napierala struct thread *p = curthread; 39369ec7b004SRick Macklem 3937c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3938c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3939c59e4cc3SRick Macklem goto nfsmout; 3940c59e4cc3SRick Macklem } 3941984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 3942a9285ae5SZack Kirsch goto out; 39439ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 39449ec7b004SRick Macklem verf = (u_char *)tl; 39459ec7b004SRick Macklem tl += (NFSX_VERF / NFSX_UNSIGNED); 39469ec7b004SRick Macklem i = fxdr_unsigned(int, *tl); 39479ec7b004SRick Macklem if (i > NFSV4_OPAQUELIMIT || i <= 0) { 39489ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 3949a9285ae5SZack Kirsch goto nfsmout; 39509ec7b004SRick Macklem } 39519ec7b004SRick Macklem idlen = i; 39529ec7b004SRick Macklem if (nd->nd_flag & ND_GSS) 39539ec7b004SRick Macklem i += nd->nd_princlen; 39541f54e596SRick Macklem clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 39551f54e596SRick Macklem M_ZERO); 39561f54e596SRick Macklem clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 39571f54e596SRick Macklem nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 39589ec7b004SRick Macklem NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3959ed2f1001SRick Macklem /* Allocated large enough for an AF_INET or AF_INET6 socket. */ 3960ed2f1001SRick Macklem clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, 3961b97b91b5SConrad Meyer M_WAITOK | M_ZERO); 39629ec7b004SRick Macklem clp->lc_req.nr_cred = NULL; 39639ec7b004SRick Macklem NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 39649ec7b004SRick Macklem clp->lc_idlen = idlen; 39659ec7b004SRick Macklem error = nfsrv_mtostr(nd, clp->lc_id, idlen); 39669ec7b004SRick Macklem if (error) 39679ec7b004SRick Macklem goto nfsmout; 39689ec7b004SRick Macklem if (nd->nd_flag & ND_GSS) { 39699ec7b004SRick Macklem clp->lc_flags = LCL_GSS; 39709ec7b004SRick Macklem if (nd->nd_flag & ND_GSSINTEGRITY) 39719ec7b004SRick Macklem clp->lc_flags |= LCL_GSSINTEGRITY; 39729ec7b004SRick Macklem else if (nd->nd_flag & ND_GSSPRIVACY) 39739ec7b004SRick Macklem clp->lc_flags |= LCL_GSSPRIVACY; 39749ec7b004SRick Macklem } else { 39759ec7b004SRick Macklem clp->lc_flags = 0; 39769ec7b004SRick Macklem } 39779ec7b004SRick Macklem if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) { 39789ec7b004SRick Macklem clp->lc_flags |= LCL_NAME; 39799ec7b004SRick Macklem clp->lc_namelen = nd->nd_princlen; 39809ec7b004SRick Macklem clp->lc_name = &clp->lc_id[idlen]; 39819ec7b004SRick Macklem NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 39829ec7b004SRick Macklem } else { 39839ec7b004SRick Macklem clp->lc_uid = nd->nd_cred->cr_uid; 39849ec7b004SRick Macklem clp->lc_gid = nd->nd_cred->cr_gid; 39859ec7b004SRick Macklem } 39866e4b6ff8SRick Macklem 39876e4b6ff8SRick Macklem /* If the client is using TLS, do so for the callback connection. */ 39886e4b6ff8SRick Macklem if (nd->nd_flag & ND_TLS) 39896e4b6ff8SRick Macklem clp->lc_flags |= LCL_TLSCB; 39906e4b6ff8SRick Macklem 39919ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 39929ec7b004SRick Macklem clp->lc_program = fxdr_unsigned(u_int32_t, *tl); 39939ec7b004SRick Macklem error = nfsrv_getclientipaddr(nd, clp); 39949ec7b004SRick Macklem if (error) 39959ec7b004SRick Macklem goto nfsmout; 39969ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 39979ec7b004SRick Macklem clp->lc_callback = fxdr_unsigned(u_int32_t, *tl); 39989ec7b004SRick Macklem 39999ec7b004SRick Macklem /* 40009ec7b004SRick Macklem * nfsrv_setclient() does the actual work of adding it to the 40019ec7b004SRick Macklem * client list. If there is no error, the structure has been 40029ec7b004SRick Macklem * linked into the client list and clp should no longer be used 40039ec7b004SRick Macklem * here. When an error is returned, it has not been linked in, 40049ec7b004SRick Macklem * so it should be free'd. 40059ec7b004SRick Macklem */ 40069ec7b004SRick Macklem nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 40079ec7b004SRick Macklem if (nd->nd_repstat == NFSERR_CLIDINUSE) { 4008ed2f1001SRick Macklem /* 4009ed2f1001SRick Macklem * 8 is the maximum length of the port# string. 4010ed2f1001SRick Macklem */ 4011ed2f1001SRick Macklem addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK); 4012ed2f1001SRick Macklem switch (clp->lc_req.nr_nam->sa_family) { 4013ed2f1001SRick Macklem #ifdef INET 4014ed2f1001SRick Macklem case AF_INET: 40159ec7b004SRick Macklem if (clp->lc_flags & LCL_TCPCALLBACK) 40169ec7b004SRick Macklem (void) nfsm_strtom(nd, "tcp", 3); 40179ec7b004SRick Macklem else 40189ec7b004SRick Macklem (void) nfsm_strtom(nd, "udp", 3); 4019ed2f1001SRick Macklem rin = (struct sockaddr_in *)clp->lc_req.nr_nam; 4020ed2f1001SRick Macklem ucp = (u_char *)&rin->sin_addr.s_addr; 4021ed2f1001SRick Macklem ucp2 = (u_char *)&rin->sin_port; 40229ec7b004SRick Macklem sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff, 40239ec7b004SRick Macklem ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff, 40249ec7b004SRick Macklem ucp2[0] & 0xff, ucp2[1] & 0xff); 4025ed2f1001SRick Macklem break; 4026ed2f1001SRick Macklem #endif 4027ed2f1001SRick Macklem #ifdef INET6 4028ed2f1001SRick Macklem case AF_INET6: 4029ed2f1001SRick Macklem if (clp->lc_flags & LCL_TCPCALLBACK) 4030ed2f1001SRick Macklem (void) nfsm_strtom(nd, "tcp6", 4); 4031ed2f1001SRick Macklem else 4032ed2f1001SRick Macklem (void) nfsm_strtom(nd, "udp6", 4); 4033ed2f1001SRick Macklem rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam; 4034ed2f1001SRick Macklem ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf, 4035ed2f1001SRick Macklem INET6_ADDRSTRLEN); 4036ed2f1001SRick Macklem if (ucp != NULL) 4037ed2f1001SRick Macklem i = strlen(ucp); 4038ed2f1001SRick Macklem else 4039ed2f1001SRick Macklem i = 0; 4040ed2f1001SRick Macklem ucp2 = (u_char *)&rin6->sin6_port; 4041ed2f1001SRick Macklem sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff, 4042ed2f1001SRick Macklem ucp2[1] & 0xff); 4043ed2f1001SRick Macklem break; 4044ed2f1001SRick Macklem #endif 4045ed2f1001SRick Macklem } 40469ec7b004SRick Macklem (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf)); 4047ed2f1001SRick Macklem free(addrbuf, M_TEMP); 40489ec7b004SRick Macklem } 40499ec7b004SRick Macklem if (clp) { 4050b97b91b5SConrad Meyer free(clp->lc_req.nr_nam, M_SONAME); 40519ec7b004SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 40521f54e596SRick Macklem free(clp->lc_stateid, M_NFSDCLIENT); 40531f54e596SRick Macklem free(clp, M_NFSDCLIENT); 40549ec7b004SRick Macklem } 40559ec7b004SRick Macklem if (!nd->nd_repstat) { 40569ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); 40579ec7b004SRick Macklem *tl++ = clientid.lval[0]; 40589ec7b004SRick Macklem *tl++ = clientid.lval[1]; 40599ec7b004SRick Macklem *tl++ = confirm.lval[0]; 40609ec7b004SRick Macklem *tl = confirm.lval[1]; 40619ec7b004SRick Macklem } 4062a9285ae5SZack Kirsch 4063a9285ae5SZack Kirsch out: 4064a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 40659ec7b004SRick Macklem return (0); 40669ec7b004SRick Macklem nfsmout: 40679ec7b004SRick Macklem if (clp) { 4068b97b91b5SConrad Meyer free(clp->lc_req.nr_nam, M_SONAME); 40699ec7b004SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 40701f54e596SRick Macklem free(clp->lc_stateid, M_NFSDCLIENT); 40711f54e596SRick Macklem free(clp, M_NFSDCLIENT); 40729ec7b004SRick Macklem } 4073a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 40749ec7b004SRick Macklem return (error); 40759ec7b004SRick Macklem } 40769ec7b004SRick Macklem 40779ec7b004SRick Macklem /* 40789ec7b004SRick Macklem * nfsv4 set client id confirm service 40799ec7b004SRick Macklem */ 4080b9cc3262SRyan Moeller int 40819ec7b004SRick Macklem nfsrvd_setclientidcfrm(struct nfsrv_descript *nd, 4082af444b18SEdward Tomasz Napierala __unused int isdgram, __unused vnode_t vp, 40839ec7b004SRick Macklem __unused struct nfsexstuff *exp) 40849ec7b004SRick Macklem { 40859ec7b004SRick Macklem u_int32_t *tl; 40869ec7b004SRick Macklem int error = 0; 40879ec7b004SRick Macklem nfsquad_t clientid, confirm; 4088af444b18SEdward Tomasz Napierala struct thread *p = curthread; 40899ec7b004SRick Macklem 4090c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 4091c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 4092c59e4cc3SRick Macklem goto nfsmout; 4093c59e4cc3SRick Macklem } 4094984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4095a9285ae5SZack Kirsch goto nfsmout; 40969ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER); 40979ec7b004SRick Macklem clientid.lval[0] = *tl++; 40989ec7b004SRick Macklem clientid.lval[1] = *tl++; 40999ec7b004SRick Macklem confirm.lval[0] = *tl++; 41009ec7b004SRick Macklem confirm.lval[1] = *tl; 41019ec7b004SRick Macklem 41029ec7b004SRick Macklem /* 41039ec7b004SRick Macklem * nfsrv_getclient() searches the client list for a match and 41049ec7b004SRick Macklem * returns the appropriate NFSERR status. 41059ec7b004SRick Macklem */ 41069ec7b004SRick Macklem nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW), 4107c59e4cc3SRick Macklem NULL, NULL, confirm, 0, nd, p); 41089ec7b004SRick Macklem nfsmout: 4109a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 41109ec7b004SRick Macklem return (error); 41119ec7b004SRick Macklem } 41129ec7b004SRick Macklem 41139ec7b004SRick Macklem /* 41149ec7b004SRick Macklem * nfsv4 verify service 41159ec7b004SRick Macklem */ 4116b9cc3262SRyan Moeller int 41179ec7b004SRick Macklem nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, 4118af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 41199ec7b004SRick Macklem { 41209ec7b004SRick Macklem int error = 0, ret, fhsize = NFSX_MYFH; 41219ec7b004SRick Macklem struct nfsvattr nva; 41222f304845SKonstantin Belousov struct statfs *sf; 41239ec7b004SRick Macklem struct nfsfsinfo fs; 41249ec7b004SRick Macklem fhandle_t fh; 4125af444b18SEdward Tomasz Napierala struct thread *p = curthread; 41269ec7b004SRick Macklem 41272f304845SKonstantin Belousov sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 412890d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 41299ec7b004SRick Macklem if (!nd->nd_repstat) 41302f304845SKonstantin Belousov nd->nd_repstat = nfsvno_statfs(vp, sf); 41319ec7b004SRick Macklem if (!nd->nd_repstat) 41329ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 41339ec7b004SRick Macklem if (!nd->nd_repstat) { 41349ec7b004SRick Macklem nfsvno_getfs(&fs, isdgram); 41359ec7b004SRick Macklem error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL, 41362f304845SKonstantin Belousov sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred); 41379ec7b004SRick Macklem if (!error) { 41389ec7b004SRick Macklem if (nd->nd_procnum == NFSV4OP_NVERIFY) { 41399ec7b004SRick Macklem if (ret == 0) 41409ec7b004SRick Macklem nd->nd_repstat = NFSERR_SAME; 41419ec7b004SRick Macklem else if (ret != NFSERR_NOTSAME) 41429ec7b004SRick Macklem nd->nd_repstat = ret; 41439ec7b004SRick Macklem } else if (ret) 41449ec7b004SRick Macklem nd->nd_repstat = ret; 41459ec7b004SRick Macklem } 41469ec7b004SRick Macklem } 41479ec7b004SRick Macklem vput(vp); 41482f304845SKonstantin Belousov free(sf, M_STATFS); 4149a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 41509ec7b004SRick Macklem return (error); 41519ec7b004SRick Macklem } 41529ec7b004SRick Macklem 41539ec7b004SRick Macklem /* 41549ec7b004SRick Macklem * nfs openattr rpc 41559ec7b004SRick Macklem */ 4156b9cc3262SRyan Moeller int 41579ec7b004SRick Macklem nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram, 41589ec7b004SRick Macklem vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp, 4159af444b18SEdward Tomasz Napierala __unused struct nfsexstuff *exp) 41609ec7b004SRick Macklem { 41619ec7b004SRick Macklem u_int32_t *tl; 41628014c971SRick Macklem int error = 0, createdir __unused; 41639ec7b004SRick Macklem 41649ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 41659ec7b004SRick Macklem createdir = fxdr_unsigned(int, *tl); 41669ec7b004SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 41679ec7b004SRick Macklem nfsmout: 41689ec7b004SRick Macklem vrele(dp); 4169a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 41709ec7b004SRick Macklem return (error); 41719ec7b004SRick Macklem } 41729ec7b004SRick Macklem 41739ec7b004SRick Macklem /* 41749ec7b004SRick Macklem * nfsv4 release lock owner service 41759ec7b004SRick Macklem */ 4176b9cc3262SRyan Moeller int 41779ec7b004SRick Macklem nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram, 4178af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 41799ec7b004SRick Macklem { 41809ec7b004SRick Macklem u_int32_t *tl; 41819ec7b004SRick Macklem struct nfsstate *stp = NULL; 41829ec7b004SRick Macklem int error = 0, len; 41839ec7b004SRick Macklem nfsquad_t clientid; 4184af444b18SEdward Tomasz Napierala struct thread *p = curthread; 41859ec7b004SRick Macklem 4186c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 4187c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 4188c59e4cc3SRick Macklem goto nfsmout; 4189c59e4cc3SRick Macklem } 4190984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4191a9285ae5SZack Kirsch goto nfsmout; 41929ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 41939ec7b004SRick Macklem len = fxdr_unsigned(int, *(tl + 2)); 41942a45247cSRick Macklem if (len <= 0 || len > NFSV4_OPAQUELIMIT) { 41952a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 4196a9285ae5SZack Kirsch goto nfsmout; 41972a45247cSRick Macklem } 4198222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate) + len, 41999ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 42009ec7b004SRick Macklem stp->ls_ownerlen = len; 42019ec7b004SRick Macklem stp->ls_op = NULL; 42029ec7b004SRick Macklem stp->ls_flags = NFSLCK_RELEASE; 42039ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 42049ec7b004SRick Macklem clientid.lval[0] = *tl++; 42059ec7b004SRick Macklem clientid.lval[1] = *tl; 4206c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 4207c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 4208c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 4209c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 4210c59e4cc3SRick Macklem printf("EEK14 multiple clids\n"); 42119ec7b004SRick Macklem } else { 4212c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 4213c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 42149ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 42159ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 42169ec7b004SRick Macklem } 42179ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, len); 42189ec7b004SRick Macklem if (error) 42199ec7b004SRick Macklem goto nfsmout; 42209ec7b004SRick Macklem nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p); 4221222daa42SConrad Meyer free(stp, M_NFSDSTATE); 4222a9285ae5SZack Kirsch 4223a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 42249ec7b004SRick Macklem return (0); 42259ec7b004SRick Macklem nfsmout: 42269ec7b004SRick Macklem if (stp) 4227222daa42SConrad Meyer free(stp, M_NFSDSTATE); 4228a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 42299ec7b004SRick Macklem return (error); 42309ec7b004SRick Macklem } 4231c59e4cc3SRick Macklem 4232c59e4cc3SRick Macklem /* 4233c59e4cc3SRick Macklem * nfsv4 exchange_id service 4234c59e4cc3SRick Macklem */ 4235b9cc3262SRyan Moeller int 4236c59e4cc3SRick Macklem nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram, 4237af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4238c59e4cc3SRick Macklem { 4239c59e4cc3SRick Macklem uint32_t *tl; 4240c59e4cc3SRick Macklem int error = 0, i, idlen; 4241c59e4cc3SRick Macklem struct nfsclient *clp = NULL; 4242c59e4cc3SRick Macklem nfsquad_t clientid, confirm; 4243c59e4cc3SRick Macklem uint8_t *verf; 4244c59e4cc3SRick Macklem uint32_t sp4type, v41flags; 4245c59e4cc3SRick Macklem uint64_t owner_minor; 4246c59e4cc3SRick Macklem struct timespec verstime; 4247ed2f1001SRick Macklem #ifdef INET 4248ed2f1001SRick Macklem struct sockaddr_in *sin, *rin; 4249ed2f1001SRick Macklem #endif 4250ed2f1001SRick Macklem #ifdef INET6 4251ed2f1001SRick Macklem struct sockaddr_in6 *sin6, *rin6; 4252ed2f1001SRick Macklem #endif 4253af444b18SEdward Tomasz Napierala struct thread *p = curthread; 4254c59e4cc3SRick Macklem 4255984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4256c59e4cc3SRick Macklem goto nfsmout; 4257c59e4cc3SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 4258c59e4cc3SRick Macklem verf = (uint8_t *)tl; 4259c59e4cc3SRick Macklem tl += (NFSX_VERF / NFSX_UNSIGNED); 4260c59e4cc3SRick Macklem i = fxdr_unsigned(int, *tl); 4261c59e4cc3SRick Macklem if (i > NFSV4_OPAQUELIMIT || i <= 0) { 4262c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 4263c59e4cc3SRick Macklem goto nfsmout; 4264c59e4cc3SRick Macklem } 4265c59e4cc3SRick Macklem idlen = i; 4266c59e4cc3SRick Macklem if (nd->nd_flag & ND_GSS) 4267c59e4cc3SRick Macklem i += nd->nd_princlen; 42681f54e596SRick Macklem clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 42691f54e596SRick Macklem M_ZERO); 42701f54e596SRick Macklem clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 42711f54e596SRick Macklem nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 4272c59e4cc3SRick Macklem NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 4273ed2f1001SRick Macklem /* Allocated large enough for an AF_INET or AF_INET6 socket. */ 4274ed2f1001SRick Macklem clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, 4275b97b91b5SConrad Meyer M_WAITOK | M_ZERO); 4276ed2f1001SRick Macklem switch (nd->nd_nam->sa_family) { 4277ed2f1001SRick Macklem #ifdef INET 4278ed2f1001SRick Macklem case AF_INET: 4279ed2f1001SRick Macklem rin = (struct sockaddr_in *)clp->lc_req.nr_nam; 4280ed2f1001SRick Macklem sin = (struct sockaddr_in *)nd->nd_nam; 4281ed2f1001SRick Macklem rin->sin_family = AF_INET; 4282ed2f1001SRick Macklem rin->sin_len = sizeof(struct sockaddr_in); 4283ed2f1001SRick Macklem rin->sin_port = 0; 4284ed2f1001SRick Macklem rin->sin_addr.s_addr = sin->sin_addr.s_addr; 4285ed2f1001SRick Macklem break; 4286ed2f1001SRick Macklem #endif 4287ed2f1001SRick Macklem #ifdef INET6 4288ed2f1001SRick Macklem case AF_INET6: 4289ed2f1001SRick Macklem rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam; 4290ed2f1001SRick Macklem sin6 = (struct sockaddr_in6 *)nd->nd_nam; 4291ed2f1001SRick Macklem rin6->sin6_family = AF_INET6; 4292ed2f1001SRick Macklem rin6->sin6_len = sizeof(struct sockaddr_in6); 4293ed2f1001SRick Macklem rin6->sin6_port = 0; 4294ed2f1001SRick Macklem rin6->sin6_addr = sin6->sin6_addr; 4295ed2f1001SRick Macklem break; 4296ed2f1001SRick Macklem #endif 4297ed2f1001SRick Macklem } 4298c59e4cc3SRick Macklem clp->lc_req.nr_cred = NULL; 4299c59e4cc3SRick Macklem NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 4300c59e4cc3SRick Macklem clp->lc_idlen = idlen; 4301c59e4cc3SRick Macklem error = nfsrv_mtostr(nd, clp->lc_id, idlen); 4302c59e4cc3SRick Macklem if (error != 0) 4303c59e4cc3SRick Macklem goto nfsmout; 4304c59e4cc3SRick Macklem if ((nd->nd_flag & ND_GSS) != 0) { 4305c59e4cc3SRick Macklem clp->lc_flags = LCL_GSS | LCL_NFSV41; 4306c59e4cc3SRick Macklem if ((nd->nd_flag & ND_GSSINTEGRITY) != 0) 4307c59e4cc3SRick Macklem clp->lc_flags |= LCL_GSSINTEGRITY; 4308c59e4cc3SRick Macklem else if ((nd->nd_flag & ND_GSSPRIVACY) != 0) 4309c59e4cc3SRick Macklem clp->lc_flags |= LCL_GSSPRIVACY; 4310c59e4cc3SRick Macklem } else 4311c59e4cc3SRick Macklem clp->lc_flags = LCL_NFSV41; 4312c057a378SRick Macklem if ((nd->nd_flag & ND_NFSV42) != 0) 4313c057a378SRick Macklem clp->lc_flags |= LCL_NFSV42; 4314c59e4cc3SRick Macklem if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) { 4315c59e4cc3SRick Macklem clp->lc_flags |= LCL_NAME; 4316c59e4cc3SRick Macklem clp->lc_namelen = nd->nd_princlen; 4317c59e4cc3SRick Macklem clp->lc_name = &clp->lc_id[idlen]; 4318c59e4cc3SRick Macklem NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 4319c59e4cc3SRick Macklem } else { 4320c59e4cc3SRick Macklem clp->lc_uid = nd->nd_cred->cr_uid; 4321c59e4cc3SRick Macklem clp->lc_gid = nd->nd_cred->cr_gid; 4322c59e4cc3SRick Macklem } 4323c59e4cc3SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4324c59e4cc3SRick Macklem v41flags = fxdr_unsigned(uint32_t, *tl++); 4325c59e4cc3SRick Macklem if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR | 4326c59e4cc3SRick Macklem NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS | 4327c59e4cc3SRick Macklem NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) { 4328c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_INVAL; 4329c59e4cc3SRick Macklem goto nfsmout; 4330c59e4cc3SRick Macklem } 4331c59e4cc3SRick Macklem if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0) 4332c59e4cc3SRick Macklem confirm.lval[1] = 1; 4333c59e4cc3SRick Macklem else 4334c59e4cc3SRick Macklem confirm.lval[1] = 0; 433590d2dfabSRick Macklem if (nfsrv_devidcnt == 0) 433690d2dfabSRick Macklem v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS; 433790d2dfabSRick Macklem else 433890d2dfabSRick Macklem v41flags = NFSV4EXCH_USEPNFSMDS; 4339c59e4cc3SRick Macklem sp4type = fxdr_unsigned(uint32_t, *tl); 4340c59e4cc3SRick Macklem if (sp4type != NFSV4EXCH_SP4NONE) { 4341c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 4342c59e4cc3SRick Macklem goto nfsmout; 4343c59e4cc3SRick Macklem } 4344c59e4cc3SRick Macklem 4345c59e4cc3SRick Macklem /* 4346c59e4cc3SRick Macklem * nfsrv_setclient() does the actual work of adding it to the 4347c59e4cc3SRick Macklem * client list. If there is no error, the structure has been 4348c59e4cc3SRick Macklem * linked into the client list and clp should no longer be used 4349c59e4cc3SRick Macklem * here. When an error is returned, it has not been linked in, 4350c59e4cc3SRick Macklem * so it should be free'd. 4351c59e4cc3SRick Macklem */ 4352c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 4353c59e4cc3SRick Macklem if (clp != NULL) { 4354b97b91b5SConrad Meyer free(clp->lc_req.nr_nam, M_SONAME); 4355c59e4cc3SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 43561f54e596SRick Macklem free(clp->lc_stateid, M_NFSDCLIENT); 4357c59e4cc3SRick Macklem free(clp, M_NFSDCLIENT); 4358c59e4cc3SRick Macklem } 4359c59e4cc3SRick Macklem if (nd->nd_repstat == 0) { 4360c59e4cc3SRick Macklem if (confirm.lval[1] != 0) 4361c59e4cc3SRick Macklem v41flags |= NFSV4EXCH_CONFIRMEDR; 4362c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED); 4363c59e4cc3SRick Macklem *tl++ = clientid.lval[0]; /* ClientID */ 4364c59e4cc3SRick Macklem *tl++ = clientid.lval[1]; 4365c59e4cc3SRick Macklem *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */ 4366c59e4cc3SRick Macklem *tl++ = txdr_unsigned(v41flags); /* Exch flags */ 4367c59e4cc3SRick Macklem *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */ 4368c59e4cc3SRick Macklem owner_minor = 0; /* Owner */ 4369c59e4cc3SRick Macklem txdr_hyper(owner_minor, tl); /* Minor */ 4370c59e4cc3SRick Macklem (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid, 4371c59e4cc3SRick Macklem strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */ 43728932a483SRick Macklem (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid, 43738932a483SRick Macklem strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Scope */ 43748932a483SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4375c59e4cc3SRick Macklem *tl = txdr_unsigned(1); 4376c59e4cc3SRick Macklem (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 4377c59e4cc3SRick Macklem (void)nfsm_strtom(nd, version, strlen(version)); 4378c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 4379c59e4cc3SRick Macklem verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 4380c59e4cc3SRick Macklem verstime.tv_nsec = 0; 4381c59e4cc3SRick Macklem txdr_nfsv4time(&verstime, tl); 4382c59e4cc3SRick Macklem } 4383c59e4cc3SRick Macklem NFSEXITCODE2(0, nd); 4384c59e4cc3SRick Macklem return (0); 4385c59e4cc3SRick Macklem nfsmout: 4386c59e4cc3SRick Macklem if (clp != NULL) { 4387b97b91b5SConrad Meyer free(clp->lc_req.nr_nam, M_SONAME); 4388c59e4cc3SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 43891f54e596SRick Macklem free(clp->lc_stateid, M_NFSDCLIENT); 4390c59e4cc3SRick Macklem free(clp, M_NFSDCLIENT); 4391c59e4cc3SRick Macklem } 4392c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4393c59e4cc3SRick Macklem return (error); 4394c59e4cc3SRick Macklem } 4395c59e4cc3SRick Macklem 4396c59e4cc3SRick Macklem /* 4397c59e4cc3SRick Macklem * nfsv4 create session service 4398c59e4cc3SRick Macklem */ 4399b9cc3262SRyan Moeller int 4400c59e4cc3SRick Macklem nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram, 4401af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4402c59e4cc3SRick Macklem { 4403c59e4cc3SRick Macklem uint32_t *tl; 4404c59e4cc3SRick Macklem int error = 0; 4405c59e4cc3SRick Macklem nfsquad_t clientid, confirm; 4406c59e4cc3SRick Macklem struct nfsdsession *sep = NULL; 4407c59e4cc3SRick Macklem uint32_t rdmacnt; 4408af444b18SEdward Tomasz Napierala struct thread *p = curthread; 4409c59e4cc3SRick Macklem 4410984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4411c59e4cc3SRick Macklem goto nfsmout; 4412c59e4cc3SRick Macklem sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession), 4413c59e4cc3SRick Macklem M_NFSDSESSION, M_WAITOK | M_ZERO); 4414c59e4cc3SRick Macklem sep->sess_refcnt = 1; 4415c59e4cc3SRick Macklem mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF); 4416c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 4417c59e4cc3SRick Macklem clientid.lval[0] = *tl++; 4418c59e4cc3SRick Macklem clientid.lval[1] = *tl++; 4419c59e4cc3SRick Macklem confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++); 4420c59e4cc3SRick Macklem sep->sess_crflags = fxdr_unsigned(uint32_t, *tl); 4421c59e4cc3SRick Macklem /* Persistent sessions and RDMA are not supported. */ 4422c59e4cc3SRick Macklem sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN; 4423c59e4cc3SRick Macklem 4424c59e4cc3SRick Macklem /* Fore channel attributes. */ 4425c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4426c59e4cc3SRick Macklem tl++; /* Header pad always 0. */ 4427c59e4cc3SRick Macklem sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++); 442890d2dfabSRick Macklem if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) { 442990d2dfabSRick Macklem sep->sess_maxreq = sb_max_adj - NFS_MAXXDR; 443090d2dfabSRick Macklem printf("Consider increasing kern.ipc.maxsockbuf\n"); 443190d2dfabSRick Macklem } 4432c59e4cc3SRick Macklem sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++); 443390d2dfabSRick Macklem if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) { 443490d2dfabSRick Macklem sep->sess_maxresp = sb_max_adj - NFS_MAXXDR; 443590d2dfabSRick Macklem printf("Consider increasing kern.ipc.maxsockbuf\n"); 443690d2dfabSRick Macklem } 4437c59e4cc3SRick Macklem sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++); 4438c59e4cc3SRick Macklem sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++); 4439c59e4cc3SRick Macklem sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++); 4440c59e4cc3SRick Macklem if (sep->sess_maxslots > NFSV4_SLOTS) 4441c59e4cc3SRick Macklem sep->sess_maxslots = NFSV4_SLOTS; 4442c59e4cc3SRick Macklem rdmacnt = fxdr_unsigned(uint32_t, *tl); 4443c59e4cc3SRick Macklem if (rdmacnt > 1) { 4444c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 4445c59e4cc3SRick Macklem goto nfsmout; 4446c59e4cc3SRick Macklem } else if (rdmacnt == 1) 4447c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4448c59e4cc3SRick Macklem 4449c59e4cc3SRick Macklem /* Back channel attributes. */ 4450c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4451c59e4cc3SRick Macklem tl++; /* Header pad always 0. */ 4452c59e4cc3SRick Macklem sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++); 4453c59e4cc3SRick Macklem sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++); 4454c59e4cc3SRick Macklem sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++); 4455c59e4cc3SRick Macklem sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++); 4456c59e4cc3SRick Macklem sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++); 4457c59e4cc3SRick Macklem rdmacnt = fxdr_unsigned(uint32_t, *tl); 4458c59e4cc3SRick Macklem if (rdmacnt > 1) { 4459c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 4460c59e4cc3SRick Macklem goto nfsmout; 4461c59e4cc3SRick Macklem } else if (rdmacnt == 1) 4462c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4463c59e4cc3SRick Macklem 4464c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4465c59e4cc3SRick Macklem sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl); 4466c59e4cc3SRick Macklem 4467c59e4cc3SRick Macklem /* 4468c59e4cc3SRick Macklem * nfsrv_getclient() searches the client list for a match and 4469c59e4cc3SRick Macklem * returns the appropriate NFSERR status. 4470c59e4cc3SRick Macklem */ 4471c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW, 4472c59e4cc3SRick Macklem NULL, sep, confirm, sep->sess_cbprogram, nd, p); 4473c59e4cc3SRick Macklem if (nd->nd_repstat == 0) { 4474c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4475c59e4cc3SRick Macklem NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID); 4476c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED); 4477c59e4cc3SRick Macklem *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */ 4478c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_crflags); 4479c59e4cc3SRick Macklem 4480c59e4cc3SRick Macklem /* Fore channel attributes. */ 4481c59e4cc3SRick Macklem *tl++ = 0; 4482c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxreq); 4483c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxresp); 4484c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxrespcached); 4485c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxops); 4486c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxslots); 4487c59e4cc3SRick Macklem *tl++ = txdr_unsigned(1); 4488c59e4cc3SRick Macklem *tl++ = txdr_unsigned(0); /* No RDMA. */ 4489c59e4cc3SRick Macklem 4490c59e4cc3SRick Macklem /* Back channel attributes. */ 4491c59e4cc3SRick Macklem *tl++ = 0; 4492c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbmaxreq); 4493c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbmaxresp); 4494c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached); 4495c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbmaxops); 4496c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots); 4497c59e4cc3SRick Macklem *tl++ = txdr_unsigned(1); 4498c59e4cc3SRick Macklem *tl = txdr_unsigned(0); /* No RDMA. */ 4499c59e4cc3SRick Macklem } 4500c59e4cc3SRick Macklem nfsmout: 4501c59e4cc3SRick Macklem if (nd->nd_repstat != 0 && sep != NULL) 4502c59e4cc3SRick Macklem free(sep, M_NFSDSESSION); 4503c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4504c59e4cc3SRick Macklem return (error); 4505c59e4cc3SRick Macklem } 4506c59e4cc3SRick Macklem 4507c59e4cc3SRick Macklem /* 4508c59e4cc3SRick Macklem * nfsv4 sequence service 4509c59e4cc3SRick Macklem */ 4510b9cc3262SRyan Moeller int 4511c59e4cc3SRick Macklem nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram, 4512af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4513c59e4cc3SRick Macklem { 4514c59e4cc3SRick Macklem uint32_t *tl; 4515c59e4cc3SRick Macklem uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid; 4516c59e4cc3SRick Macklem int cache_this, error = 0; 4517af444b18SEdward Tomasz Napierala struct thread *p = curthread; 4518c59e4cc3SRick Macklem 4519984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4520c59e4cc3SRick Macklem goto nfsmout; 4521c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID); 4522c59e4cc3SRick Macklem NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID); 4523c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 4524c59e4cc3SRick Macklem sequenceid = fxdr_unsigned(uint32_t, *tl++); 4525c59e4cc3SRick Macklem nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++); 4526c59e4cc3SRick Macklem highest_slotid = fxdr_unsigned(uint32_t, *tl++); 4527c59e4cc3SRick Macklem if (*tl == newnfs_true) 4528c59e4cc3SRick Macklem cache_this = 1; 4529c59e4cc3SRick Macklem else 4530c59e4cc3SRick Macklem cache_this = 0; 4531c59e4cc3SRick Macklem nd->nd_flag |= ND_HASSEQUENCE; 4532c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid, 4533c59e4cc3SRick Macklem &target_highest_slotid, cache_this, &sflags, p); 4534c59e4cc3SRick Macklem if (nd->nd_repstat == 0) { 4535c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4536c59e4cc3SRick Macklem NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID); 4537c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 4538c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sequenceid); 4539c59e4cc3SRick Macklem *tl++ = txdr_unsigned(nd->nd_slotid); 4540c59e4cc3SRick Macklem *tl++ = txdr_unsigned(highest_slotid); 4541c59e4cc3SRick Macklem *tl++ = txdr_unsigned(target_highest_slotid); 4542c59e4cc3SRick Macklem *tl = txdr_unsigned(sflags); 4543c59e4cc3SRick Macklem } 4544c59e4cc3SRick Macklem nfsmout: 4545c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4546c59e4cc3SRick Macklem return (error); 4547c59e4cc3SRick Macklem } 4548c59e4cc3SRick Macklem 4549c59e4cc3SRick Macklem /* 4550c59e4cc3SRick Macklem * nfsv4 reclaim complete service 4551c59e4cc3SRick Macklem */ 4552b9cc3262SRyan Moeller int 4553c59e4cc3SRick Macklem nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram, 4554af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4555c59e4cc3SRick Macklem { 4556c59e4cc3SRick Macklem uint32_t *tl; 4557a3e709cdSRick Macklem int error = 0, onefs; 4558c59e4cc3SRick Macklem 4559c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4560a3e709cdSRick Macklem /* 4561a3e709cdSRick Macklem * I believe that a ReclaimComplete with rca_one_fs == TRUE is only 4562a3e709cdSRick Macklem * to be used after a file system has been transferred to a different 4563a3e709cdSRick Macklem * file server. However, RFC5661 is somewhat vague w.r.t. this and 4564a3e709cdSRick Macklem * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs 4565a3e709cdSRick Macklem * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE. 4566a3e709cdSRick Macklem * Therefore, just ignore the rca_one_fs == TRUE operation and return 4567a3e709cdSRick Macklem * NFS_OK without doing anything. 4568a3e709cdSRick Macklem */ 4569a3e709cdSRick Macklem onefs = 0; 4570c59e4cc3SRick Macklem if (*tl == newnfs_true) 4571a3e709cdSRick Macklem onefs = 1; 4572a3e709cdSRick Macklem nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs); 4573c59e4cc3SRick Macklem nfsmout: 4574c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4575c59e4cc3SRick Macklem return (error); 4576c59e4cc3SRick Macklem } 4577c59e4cc3SRick Macklem 4578c59e4cc3SRick Macklem /* 4579c59e4cc3SRick Macklem * nfsv4 destroy clientid service 4580c59e4cc3SRick Macklem */ 4581b9cc3262SRyan Moeller int 4582c59e4cc3SRick Macklem nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram, 4583af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4584c59e4cc3SRick Macklem { 4585c59e4cc3SRick Macklem uint32_t *tl; 4586c59e4cc3SRick Macklem nfsquad_t clientid; 4587c59e4cc3SRick Macklem int error = 0; 4588af444b18SEdward Tomasz Napierala struct thread *p = curthread; 4589c59e4cc3SRick Macklem 4590984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4591c59e4cc3SRick Macklem goto nfsmout; 4592c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4593c59e4cc3SRick Macklem clientid.lval[0] = *tl++; 4594c59e4cc3SRick Macklem clientid.lval[1] = *tl; 4595c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_destroyclient(clientid, p); 4596c59e4cc3SRick Macklem nfsmout: 4597c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4598c59e4cc3SRick Macklem return (error); 4599c59e4cc3SRick Macklem } 4600c59e4cc3SRick Macklem 4601c59e4cc3SRick Macklem /* 46029442a64eSRick Macklem * nfsv4 bind connection to session service 46039442a64eSRick Macklem */ 4604b9cc3262SRyan Moeller int 46059442a64eSRick Macklem nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram, 4606af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 46079442a64eSRick Macklem { 46089442a64eSRick Macklem uint32_t *tl; 46099442a64eSRick Macklem uint8_t sessid[NFSX_V4SESSIONID]; 46109442a64eSRick Macklem int error = 0, foreaft; 46119442a64eSRick Macklem 4612984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 46139442a64eSRick Macklem goto nfsmout; 46149442a64eSRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED); 46159442a64eSRick Macklem NFSBCOPY(tl, sessid, NFSX_V4SESSIONID); 46169442a64eSRick Macklem tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); 46179442a64eSRick Macklem foreaft = fxdr_unsigned(int, *tl++); 46189442a64eSRick Macklem if (*tl == newnfs_true) { 46199442a64eSRick Macklem /* RDMA is not supported. */ 46209442a64eSRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 46219442a64eSRick Macklem goto nfsmout; 46229442a64eSRick Macklem } 46239442a64eSRick Macklem 46249442a64eSRick Macklem nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft); 46259442a64eSRick Macklem if (nd->nd_repstat == 0) { 46269442a64eSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 * 46279442a64eSRick Macklem NFSX_UNSIGNED); 46289442a64eSRick Macklem NFSBCOPY(sessid, tl, NFSX_V4SESSIONID); 46299442a64eSRick Macklem tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); 46309442a64eSRick Macklem *tl++ = txdr_unsigned(foreaft); 46319442a64eSRick Macklem *tl = newnfs_false; 46329442a64eSRick Macklem } 46339442a64eSRick Macklem nfsmout: 46349442a64eSRick Macklem NFSEXITCODE2(error, nd); 46359442a64eSRick Macklem return (error); 46369442a64eSRick Macklem } 46379442a64eSRick Macklem 46389442a64eSRick Macklem /* 4639c59e4cc3SRick Macklem * nfsv4 destroy session service 4640c59e4cc3SRick Macklem */ 4641b9cc3262SRyan Moeller int 4642c59e4cc3SRick Macklem nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram, 4643af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4644c59e4cc3SRick Macklem { 4645c59e4cc3SRick Macklem uint8_t *cp, sessid[NFSX_V4SESSIONID]; 4646c59e4cc3SRick Macklem int error = 0; 4647c59e4cc3SRick Macklem 4648984c71f9SRick Macklem if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4649c59e4cc3SRick Macklem goto nfsmout; 4650c59e4cc3SRick Macklem NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID); 4651c59e4cc3SRick Macklem NFSBCOPY(cp, sessid, NFSX_V4SESSIONID); 4652c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_destroysession(nd, sessid); 4653c59e4cc3SRick Macklem nfsmout: 4654c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4655c59e4cc3SRick Macklem return (error); 4656c59e4cc3SRick Macklem } 4657c59e4cc3SRick Macklem 4658c59e4cc3SRick Macklem /* 4659c59e4cc3SRick Macklem * nfsv4 free stateid service 4660c59e4cc3SRick Macklem */ 4661b9cc3262SRyan Moeller int 4662c59e4cc3SRick Macklem nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram, 4663af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4664c59e4cc3SRick Macklem { 4665c59e4cc3SRick Macklem uint32_t *tl; 4666c59e4cc3SRick Macklem nfsv4stateid_t stateid; 4667c59e4cc3SRick Macklem int error = 0; 4668af444b18SEdward Tomasz Napierala struct thread *p = curthread; 4669c59e4cc3SRick Macklem 4670c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 4671c59e4cc3SRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4672c59e4cc3SRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 467390d2dfabSRick Macklem 467490d2dfabSRick Macklem /* 467590d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 467690d2dfabSRick Macklem * stateid to the current stateid, if it is set. 467790d2dfabSRick Macklem */ 467890d2dfabSRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 467990d2dfabSRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 468090d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 468190d2dfabSRick Macklem stateid = nd->nd_curstateid; 468290d2dfabSRick Macklem stateid.seqid = 0; 468390d2dfabSRick Macklem } else { 468490d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 468590d2dfabSRick Macklem goto nfsmout; 468690d2dfabSRick Macklem } 468790d2dfabSRick Macklem } 468890d2dfabSRick Macklem 4689c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p); 469090d2dfabSRick Macklem 469190d2dfabSRick Macklem /* If the current stateid has been free'd, unset it. */ 469290d2dfabSRick Macklem if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 && 469390d2dfabSRick Macklem stateid.other[0] == nd->nd_curstateid.other[0] && 469490d2dfabSRick Macklem stateid.other[1] == nd->nd_curstateid.other[1] && 469590d2dfabSRick Macklem stateid.other[2] == nd->nd_curstateid.other[2]) 469690d2dfabSRick Macklem nd->nd_flag &= ~ND_CURSTATEID; 469790d2dfabSRick Macklem nfsmout: 469890d2dfabSRick Macklem NFSEXITCODE2(error, nd); 469990d2dfabSRick Macklem return (error); 470090d2dfabSRick Macklem } 470190d2dfabSRick Macklem 470290d2dfabSRick Macklem /* 470390d2dfabSRick Macklem * nfsv4 layoutget service 470490d2dfabSRick Macklem */ 4705b9cc3262SRyan Moeller int 470690d2dfabSRick Macklem nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram, 4707af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 470890d2dfabSRick Macklem { 470990d2dfabSRick Macklem uint32_t *tl; 471090d2dfabSRick Macklem nfsv4stateid_t stateid; 471190d2dfabSRick Macklem int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose; 471290d2dfabSRick Macklem uint64_t offset, len, minlen; 471390d2dfabSRick Macklem char *layp; 4714af444b18SEdward Tomasz Napierala struct thread *p = curthread; 471590d2dfabSRick Macklem 471690d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 471790d2dfabSRick Macklem NFSX_STATEID); 471890d2dfabSRick Macklem tl++; /* Signal layout available. Ignore for now. */ 471990d2dfabSRick Macklem layouttype = fxdr_unsigned(int, *tl++); 472090d2dfabSRick Macklem iomode = fxdr_unsigned(int, *tl++); 472190d2dfabSRick Macklem offset = fxdr_hyper(tl); tl += 2; 472290d2dfabSRick Macklem len = fxdr_hyper(tl); tl += 2; 472390d2dfabSRick Macklem minlen = fxdr_hyper(tl); tl += 2; 472490d2dfabSRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 472590d2dfabSRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 472690d2dfabSRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 472790d2dfabSRick Macklem maxcnt = fxdr_unsigned(int, *tl); 472890d2dfabSRick Macklem NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n", 472990d2dfabSRick Macklem layouttype, iomode, (uintmax_t)offset, (uintmax_t)len, 473090d2dfabSRick Macklem (uintmax_t)minlen); 473190d2dfabSRick Macklem if (len < minlen || 473290d2dfabSRick Macklem (minlen != UINT64_MAX && offset + minlen < offset) || 473390d2dfabSRick Macklem (len != UINT64_MAX && offset + len < offset)) { 473490d2dfabSRick Macklem nd->nd_repstat = NFSERR_INVAL; 473590d2dfabSRick Macklem goto nfsmout; 473690d2dfabSRick Macklem } 473790d2dfabSRick Macklem 473890d2dfabSRick Macklem /* 473990d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 474090d2dfabSRick Macklem * stateid to the current stateid, if it is set. 474190d2dfabSRick Macklem */ 474290d2dfabSRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 474390d2dfabSRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 474490d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 474590d2dfabSRick Macklem stateid = nd->nd_curstateid; 474690d2dfabSRick Macklem stateid.seqid = 0; 474790d2dfabSRick Macklem } else { 474890d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 474990d2dfabSRick Macklem goto nfsmout; 475090d2dfabSRick Macklem } 475190d2dfabSRick Macklem } 475290d2dfabSRick Macklem 475390d2dfabSRick Macklem layp = NULL; 475490d2dfabSRick Macklem if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1) 475590d2dfabSRick Macklem layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK); 475690d2dfabSRick Macklem else if (layouttype == NFSLAYOUT_FLEXFILE) 475790d2dfabSRick Macklem layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP, 475890d2dfabSRick Macklem M_WAITOK); 475990d2dfabSRick Macklem else 476090d2dfabSRick Macklem nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE; 476190d2dfabSRick Macklem if (layp != NULL) 476290d2dfabSRick Macklem nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype, 476390d2dfabSRick Macklem &iomode, &offset, &len, minlen, &stateid, maxcnt, 476490d2dfabSRick Macklem &retonclose, &layoutlen, layp, nd->nd_cred, p); 476590d2dfabSRick Macklem NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat, 476690d2dfabSRick Macklem layoutlen); 476790d2dfabSRick Macklem if (nd->nd_repstat == 0) { 476890d2dfabSRick Macklem /* For NFSv4.1, set the Current StateID. */ 476990d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 477090d2dfabSRick Macklem nd->nd_curstateid = stateid; 477190d2dfabSRick Macklem nd->nd_flag |= ND_CURSTATEID; 477290d2dfabSRick Macklem } 477390d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID + 477490d2dfabSRick Macklem 2 * NFSX_HYPER); 477590d2dfabSRick Macklem *tl++ = txdr_unsigned(retonclose); 477690d2dfabSRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 477790d2dfabSRick Macklem NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER); 477890d2dfabSRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 477990d2dfabSRick Macklem *tl++ = txdr_unsigned(1); /* Only returns one layout. */ 478090d2dfabSRick Macklem txdr_hyper(offset, tl); tl += 2; 478190d2dfabSRick Macklem txdr_hyper(len, tl); tl += 2; 478290d2dfabSRick Macklem *tl++ = txdr_unsigned(iomode); 478390d2dfabSRick Macklem *tl = txdr_unsigned(layouttype); 478490d2dfabSRick Macklem nfsm_strtom(nd, layp, layoutlen); 478590d2dfabSRick Macklem } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) { 478690d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 478790d2dfabSRick Macklem *tl = newnfs_false; 478890d2dfabSRick Macklem } 478990d2dfabSRick Macklem free(layp, M_TEMP); 479090d2dfabSRick Macklem nfsmout: 479190d2dfabSRick Macklem vput(vp); 479290d2dfabSRick Macklem NFSEXITCODE2(error, nd); 479390d2dfabSRick Macklem return (error); 479490d2dfabSRick Macklem } 479590d2dfabSRick Macklem 479690d2dfabSRick Macklem /* 479790d2dfabSRick Macklem * nfsv4 layoutcommit service 479890d2dfabSRick Macklem */ 4799b9cc3262SRyan Moeller int 480090d2dfabSRick Macklem nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram, 4801af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 480290d2dfabSRick Macklem { 480390d2dfabSRick Macklem uint32_t *tl; 480490d2dfabSRick Macklem nfsv4stateid_t stateid; 480590d2dfabSRick Macklem int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim; 480690d2dfabSRick Macklem int hasnewsize; 4807f808cf72SRick Macklem uint64_t offset, len, newoff = 0, newsize; 480890d2dfabSRick Macklem struct timespec newmtime; 480990d2dfabSRick Macklem char *layp; 4810af444b18SEdward Tomasz Napierala struct thread *p = curthread; 481190d2dfabSRick Macklem 481290d2dfabSRick Macklem layp = NULL; 481390d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER + 481490d2dfabSRick Macklem NFSX_STATEID); 481590d2dfabSRick Macklem offset = fxdr_hyper(tl); tl += 2; 481690d2dfabSRick Macklem len = fxdr_hyper(tl); tl += 2; 481790d2dfabSRick Macklem reclaim = fxdr_unsigned(int, *tl++); 481890d2dfabSRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 481990d2dfabSRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 482090d2dfabSRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 482190d2dfabSRick Macklem /* 482290d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 482390d2dfabSRick Macklem * stateid to the current stateid, if it is set. 482490d2dfabSRick Macklem */ 482590d2dfabSRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 482690d2dfabSRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 482790d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 482890d2dfabSRick Macklem stateid = nd->nd_curstateid; 482990d2dfabSRick Macklem stateid.seqid = 0; 483090d2dfabSRick Macklem } else { 483190d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 483290d2dfabSRick Macklem goto nfsmout; 483390d2dfabSRick Macklem } 483490d2dfabSRick Macklem } 483590d2dfabSRick Macklem 483690d2dfabSRick Macklem hasnewoff = fxdr_unsigned(int, *tl); 483790d2dfabSRick Macklem if (hasnewoff != 0) { 483890d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 483990d2dfabSRick Macklem newoff = fxdr_hyper(tl); tl += 2; 484090d2dfabSRick Macklem } else 484190d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 484290d2dfabSRick Macklem hasnewmtime = fxdr_unsigned(int, *tl); 484390d2dfabSRick Macklem if (hasnewmtime != 0) { 484490d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED); 484590d2dfabSRick Macklem fxdr_nfsv4time(tl, &newmtime); 484690d2dfabSRick Macklem tl += (NFSX_V4TIME / NFSX_UNSIGNED); 484790d2dfabSRick Macklem } else 484890d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 484990d2dfabSRick Macklem layouttype = fxdr_unsigned(int, *tl++); 485090d2dfabSRick Macklem maxcnt = fxdr_unsigned(int, *tl); 485190d2dfabSRick Macklem if (maxcnt > 0) { 485290d2dfabSRick Macklem layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK); 485390d2dfabSRick Macklem error = nfsrv_mtostr(nd, layp, maxcnt); 485490d2dfabSRick Macklem if (error != 0) 485590d2dfabSRick Macklem goto nfsmout; 485690d2dfabSRick Macklem } 485790d2dfabSRick Macklem nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff, 485890d2dfabSRick Macklem newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid, 485990d2dfabSRick Macklem maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p); 486090d2dfabSRick Macklem NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat); 486190d2dfabSRick Macklem if (nd->nd_repstat == 0) { 486290d2dfabSRick Macklem if (hasnewsize != 0) { 486390d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); 486490d2dfabSRick Macklem *tl++ = newnfs_true; 486590d2dfabSRick Macklem txdr_hyper(newsize, tl); 486690d2dfabSRick Macklem } else { 486790d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 486890d2dfabSRick Macklem *tl = newnfs_false; 486990d2dfabSRick Macklem } 487090d2dfabSRick Macklem } 487190d2dfabSRick Macklem nfsmout: 487290d2dfabSRick Macklem free(layp, M_TEMP); 487390d2dfabSRick Macklem vput(vp); 487490d2dfabSRick Macklem NFSEXITCODE2(error, nd); 487590d2dfabSRick Macklem return (error); 487690d2dfabSRick Macklem } 487790d2dfabSRick Macklem 487890d2dfabSRick Macklem /* 487990d2dfabSRick Macklem * nfsv4 layoutreturn service 488090d2dfabSRick Macklem */ 4881b9cc3262SRyan Moeller int 488290d2dfabSRick Macklem nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram, 4883af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 488490d2dfabSRick Macklem { 488590d2dfabSRick Macklem uint32_t *tl, *layp; 488690d2dfabSRick Macklem nfsv4stateid_t stateid; 488790d2dfabSRick Macklem int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim; 488890d2dfabSRick Macklem uint64_t offset, len; 4889af444b18SEdward Tomasz Napierala struct thread *p = curthread; 489090d2dfabSRick Macklem 489190d2dfabSRick Macklem layp = NULL; 489290d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 489390d2dfabSRick Macklem reclaim = *tl++; 489490d2dfabSRick Macklem layouttype = fxdr_unsigned(int, *tl++); 489590d2dfabSRick Macklem iomode = fxdr_unsigned(int, *tl++); 489690d2dfabSRick Macklem kind = fxdr_unsigned(int, *tl); 489790d2dfabSRick Macklem NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim, 489890d2dfabSRick Macklem layouttype, iomode, kind); 489990d2dfabSRick Macklem if (kind == NFSV4LAYOUTRET_FILE) { 490090d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 490190d2dfabSRick Macklem NFSX_UNSIGNED); 490290d2dfabSRick Macklem offset = fxdr_hyper(tl); tl += 2; 490390d2dfabSRick Macklem len = fxdr_hyper(tl); tl += 2; 490490d2dfabSRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 490590d2dfabSRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 490690d2dfabSRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 490790d2dfabSRick Macklem 490890d2dfabSRick Macklem /* 490990d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set 491090d2dfabSRick Macklem * the stateid to the current stateid, if it is set. 491190d2dfabSRick Macklem */ 491290d2dfabSRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 491390d2dfabSRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 491490d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 491590d2dfabSRick Macklem stateid = nd->nd_curstateid; 491690d2dfabSRick Macklem stateid.seqid = 0; 491790d2dfabSRick Macklem } else { 491890d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 491990d2dfabSRick Macklem goto nfsmout; 492090d2dfabSRick Macklem } 492190d2dfabSRick Macklem } 492290d2dfabSRick Macklem 492390d2dfabSRick Macklem maxcnt = fxdr_unsigned(int, *tl); 492490d2dfabSRick Macklem if (maxcnt > 0) { 492590d2dfabSRick Macklem layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK); 492690d2dfabSRick Macklem error = nfsrv_mtostr(nd, (char *)layp, maxcnt); 492790d2dfabSRick Macklem if (error != 0) 492890d2dfabSRick Macklem goto nfsmout; 492990d2dfabSRick Macklem } 493090d2dfabSRick Macklem } else { 493190d2dfabSRick Macklem if (reclaim == newnfs_true) { 493290d2dfabSRick Macklem nd->nd_repstat = NFSERR_INVAL; 493390d2dfabSRick Macklem goto nfsmout; 493490d2dfabSRick Macklem } 493590d2dfabSRick Macklem offset = len = 0; 493690d2dfabSRick Macklem maxcnt = 0; 493790d2dfabSRick Macklem } 493890d2dfabSRick Macklem nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode, 493990d2dfabSRick Macklem offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd, 494090d2dfabSRick Macklem nd->nd_cred, p); 494190d2dfabSRick Macklem NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat, 494290d2dfabSRick Macklem fnd); 494390d2dfabSRick Macklem if (nd->nd_repstat == 0) { 494490d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 494590d2dfabSRick Macklem if (fnd != 0) { 494690d2dfabSRick Macklem *tl = newnfs_true; 494790d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_STATEID); 494890d2dfabSRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 494990d2dfabSRick Macklem NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER); 495090d2dfabSRick Macklem } else 495190d2dfabSRick Macklem *tl = newnfs_false; 495290d2dfabSRick Macklem } 495390d2dfabSRick Macklem nfsmout: 495490d2dfabSRick Macklem free(layp, M_TEMP); 495590d2dfabSRick Macklem vput(vp); 495690d2dfabSRick Macklem NFSEXITCODE2(error, nd); 495790d2dfabSRick Macklem return (error); 495890d2dfabSRick Macklem } 495990d2dfabSRick Macklem 496090d2dfabSRick Macklem /* 4961c057a378SRick Macklem * nfsv4 layout error service 4962c057a378SRick Macklem */ 4963b9cc3262SRyan Moeller int 4964c057a378SRick Macklem nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram, 4965c057a378SRick Macklem vnode_t vp, struct nfsexstuff *exp) 4966c057a378SRick Macklem { 4967c057a378SRick Macklem uint32_t *tl; 4968c057a378SRick Macklem nfsv4stateid_t stateid; 4969c057a378SRick Macklem int cnt, error = 0, i, stat; 4970c057a378SRick Macklem int opnum __unused; 4971c057a378SRick Macklem char devid[NFSX_V4DEVICEID]; 4972c057a378SRick Macklem uint64_t offset, len; 4973c057a378SRick Macklem 4974c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 4975c057a378SRick Macklem NFSX_UNSIGNED); 4976c057a378SRick Macklem offset = fxdr_hyper(tl); tl += 2; 4977c057a378SRick Macklem len = fxdr_hyper(tl); tl += 2; 4978c057a378SRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4979c057a378SRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4980c057a378SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4981c057a378SRick Macklem cnt = fxdr_unsigned(int, *tl); 4982c057a378SRick Macklem NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset, 4983c057a378SRick Macklem (uintmax_t)len, cnt); 4984c057a378SRick Macklem /* 4985c057a378SRick Macklem * For the special stateid of other all 0s and seqid == 1, set 4986c057a378SRick Macklem * the stateid to the current stateid, if it is set. 4987c057a378SRick Macklem */ 4988c057a378SRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 4989c057a378SRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 4990c057a378SRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4991c057a378SRick Macklem stateid = nd->nd_curstateid; 4992c057a378SRick Macklem stateid.seqid = 0; 4993c057a378SRick Macklem } else { 4994c057a378SRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 4995c057a378SRick Macklem goto nfsmout; 4996c057a378SRick Macklem } 4997c057a378SRick Macklem } 4998c057a378SRick Macklem 4999c057a378SRick Macklem /* 5000c057a378SRick Macklem * Ignore offset, len and stateid for now. 5001c057a378SRick Macklem */ 5002c057a378SRick Macklem for (i = 0; i < cnt; i++) { 5003c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 * 5004c057a378SRick Macklem NFSX_UNSIGNED); 5005c057a378SRick Macklem NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 5006c057a378SRick Macklem tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5007c057a378SRick Macklem stat = fxdr_unsigned(int, *tl++); 5008c057a378SRick Macklem opnum = fxdr_unsigned(int, *tl); 5009c057a378SRick Macklem NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat); 5010c057a378SRick Macklem /* 5011c057a378SRick Macklem * Except for NFSERR_ACCES and NFSERR_STALE errors, 5012c057a378SRick Macklem * disable the mirror. 5013c057a378SRick Macklem */ 5014c057a378SRick Macklem if (stat != NFSERR_ACCES && stat != NFSERR_STALE) 5015c057a378SRick Macklem nfsrv_delds(devid, curthread); 5016c057a378SRick Macklem } 5017c057a378SRick Macklem nfsmout: 5018c057a378SRick Macklem vput(vp); 5019c057a378SRick Macklem NFSEXITCODE2(error, nd); 5020c057a378SRick Macklem return (error); 5021c057a378SRick Macklem } 5022c057a378SRick Macklem 5023c057a378SRick Macklem /* 5024c057a378SRick Macklem * nfsv4 layout stats service 5025c057a378SRick Macklem */ 5026b9cc3262SRyan Moeller int 5027c057a378SRick Macklem nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram, 5028c057a378SRick Macklem vnode_t vp, struct nfsexstuff *exp) 5029c057a378SRick Macklem { 5030c057a378SRick Macklem uint32_t *tl; 5031c057a378SRick Macklem nfsv4stateid_t stateid; 5032c057a378SRick Macklem int cnt, error = 0; 5033c057a378SRick Macklem int layouttype __unused; 5034c057a378SRick Macklem char devid[NFSX_V4DEVICEID] __unused; 5035c057a378SRick Macklem uint64_t offset, len, readcount, readbytes, writecount, writebytes 5036c057a378SRick Macklem __unused; 5037c057a378SRick Macklem 5038c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID + 5039c057a378SRick Macklem NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED); 5040c057a378SRick Macklem offset = fxdr_hyper(tl); tl += 2; 5041c057a378SRick Macklem len = fxdr_hyper(tl); tl += 2; 5042c057a378SRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5043c057a378SRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 5044c057a378SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 5045c057a378SRick Macklem readcount = fxdr_hyper(tl); tl += 2; 5046c057a378SRick Macklem readbytes = fxdr_hyper(tl); tl += 2; 5047c057a378SRick Macklem writecount = fxdr_hyper(tl); tl += 2; 5048c057a378SRick Macklem writebytes = fxdr_hyper(tl); tl += 2; 5049c057a378SRick Macklem NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 5050c057a378SRick Macklem tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5051c057a378SRick Macklem layouttype = fxdr_unsigned(int, *tl++); 5052c057a378SRick Macklem cnt = fxdr_unsigned(int, *tl); 5053c057a378SRick Macklem error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1); 5054c057a378SRick Macklem if (error != 0) 5055c057a378SRick Macklem goto nfsmout; 5056c057a378SRick Macklem NFSD_DEBUG(4, "layoutstats cnt=%d\n", cnt); 5057c057a378SRick Macklem /* 5058c057a378SRick Macklem * For the special stateid of other all 0s and seqid == 1, set 5059c057a378SRick Macklem * the stateid to the current stateid, if it is set. 5060c057a378SRick Macklem */ 5061c057a378SRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 5062c057a378SRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 5063c057a378SRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 5064c057a378SRick Macklem stateid = nd->nd_curstateid; 5065c057a378SRick Macklem stateid.seqid = 0; 5066c057a378SRick Macklem } else { 5067c057a378SRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 5068c057a378SRick Macklem goto nfsmout; 5069c057a378SRick Macklem } 5070c057a378SRick Macklem } 5071c057a378SRick Macklem 5072c057a378SRick Macklem /* 5073c057a378SRick Macklem * No use for the stats for now. 5074c057a378SRick Macklem */ 5075c057a378SRick Macklem nfsmout: 5076c057a378SRick Macklem vput(vp); 5077c057a378SRick Macklem NFSEXITCODE2(error, nd); 5078c057a378SRick Macklem return (error); 5079c057a378SRick Macklem } 5080c057a378SRick Macklem 5081c057a378SRick Macklem /* 5082c057a378SRick Macklem * nfsv4 io_advise service 5083c057a378SRick Macklem */ 5084b9cc3262SRyan Moeller int 5085c057a378SRick Macklem nfsrvd_ioadvise(struct nfsrv_descript *nd, __unused int isdgram, 5086c057a378SRick Macklem vnode_t vp, struct nfsexstuff *exp) 5087c057a378SRick Macklem { 5088c057a378SRick Macklem uint32_t *tl; 5089c057a378SRick Macklem nfsv4stateid_t stateid; 5090c057a378SRick Macklem nfsattrbit_t hints; 5091c057a378SRick Macklem int error = 0, ret; 5092c057a378SRick Macklem off_t offset, len; 5093c057a378SRick Macklem 5094c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); 5095c057a378SRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5096c057a378SRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 5097c057a378SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 5098c057a378SRick Macklem offset = fxdr_hyper(tl); tl += 2; 5099c057a378SRick Macklem len = fxdr_hyper(tl); 5100c057a378SRick Macklem error = nfsrv_getattrbits(nd, &hints, NULL, NULL); 5101c057a378SRick Macklem if (error != 0) 5102c057a378SRick Macklem goto nfsmout; 5103c057a378SRick Macklem /* 5104c057a378SRick Macklem * For the special stateid of other all 0s and seqid == 1, set 5105c057a378SRick Macklem * the stateid to the current stateid, if it is set. 5106c057a378SRick Macklem */ 5107c057a378SRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 5108c057a378SRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 5109c057a378SRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 5110c057a378SRick Macklem stateid = nd->nd_curstateid; 5111c057a378SRick Macklem stateid.seqid = 0; 5112c057a378SRick Macklem } else { 5113c057a378SRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 5114c057a378SRick Macklem goto nfsmout; 5115c057a378SRick Macklem } 5116c057a378SRick Macklem } 5117c057a378SRick Macklem 5118c057a378SRick Macklem if (offset < 0) { 5119c057a378SRick Macklem nd->nd_repstat = NFSERR_INVAL; 5120c057a378SRick Macklem goto nfsmout; 5121c057a378SRick Macklem } 5122c057a378SRick Macklem if (len < 0) 5123c057a378SRick Macklem len = 0; 5124c057a378SRick Macklem if (vp->v_type != VREG) { 5125c057a378SRick Macklem if (vp->v_type == VDIR) 5126c057a378SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 5127c057a378SRick Macklem else 5128c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGTYPE; 5129c057a378SRick Macklem goto nfsmout; 5130c057a378SRick Macklem } 5131c057a378SRick Macklem 5132c057a378SRick Macklem /* 5133c057a378SRick Macklem * For now, we can only handle WILLNEED and DONTNEED and don't use 5134c057a378SRick Macklem * the stateid. 5135c057a378SRick Macklem */ 5136c057a378SRick Macklem if ((NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED) && 5137c057a378SRick Macklem !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED)) || 5138c057a378SRick Macklem (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED) && 5139c057a378SRick Macklem !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED))) { 5140b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 5141c057a378SRick Macklem if (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED)) { 5142c057a378SRick Macklem ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_WILLNEED); 5143c057a378SRick Macklem NFSZERO_ATTRBIT(&hints); 5144c057a378SRick Macklem if (ret == 0) 5145c057a378SRick Macklem NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED); 5146c057a378SRick Macklem else 5147c057a378SRick Macklem NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 5148c057a378SRick Macklem } else { 5149c057a378SRick Macklem ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_DONTNEED); 5150c057a378SRick Macklem NFSZERO_ATTRBIT(&hints); 5151c057a378SRick Macklem if (ret == 0) 5152c057a378SRick Macklem NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED); 5153c057a378SRick Macklem else 5154c057a378SRick Macklem NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 5155c057a378SRick Macklem } 5156c057a378SRick Macklem vrele(vp); 5157c057a378SRick Macklem } else { 5158c057a378SRick Macklem NFSZERO_ATTRBIT(&hints); 5159c057a378SRick Macklem NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 5160c057a378SRick Macklem vput(vp); 5161c057a378SRick Macklem } 5162c057a378SRick Macklem nfsrv_putattrbit(nd, &hints); 5163c057a378SRick Macklem NFSEXITCODE2(error, nd); 5164c057a378SRick Macklem return (error); 5165c057a378SRick Macklem nfsmout: 5166c057a378SRick Macklem vput(vp); 5167c057a378SRick Macklem NFSEXITCODE2(error, nd); 5168c057a378SRick Macklem return (error); 5169c057a378SRick Macklem } 5170c057a378SRick Macklem 5171c057a378SRick Macklem /* 517290d2dfabSRick Macklem * nfsv4 getdeviceinfo service 517390d2dfabSRick Macklem */ 5174b9cc3262SRyan Moeller int 517590d2dfabSRick Macklem nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram, 5176af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 517790d2dfabSRick Macklem { 517890d2dfabSRick Macklem uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP]; 517990d2dfabSRick Macklem int cnt, devaddrlen, error = 0, i, layouttype; 518090d2dfabSRick Macklem char devid[NFSX_V4DEVICEID], *devaddr; 518190d2dfabSRick Macklem time_t dev_time; 518290d2dfabSRick Macklem 518390d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID); 518490d2dfabSRick Macklem NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 518590d2dfabSRick Macklem tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 518690d2dfabSRick Macklem layouttype = fxdr_unsigned(int, *tl++); 518790d2dfabSRick Macklem maxcnt = fxdr_unsigned(uint32_t, *tl++); 518890d2dfabSRick Macklem cnt = fxdr_unsigned(int, *tl); 518990d2dfabSRick Macklem NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype, 519090d2dfabSRick Macklem maxcnt, cnt); 519190d2dfabSRick Macklem if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) { 519290d2dfabSRick Macklem nd->nd_repstat = NFSERR_INVAL; 519390d2dfabSRick Macklem goto nfsmout; 519490d2dfabSRick Macklem } 519590d2dfabSRick Macklem if (cnt > 0) { 519690d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED); 519790d2dfabSRick Macklem for (i = 0; i < cnt; i++) 519890d2dfabSRick Macklem notify[i] = fxdr_unsigned(uint32_t, *tl++); 519990d2dfabSRick Macklem } 520090d2dfabSRick Macklem for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++) 520190d2dfabSRick Macklem notify[i] = 0; 520290d2dfabSRick Macklem 520390d2dfabSRick Macklem /* 520490d2dfabSRick Macklem * Check that the device id is not stale. Device ids are recreated 520590d2dfabSRick Macklem * each time the nfsd threads are restarted. 520690d2dfabSRick Macklem */ 520790d2dfabSRick Macklem NFSBCOPY(devid, &dev_time, sizeof(dev_time)); 520890d2dfabSRick Macklem if (dev_time != nfsdev_time) { 520990d2dfabSRick Macklem nd->nd_repstat = NFSERR_NOENT; 521090d2dfabSRick Macklem goto nfsmout; 521190d2dfabSRick Macklem } 521290d2dfabSRick Macklem 521390d2dfabSRick Macklem /* Look for the device id. */ 521490d2dfabSRick Macklem nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt, 521590d2dfabSRick Macklem notify, &devaddrlen, &devaddr); 521690d2dfabSRick Macklem NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat); 521790d2dfabSRick Macklem if (nd->nd_repstat == 0) { 521890d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 521990d2dfabSRick Macklem *tl = txdr_unsigned(layouttype); 522090d2dfabSRick Macklem nfsm_strtom(nd, devaddr, devaddrlen); 522190d2dfabSRick Macklem cnt = 0; 522290d2dfabSRick Macklem for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) { 522390d2dfabSRick Macklem if (notify[i] != 0) 522490d2dfabSRick Macklem cnt = i + 1; 522590d2dfabSRick Macklem } 522690d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED); 522790d2dfabSRick Macklem *tl++ = txdr_unsigned(cnt); 522890d2dfabSRick Macklem for (i = 0; i < cnt; i++) 522990d2dfabSRick Macklem *tl++ = txdr_unsigned(notify[i]); 523090d2dfabSRick Macklem } else if (nd->nd_repstat == NFSERR_TOOSMALL) { 523190d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 523290d2dfabSRick Macklem *tl = txdr_unsigned(maxcnt); 523390d2dfabSRick Macklem } 5234c59e4cc3SRick Macklem nfsmout: 5235c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 5236c59e4cc3SRick Macklem return (error); 5237c59e4cc3SRick Macklem } 5238c59e4cc3SRick Macklem 5239c59e4cc3SRick Macklem /* 52405d4835e4SRick Macklem * nfsv4 test stateid service 52415d4835e4SRick Macklem */ 5242b9cc3262SRyan Moeller int 52435d4835e4SRick Macklem nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram, 5244af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 52455d4835e4SRick Macklem { 52465d4835e4SRick Macklem uint32_t *tl; 52475d4835e4SRick Macklem nfsv4stateid_t *stateidp = NULL, *tstateidp; 52485d4835e4SRick Macklem int cnt, error = 0, i, ret; 5249af444b18SEdward Tomasz Napierala struct thread *p = curthread; 52505d4835e4SRick Macklem 52515d4835e4SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 52525d4835e4SRick Macklem cnt = fxdr_unsigned(int, *tl); 52535d4835e4SRick Macklem if (cnt <= 0 || cnt > 1024) { 52545d4835e4SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 52555d4835e4SRick Macklem goto nfsmout; 52565d4835e4SRick Macklem } 52575d4835e4SRick Macklem stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK); 52585d4835e4SRick Macklem tstateidp = stateidp; 52595d4835e4SRick Macklem for (i = 0; i < cnt; i++) { 52605d4835e4SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 52615d4835e4SRick Macklem tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 52625d4835e4SRick Macklem NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER); 52635d4835e4SRick Macklem tstateidp++; 52645d4835e4SRick Macklem } 52655d4835e4SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 52665d4835e4SRick Macklem *tl = txdr_unsigned(cnt); 52675d4835e4SRick Macklem tstateidp = stateidp; 52685d4835e4SRick Macklem for (i = 0; i < cnt; i++) { 52695d4835e4SRick Macklem ret = nfsrv_teststateid(nd, tstateidp, p); 52705d4835e4SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 52715d4835e4SRick Macklem *tl = txdr_unsigned(ret); 52725d4835e4SRick Macklem tstateidp++; 52735d4835e4SRick Macklem } 52745d4835e4SRick Macklem nfsmout: 52755d4835e4SRick Macklem free(stateidp, M_TEMP); 52765d4835e4SRick Macklem NFSEXITCODE2(error, nd); 52775d4835e4SRick Macklem return (error); 52785d4835e4SRick Macklem } 52795d4835e4SRick Macklem 52805d4835e4SRick Macklem /* 5281c057a378SRick Macklem * nfs allocate service 5282c057a378SRick Macklem */ 5283b9cc3262SRyan Moeller int 5284c057a378SRick Macklem nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram, 5285c057a378SRick Macklem vnode_t vp, struct nfsexstuff *exp) 5286c057a378SRick Macklem { 5287c057a378SRick Macklem uint32_t *tl; 5288c057a378SRick Macklem struct nfsvattr forat; 5289c057a378SRick Macklem int error = 0, forat_ret = 1, gotproxystateid; 5290c057a378SRick Macklem off_t off, len; 5291c057a378SRick Macklem struct nfsstate st, *stp = &st; 5292c057a378SRick Macklem struct nfslock lo, *lop = &lo; 5293c057a378SRick Macklem nfsv4stateid_t stateid; 5294c057a378SRick Macklem nfsquad_t clientid; 5295c057a378SRick Macklem nfsattrbit_t attrbits; 5296c057a378SRick Macklem 5297c057a378SRick Macklem gotproxystateid = 0; 5298c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); 5299c057a378SRick Macklem stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 5300c057a378SRick Macklem lop->lo_flags = NFSLCK_WRITE; 5301c057a378SRick Macklem stp->ls_ownerlen = 0; 5302c057a378SRick Macklem stp->ls_op = NULL; 5303c057a378SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 5304c057a378SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 5305c057a378SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 5306c057a378SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 5307c057a378SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 5308c057a378SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 5309c057a378SRick Macklem clientid.qval = nd->nd_clientid.qval; 5310c057a378SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 5311c057a378SRick Macklem printf("EEK2 multiple clids\n"); 5312c057a378SRick Macklem } else { 5313c057a378SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 5314c057a378SRick Macklem printf("EEK! no clientid from session\n"); 5315c057a378SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 5316c057a378SRick Macklem nd->nd_clientid.qval = clientid.qval; 5317c057a378SRick Macklem } 5318c057a378SRick Macklem stp->ls_stateid.other[2] = *tl++; 5319c057a378SRick Macklem /* 5320c057a378SRick Macklem * Don't allow this to be done for a DS. 5321c057a378SRick Macklem */ 5322c057a378SRick Macklem if ((nd->nd_flag & ND_DSSERVER) != 0) 5323c057a378SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 5324c057a378SRick Macklem /* However, allow the proxy stateid. */ 5325c057a378SRick Macklem if (stp->ls_stateid.seqid == 0xffffffff && 5326c057a378SRick Macklem stp->ls_stateid.other[0] == 0x55555555 && 5327c057a378SRick Macklem stp->ls_stateid.other[1] == 0x55555555 && 5328c057a378SRick Macklem stp->ls_stateid.other[2] == 0x55555555) 5329c057a378SRick Macklem gotproxystateid = 1; 5330c057a378SRick Macklem off = fxdr_hyper(tl); tl += 2; 5331c057a378SRick Macklem lop->lo_first = off; 5332c057a378SRick Macklem len = fxdr_hyper(tl); 5333c057a378SRick Macklem lop->lo_end = off + len; 5334c057a378SRick Macklem /* 5335c057a378SRick Macklem * Paranoia, just in case it wraps around, which shouldn't 5336c057a378SRick Macklem * ever happen anyhow. 5337c057a378SRick Macklem */ 5338c057a378SRick Macklem if (nd->nd_repstat == 0 && (lop->lo_end < lop->lo_first || len <= 0)) 5339c057a378SRick Macklem nd->nd_repstat = NFSERR_INVAL; 5340c057a378SRick Macklem 5341c057a378SRick Macklem if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG) 5342c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGTYPE; 5343c057a378SRick Macklem NFSZERO_ATTRBIT(&attrbits); 5344c057a378SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5345c057a378SRick Macklem forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits); 5346c057a378SRick Macklem if (nd->nd_repstat == 0) 5347c057a378SRick Macklem nd->nd_repstat = forat_ret; 5348c057a378SRick Macklem if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid || 5349c057a378SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) 5350c057a378SRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, 5351c057a378SRick Macklem curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5352c057a378SRick Macklem NULL); 5353c057a378SRick Macklem if (nd->nd_repstat == 0 && gotproxystateid == 0) 5354c057a378SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 5355c057a378SRick Macklem &stateid, exp, nd, curthread); 5356c057a378SRick Macklem 5357c057a378SRick Macklem if (nd->nd_repstat == 0) 5358c057a378SRick Macklem nd->nd_repstat = nfsvno_allocate(vp, off, len, nd->nd_cred, 5359c057a378SRick Macklem curthread); 5360c057a378SRick Macklem vput(vp); 5361c057a378SRick Macklem NFSEXITCODE2(0, nd); 5362c057a378SRick Macklem return (0); 5363c057a378SRick Macklem nfsmout: 5364c057a378SRick Macklem vput(vp); 5365c057a378SRick Macklem NFSEXITCODE2(error, nd); 5366c057a378SRick Macklem return (error); 5367c057a378SRick Macklem } 5368c057a378SRick Macklem 5369c057a378SRick Macklem /* 5370c057a378SRick Macklem * nfs copy service 5371c057a378SRick Macklem */ 5372b9cc3262SRyan Moeller int 5373c057a378SRick Macklem nfsrvd_copy_file_range(struct nfsrv_descript *nd, __unused int isdgram, 5374c057a378SRick Macklem vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp) 5375c057a378SRick Macklem { 5376c057a378SRick Macklem uint32_t *tl; 5377c057a378SRick Macklem struct nfsvattr at; 5378c057a378SRick Macklem int cnt, error = 0, ret; 5379c057a378SRick Macklem off_t inoff, outoff; 5380c057a378SRick Macklem uint64_t len; 5381c057a378SRick Macklem size_t xfer; 5382c057a378SRick Macklem struct nfsstate inst, outst, *instp = &inst, *outstp = &outst; 5383c057a378SRick Macklem struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo; 5384c057a378SRick Macklem nfsquad_t clientid; 5385c057a378SRick Macklem nfsv4stateid_t stateid; 5386c057a378SRick Macklem nfsattrbit_t attrbits; 5387c057a378SRick Macklem void *rl_rcookie, *rl_wcookie; 5388c057a378SRick Macklem 5389c057a378SRick Macklem rl_rcookie = rl_wcookie = NULL; 5390c057a378SRick Macklem if (nfsrv_devidcnt > 0) { 5391c057a378SRick Macklem /* 5392c057a378SRick Macklem * For a pNFS server, reply NFSERR_NOTSUPP so that the client 5393c057a378SRick Macklem * will do the copy via I/O on the DS(s). 5394c057a378SRick Macklem */ 5395c057a378SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 5396c057a378SRick Macklem goto nfsmout; 5397c057a378SRick Macklem } 5398c057a378SRick Macklem if (vp == tovp) { 5399c057a378SRick Macklem /* Copying a byte range within the same file is not allowed. */ 5400c057a378SRick Macklem nd->nd_repstat = NFSERR_INVAL; 5401c057a378SRick Macklem goto nfsmout; 5402c057a378SRick Macklem } 5403c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER + 5404c057a378SRick Macklem 3 * NFSX_UNSIGNED); 5405c057a378SRick Macklem instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS); 5406c057a378SRick Macklem inlop->lo_flags = NFSLCK_READ; 5407c057a378SRick Macklem instp->ls_ownerlen = 0; 5408c057a378SRick Macklem instp->ls_op = NULL; 5409c057a378SRick Macklem instp->ls_uid = nd->nd_cred->cr_uid; 5410c057a378SRick Macklem instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5411c057a378SRick Macklem clientid.lval[0] = instp->ls_stateid.other[0] = *tl++; 5412c057a378SRick Macklem clientid.lval[1] = instp->ls_stateid.other[1] = *tl++; 5413c057a378SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) 5414c057a378SRick Macklem clientid.qval = nd->nd_clientid.qval; 5415c057a378SRick Macklem instp->ls_stateid.other[2] = *tl++; 5416c057a378SRick Macklem outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 5417c057a378SRick Macklem outlop->lo_flags = NFSLCK_WRITE; 5418c057a378SRick Macklem outstp->ls_ownerlen = 0; 5419c057a378SRick Macklem outstp->ls_op = NULL; 5420c057a378SRick Macklem outstp->ls_uid = nd->nd_cred->cr_uid; 5421c057a378SRick Macklem outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5422c057a378SRick Macklem outstp->ls_stateid.other[0] = *tl++; 5423c057a378SRick Macklem outstp->ls_stateid.other[1] = *tl++; 5424c057a378SRick Macklem outstp->ls_stateid.other[2] = *tl++; 5425c057a378SRick Macklem inoff = fxdr_hyper(tl); tl += 2; 5426c057a378SRick Macklem inlop->lo_first = inoff; 5427c057a378SRick Macklem outoff = fxdr_hyper(tl); tl += 2; 5428c057a378SRick Macklem outlop->lo_first = outoff; 5429c057a378SRick Macklem len = fxdr_hyper(tl); tl += 2; 5430c057a378SRick Macklem if (len == 0) { 5431c057a378SRick Macklem /* len == 0 means to EOF. */ 5432c057a378SRick Macklem inlop->lo_end = OFF_MAX; 5433c057a378SRick Macklem outlop->lo_end = OFF_MAX; 5434c057a378SRick Macklem } else { 5435c057a378SRick Macklem inlop->lo_end = inlop->lo_first + len; 5436c057a378SRick Macklem outlop->lo_end = outlop->lo_first + len; 5437c057a378SRick Macklem } 5438c057a378SRick Macklem 5439c057a378SRick Macklem /* 5440c057a378SRick Macklem * At this time only consecutive, synchronous copy is supported, 5441c057a378SRick Macklem * so ca_consecutive and ca_synchronous can be ignored. 5442c057a378SRick Macklem */ 5443c057a378SRick Macklem tl += 2; 5444c057a378SRick Macklem 5445c057a378SRick Macklem cnt = fxdr_unsigned(int, *tl); 5446c057a378SRick Macklem if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0) 5447c057a378SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 5448c057a378SRick Macklem if (nd->nd_repstat == 0 && (inoff > OFF_MAX || outoff > OFF_MAX || 5449c057a378SRick Macklem inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX || 5450c057a378SRick Macklem inlop->lo_end < inlop->lo_first || outlop->lo_end < 5451c057a378SRick Macklem outlop->lo_first)) 5452c057a378SRick Macklem nd->nd_repstat = NFSERR_INVAL; 5453c057a378SRick Macklem 5454c057a378SRick Macklem if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG) 5455c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGTYPE; 5456c057a378SRick Macklem 5457c057a378SRick Macklem /* Check permissions for the input file. */ 5458c057a378SRick Macklem NFSZERO_ATTRBIT(&attrbits); 5459c057a378SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5460c057a378SRick Macklem ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits); 5461c057a378SRick Macklem if (nd->nd_repstat == 0) 5462c057a378SRick Macklem nd->nd_repstat = ret; 5463c057a378SRick Macklem if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 5464c057a378SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) 5465c057a378SRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, 5466c057a378SRick Macklem curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5467c057a378SRick Macklem NULL); 5468c057a378SRick Macklem if (nd->nd_repstat == 0) 5469c057a378SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL, 5470c057a378SRick Macklem clientid, &stateid, exp, nd, curthread); 5471b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 5472c057a378SRick Macklem if (nd->nd_repstat != 0) 5473c057a378SRick Macklem goto out; 5474c057a378SRick Macklem 5475c057a378SRick Macklem error = NFSVOPLOCK(tovp, LK_SHARED); 5476c057a378SRick Macklem if (error != 0) 5477c057a378SRick Macklem goto out; 5478c057a378SRick Macklem if (vnode_vtype(tovp) != VREG) 5479c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGTYPE; 5480c057a378SRick Macklem 5481c057a378SRick Macklem /* For the output file, we only need the Owner attribute. */ 5482c057a378SRick Macklem ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits); 5483c057a378SRick Macklem if (nd->nd_repstat == 0) 5484c057a378SRick Macklem nd->nd_repstat = ret; 5485c057a378SRick Macklem if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 5486c057a378SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) 5487c057a378SRick Macklem nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp, 5488c057a378SRick Macklem curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5489c057a378SRick Macklem NULL); 5490c057a378SRick Macklem if (nd->nd_repstat == 0) 5491c057a378SRick Macklem nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL, 5492c057a378SRick Macklem clientid, &stateid, toexp, nd, curthread); 5493b249ce48SMateusz Guzik NFSVOPUNLOCK(tovp); 5494c057a378SRick Macklem 5495c057a378SRick Macklem /* Range lock the byte ranges for both invp and outvp. */ 5496c057a378SRick Macklem if (nd->nd_repstat == 0) { 5497c057a378SRick Macklem for (;;) { 5498c057a378SRick Macklem if (len == 0) { 5499c057a378SRick Macklem rl_wcookie = vn_rangelock_wlock(tovp, outoff, 5500c057a378SRick Macklem OFF_MAX); 5501c057a378SRick Macklem rl_rcookie = vn_rangelock_tryrlock(vp, inoff, 5502c057a378SRick Macklem OFF_MAX); 5503c057a378SRick Macklem } else { 5504c057a378SRick Macklem rl_wcookie = vn_rangelock_wlock(tovp, outoff, 5505c057a378SRick Macklem outoff + len); 5506c057a378SRick Macklem rl_rcookie = vn_rangelock_tryrlock(vp, inoff, 5507c057a378SRick Macklem inoff + len); 5508c057a378SRick Macklem } 5509c057a378SRick Macklem if (rl_rcookie != NULL) 5510c057a378SRick Macklem break; 5511c057a378SRick Macklem vn_rangelock_unlock(tovp, rl_wcookie); 5512c057a378SRick Macklem if (len == 0) 5513c057a378SRick Macklem rl_rcookie = vn_rangelock_rlock(vp, inoff, 5514c057a378SRick Macklem OFF_MAX); 5515c057a378SRick Macklem else 5516c057a378SRick Macklem rl_rcookie = vn_rangelock_rlock(vp, inoff, 5517c057a378SRick Macklem inoff + len); 5518c057a378SRick Macklem vn_rangelock_unlock(vp, rl_rcookie); 5519c057a378SRick Macklem } 5520c057a378SRick Macklem 5521c057a378SRick Macklem error = NFSVOPLOCK(vp, LK_SHARED); 5522c057a378SRick Macklem if (error == 0) { 5523c057a378SRick Macklem ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL); 5524c057a378SRick Macklem if (ret == 0) { 5525c057a378SRick Macklem /* 5526c057a378SRick Macklem * Since invp is range locked, na_size should 5527c057a378SRick Macklem * not change. 5528c057a378SRick Macklem */ 5529c057a378SRick Macklem if (len == 0 && at.na_size > inoff) { 5530c057a378SRick Macklem /* 5531c057a378SRick Macklem * If len == 0, set it based on invp's 5532c057a378SRick Macklem * size. If offset is past EOF, just 5533c057a378SRick Macklem * leave len == 0. 5534c057a378SRick Macklem */ 5535c057a378SRick Macklem len = at.na_size - inoff; 5536c057a378SRick Macklem } else if (nfsrv_linux42server == 0 && 5537c057a378SRick Macklem inoff + len > at.na_size) { 5538c057a378SRick Macklem /* 5539c057a378SRick Macklem * RFC-7862 says that NFSERR_INVAL must 5540c057a378SRick Macklem * be returned when inoff + len exceeds 5541c057a378SRick Macklem * the file size, however the NFSv4.2 5542c057a378SRick Macklem * Linux client likes to do this, so 5543c057a378SRick Macklem * only check if nfsrv_linux42server 5544c057a378SRick Macklem * is not set. 5545c057a378SRick Macklem */ 5546c057a378SRick Macklem nd->nd_repstat = NFSERR_INVAL; 5547c057a378SRick Macklem } 5548c057a378SRick Macklem } 5549b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 5550c057a378SRick Macklem if (ret != 0 && nd->nd_repstat == 0) 5551c057a378SRick Macklem nd->nd_repstat = ret; 5552c057a378SRick Macklem } else if (nd->nd_repstat == 0) 5553c057a378SRick Macklem nd->nd_repstat = error; 5554c057a378SRick Macklem } 5555c057a378SRick Macklem 5556c057a378SRick Macklem /* 5557c057a378SRick Macklem * Do the actual copy to an upper limit of vfs.nfs.maxcopyrange. 5558c057a378SRick Macklem * This limit is applied to ensure that the RPC replies in a 5559c057a378SRick Macklem * reasonable time. 5560c057a378SRick Macklem */ 5561c057a378SRick Macklem if (len > nfs_maxcopyrange) 5562c057a378SRick Macklem xfer = nfs_maxcopyrange; 5563c057a378SRick Macklem else 5564c057a378SRick Macklem xfer = len; 5565c057a378SRick Macklem if (nd->nd_repstat == 0) { 5566c057a378SRick Macklem nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff, 5567c057a378SRick Macklem &xfer, 0, nd->nd_cred, nd->nd_cred, NULL); 5568c057a378SRick Macklem if (nd->nd_repstat == 0) 5569c057a378SRick Macklem len = xfer; 5570c057a378SRick Macklem } 5571c057a378SRick Macklem 5572c057a378SRick Macklem /* Unlock the ranges. */ 5573c057a378SRick Macklem if (rl_rcookie != NULL) 5574c057a378SRick Macklem vn_rangelock_unlock(vp, rl_rcookie); 5575c057a378SRick Macklem if (rl_wcookie != NULL) 5576c057a378SRick Macklem vn_rangelock_unlock(tovp, rl_wcookie); 5577c057a378SRick Macklem 5578c057a378SRick Macklem if (nd->nd_repstat == 0) { 5579c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER + 5580c057a378SRick Macklem NFSX_VERF); 5581c057a378SRick Macklem *tl++ = txdr_unsigned(0); /* No callback ids. */ 5582c057a378SRick Macklem txdr_hyper(len, tl); tl += 2; 5583c057a378SRick Macklem *tl++ = txdr_unsigned(NFSWRITE_UNSTABLE); 5584c057a378SRick Macklem *tl++ = txdr_unsigned(nfsboottime.tv_sec); 5585c057a378SRick Macklem *tl++ = txdr_unsigned(nfsboottime.tv_usec); 5586c057a378SRick Macklem *tl++ = newnfs_true; 5587c057a378SRick Macklem *tl = newnfs_true; 5588c057a378SRick Macklem } 5589c057a378SRick Macklem out: 5590c057a378SRick Macklem vrele(vp); 5591c057a378SRick Macklem vrele(tovp); 5592c057a378SRick Macklem NFSEXITCODE2(error, nd); 5593c057a378SRick Macklem return (error); 5594c057a378SRick Macklem nfsmout: 5595c057a378SRick Macklem vput(vp); 5596c057a378SRick Macklem vrele(tovp); 5597c057a378SRick Macklem NFSEXITCODE2(error, nd); 5598c057a378SRick Macklem return (error); 5599c057a378SRick Macklem } 5600c057a378SRick Macklem 5601c057a378SRick Macklem /* 5602c057a378SRick Macklem * nfs seek service 5603c057a378SRick Macklem */ 5604b9cc3262SRyan Moeller int 5605c057a378SRick Macklem nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram, 5606c057a378SRick Macklem vnode_t vp, struct nfsexstuff *exp) 5607c057a378SRick Macklem { 5608c057a378SRick Macklem uint32_t *tl; 5609c057a378SRick Macklem struct nfsvattr at; 5610c057a378SRick Macklem int content, error = 0; 5611c057a378SRick Macklem off_t off; 5612c057a378SRick Macklem u_long cmd; 5613c057a378SRick Macklem nfsattrbit_t attrbits; 5614c057a378SRick Macklem bool eof; 5615c057a378SRick Macklem 5616c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED); 5617c057a378SRick Macklem /* Ignore the stateid for now. */ 5618c057a378SRick Macklem tl += (NFSX_STATEID / NFSX_UNSIGNED); 5619c057a378SRick Macklem off = fxdr_hyper(tl); tl += 2; 5620c057a378SRick Macklem content = fxdr_unsigned(int, *tl); 5621c057a378SRick Macklem if (content == NFSV4CONTENT_DATA) 5622c057a378SRick Macklem cmd = FIOSEEKDATA; 5623c057a378SRick Macklem else if (content == NFSV4CONTENT_HOLE) 5624c057a378SRick Macklem cmd = FIOSEEKHOLE; 5625c057a378SRick Macklem else 5626c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 5627c057a378SRick Macklem if (nd->nd_repstat == 0 && vnode_vtype(vp) == VDIR) 5628c057a378SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 5629c057a378SRick Macklem if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG) 5630c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGTYPE; 5631c057a378SRick Macklem if (nd->nd_repstat == 0 && off < 0) 5632c057a378SRick Macklem nd->nd_repstat = NFSERR_NXIO; 5633c057a378SRick Macklem if (nd->nd_repstat == 0) { 5634c057a378SRick Macklem /* Check permissions for the input file. */ 5635c057a378SRick Macklem NFSZERO_ATTRBIT(&attrbits); 5636c057a378SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5637c057a378SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1, 5638c057a378SRick Macklem &attrbits); 5639c057a378SRick Macklem } 5640c057a378SRick Macklem if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 5641c057a378SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) 5642c057a378SRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, 5643c057a378SRick Macklem curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5644c057a378SRick Macklem NULL); 5645c057a378SRick Macklem if (nd->nd_repstat != 0) 5646c057a378SRick Macklem goto nfsmout; 5647c057a378SRick Macklem 5648c057a378SRick Macklem /* nfsvno_seek() unlocks and vrele()s the vp. */ 5649c057a378SRick Macklem nd->nd_repstat = nfsvno_seek(nd, vp, cmd, &off, content, &eof, 5650c057a378SRick Macklem nd->nd_cred, curthread); 5651c057a378SRick Macklem if (nd->nd_repstat == 0 && eof && content == NFSV4CONTENT_DATA && 5652c057a378SRick Macklem nfsrv_linux42server != 0) 5653c057a378SRick Macklem nd->nd_repstat = NFSERR_NXIO; 5654c057a378SRick Macklem if (nd->nd_repstat == 0) { 5655c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); 5656c057a378SRick Macklem if (eof) 5657c057a378SRick Macklem *tl++ = newnfs_true; 5658c057a378SRick Macklem else 5659c057a378SRick Macklem *tl++ = newnfs_false; 5660c057a378SRick Macklem txdr_hyper(off, tl); 5661c057a378SRick Macklem } 5662c057a378SRick Macklem NFSEXITCODE2(error, nd); 5663c057a378SRick Macklem return (error); 5664c057a378SRick Macklem nfsmout: 5665c057a378SRick Macklem vput(vp); 5666c057a378SRick Macklem NFSEXITCODE2(error, nd); 5667c057a378SRick Macklem return (error); 5668c057a378SRick Macklem } 5669c057a378SRick Macklem 5670c057a378SRick Macklem /* 5671c057a378SRick Macklem * nfs get extended attribute service 5672c057a378SRick Macklem */ 5673b9cc3262SRyan Moeller int 5674c057a378SRick Macklem nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram, 5675c057a378SRick Macklem vnode_t vp, __unused struct nfsexstuff *exp) 5676c057a378SRick Macklem { 5677c057a378SRick Macklem uint32_t *tl; 5678ae070589SRick Macklem struct mbuf *mp = NULL, *mpend = NULL; 5679c057a378SRick Macklem int error, len; 5680c057a378SRick Macklem char *name; 5681c057a378SRick Macklem struct thread *p = curthread; 5682cb889ce6SRick Macklem uint16_t off; 5683c057a378SRick Macklem 5684c057a378SRick Macklem error = 0; 5685c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5686c057a378SRick Macklem len = fxdr_unsigned(int, *tl); 5687c057a378SRick Macklem if (len <= 0) { 5688c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 5689c057a378SRick Macklem goto nfsmout; 5690c057a378SRick Macklem } 5691c057a378SRick Macklem if (len > EXTATTR_MAXNAMELEN) { 5692c057a378SRick Macklem nd->nd_repstat = NFSERR_NOXATTR; 5693c057a378SRick Macklem goto nfsmout; 5694c057a378SRick Macklem } 5695c057a378SRick Macklem name = malloc(len + 1, M_TEMP, M_WAITOK); 5696c057a378SRick Macklem nd->nd_repstat = nfsrv_mtostr(nd, name, len); 5697c057a378SRick Macklem if (nd->nd_repstat == 0) 5698cb889ce6SRick Macklem nd->nd_repstat = nfsvno_getxattr(vp, name, 5699cb889ce6SRick Macklem nd->nd_maxresp, nd->nd_cred, nd->nd_flag, 5700cb889ce6SRick Macklem nd->nd_maxextsiz, p, &mp, &mpend, &len); 5701c057a378SRick Macklem if (nd->nd_repstat == ENOATTR) 5702c057a378SRick Macklem nd->nd_repstat = NFSERR_NOXATTR; 5703c057a378SRick Macklem else if (nd->nd_repstat == EOPNOTSUPP) 5704c057a378SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 5705c057a378SRick Macklem if (nd->nd_repstat == 0) { 5706c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5707c057a378SRick Macklem *tl = txdr_unsigned(len); 5708fb8ed4c5SRick Macklem if (len > 0) { 57099f6624d3SRick Macklem nd->nd_mb->m_next = mp; 5710c057a378SRick Macklem nd->nd_mb = mpend; 5711cb889ce6SRick Macklem if ((mpend->m_flags & M_EXTPG) != 0) { 5712cb889ce6SRick Macklem nd->nd_flag |= ND_EXTPG; 5713cb889ce6SRick Macklem nd->nd_bextpg = mpend->m_epg_npgs - 1; 5714cb889ce6SRick Macklem nd->nd_bpos = (char *)(void *) 5715cb889ce6SRick Macklem PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]); 5716cb889ce6SRick Macklem off = (nd->nd_bextpg == 0) ? 5717cb889ce6SRick Macklem mpend->m_epg_1st_off : 0; 5718cb889ce6SRick Macklem nd->nd_bpos += off + mpend->m_epg_last_len; 5719cb889ce6SRick Macklem nd->nd_bextpgsiz = PAGE_SIZE - 5720cb889ce6SRick Macklem mpend->m_epg_last_len - off; 5721cb889ce6SRick Macklem } else 5722cb889ce6SRick Macklem nd->nd_bpos = mtod(mpend, char *) + 5723cb889ce6SRick Macklem mpend->m_len; 5724c057a378SRick Macklem } 5725fb8ed4c5SRick Macklem } 5726c057a378SRick Macklem free(name, M_TEMP); 5727c057a378SRick Macklem 5728c057a378SRick Macklem nfsmout: 5729c057a378SRick Macklem if (nd->nd_repstat == 0) 5730c057a378SRick Macklem nd->nd_repstat = error; 5731c057a378SRick Macklem vput(vp); 5732c057a378SRick Macklem NFSEXITCODE2(0, nd); 5733c057a378SRick Macklem return (0); 5734c057a378SRick Macklem } 5735c057a378SRick Macklem 5736c057a378SRick Macklem /* 5737c057a378SRick Macklem * nfs set extended attribute service 5738c057a378SRick Macklem */ 5739b9cc3262SRyan Moeller int 5740c057a378SRick Macklem nfsrvd_setxattr(struct nfsrv_descript *nd, __unused int isdgram, 5741c057a378SRick Macklem vnode_t vp, __unused struct nfsexstuff *exp) 5742c057a378SRick Macklem { 5743c057a378SRick Macklem uint32_t *tl; 5744c057a378SRick Macklem struct nfsvattr ova, nva; 5745c057a378SRick Macklem nfsattrbit_t attrbits; 5746c057a378SRick Macklem int error, len, opt; 5747c057a378SRick Macklem char *name; 5748c057a378SRick Macklem size_t siz; 5749c057a378SRick Macklem struct thread *p = curthread; 5750c057a378SRick Macklem 5751c057a378SRick Macklem error = 0; 5752c057a378SRick Macklem name = NULL; 5753c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5754c057a378SRick Macklem opt = fxdr_unsigned(int, *tl++); 5755c057a378SRick Macklem len = fxdr_unsigned(int, *tl); 5756c057a378SRick Macklem if (len <= 0) { 5757c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 5758c057a378SRick Macklem goto nfsmout; 5759c057a378SRick Macklem } 5760c057a378SRick Macklem if (len > EXTATTR_MAXNAMELEN) { 5761c057a378SRick Macklem nd->nd_repstat = NFSERR_NOXATTR; 5762c057a378SRick Macklem goto nfsmout; 5763c057a378SRick Macklem } 5764c057a378SRick Macklem name = malloc(len + 1, M_TEMP, M_WAITOK); 5765c057a378SRick Macklem error = nfsrv_mtostr(nd, name, len); 5766c057a378SRick Macklem if (error != 0) 5767c057a378SRick Macklem goto nfsmout; 5768c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5769c057a378SRick Macklem len = fxdr_unsigned(int, *tl); 5770fb8ed4c5SRick Macklem if (len < 0 || len > IOSIZE_MAX) { 5771c057a378SRick Macklem nd->nd_repstat = NFSERR_XATTR2BIG; 5772c057a378SRick Macklem goto nfsmout; 5773c057a378SRick Macklem } 5774c057a378SRick Macklem switch (opt) { 5775c057a378SRick Macklem case NFSV4SXATTR_CREATE: 5776c057a378SRick Macklem error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL, 5777c057a378SRick Macklem &siz, nd->nd_cred, p); 5778c057a378SRick Macklem if (error != ENOATTR) 5779c057a378SRick Macklem nd->nd_repstat = NFSERR_EXIST; 5780c057a378SRick Macklem error = 0; 5781c057a378SRick Macklem break; 5782c057a378SRick Macklem case NFSV4SXATTR_REPLACE: 5783c057a378SRick Macklem error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL, 5784c057a378SRick Macklem &siz, nd->nd_cred, p); 5785c057a378SRick Macklem if (error != 0) 5786c057a378SRick Macklem nd->nd_repstat = NFSERR_NOXATTR; 5787c057a378SRick Macklem break; 5788c057a378SRick Macklem case NFSV4SXATTR_EITHER: 5789c057a378SRick Macklem break; 5790c057a378SRick Macklem default: 5791c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 5792c057a378SRick Macklem } 5793c057a378SRick Macklem if (nd->nd_repstat != 0) 5794c057a378SRick Macklem goto nfsmout; 5795c057a378SRick Macklem 5796c057a378SRick Macklem /* Now, do the Set Extended attribute, with Change before and after. */ 5797c057a378SRick Macklem NFSZERO_ATTRBIT(&attrbits); 5798c057a378SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 5799c057a378SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits); 5800c057a378SRick Macklem if (nd->nd_repstat == 0) { 5801c057a378SRick Macklem nd->nd_repstat = nfsvno_setxattr(vp, name, len, nd->nd_md, 5802c057a378SRick Macklem nd->nd_dpos, nd->nd_cred, p); 5803c057a378SRick Macklem if (nd->nd_repstat == ENXIO) 5804c057a378SRick Macklem nd->nd_repstat = NFSERR_XATTR2BIG; 5805c057a378SRick Macklem } 5806fb8ed4c5SRick Macklem if (nd->nd_repstat == 0 && len > 0) 5807c057a378SRick Macklem nd->nd_repstat = nfsm_advance(nd, NFSM_RNDUP(len), -1); 5808c057a378SRick Macklem if (nd->nd_repstat == 0) 5809c057a378SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); 5810c057a378SRick Macklem if (nd->nd_repstat == 0) { 5811c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); 5812c057a378SRick Macklem *tl++ = newnfs_true; 5813c057a378SRick Macklem txdr_hyper(ova.na_filerev, tl); tl += 2; 5814c057a378SRick Macklem txdr_hyper(nva.na_filerev, tl); 5815c057a378SRick Macklem } 5816c057a378SRick Macklem 5817c057a378SRick Macklem nfsmout: 5818c057a378SRick Macklem free(name, M_TEMP); 5819c057a378SRick Macklem if (nd->nd_repstat == 0) 5820c057a378SRick Macklem nd->nd_repstat = error; 5821c057a378SRick Macklem vput(vp); 5822c057a378SRick Macklem NFSEXITCODE2(0, nd); 5823c057a378SRick Macklem return (0); 5824c057a378SRick Macklem } 5825c057a378SRick Macklem 5826c057a378SRick Macklem /* 5827c057a378SRick Macklem * nfs remove extended attribute service 5828c057a378SRick Macklem */ 5829b9cc3262SRyan Moeller int 5830c057a378SRick Macklem nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int isdgram, 5831c057a378SRick Macklem vnode_t vp, __unused struct nfsexstuff *exp) 5832c057a378SRick Macklem { 5833c057a378SRick Macklem uint32_t *tl; 5834c057a378SRick Macklem struct nfsvattr ova, nva; 5835c057a378SRick Macklem nfsattrbit_t attrbits; 5836c057a378SRick Macklem int error, len; 5837c057a378SRick Macklem char *name; 5838c057a378SRick Macklem struct thread *p = curthread; 5839c057a378SRick Macklem 5840c057a378SRick Macklem error = 0; 5841c057a378SRick Macklem name = NULL; 5842c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5843c057a378SRick Macklem len = fxdr_unsigned(int, *tl); 5844c057a378SRick Macklem if (len <= 0) { 5845c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 5846c057a378SRick Macklem goto nfsmout; 5847c057a378SRick Macklem } 5848c057a378SRick Macklem if (len > EXTATTR_MAXNAMELEN) { 5849c057a378SRick Macklem nd->nd_repstat = NFSERR_NOXATTR; 5850c057a378SRick Macklem goto nfsmout; 5851c057a378SRick Macklem } 5852c057a378SRick Macklem name = malloc(len + 1, M_TEMP, M_WAITOK); 5853c057a378SRick Macklem error = nfsrv_mtostr(nd, name, len); 5854c057a378SRick Macklem if (error != 0) 5855c057a378SRick Macklem goto nfsmout; 5856c057a378SRick Macklem 5857c057a378SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) == 0) { 5858c057a378SRick Macklem printf("EEK! nfsrvd_rmxattr: no implied clientid\n"); 5859c057a378SRick Macklem error = NFSERR_NOXATTR; 5860c057a378SRick Macklem goto nfsmout; 5861c057a378SRick Macklem } 5862c057a378SRick Macklem /* 5863c057a378SRick Macklem * Now, do the Remove Extended attribute, with Change before and 5864c057a378SRick Macklem * after. 5865c057a378SRick Macklem */ 5866c057a378SRick Macklem NFSZERO_ATTRBIT(&attrbits); 5867c057a378SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 5868c057a378SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits); 5869c057a378SRick Macklem if (nd->nd_repstat == 0) { 5870c057a378SRick Macklem nd->nd_repstat = nfsvno_rmxattr(nd, vp, name, nd->nd_cred, p); 5871c057a378SRick Macklem if (nd->nd_repstat == ENOATTR) 5872c057a378SRick Macklem nd->nd_repstat = NFSERR_NOXATTR; 5873c057a378SRick Macklem } 5874c057a378SRick Macklem if (nd->nd_repstat == 0) 5875c057a378SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); 5876c057a378SRick Macklem if (nd->nd_repstat == 0) { 58770bda1dddSRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); 58780bda1dddSRick Macklem *tl++ = newnfs_true; 5879c057a378SRick Macklem txdr_hyper(ova.na_filerev, tl); tl += 2; 5880c057a378SRick Macklem txdr_hyper(nva.na_filerev, tl); 5881c057a378SRick Macklem } 5882c057a378SRick Macklem 5883c057a378SRick Macklem nfsmout: 5884c057a378SRick Macklem free(name, M_TEMP); 5885c057a378SRick Macklem if (nd->nd_repstat == 0) 5886c057a378SRick Macklem nd->nd_repstat = error; 5887c057a378SRick Macklem vput(vp); 5888c057a378SRick Macklem NFSEXITCODE2(0, nd); 5889c057a378SRick Macklem return (0); 5890c057a378SRick Macklem } 5891c057a378SRick Macklem 5892c057a378SRick Macklem /* 5893c057a378SRick Macklem * nfs list extended attribute service 5894c057a378SRick Macklem */ 5895b9cc3262SRyan Moeller int 5896c057a378SRick Macklem nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram, 5897c057a378SRick Macklem vnode_t vp, __unused struct nfsexstuff *exp) 5898c057a378SRick Macklem { 5899c057a378SRick Macklem uint32_t cnt, *tl, len, len2, i, pos, retlen; 5900c057a378SRick Macklem int error; 5901c057a378SRick Macklem uint64_t cookie, cookie2; 5902c057a378SRick Macklem u_char *buf; 5903c057a378SRick Macklem bool eof; 5904c057a378SRick Macklem struct thread *p = curthread; 5905c057a378SRick Macklem 5906c057a378SRick Macklem error = 0; 5907c057a378SRick Macklem buf = NULL; 5908c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 5909c057a378SRick Macklem /* 5910c057a378SRick Macklem * The cookie doesn't need to be in net byte order, but FreeBSD 5911c057a378SRick Macklem * does so to make it more readable in packet traces. 5912c057a378SRick Macklem */ 5913c057a378SRick Macklem cookie = fxdr_hyper(tl); tl += 2; 5914c057a378SRick Macklem len = fxdr_unsigned(uint32_t, *tl); 5915c057a378SRick Macklem if (len == 0 || cookie >= IOSIZE_MAX) { 5916c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 5917c057a378SRick Macklem goto nfsmout; 5918c057a378SRick Macklem } 5919c057a378SRick Macklem if (len > nd->nd_maxresp - NFS_MAXXDR) 5920c057a378SRick Macklem len = nd->nd_maxresp - NFS_MAXXDR; 5921c057a378SRick Macklem len2 = len; 5922c057a378SRick Macklem nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf, 5923c057a378SRick Macklem &len, &eof); 5924c057a378SRick Macklem if (nd->nd_repstat == EOPNOTSUPP) 5925c057a378SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 5926c057a378SRick Macklem if (nd->nd_repstat == 0) { 5927c057a378SRick Macklem cookie2 = cookie + len; 5928c057a378SRick Macklem if (cookie2 < cookie) 5929c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 5930c057a378SRick Macklem } 5931c057a378SRick Macklem if (nd->nd_repstat == 0) { 5932c057a378SRick Macklem /* Now copy the entries out. */ 5933c057a378SRick Macklem retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED; 5934c057a378SRick Macklem if (len == 0 && retlen <= len2) { 5935c057a378SRick Macklem /* The cookie was at eof. */ 5936c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * 5937c057a378SRick Macklem NFSX_UNSIGNED); 5938c057a378SRick Macklem txdr_hyper(cookie2, tl); tl += 2; 5939c057a378SRick Macklem *tl++ = txdr_unsigned(0); 5940c057a378SRick Macklem *tl = newnfs_true; 5941c057a378SRick Macklem goto nfsmout; 5942c057a378SRick Macklem } 5943c057a378SRick Macklem 5944c057a378SRick Macklem /* Sanity check the cookie. */ 5945c057a378SRick Macklem for (pos = 0; pos < len; pos += (i + 1)) { 5946c057a378SRick Macklem if (pos == cookie) 5947c057a378SRick Macklem break; 5948c057a378SRick Macklem i = buf[pos]; 5949c057a378SRick Macklem } 5950c057a378SRick Macklem if (pos != cookie) { 5951c057a378SRick Macklem nd->nd_repstat = NFSERR_INVAL; 5952c057a378SRick Macklem goto nfsmout; 5953c057a378SRick Macklem } 5954c057a378SRick Macklem 5955c057a378SRick Macklem /* Loop around copying the entrie(s) out. */ 5956c057a378SRick Macklem cnt = 0; 5957c057a378SRick Macklem len -= cookie; 5958c057a378SRick Macklem i = buf[pos]; 5959c057a378SRick Macklem while (i < len && len2 >= retlen + NFSM_RNDUP(i) + 5960c057a378SRick Macklem NFSX_UNSIGNED) { 5961c057a378SRick Macklem if (cnt == 0) { 5962c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 5963c057a378SRick Macklem NFSX_UNSIGNED); 5964c057a378SRick Macklem txdr_hyper(cookie2, tl); tl += 2; 5965c057a378SRick Macklem } 5966c057a378SRick Macklem retlen += nfsm_strtom(nd, &buf[pos + 1], i); 5967c057a378SRick Macklem len -= (i + 1); 5968c057a378SRick Macklem pos += (i + 1); 5969c057a378SRick Macklem i = buf[pos]; 5970c057a378SRick Macklem cnt++; 5971c057a378SRick Macklem } 5972c057a378SRick Macklem /* 5973c057a378SRick Macklem * eof is set true/false by nfsvno_listxattr(), but if we 5974c057a378SRick Macklem * can't copy all entries returned by nfsvno_listxattr(), 5975c057a378SRick Macklem * we are not at eof. 5976c057a378SRick Macklem */ 5977c057a378SRick Macklem if (len > 0) 5978c057a378SRick Macklem eof = false; 5979c057a378SRick Macklem if (cnt > 0) { 5980c057a378SRick Macklem /* *tl is set above. */ 5981c057a378SRick Macklem *tl = txdr_unsigned(cnt); 5982c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5983c057a378SRick Macklem if (eof) 5984c057a378SRick Macklem *tl = newnfs_true; 5985c057a378SRick Macklem else 5986c057a378SRick Macklem *tl = newnfs_false; 5987c057a378SRick Macklem } else 5988c057a378SRick Macklem nd->nd_repstat = NFSERR_TOOSMALL; 5989c057a378SRick Macklem } 5990c057a378SRick Macklem 5991c057a378SRick Macklem nfsmout: 5992c057a378SRick Macklem free(buf, M_TEMP); 5993c057a378SRick Macklem if (nd->nd_repstat == 0) 5994c057a378SRick Macklem nd->nd_repstat = error; 5995c057a378SRick Macklem vput(vp); 5996c057a378SRick Macklem NFSEXITCODE2(0, nd); 5997c057a378SRick Macklem return (0); 5998c057a378SRick Macklem } 5999c057a378SRick Macklem 6000c057a378SRick Macklem /* 6001c59e4cc3SRick Macklem * nfsv4 service not supported 6002c59e4cc3SRick Macklem */ 6003b9cc3262SRyan Moeller int 6004c59e4cc3SRick Macklem nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram, 6005af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 6006c59e4cc3SRick Macklem { 6007c59e4cc3SRick Macklem 6008c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 6009c59e4cc3SRick Macklem NFSEXITCODE2(0, nd); 6010c59e4cc3SRick Macklem return (0); 6011c59e4cc3SRick Macklem } 6012