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; 59c9aad40fSRick Macklem extern int nfs_rootfhset; 6007c0c166SRick Macklem extern int nfsrv_enable_crossmntpt; 611f54e596SRick Macklem extern int nfsrv_statehashsize; 6290d2dfabSRick Macklem extern int nfsrv_layouthashsize; 6390d2dfabSRick Macklem extern time_t nfsdev_time; 6490d2dfabSRick Macklem extern volatile int nfsrv_devidcnt; 6590d2dfabSRick Macklem extern int nfsd_debuglevel; 6690d2dfabSRick Macklem extern u_long sb_max_adj; 6790d2dfabSRick Macklem extern int nfsrv_pnfsatime; 6890d2dfabSRick Macklem extern int nfsrv_maxpnfsmirror; 69c057a378SRick Macklem extern int nfs_maxcopyrange; 709ec7b004SRick Macklem 71e4558aacSXin LI static int nfs_async = 0; 72e4558aacSXin LI SYSCTL_DECL(_vfs_nfsd); 73e4558aacSXin LI SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0, 74e4558aacSXin LI "Tell client that writes were synced even though they were not"); 7590d2dfabSRick Macklem extern int nfsrv_doflexfile; 7690d2dfabSRick Macklem SYSCTL_INT(_vfs_nfsd, OID_AUTO, default_flexfile, CTLFLAG_RW, 7790d2dfabSRick Macklem &nfsrv_doflexfile, 0, "Make Flex File Layout the default for pNFS"); 78c057a378SRick Macklem static int nfsrv_linux42server = 1; 79c057a378SRick Macklem SYSCTL_INT(_vfs_nfsd, OID_AUTO, linux42server, CTLFLAG_RW, 80c057a378SRick Macklem &nfsrv_linux42server, 0, 81c057a378SRick Macklem "Enable Linux style NFSv4.2 server (non-RFC compliant)"); 82b0b7d978SRick Macklem static bool nfsrv_openaccess = true; 83b0b7d978SRick Macklem SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, v4openaccess, CTLFLAG_RW, 84b0b7d978SRick Macklem &nfsrv_openaccess, 0, 85b0b7d978SRick Macklem "Enable Linux style NFSv4 Open access check"); 86e4558aacSXin LI 879ec7b004SRick Macklem /* 889ec7b004SRick Macklem * This list defines the GSS mechanisms supported. 899ec7b004SRick Macklem * (Don't ask me how you get these strings from the RFC stuff like 909ec7b004SRick Macklem * iso(1), org(3)... but someone did it, so I don't need to know.) 919ec7b004SRick Macklem */ 929ec7b004SRick Macklem static struct nfsgss_mechlist nfsgss_mechlist[] = { 939ec7b004SRick Macklem { 9, "\052\206\110\206\367\022\001\002\002", 11 }, 949ec7b004SRick Macklem { 0, "", 0 }, 959ec7b004SRick Macklem }; 969ec7b004SRick Macklem 979ec7b004SRick Macklem /* local functions */ 989ec7b004SRick Macklem static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 999ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 1009ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 1019ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, 1029ec7b004SRick Macklem NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 1039ec7b004SRick Macklem int pathlen); 1049ec7b004SRick Macklem static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 1059ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 1069ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 1079ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 1089ec7b004SRick Macklem NFSPROC_T *p, struct nfsexstuff *exp); 1099ec7b004SRick Macklem 1109ec7b004SRick Macklem /* 1119ec7b004SRick Macklem * nfs access service (not a part of NFS V2) 1129ec7b004SRick Macklem */ 113b9cc3262SRyan Moeller int 1149ec7b004SRick Macklem nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram, 115af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 1169ec7b004SRick Macklem { 1179ec7b004SRick Macklem u_int32_t *tl; 1189ec7b004SRick Macklem int getret, error = 0; 1199ec7b004SRick Macklem struct nfsvattr nva; 1209ec7b004SRick Macklem u_int32_t testmode, nfsmode, supported = 0; 1218da45f2cSRick Macklem accmode_t deletebit; 122af444b18SEdward Tomasz Napierala struct thread *p = curthread; 1239ec7b004SRick Macklem 1249ec7b004SRick Macklem if (nd->nd_repstat) { 1259ec7b004SRick Macklem nfsrv_postopattr(nd, 1, &nva); 126a9285ae5SZack Kirsch goto out; 1279ec7b004SRick Macklem } 1289ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1299ec7b004SRick Macklem nfsmode = fxdr_unsigned(u_int32_t, *tl); 1309ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && 1319ec7b004SRick Macklem (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP | 1329ec7b004SRick Macklem NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE | 133c057a378SRick Macklem NFSACCESS_EXECUTE | NFSACCESS_XAREAD | NFSACCESS_XAWRITE | 134c057a378SRick Macklem NFSACCESS_XALIST))) { 1359ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 1369ec7b004SRick Macklem vput(vp); 137a9285ae5SZack Kirsch goto out; 1389ec7b004SRick Macklem } 1399ec7b004SRick Macklem if (nfsmode & NFSACCESS_READ) { 1409ec7b004SRick Macklem supported |= NFSACCESS_READ; 1418da45f2cSRick Macklem if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, 1428da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1439ec7b004SRick Macklem nfsmode &= ~NFSACCESS_READ; 1449ec7b004SRick Macklem } 1459ec7b004SRick Macklem if (nfsmode & NFSACCESS_MODIFY) { 1469ec7b004SRick Macklem supported |= NFSACCESS_MODIFY; 1478da45f2cSRick Macklem if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, 1488da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1499ec7b004SRick Macklem nfsmode &= ~NFSACCESS_MODIFY; 1509ec7b004SRick Macklem } 1519ec7b004SRick Macklem if (nfsmode & NFSACCESS_EXTEND) { 1529ec7b004SRick Macklem supported |= NFSACCESS_EXTEND; 1538da45f2cSRick Macklem if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p, 1548da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1559ec7b004SRick Macklem nfsmode &= ~NFSACCESS_EXTEND; 1569ec7b004SRick Macklem } 157c057a378SRick Macklem if (nfsmode & NFSACCESS_XAREAD) { 158c057a378SRick Macklem supported |= NFSACCESS_XAREAD; 159c057a378SRick Macklem if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, 160c057a378SRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 161c057a378SRick Macklem nfsmode &= ~NFSACCESS_XAREAD; 162c057a378SRick Macklem } 163c057a378SRick Macklem if (nfsmode & NFSACCESS_XAWRITE) { 164c057a378SRick Macklem supported |= NFSACCESS_XAWRITE; 165c057a378SRick Macklem if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, 166c057a378SRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 167c057a378SRick Macklem nfsmode &= ~NFSACCESS_XAWRITE; 168c057a378SRick Macklem } 169c057a378SRick Macklem if (nfsmode & NFSACCESS_XALIST) { 170c057a378SRick Macklem supported |= NFSACCESS_XALIST; 171c057a378SRick Macklem if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, 172c057a378SRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 173c057a378SRick Macklem nfsmode &= ~NFSACCESS_XALIST; 174c057a378SRick Macklem } 1759ec7b004SRick Macklem if (nfsmode & NFSACCESS_DELETE) { 1769ec7b004SRick Macklem supported |= NFSACCESS_DELETE; 1778da45f2cSRick Macklem if (vp->v_type == VDIR) 1788da45f2cSRick Macklem deletebit = VDELETE_CHILD; 1798da45f2cSRick Macklem else 1808da45f2cSRick Macklem deletebit = VDELETE; 1818da45f2cSRick Macklem if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p, 1828da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1839ec7b004SRick Macklem nfsmode &= ~NFSACCESS_DELETE; 1849ec7b004SRick Macklem } 1859ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 1869ec7b004SRick Macklem testmode = NFSACCESS_LOOKUP; 1879ec7b004SRick Macklem else 1889ec7b004SRick Macklem testmode = NFSACCESS_EXECUTE; 1899ec7b004SRick Macklem if (nfsmode & testmode) { 1909ec7b004SRick Macklem supported |= (nfsmode & testmode); 1918da45f2cSRick Macklem if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p, 1928da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 1939ec7b004SRick Macklem nfsmode &= ~testmode; 1949ec7b004SRick Macklem } 1959ec7b004SRick Macklem nfsmode &= supported; 1969ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 19790d2dfabSRick Macklem getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 1989ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 1999ec7b004SRick Macklem } 2009ec7b004SRick Macklem vput(vp); 2019ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 2029ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2039ec7b004SRick Macklem *tl++ = txdr_unsigned(supported); 2049ec7b004SRick Macklem } else 2059ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2069ec7b004SRick Macklem *tl = txdr_unsigned(nfsmode); 207a9285ae5SZack Kirsch 208a9285ae5SZack Kirsch out: 209a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 2109ec7b004SRick Macklem return (0); 2119ec7b004SRick Macklem nfsmout: 2129ec7b004SRick Macklem vput(vp); 213a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 2149ec7b004SRick Macklem return (error); 2159ec7b004SRick Macklem } 2169ec7b004SRick Macklem 2179ec7b004SRick Macklem /* 2189ec7b004SRick Macklem * nfs getattr service 2199ec7b004SRick Macklem */ 220b9cc3262SRyan Moeller int 2219ec7b004SRick Macklem nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram, 222af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 2239ec7b004SRick Macklem { 2249ec7b004SRick Macklem struct nfsvattr nva; 2259ec7b004SRick Macklem fhandle_t fh; 226a09001a8SRick Macklem int at_root = 0, error = 0, supports_nfsv4acls; 2279ec7b004SRick Macklem struct nfsreferral *refp; 22853f476caSRick Macklem nfsattrbit_t attrbits, tmpbits; 22907c0c166SRick Macklem struct mount *mp; 23007c0c166SRick Macklem struct vnode *tvp = NULL; 23107c0c166SRick Macklem struct vattr va; 23207c0c166SRick Macklem uint64_t mounted_on_fileno = 0; 23353f476caSRick Macklem accmode_t accmode; 234af444b18SEdward Tomasz Napierala struct thread *p = curthread; 2359ec7b004SRick Macklem 2369ec7b004SRick Macklem if (nd->nd_repstat) 237a9285ae5SZack Kirsch goto out; 2389ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 2399ec7b004SRick Macklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 2409ec7b004SRick Macklem if (error) { 2419ec7b004SRick Macklem vput(vp); 242a9285ae5SZack Kirsch goto out; 2439ec7b004SRick Macklem } 2449ec7b004SRick Macklem 2459ec7b004SRick Macklem /* 2469ec7b004SRick Macklem * Check for a referral. 2479ec7b004SRick Macklem */ 2489ec7b004SRick Macklem refp = nfsv4root_getreferral(vp, NULL, 0); 2499ec7b004SRick Macklem if (refp != NULL) { 2509ec7b004SRick Macklem (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1, 2519ec7b004SRick Macklem &nd->nd_repstat); 2529ec7b004SRick Macklem vput(vp); 253a9285ae5SZack Kirsch goto out; 2549ec7b004SRick Macklem } 25553f476caSRick Macklem if (nd->nd_repstat == 0) { 25653f476caSRick Macklem accmode = 0; 25753f476caSRick Macklem NFSSET_ATTRBIT(&tmpbits, &attrbits); 258d8a5961fSMarcelo Araujo 259d8a5961fSMarcelo Araujo /* 260d8a5961fSMarcelo Araujo * GETATTR with write-only attr time_access_set and time_modify_set 261d8a5961fSMarcelo Araujo * should return NFS4ERR_INVAL. 262d8a5961fSMarcelo Araujo */ 263d8a5961fSMarcelo Araujo if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) || 264d8a5961fSMarcelo Araujo NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){ 265d8a5961fSMarcelo Araujo error = NFSERR_INVAL; 266d8a5961fSMarcelo Araujo vput(vp); 267d8a5961fSMarcelo Araujo goto out; 268d8a5961fSMarcelo Araujo } 26953f476caSRick Macklem if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) { 27053f476caSRick Macklem NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL); 27153f476caSRick Macklem accmode |= VREAD_ACL; 27253f476caSRick Macklem } 27353f476caSRick Macklem if (NFSNONZERO_ATTRBIT(&tmpbits)) 27453f476caSRick Macklem accmode |= VREAD_ATTRIBUTES; 27553f476caSRick Macklem if (accmode != 0) 27653f476caSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, accmode, 2778da45f2cSRick Macklem nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, 2788da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 2799ec7b004SRick Macklem } 28053f476caSRick Macklem } 2819ec7b004SRick Macklem if (!nd->nd_repstat) 28290d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); 2839ec7b004SRick Macklem if (!nd->nd_repstat) { 2849ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 2859ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE)) 2869ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 2879ec7b004SRick Macklem if (!nd->nd_repstat) 2889ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkgetattr(nd, vp, 28990d2dfabSRick Macklem &nva, &attrbits, p); 29007c0c166SRick Macklem if (nd->nd_repstat == 0) { 291a09001a8SRick Macklem supports_nfsv4acls = nfs_supportsnfsv4acls(vp); 29207c0c166SRick Macklem mp = vp->v_mount; 29307c0c166SRick Macklem if (nfsrv_enable_crossmntpt != 0 && 29407c0c166SRick Macklem vp->v_type == VDIR && 29507c0c166SRick Macklem (vp->v_vflag & VV_ROOT) != 0 && 29607c0c166SRick Macklem vp != rootvnode) { 29707c0c166SRick Macklem tvp = mp->mnt_vnodecovered; 29807c0c166SRick Macklem VREF(tvp); 29907c0c166SRick Macklem at_root = 1; 30007c0c166SRick Macklem } else 30107c0c166SRick Macklem at_root = 0; 30207c0c166SRick Macklem vfs_ref(mp); 303b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 30407c0c166SRick Macklem if (at_root != 0) { 30507c0c166SRick Macklem if ((nd->nd_repstat = 30698f234f3SZack Kirsch NFSVOPLOCK(tvp, LK_SHARED)) == 0) { 30707c0c166SRick Macklem nd->nd_repstat = VOP_GETATTR( 30807c0c166SRick Macklem tvp, &va, nd->nd_cred); 30907c0c166SRick Macklem vput(tvp); 31007c0c166SRick Macklem } else 31107c0c166SRick Macklem vrele(tvp); 31207c0c166SRick Macklem if (nd->nd_repstat == 0) 31307c0c166SRick Macklem mounted_on_fileno = (uint64_t) 31407c0c166SRick Macklem va.va_fileid; 31507c0c166SRick Macklem else 31607c0c166SRick Macklem at_root = 0; 31707c0c166SRick Macklem } 31807c0c166SRick Macklem if (nd->nd_repstat == 0) 31907c0c166SRick Macklem nd->nd_repstat = vfs_busy(mp, 0); 32007c0c166SRick Macklem vfs_rel(mp); 32107c0c166SRick Macklem if (nd->nd_repstat == 0) { 32207c0c166SRick Macklem (void)nfsvno_fillattr(nd, mp, vp, &nva, 32307c0c166SRick Macklem &fh, 0, &attrbits, nd->nd_cred, p, 324a09001a8SRick Macklem isdgram, 1, supports_nfsv4acls, 325a09001a8SRick Macklem at_root, mounted_on_fileno); 32607c0c166SRick Macklem vfs_unbusy(mp); 32707c0c166SRick Macklem } 3289ec7b004SRick Macklem vrele(vp); 32907c0c166SRick Macklem } else 33007c0c166SRick Macklem vput(vp); 3319ec7b004SRick Macklem } else { 3329ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 3339ec7b004SRick Macklem vput(vp); 3349ec7b004SRick Macklem } 3359ec7b004SRick Macklem } else { 3369ec7b004SRick Macklem vput(vp); 3379ec7b004SRick Macklem } 338a9285ae5SZack Kirsch 339a9285ae5SZack Kirsch out: 340a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 341a9285ae5SZack Kirsch return (error); 3429ec7b004SRick Macklem } 3439ec7b004SRick Macklem 3449ec7b004SRick Macklem /* 3459ec7b004SRick Macklem * nfs setattr service 3469ec7b004SRick Macklem */ 347b9cc3262SRyan Moeller int 3489ec7b004SRick Macklem nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram, 349af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 3509ec7b004SRick Macklem { 3519ec7b004SRick Macklem struct nfsvattr nva, nva2; 3529ec7b004SRick Macklem u_int32_t *tl; 3539ec7b004SRick Macklem int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0; 35490d2dfabSRick Macklem int gotproxystateid; 3559ec7b004SRick Macklem struct timespec guard = { 0, 0 }; 3569ec7b004SRick Macklem nfsattrbit_t attrbits, retbits; 3579ec7b004SRick Macklem nfsv4stateid_t stateid; 3589ec7b004SRick Macklem NFSACL_T *aclp = NULL; 359af444b18SEdward Tomasz Napierala struct thread *p = curthread; 3609ec7b004SRick Macklem 3619ec7b004SRick Macklem if (nd->nd_repstat) { 3629ec7b004SRick Macklem nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 363a9285ae5SZack Kirsch goto out; 3649ec7b004SRick Macklem } 3659ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 366c3e22f83SRick Macklem aclp = acl_alloc(M_WAITOK); 3679ec7b004SRick Macklem aclp->acl_cnt = 0; 3689ec7b004SRick Macklem #endif 36990d2dfabSRick Macklem gotproxystateid = 0; 3709ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 3719ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 3729ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3739ec7b004SRick Macklem stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 37490d2dfabSRick Macklem stateid.other[0] = *tl++; 37590d2dfabSRick Macklem stateid.other[1] = *tl++; 37690d2dfabSRick Macklem stateid.other[2] = *tl; 37790d2dfabSRick Macklem if (stateid.other[0] == 0x55555555 && 37890d2dfabSRick Macklem stateid.other[1] == 0x55555555 && 37990d2dfabSRick Macklem stateid.other[2] == 0x55555555 && 38090d2dfabSRick Macklem stateid.seqid == 0xffffffff) 38190d2dfabSRick Macklem gotproxystateid = 1; 3829ec7b004SRick Macklem } 383d8a5961fSMarcelo Araujo error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p); 3849ec7b004SRick Macklem if (error) 3859ec7b004SRick Macklem goto nfsmout; 38690d2dfabSRick Macklem 38790d2dfabSRick Macklem /* For NFSv4, only va_uid is used from nva2. */ 38890d2dfabSRick Macklem NFSZERO_ATTRBIT(&retbits); 38990d2dfabSRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER); 39090d2dfabSRick Macklem preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits); 3919ec7b004SRick Macklem if (!nd->nd_repstat) 3929ec7b004SRick Macklem nd->nd_repstat = preat_ret; 39390d2dfabSRick Macklem 39490d2dfabSRick Macklem NFSZERO_ATTRBIT(&retbits); 3959ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 3969ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3979ec7b004SRick Macklem gcheck = fxdr_unsigned(int, *tl); 3989ec7b004SRick Macklem if (gcheck) { 3999ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4009ec7b004SRick Macklem fxdr_nfsv3time(tl, &guard); 4019ec7b004SRick Macklem } 4029ec7b004SRick Macklem if (!nd->nd_repstat && gcheck && 4039ec7b004SRick Macklem (nva2.na_ctime.tv_sec != guard.tv_sec || 4049ec7b004SRick Macklem nva2.na_ctime.tv_nsec != guard.tv_nsec)) 4059ec7b004SRick Macklem nd->nd_repstat = NFSERR_NOT_SYNC; 4069ec7b004SRick Macklem if (nd->nd_repstat) { 4079ec7b004SRick Macklem vput(vp); 4089ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 4099ec7b004SRick Macklem acl_free(aclp); 4109ec7b004SRick Macklem #endif 4119ec7b004SRick Macklem nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 412a9285ae5SZack Kirsch goto out; 4139ec7b004SRick Macklem } 4149ec7b004SRick Macklem } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) 4159ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 4169ec7b004SRick Macklem 4179ec7b004SRick Macklem /* 4189ec7b004SRick Macklem * Now that we have all the fields, lets do it. 4199ec7b004SRick Macklem * If the size is being changed write access is required, otherwise 4209ec7b004SRick Macklem * just check for a read only file system. 4219ec7b004SRick Macklem */ 4229ec7b004SRick Macklem if (!nd->nd_repstat) { 4239ec7b004SRick Macklem if (NFSVNO_NOTSETSIZE(&nva)) { 4249ec7b004SRick Macklem if (NFSVNO_EXRDONLY(exp) || 425eea79fdeSAlan Somers (vfs_flags(vp->v_mount) & MNT_RDONLY)) 4269ec7b004SRick Macklem nd->nd_repstat = EROFS; 4279ec7b004SRick Macklem } else { 4289ec7b004SRick Macklem if (vnode_vtype(vp) != VREG) 4299ec7b004SRick Macklem nd->nd_repstat = EINVAL; 4309ec7b004SRick Macklem else if (nva2.na_uid != nd->nd_cred->cr_uid || 4319ec7b004SRick Macklem NFSVNO_EXSTRICTACCESS(exp)) 4329ec7b004SRick Macklem nd->nd_repstat = nfsvno_accchk(vp, 4338da45f2cSRick Macklem VWRITE, nd->nd_cred, exp, p, 4348da45f2cSRick Macklem NFSACCCHK_NOOVERRIDE, 4358da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 4369ec7b004SRick Macklem } 4379ec7b004SRick Macklem } 43890d2dfabSRick Macklem /* 43990d2dfabSRick Macklem * Proxy operations from the MDS are allowed via the all 0s special 44090d2dfabSRick Macklem * stateid. 44190d2dfabSRick Macklem */ 44290d2dfabSRick Macklem if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0 && 44390d2dfabSRick Macklem gotproxystateid == 0) 4449ec7b004SRick Macklem nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid, 4459ec7b004SRick Macklem &nva, &attrbits, exp, p); 4469ec7b004SRick Macklem 4479ec7b004SRick Macklem if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 4489ec7b004SRick Macklem /* 4499ec7b004SRick Macklem * For V4, try setting the attrbutes in sets, so that the 4509ec7b004SRick Macklem * reply bitmap will be correct for an error case. 4519ec7b004SRick Macklem */ 4529ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) || 4539ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) { 4549ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 4559ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid); 4569ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid); 4579ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 4589ec7b004SRick Macklem exp); 4599ec7b004SRick Macklem if (!nd->nd_repstat) { 4609ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER)) 4619ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER); 4629ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) 4639ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP); 4649ec7b004SRick Macklem } 4659ec7b004SRick Macklem } 4669ec7b004SRick Macklem if (!nd->nd_repstat && 4679ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) { 4689ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 4699ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, size, nva.na_size); 4709ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 4719ec7b004SRick Macklem exp); 4729ec7b004SRick Macklem if (!nd->nd_repstat) 4739ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE); 4749ec7b004SRick Macklem } 4759ec7b004SRick Macklem if (!nd->nd_repstat && 4769ec7b004SRick Macklem (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) || 4779ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) { 4789ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 4799ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime); 4809ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime); 4819ec7b004SRick Macklem if (nva.na_vaflags & VA_UTIMES_NULL) { 4829ec7b004SRick Macklem nva2.na_vaflags |= VA_UTIMES_NULL; 4839ec7b004SRick Macklem NFSVNO_SETACTIVE(&nva2, vaflags); 4849ec7b004SRick Macklem } 4859ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 4869ec7b004SRick Macklem exp); 4879ec7b004SRick Macklem if (!nd->nd_repstat) { 4889ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET)) 4899ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET); 4909ec7b004SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET)) 4919ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET); 4929ec7b004SRick Macklem } 4939ec7b004SRick Macklem } 4949ec7b004SRick Macklem if (!nd->nd_repstat && 495b4372164SRick Macklem (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE) || 496b4372164SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))) { 4979ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva2); 4989ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode); 4999ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 5009ec7b004SRick Macklem exp); 501b4372164SRick Macklem if (!nd->nd_repstat) { 502b4372164SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) 5039ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE); 504b4372164SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED)) 505b4372164SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODESETMASKED); 506b4372164SRick Macklem } 5079ec7b004SRick Macklem } 5089ec7b004SRick Macklem 5099ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 5109ec7b004SRick Macklem if (!nd->nd_repstat && aclp->acl_cnt > 0 && 5119ec7b004SRick Macklem NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) { 5129ec7b004SRick Macklem nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p); 5139ec7b004SRick Macklem if (!nd->nd_repstat) 5149ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL); 5159ec7b004SRick Macklem } 5169ec7b004SRick Macklem #endif 5179ec7b004SRick Macklem } else if (!nd->nd_repstat) { 5189ec7b004SRick Macklem nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p, 5199ec7b004SRick Macklem exp); 5209ec7b004SRick Macklem } 5219ec7b004SRick Macklem if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) { 52290d2dfabSRick Macklem postat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 5239ec7b004SRick Macklem if (!nd->nd_repstat) 5249ec7b004SRick Macklem nd->nd_repstat = postat_ret; 5259ec7b004SRick Macklem } 5269ec7b004SRick Macklem vput(vp); 5279ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 5289ec7b004SRick Macklem acl_free(aclp); 5299ec7b004SRick Macklem #endif 5309ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 5319ec7b004SRick Macklem nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 5329ec7b004SRick Macklem else if (nd->nd_flag & ND_NFSV4) 5339ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &retbits); 5349ec7b004SRick Macklem else if (!nd->nd_repstat) 5359ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 536a9285ae5SZack Kirsch 537a9285ae5SZack Kirsch out: 538a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 5399ec7b004SRick Macklem return (0); 5409ec7b004SRick Macklem nfsmout: 5419ec7b004SRick Macklem vput(vp); 5429ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 5439ec7b004SRick Macklem acl_free(aclp); 5449ec7b004SRick Macklem #endif 5459ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 5469ec7b004SRick Macklem /* 5479ec7b004SRick Macklem * For all nd_repstat, the V4 reply includes a bitmap, 5489ec7b004SRick Macklem * even NFSERR_BADXDR, which is what this will end up 5499ec7b004SRick Macklem * returning. 5509ec7b004SRick Macklem */ 5519ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &retbits); 5529ec7b004SRick Macklem } 553a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 5549ec7b004SRick Macklem return (error); 5559ec7b004SRick Macklem } 5569ec7b004SRick Macklem 5579ec7b004SRick Macklem /* 5589ec7b004SRick Macklem * nfs lookup rpc 5599ec7b004SRick Macklem * (Also performs lookup parent for v4) 5609ec7b004SRick Macklem */ 561b9cc3262SRyan Moeller int 5629ec7b004SRick Macklem nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram, 563af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 5649ec7b004SRick Macklem { 5659ec7b004SRick Macklem struct nameidata named; 5669ec7b004SRick Macklem vnode_t vp, dirp = NULL; 567a9285ae5SZack Kirsch int error = 0, dattr_ret = 1; 5689ec7b004SRick Macklem struct nfsvattr nva, dattr; 5699ec7b004SRick Macklem char *bufp; 5709ec7b004SRick Macklem u_long *hashp; 571af444b18SEdward Tomasz Napierala struct thread *p = curthread; 5729ec7b004SRick Macklem 5739ec7b004SRick Macklem if (nd->nd_repstat) { 5749ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 575a9285ae5SZack Kirsch goto out; 5769ec7b004SRick Macklem } 5779ec7b004SRick Macklem 5789ec7b004SRick Macklem /* 5799ec7b004SRick Macklem * For some reason, if dp is a symlink, the error 5809ec7b004SRick Macklem * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR. 5819ec7b004SRick Macklem */ 5829ec7b004SRick Macklem if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) { 5839ec7b004SRick Macklem nd->nd_repstat = NFSERR_SYMLINK; 5849ec7b004SRick Macklem vrele(dp); 585a9285ae5SZack Kirsch goto out; 5869ec7b004SRick Macklem } 5879ec7b004SRick Macklem 5889ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 5899ec7b004SRick Macklem LOCKLEAF | SAVESTART); 5909ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 5919ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 5929ec7b004SRick Macklem if (error) { 5939ec7b004SRick Macklem vrele(dp); 5949ec7b004SRick Macklem nfsvno_relpathbuf(&named); 595a9285ae5SZack Kirsch goto out; 5969ec7b004SRick Macklem } 5979ec7b004SRick Macklem if (!nd->nd_repstat) { 5989ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 5999ec7b004SRick Macklem } else { 6009ec7b004SRick Macklem vrele(dp); 6019ec7b004SRick Macklem nfsvno_relpathbuf(&named); 6029ec7b004SRick Macklem } 6039ec7b004SRick Macklem if (nd->nd_repstat) { 6049ec7b004SRick Macklem if (dirp) { 6059ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 60690d2dfabSRick Macklem dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 60790d2dfabSRick Macklem 0, NULL); 6089ec7b004SRick Macklem vrele(dirp); 6099ec7b004SRick Macklem } 6109ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 6119ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 612a9285ae5SZack Kirsch goto out; 6139ec7b004SRick Macklem } 6149ec7b004SRick Macklem if (named.ni_startdir) 6159ec7b004SRick Macklem vrele(named.ni_startdir); 6169ec7b004SRick Macklem nfsvno_relpathbuf(&named); 6179ec7b004SRick Macklem vp = named.ni_vp; 61837b88c2dSRick Macklem if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) && 61937b88c2dSRick Macklem vp->v_type != VDIR && vp->v_type != VLNK) 62037b88c2dSRick Macklem /* 62137b88c2dSRick Macklem * Only allow lookup of VDIR and VLNK for traversal of 62237b88c2dSRick Macklem * non-exported volumes during NFSv4 mounting. 62337b88c2dSRick Macklem */ 62437b88c2dSRick Macklem nd->nd_repstat = ENOENT; 62537b88c2dSRick Macklem if (nd->nd_repstat == 0) 6269ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 6279ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 62890d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 62981f78d99SRick Macklem if (vpp != NULL && nd->nd_repstat == 0) 6309ec7b004SRick Macklem *vpp = vp; 63181f78d99SRick Macklem else 6329ec7b004SRick Macklem vput(vp); 6339ec7b004SRick Macklem if (dirp) { 6349ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 63590d2dfabSRick Macklem dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0, 63690d2dfabSRick Macklem NULL); 6379ec7b004SRick Macklem vrele(dirp); 6389ec7b004SRick Macklem } 6399ec7b004SRick Macklem if (nd->nd_repstat) { 6409ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 6419ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 642a9285ae5SZack Kirsch goto out; 6439ec7b004SRick Macklem } 6449ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 6459ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 6469ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 6479ec7b004SRick Macklem } else if (nd->nd_flag & ND_NFSV3) { 6489ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 6499ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 6509ec7b004SRick Macklem nfsrv_postopattr(nd, dattr_ret, &dattr); 6519ec7b004SRick Macklem } 652a9285ae5SZack Kirsch 653a9285ae5SZack Kirsch out: 654a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 655a9285ae5SZack Kirsch return (error); 6569ec7b004SRick Macklem } 6579ec7b004SRick Macklem 6589ec7b004SRick Macklem /* 6599ec7b004SRick Macklem * nfs readlink service 6609ec7b004SRick Macklem */ 661b9cc3262SRyan Moeller int 6629ec7b004SRick Macklem nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram, 663af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 6649ec7b004SRick Macklem { 6659ec7b004SRick Macklem u_int32_t *tl; 666ae070589SRick Macklem struct mbuf *mp = NULL, *mpend = NULL; 6679ec7b004SRick Macklem int getret = 1, len; 6689ec7b004SRick Macklem struct nfsvattr nva; 669af444b18SEdward Tomasz Napierala struct thread *p = curthread; 6709ec7b004SRick Macklem 6719ec7b004SRick Macklem if (nd->nd_repstat) { 6729ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 673a9285ae5SZack Kirsch goto out; 6749ec7b004SRick Macklem } 6759ec7b004SRick Macklem if (vnode_vtype(vp) != VLNK) { 6769ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) 6779ec7b004SRick Macklem nd->nd_repstat = ENXIO; 6789ec7b004SRick Macklem else 6799ec7b004SRick Macklem nd->nd_repstat = EINVAL; 6809ec7b004SRick Macklem } 6819ec7b004SRick Macklem if (!nd->nd_repstat) 6829ec7b004SRick Macklem nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p, 6839ec7b004SRick Macklem &mp, &mpend, &len); 6849ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 68590d2dfabSRick Macklem getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 6869ec7b004SRick Macklem vput(vp); 6879ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 6889ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 6899ec7b004SRick Macklem if (nd->nd_repstat) 690a9285ae5SZack Kirsch goto out; 6919ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 6929ec7b004SRick Macklem *tl = txdr_unsigned(len); 693*18a48314SRick Macklem if (mp != NULL) { 6949f6624d3SRick Macklem nd->nd_mb->m_next = mp; 6959ec7b004SRick Macklem nd->nd_mb = mpend; 6969f6624d3SRick Macklem nd->nd_bpos = mtod(mpend, caddr_t) + mpend->m_len; 697*18a48314SRick Macklem } 698a9285ae5SZack Kirsch 699a9285ae5SZack Kirsch out: 700a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 7019ec7b004SRick Macklem return (0); 7029ec7b004SRick Macklem } 7039ec7b004SRick Macklem 7049ec7b004SRick Macklem /* 7059ec7b004SRick Macklem * nfs read service 7069ec7b004SRick Macklem */ 707b9cc3262SRyan Moeller int 7089ec7b004SRick Macklem nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram, 709af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 7109ec7b004SRick Macklem { 7119ec7b004SRick Macklem u_int32_t *tl; 71290d2dfabSRick Macklem int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0; 713ae070589SRick Macklem struct mbuf *m2, *m3; 7149ec7b004SRick Macklem struct nfsvattr nva; 7159ec7b004SRick Macklem off_t off = 0x0; 7169ec7b004SRick Macklem struct nfsstate st, *stp = &st; 7179ec7b004SRick Macklem struct nfslock lo, *lop = &lo; 7189ec7b004SRick Macklem nfsv4stateid_t stateid; 7199ec7b004SRick Macklem nfsquad_t clientid; 720af444b18SEdward Tomasz Napierala struct thread *p = curthread; 7219ec7b004SRick Macklem 7229ec7b004SRick Macklem if (nd->nd_repstat) { 7239ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 724a9285ae5SZack Kirsch goto out; 7259ec7b004SRick Macklem } 7269ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 7279ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 7289ec7b004SRick Macklem off = (off_t)fxdr_unsigned(u_int32_t, *tl++); 7299ec7b004SRick Macklem reqlen = fxdr_unsigned(int, *tl); 7309ec7b004SRick Macklem } else if (nd->nd_flag & ND_NFSV3) { 7319ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 7329ec7b004SRick Macklem off = fxdr_hyper(tl); 7339ec7b004SRick Macklem tl += 2; 7349ec7b004SRick Macklem reqlen = fxdr_unsigned(int, *tl); 7359ec7b004SRick Macklem } else { 7369ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED); 7379ec7b004SRick Macklem reqlen = fxdr_unsigned(int, *(tl + 6)); 7389ec7b004SRick Macklem } 7399ec7b004SRick Macklem if (reqlen > NFS_SRVMAXDATA(nd)) { 7409ec7b004SRick Macklem reqlen = NFS_SRVMAXDATA(nd); 7419ec7b004SRick Macklem } else if (reqlen < 0) { 7429ec7b004SRick Macklem error = EBADRPC; 7439ec7b004SRick Macklem goto nfsmout; 7449ec7b004SRick Macklem } 74590d2dfabSRick Macklem gotproxystateid = 0; 7469ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 7479ec7b004SRick Macklem stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS); 7489ec7b004SRick Macklem lop->lo_flags = NFSLCK_READ; 7499ec7b004SRick Macklem stp->ls_ownerlen = 0; 7509ec7b004SRick Macklem stp->ls_op = NULL; 7519ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 7529ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 7539ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 7549ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 755c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 756c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 757c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 758c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 759c59e4cc3SRick Macklem printf("EEK1 multiple clids\n"); 7609ec7b004SRick Macklem } else { 761c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 762c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 7639ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 7649ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 7659ec7b004SRick Macklem } 7669ec7b004SRick Macklem stp->ls_stateid.other[2] = *tl++; 76790d2dfabSRick Macklem /* 76890d2dfabSRick Macklem * Don't allow the client to use a special stateid for a DS op. 76990d2dfabSRick Macklem */ 77090d2dfabSRick Macklem if ((nd->nd_flag & ND_DSSERVER) != 0 && 77190d2dfabSRick Macklem ((stp->ls_stateid.other[0] == 0x0 && 77290d2dfabSRick Macklem stp->ls_stateid.other[1] == 0x0 && 77390d2dfabSRick Macklem stp->ls_stateid.other[2] == 0x0) || 77490d2dfabSRick Macklem (stp->ls_stateid.other[0] == 0xffffffff && 77590d2dfabSRick Macklem stp->ls_stateid.other[1] == 0xffffffff && 77690d2dfabSRick Macklem stp->ls_stateid.other[2] == 0xffffffff) || 77790d2dfabSRick Macklem stp->ls_stateid.seqid != 0)) 77890d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 77990d2dfabSRick Macklem /* However, allow the proxy stateid. */ 78090d2dfabSRick Macklem if (stp->ls_stateid.seqid == 0xffffffff && 78190d2dfabSRick Macklem stp->ls_stateid.other[0] == 0x55555555 && 78290d2dfabSRick Macklem stp->ls_stateid.other[1] == 0x55555555 && 78390d2dfabSRick Macklem stp->ls_stateid.other[2] == 0x55555555) 78490d2dfabSRick Macklem gotproxystateid = 1; 7859ec7b004SRick Macklem off = fxdr_hyper(tl); 7869ec7b004SRick Macklem lop->lo_first = off; 7879ec7b004SRick Macklem tl += 2; 7889ec7b004SRick Macklem lop->lo_end = off + reqlen; 7899ec7b004SRick Macklem /* 7909ec7b004SRick Macklem * Paranoia, just in case it wraps around. 7919ec7b004SRick Macklem */ 7929ec7b004SRick Macklem if (lop->lo_end < off) 7939ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 7949ec7b004SRick Macklem } 7959ec7b004SRick Macklem if (vnode_vtype(vp) != VREG) { 7969ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 7979ec7b004SRick Macklem nd->nd_repstat = EINVAL; 7989ec7b004SRick Macklem else 7999ec7b004SRick Macklem nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR : 8009ec7b004SRick Macklem EINVAL; 8019ec7b004SRick Macklem } 80290d2dfabSRick Macklem getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 8039ec7b004SRick Macklem if (!nd->nd_repstat) 8049ec7b004SRick Macklem nd->nd_repstat = getret; 8059ec7b004SRick Macklem if (!nd->nd_repstat && 8069ec7b004SRick Macklem (nva.na_uid != nd->nd_cred->cr_uid || 8079ec7b004SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) { 8088da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, 8099ec7b004SRick Macklem nd->nd_cred, exp, p, 8108da45f2cSRick Macklem NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 8119ec7b004SRick Macklem if (nd->nd_repstat) 8128da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 8138da45f2cSRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 8148da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 8159ec7b004SRick Macklem } 81690d2dfabSRick Macklem /* 81790d2dfabSRick Macklem * DS reads are marked by ND_DSSERVER or use the proxy special 81890d2dfabSRick Macklem * stateid. 81990d2dfabSRick Macklem */ 82090d2dfabSRick Macklem if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) == 82190d2dfabSRick Macklem ND_NFSV4 && gotproxystateid == 0) 8229ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 8239ec7b004SRick Macklem &stateid, exp, nd, p); 8249ec7b004SRick Macklem if (nd->nd_repstat) { 8259ec7b004SRick Macklem vput(vp); 8269ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 8279ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 828a9285ae5SZack Kirsch goto out; 8299ec7b004SRick Macklem } 8309ec7b004SRick Macklem if (off >= nva.na_size) { 8319ec7b004SRick Macklem cnt = 0; 8329ec7b004SRick Macklem eof = 1; 8339ec7b004SRick Macklem } else if (reqlen == 0) 8349ec7b004SRick Macklem cnt = 0; 83506521fbbSZack Kirsch else if ((off + reqlen) >= nva.na_size) { 8369ec7b004SRick Macklem cnt = nva.na_size - off; 83706521fbbSZack Kirsch eof = 1; 83806521fbbSZack Kirsch } else 8399ec7b004SRick Macklem cnt = reqlen; 8409ec7b004SRick Macklem m3 = NULL; 8419ec7b004SRick Macklem if (cnt > 0) { 8429ec7b004SRick Macklem nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p, 8439ec7b004SRick Macklem &m3, &m2); 8449ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV4)) { 84590d2dfabSRick Macklem getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 8469ec7b004SRick Macklem if (!nd->nd_repstat) 8479ec7b004SRick Macklem nd->nd_repstat = getret; 8489ec7b004SRick Macklem } 8499ec7b004SRick Macklem if (nd->nd_repstat) { 8509ec7b004SRick Macklem vput(vp); 8519ec7b004SRick Macklem if (m3) 8529f6624d3SRick Macklem m_freem(m3); 8539ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 8549ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 855a9285ae5SZack Kirsch goto out; 8569ec7b004SRick Macklem } 8579ec7b004SRick Macklem } 8589ec7b004SRick Macklem vput(vp); 8599ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 8609ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 8619ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 8629ec7b004SRick Macklem } else { 8639ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 8649ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &nva); 8659ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 8669ec7b004SRick Macklem *tl++ = txdr_unsigned(cnt); 8679ec7b004SRick Macklem } else 8689ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 86906521fbbSZack Kirsch if (eof) 8709ec7b004SRick Macklem *tl++ = newnfs_true; 8719ec7b004SRick Macklem else 8729ec7b004SRick Macklem *tl++ = newnfs_false; 8739ec7b004SRick Macklem } 8749ec7b004SRick Macklem *tl = txdr_unsigned(cnt); 8759ec7b004SRick Macklem if (m3) { 8769f6624d3SRick Macklem nd->nd_mb->m_next = m3; 8779ec7b004SRick Macklem nd->nd_mb = m2; 8789f6624d3SRick Macklem nd->nd_bpos = mtod(m2, caddr_t) + m2->m_len; 8799ec7b004SRick Macklem } 880a9285ae5SZack Kirsch 881a9285ae5SZack Kirsch out: 882a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 8839ec7b004SRick Macklem return (0); 8849ec7b004SRick Macklem nfsmout: 8859ec7b004SRick Macklem vput(vp); 886a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 8879ec7b004SRick Macklem return (error); 8889ec7b004SRick Macklem } 8899ec7b004SRick Macklem 8909ec7b004SRick Macklem /* 8919ec7b004SRick Macklem * nfs write service 8929ec7b004SRick Macklem */ 893b9cc3262SRyan Moeller int 8949ec7b004SRick Macklem nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram, 895af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 8969ec7b004SRick Macklem { 8979ec7b004SRick Macklem u_int32_t *tl; 8989ec7b004SRick Macklem struct nfsvattr nva, forat; 8999ec7b004SRick Macklem int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1; 90090d2dfabSRick Macklem int gotproxystateid, stable = NFSWRITE_FILESYNC; 9019ec7b004SRick Macklem off_t off; 9029ec7b004SRick Macklem struct nfsstate st, *stp = &st; 9039ec7b004SRick Macklem struct nfslock lo, *lop = &lo; 9049ec7b004SRick Macklem nfsv4stateid_t stateid; 9059ec7b004SRick Macklem nfsquad_t clientid; 90690d2dfabSRick Macklem nfsattrbit_t attrbits; 907af444b18SEdward Tomasz Napierala struct thread *p = curthread; 9089ec7b004SRick Macklem 9099ec7b004SRick Macklem if (nd->nd_repstat) { 9109ec7b004SRick Macklem nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 911a9285ae5SZack Kirsch goto out; 9129ec7b004SRick Macklem } 91390d2dfabSRick Macklem gotproxystateid = 0; 9149ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 9159ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 9169ec7b004SRick Macklem off = (off_t)fxdr_unsigned(u_int32_t, *++tl); 9179ec7b004SRick Macklem tl += 2; 9189ec7b004SRick Macklem retlen = len = fxdr_unsigned(int32_t, *tl); 9199ec7b004SRick Macklem } else if (nd->nd_flag & ND_NFSV3) { 9209ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 9219ec7b004SRick Macklem off = fxdr_hyper(tl); 9229ec7b004SRick Macklem tl += 3; 9239ec7b004SRick Macklem stable = fxdr_unsigned(int, *tl++); 9249ec7b004SRick Macklem retlen = len = fxdr_unsigned(int32_t, *tl); 9259ec7b004SRick Macklem } else { 9269ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED); 9279ec7b004SRick Macklem stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 9289ec7b004SRick Macklem lop->lo_flags = NFSLCK_WRITE; 9299ec7b004SRick Macklem stp->ls_ownerlen = 0; 9309ec7b004SRick Macklem stp->ls_op = NULL; 9319ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 9329ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 9339ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 9349ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 935c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 936c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 937c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 938c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 939c59e4cc3SRick Macklem printf("EEK2 multiple clids\n"); 9409ec7b004SRick Macklem } else { 941c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 942c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 9439ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 9449ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 9459ec7b004SRick Macklem } 9469ec7b004SRick Macklem stp->ls_stateid.other[2] = *tl++; 94790d2dfabSRick Macklem /* 94890d2dfabSRick Macklem * Don't allow the client to use a special stateid for a DS op. 94990d2dfabSRick Macklem */ 95090d2dfabSRick Macklem if ((nd->nd_flag & ND_DSSERVER) != 0 && 95190d2dfabSRick Macklem ((stp->ls_stateid.other[0] == 0x0 && 95290d2dfabSRick Macklem stp->ls_stateid.other[1] == 0x0 && 95390d2dfabSRick Macklem stp->ls_stateid.other[2] == 0x0) || 95490d2dfabSRick Macklem (stp->ls_stateid.other[0] == 0xffffffff && 95590d2dfabSRick Macklem stp->ls_stateid.other[1] == 0xffffffff && 95690d2dfabSRick Macklem stp->ls_stateid.other[2] == 0xffffffff) || 95790d2dfabSRick Macklem stp->ls_stateid.seqid != 0)) 95890d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 95990d2dfabSRick Macklem /* However, allow the proxy stateid. */ 96090d2dfabSRick Macklem if (stp->ls_stateid.seqid == 0xffffffff && 96190d2dfabSRick Macklem stp->ls_stateid.other[0] == 0x55555555 && 96290d2dfabSRick Macklem stp->ls_stateid.other[1] == 0x55555555 && 96390d2dfabSRick Macklem stp->ls_stateid.other[2] == 0x55555555) 96490d2dfabSRick Macklem gotproxystateid = 1; 9659ec7b004SRick Macklem off = fxdr_hyper(tl); 9669ec7b004SRick Macklem lop->lo_first = off; 9679ec7b004SRick Macklem tl += 2; 9689ec7b004SRick Macklem stable = fxdr_unsigned(int, *tl++); 9699ec7b004SRick Macklem retlen = len = fxdr_unsigned(int32_t, *tl); 9709ec7b004SRick Macklem lop->lo_end = off + len; 9719ec7b004SRick Macklem /* 9729ec7b004SRick Macklem * Paranoia, just in case it wraps around, which shouldn't 9739ec7b004SRick Macklem * ever happen anyhow. 9749ec7b004SRick Macklem */ 9759ec7b004SRick Macklem if (lop->lo_end < lop->lo_first) 9769ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 9779ec7b004SRick Macklem } 9789ec7b004SRick Macklem 97966e80f77SRick Macklem if (retlen > NFS_SRVMAXIO || retlen < 0) 9809ec7b004SRick Macklem nd->nd_repstat = EIO; 9819ec7b004SRick Macklem if (vnode_vtype(vp) != VREG && !nd->nd_repstat) { 9829ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 9839ec7b004SRick Macklem nd->nd_repstat = EINVAL; 9849ec7b004SRick Macklem else 9859ec7b004SRick Macklem nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR : 9869ec7b004SRick Macklem EINVAL; 9879ec7b004SRick Macklem } 98890d2dfabSRick Macklem NFSZERO_ATTRBIT(&attrbits); 98990d2dfabSRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 99090d2dfabSRick Macklem forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits); 9919ec7b004SRick Macklem if (!nd->nd_repstat) 9929ec7b004SRick Macklem nd->nd_repstat = forat_ret; 9939ec7b004SRick Macklem if (!nd->nd_repstat && 9949ec7b004SRick Macklem (forat.na_uid != nd->nd_cred->cr_uid || 9959ec7b004SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) 9968da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 9979ec7b004SRick Macklem nd->nd_cred, exp, p, 9988da45f2cSRick Macklem NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 99990d2dfabSRick Macklem /* 100090d2dfabSRick Macklem * DS reads are marked by ND_DSSERVER or use the proxy special 100190d2dfabSRick Macklem * stateid. 100290d2dfabSRick Macklem */ 100390d2dfabSRick Macklem if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) == 100490d2dfabSRick Macklem ND_NFSV4 && gotproxystateid == 0) 10059ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 10069ec7b004SRick Macklem &stateid, exp, nd, p); 10079ec7b004SRick Macklem if (nd->nd_repstat) { 10089ec7b004SRick Macklem vput(vp); 10099ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 10109ec7b004SRick Macklem nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 1011a9285ae5SZack Kirsch goto out; 10129ec7b004SRick Macklem } 10139ec7b004SRick Macklem 10149ec7b004SRick Macklem /* 10159ec7b004SRick Macklem * For NFS Version 2, it is not obvious what a write of zero length 10169ec7b004SRick Macklem * should do, but I might as well be consistent with Version 3, 10179ec7b004SRick Macklem * which is to return ok so long as there are no permission problems. 10189ec7b004SRick Macklem */ 10199ec7b004SRick Macklem if (retlen > 0) { 1020c057a378SRick Macklem nd->nd_repstat = nfsvno_write(vp, off, retlen, &stable, 10219ec7b004SRick Macklem nd->nd_md, nd->nd_dpos, nd->nd_cred, p); 10229ec7b004SRick Macklem error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1); 10239ec7b004SRick Macklem if (error) 1024ce8d06feSRick Macklem goto nfsmout; 10259ec7b004SRick Macklem } 10269ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) 10279ec7b004SRick Macklem aftat_ret = 0; 10289ec7b004SRick Macklem else 102990d2dfabSRick Macklem aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 10309ec7b004SRick Macklem vput(vp); 10319ec7b004SRick Macklem if (!nd->nd_repstat) 10329ec7b004SRick Macklem nd->nd_repstat = aftat_ret; 10339ec7b004SRick Macklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 10349ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 10359ec7b004SRick Macklem nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 10369ec7b004SRick Macklem if (nd->nd_repstat) 1037a9285ae5SZack Kirsch goto out; 10389ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 10399ec7b004SRick Macklem *tl++ = txdr_unsigned(retlen); 1040e4558aacSXin LI /* 1041e4558aacSXin LI * If nfs_async is set, then pretend the write was FILESYNC. 1042e4558aacSXin LI * Warning: Doing this violates RFC1813 and runs a risk 1043e4558aacSXin LI * of data written by a client being lost when the server 1044e4558aacSXin LI * crashes/reboots. 1045e4558aacSXin LI */ 1046e4558aacSXin LI if (stable == NFSWRITE_UNSTABLE && nfs_async == 0) 10479ec7b004SRick Macklem *tl++ = txdr_unsigned(stable); 10489ec7b004SRick Macklem else 10499ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSWRITE_FILESYNC); 10509ec7b004SRick Macklem /* 10519ec7b004SRick Macklem * Actually, there is no need to txdr these fields, 10529ec7b004SRick Macklem * but it may make the values more human readable, 10539ec7b004SRick Macklem * for debugging purposes. 10549ec7b004SRick Macklem */ 10559ec7b004SRick Macklem *tl++ = txdr_unsigned(nfsboottime.tv_sec); 10569ec7b004SRick Macklem *tl = txdr_unsigned(nfsboottime.tv_usec); 10579ec7b004SRick Macklem } else if (!nd->nd_repstat) 10589ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 1059a9285ae5SZack Kirsch 1060a9285ae5SZack Kirsch out: 1061a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 10629ec7b004SRick Macklem return (0); 10639ec7b004SRick Macklem nfsmout: 10649ec7b004SRick Macklem vput(vp); 1065a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 10669ec7b004SRick Macklem return (error); 10679ec7b004SRick Macklem } 10689ec7b004SRick Macklem 10699ec7b004SRick Macklem /* 10709ec7b004SRick Macklem * nfs create service (creates regular files for V2 and V3. Spec. files for V2.) 10719ec7b004SRick Macklem * now does a truncate to 0 length via. setattr if it already exists 10729ec7b004SRick Macklem * The core creation routine has been extracted out into nfsrv_creatsub(), 10739ec7b004SRick Macklem * so it can also be used by nfsrv_open() for V4. 10749ec7b004SRick Macklem */ 1075b9cc3262SRyan Moeller int 10769ec7b004SRick Macklem nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram, 1077af444b18SEdward Tomasz Napierala vnode_t dp, struct nfsexstuff *exp) 10789ec7b004SRick Macklem { 10799ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 10809ec7b004SRick Macklem struct nfsv2_sattr *sp; 10819ec7b004SRick Macklem struct nameidata named; 10829ec7b004SRick Macklem u_int32_t *tl; 10839ec7b004SRick Macklem int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1; 10849ec7b004SRick Macklem int how = NFSCREATE_UNCHECKED, exclusive_flag = 0; 10859ec7b004SRick Macklem NFSDEV_T rdev = 0; 10869ec7b004SRick Macklem vnode_t vp = NULL, dirp = NULL; 10879ec7b004SRick Macklem fhandle_t fh; 10889ec7b004SRick Macklem char *bufp; 10899ec7b004SRick Macklem u_long *hashp; 10909ec7b004SRick Macklem enum vtype vtyp; 1091086f6e0cSRick Macklem int32_t cverf[2], tverf[2] = { 0, 0 }; 1092af444b18SEdward Tomasz Napierala struct thread *p = curthread; 10939ec7b004SRick Macklem 10949ec7b004SRick Macklem if (nd->nd_repstat) { 10959ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1096a9285ae5SZack Kirsch goto out; 10979ec7b004SRick Macklem } 10989ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 10996c21f6edSKonstantin Belousov LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE); 11009ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 11019ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1102a9285ae5SZack Kirsch if (error) 1103a9285ae5SZack Kirsch goto nfsmout; 11049ec7b004SRick Macklem if (!nd->nd_repstat) { 11059ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 11069ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 11079ec7b004SRick Macklem NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 11089ec7b004SRick Macklem vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode)); 11099ec7b004SRick Macklem if (vtyp == VNON) 11109ec7b004SRick Macklem vtyp = VREG; 11119ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, type, vtyp); 11129ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, mode, 11139ec7b004SRick Macklem nfstov_mode(sp->sa_mode)); 11149ec7b004SRick Macklem switch (nva.na_type) { 11159ec7b004SRick Macklem case VREG: 11169ec7b004SRick Macklem tsize = fxdr_unsigned(int32_t, sp->sa_size); 11179ec7b004SRick Macklem if (tsize != -1) 11189ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, size, 11199ec7b004SRick Macklem (u_quad_t)tsize); 11209ec7b004SRick Macklem break; 11219ec7b004SRick Macklem case VCHR: 11229ec7b004SRick Macklem case VBLK: 11239ec7b004SRick Macklem case VFIFO: 11249ec7b004SRick Macklem rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size); 11259ec7b004SRick Macklem break; 11269ec7b004SRick Macklem default: 11279ec7b004SRick Macklem break; 112874b8d63dSPedro F. Giffuni } 11299ec7b004SRick Macklem } else { 11309ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 11319ec7b004SRick Macklem how = fxdr_unsigned(int, *tl); 11329ec7b004SRick Macklem switch (how) { 11339ec7b004SRick Macklem case NFSCREATE_GUARDED: 11349ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 1135d8a5961fSMarcelo Araujo error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p); 11369ec7b004SRick Macklem if (error) 11379ec7b004SRick Macklem goto nfsmout; 11389ec7b004SRick Macklem break; 11399ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 1140086f6e0cSRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 1141086f6e0cSRick Macklem cverf[0] = *tl++; 1142086f6e0cSRick Macklem cverf[1] = *tl; 11439ec7b004SRick Macklem exclusive_flag = 1; 11449ec7b004SRick Macklem break; 114574b8d63dSPedro F. Giffuni } 11469ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, type, VREG); 11479ec7b004SRick Macklem } 11489ec7b004SRick Macklem } 11499ec7b004SRick Macklem if (nd->nd_repstat) { 11509ec7b004SRick Macklem nfsvno_relpathbuf(&named); 11519ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 115290d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1, 115390d2dfabSRick Macklem NULL); 11549ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 11559ec7b004SRick Macklem &diraft); 11569ec7b004SRick Macklem } 11579ec7b004SRick Macklem vput(dp); 1158a9285ae5SZack Kirsch goto out; 11599ec7b004SRick Macklem } 11609ec7b004SRick Macklem 11619ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 11629ec7b004SRick Macklem if (dirp) { 11639ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 11649ec7b004SRick Macklem vrele(dirp); 11659ec7b004SRick Macklem dirp = NULL; 11669ec7b004SRick Macklem } else { 116790d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 116890d2dfabSRick Macklem NULL); 11699ec7b004SRick Macklem } 11709ec7b004SRick Macklem } 11719ec7b004SRick Macklem if (nd->nd_repstat) { 11729ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 11739ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 11749ec7b004SRick Macklem &diraft); 11759ec7b004SRick Macklem if (dirp) 11769ec7b004SRick Macklem vrele(dirp); 1177a9285ae5SZack Kirsch goto out; 11789ec7b004SRick Macklem } 11799ec7b004SRick Macklem 11809ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) { 11819ec7b004SRick Macklem switch (how) { 11829ec7b004SRick Macklem case NFSCREATE_GUARDED: 11839ec7b004SRick Macklem if (named.ni_vp) 11849ec7b004SRick Macklem nd->nd_repstat = EEXIST; 11859ec7b004SRick Macklem break; 11869ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 11879ec7b004SRick Macklem break; 11889ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 11899ec7b004SRick Macklem if (named.ni_vp == NULL) 11909ec7b004SRick Macklem NFSVNO_SETATTRVAL(&nva, mode, 0); 11919ec7b004SRick Macklem break; 119274b8d63dSPedro F. Giffuni } 11939ec7b004SRick Macklem } 11949ec7b004SRick Macklem 11959ec7b004SRick Macklem /* 11969ec7b004SRick Macklem * Iff doesn't exist, create it 11979ec7b004SRick Macklem * otherwise just truncate to 0 length 11989ec7b004SRick Macklem * should I set the mode too ? 11999ec7b004SRick Macklem */ 12009ec7b004SRick Macklem nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva, 1201127152feSEdward Tomasz Napierala &exclusive_flag, cverf, rdev, exp); 12029ec7b004SRick Macklem 12039ec7b004SRick Macklem if (!nd->nd_repstat) { 12049ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 12059ec7b004SRick Macklem if (!nd->nd_repstat) 120690d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, 120790d2dfabSRick Macklem NULL); 12089ec7b004SRick Macklem vput(vp); 1209086f6e0cSRick Macklem if (!nd->nd_repstat) { 1210086f6e0cSRick Macklem tverf[0] = nva.na_atime.tv_sec; 1211086f6e0cSRick Macklem tverf[1] = nva.na_atime.tv_nsec; 1212086f6e0cSRick Macklem } 12139ec7b004SRick Macklem } 12149ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 12159ec7b004SRick Macklem if (!nd->nd_repstat) { 12169ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 12179ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 12189ec7b004SRick Macklem } 12199ec7b004SRick Macklem } else { 1220086f6e0cSRick Macklem if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0] 1221086f6e0cSRick Macklem || cverf[1] != tverf[1])) 12229ec7b004SRick Macklem nd->nd_repstat = EEXIST; 122390d2dfabSRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 12249ec7b004SRick Macklem vrele(dirp); 12259ec7b004SRick Macklem if (!nd->nd_repstat) { 12269ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1); 12279ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 12289ec7b004SRick Macklem } 12299ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 12309ec7b004SRick Macklem } 1231a9285ae5SZack Kirsch 1232a9285ae5SZack Kirsch out: 1233a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 12349ec7b004SRick Macklem return (0); 12359ec7b004SRick Macklem nfsmout: 12369ec7b004SRick Macklem vput(dp); 12379ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1238a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 12399ec7b004SRick Macklem return (error); 12409ec7b004SRick Macklem } 12419ec7b004SRick Macklem 12429ec7b004SRick Macklem /* 12439ec7b004SRick Macklem * nfs v3 mknod service (and v4 create) 12449ec7b004SRick Macklem */ 1245b9cc3262SRyan Moeller int 12469ec7b004SRick Macklem nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram, 1247af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 12489ec7b004SRick Macklem { 12499ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 12509ec7b004SRick Macklem u_int32_t *tl; 12519ec7b004SRick Macklem struct nameidata named; 12529ec7b004SRick Macklem int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 12539ec7b004SRick Macklem u_int32_t major, minor; 12549ec7b004SRick Macklem enum vtype vtyp = VNON; 12559ec7b004SRick Macklem nfstype nfs4type = NFNON; 12569ec7b004SRick Macklem vnode_t vp, dirp = NULL; 12579ec7b004SRick Macklem nfsattrbit_t attrbits; 12589ec7b004SRick Macklem char *bufp = NULL, *pathcp = NULL; 12599ec7b004SRick Macklem u_long *hashp, cnflags; 12609ec7b004SRick Macklem NFSACL_T *aclp = NULL; 1261af444b18SEdward Tomasz Napierala struct thread *p = curthread; 12629ec7b004SRick Macklem 12639ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 12649ec7b004SRick Macklem cnflags = (LOCKPARENT | SAVESTART); 12659ec7b004SRick Macklem if (nd->nd_repstat) { 12669ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1267a9285ae5SZack Kirsch goto out; 12689ec7b004SRick Macklem } 12699ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 1270c3e22f83SRick Macklem aclp = acl_alloc(M_WAITOK); 12719ec7b004SRick Macklem aclp->acl_cnt = 0; 12729ec7b004SRick Macklem #endif 12739ec7b004SRick Macklem 12749ec7b004SRick Macklem /* 12759ec7b004SRick Macklem * For V4, the creation stuff is here, Yuck! 12769ec7b004SRick Macklem */ 12779ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 12789ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 12799ec7b004SRick Macklem vtyp = nfsv34tov_type(*tl); 12809ec7b004SRick Macklem nfs4type = fxdr_unsigned(nfstype, *tl); 12819ec7b004SRick Macklem switch (nfs4type) { 12829ec7b004SRick Macklem case NFLNK: 12839ec7b004SRick Macklem error = nfsvno_getsymlink(nd, &nva, p, &pathcp, 12849ec7b004SRick Macklem &pathlen); 1285a9285ae5SZack Kirsch if (error) 1286a9285ae5SZack Kirsch goto nfsmout; 12879ec7b004SRick Macklem break; 12889ec7b004SRick Macklem case NFCHR: 12899ec7b004SRick Macklem case NFBLK: 12909ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 12919ec7b004SRick Macklem major = fxdr_unsigned(u_int32_t, *tl++); 12929ec7b004SRick Macklem minor = fxdr_unsigned(u_int32_t, *tl); 12939ec7b004SRick Macklem nva.na_rdev = NFSMAKEDEV(major, minor); 12949ec7b004SRick Macklem break; 12959ec7b004SRick Macklem case NFSOCK: 12969ec7b004SRick Macklem case NFFIFO: 12979ec7b004SRick Macklem break; 12989ec7b004SRick Macklem case NFDIR: 1299f61786cbSRick Macklem cnflags = (LOCKPARENT | SAVENAME); 13009ec7b004SRick Macklem break; 13019ec7b004SRick Macklem default: 13029ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADTYPE; 13039ec7b004SRick Macklem vrele(dp); 13049ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 13059ec7b004SRick Macklem acl_free(aclp); 13069ec7b004SRick Macklem #endif 1307a9285ae5SZack Kirsch goto out; 1308a9285ae5SZack Kirsch } 13099ec7b004SRick Macklem } 13106c21f6edSKonstantin Belousov NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE); 13119ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 13129ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1313a9285ae5SZack Kirsch if (error) 1314a9285ae5SZack Kirsch goto nfsmout; 13159ec7b004SRick Macklem if (!nd->nd_repstat) { 13169ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 13179ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 13189ec7b004SRick Macklem vtyp = nfsv34tov_type(*tl); 13199ec7b004SRick Macklem } 1320d8a5961fSMarcelo Araujo error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p); 1321a9285ae5SZack Kirsch if (error) 1322a9285ae5SZack Kirsch goto nfsmout; 13239ec7b004SRick Macklem nva.na_type = vtyp; 13249ec7b004SRick Macklem if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) && 13259ec7b004SRick Macklem (vtyp == VCHR || vtyp == VBLK)) { 13269ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 13279ec7b004SRick Macklem major = fxdr_unsigned(u_int32_t, *tl++); 13289ec7b004SRick Macklem minor = fxdr_unsigned(u_int32_t, *tl); 13299ec7b004SRick Macklem nva.na_rdev = NFSMAKEDEV(major, minor); 13309ec7b004SRick Macklem } 13319ec7b004SRick Macklem } 13329ec7b004SRick Macklem 133390d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL); 13349ec7b004SRick Macklem if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 13359ec7b004SRick Macklem if (!dirfor_ret && NFSVNO_ISSETGID(&nva) && 13369ec7b004SRick Macklem dirfor.na_gid == nva.na_gid) 13379ec7b004SRick Macklem NFSVNO_UNSET(&nva, gid); 13389ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 13399ec7b004SRick Macklem } 13409ec7b004SRick Macklem if (nd->nd_repstat) { 13419ec7b004SRick Macklem vrele(dp); 13429ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 13439ec7b004SRick Macklem acl_free(aclp); 13449ec7b004SRick Macklem #endif 13459ec7b004SRick Macklem nfsvno_relpathbuf(&named); 13469ec7b004SRick Macklem if (pathcp) 1347222daa42SConrad Meyer free(pathcp, M_TEMP); 13489ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 13499ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 13509ec7b004SRick Macklem &diraft); 1351a9285ae5SZack Kirsch goto out; 13529ec7b004SRick Macklem } 13539ec7b004SRick Macklem 13549ec7b004SRick Macklem /* 13559ec7b004SRick Macklem * Yuck! For V4, mkdir and link are here and some V4 clients don't fill 13569ec7b004SRick Macklem * in va_mode, so we'll have to set a default here. 13579ec7b004SRick Macklem */ 13589ec7b004SRick Macklem if (NFSVNO_NOTSETMODE(&nva)) { 13599ec7b004SRick Macklem if (vtyp == VLNK) 13609ec7b004SRick Macklem nva.na_mode = 0755; 13619ec7b004SRick Macklem else 13629ec7b004SRick Macklem nva.na_mode = 0400; 13639ec7b004SRick Macklem } 13649ec7b004SRick Macklem 13659ec7b004SRick Macklem if (vtyp == VDIR) 13669ec7b004SRick Macklem named.ni_cnd.cn_flags |= WILLBEDIR; 13679ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 13689ec7b004SRick Macklem if (nd->nd_repstat) { 13699ec7b004SRick Macklem if (dirp) { 13709ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 137190d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, 137290d2dfabSRick Macklem p, 0, NULL); 13739ec7b004SRick Macklem vrele(dirp); 13749ec7b004SRick Macklem } 13759ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 13769ec7b004SRick Macklem acl_free(aclp); 13779ec7b004SRick Macklem #endif 13789ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 13799ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 13809ec7b004SRick Macklem &diraft); 1381a9285ae5SZack Kirsch goto out; 13829ec7b004SRick Macklem } 13839ec7b004SRick Macklem if (dirp) 138490d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); 13859ec7b004SRick Macklem 13869ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) { 13879ec7b004SRick Macklem if (vtyp == VDIR) { 13889ec7b004SRick Macklem nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, 13899ec7b004SRick Macklem &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p, 13909ec7b004SRick Macklem exp); 13919ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 13929ec7b004SRick Macklem acl_free(aclp); 13939ec7b004SRick Macklem #endif 1394a9285ae5SZack Kirsch goto out; 13959ec7b004SRick Macklem } else if (vtyp == VLNK) { 13969ec7b004SRick Macklem nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 13979ec7b004SRick Macklem &dirfor, &diraft, &diraft_ret, &attrbits, 13989ec7b004SRick Macklem aclp, p, exp, pathcp, pathlen); 13999ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 14009ec7b004SRick Macklem acl_free(aclp); 14019ec7b004SRick Macklem #endif 1402222daa42SConrad Meyer free(pathcp, M_TEMP); 1403a9285ae5SZack Kirsch goto out; 14049ec7b004SRick Macklem } 14059ec7b004SRick Macklem } 14069ec7b004SRick Macklem 14079ec7b004SRick Macklem nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p); 14089ec7b004SRick Macklem if (!nd->nd_repstat) { 14099ec7b004SRick Macklem vp = named.ni_vp; 14109ec7b004SRick Macklem nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp); 14119ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 14129ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat) 141390d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, 141490d2dfabSRick Macklem NULL); 141581f78d99SRick Macklem if (vpp != NULL && nd->nd_repstat == 0) { 1416b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 14179ec7b004SRick Macklem *vpp = vp; 141881f78d99SRick Macklem } else 14199ec7b004SRick Macklem vput(vp); 14209ec7b004SRick Macklem } 14219ec7b004SRick Macklem 142290d2dfabSRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 14239ec7b004SRick Macklem vrele(dirp); 14249ec7b004SRick Macklem if (!nd->nd_repstat) { 14259ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 14269ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 14279ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 14289ec7b004SRick Macklem } else { 14299ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 14309ec7b004SRick Macklem *tl++ = newnfs_false; 14319ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 14329ec7b004SRick Macklem tl += 2; 14339ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 14349ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &attrbits); 14359ec7b004SRick Macklem } 14369ec7b004SRick Macklem } 14379ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 14389ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 14399ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 14409ec7b004SRick Macklem acl_free(aclp); 14419ec7b004SRick Macklem #endif 1442a9285ae5SZack Kirsch 1443a9285ae5SZack Kirsch out: 1444a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 14459ec7b004SRick Macklem return (0); 14469ec7b004SRick Macklem nfsmout: 14479ec7b004SRick Macklem vrele(dp); 14489ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 14499ec7b004SRick Macklem acl_free(aclp); 14509ec7b004SRick Macklem #endif 14519ec7b004SRick Macklem if (bufp) 14529ec7b004SRick Macklem nfsvno_relpathbuf(&named); 14539ec7b004SRick Macklem if (pathcp) 1454222daa42SConrad Meyer free(pathcp, M_TEMP); 1455a9285ae5SZack Kirsch 1456a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 14579ec7b004SRick Macklem return (error); 14589ec7b004SRick Macklem } 14599ec7b004SRick Macklem 14609ec7b004SRick Macklem /* 14619ec7b004SRick Macklem * nfs remove service 14629ec7b004SRick Macklem */ 1463b9cc3262SRyan Moeller int 14649ec7b004SRick Macklem nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram, 1465af444b18SEdward Tomasz Napierala vnode_t dp, struct nfsexstuff *exp) 14669ec7b004SRick Macklem { 14679ec7b004SRick Macklem struct nameidata named; 14689ec7b004SRick Macklem u_int32_t *tl; 1469a9285ae5SZack Kirsch int error = 0, dirfor_ret = 1, diraft_ret = 1; 14709ec7b004SRick Macklem vnode_t dirp = NULL; 14719ec7b004SRick Macklem struct nfsvattr dirfor, diraft; 14729ec7b004SRick Macklem char *bufp; 14739ec7b004SRick Macklem u_long *hashp; 1474af444b18SEdward Tomasz Napierala struct thread *p = curthread; 14759ec7b004SRick Macklem 14769ec7b004SRick Macklem if (nd->nd_repstat) { 14779ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1478a9285ae5SZack Kirsch goto out; 14799ec7b004SRick Macklem } 14809ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE, 14819ec7b004SRick Macklem LOCKPARENT | LOCKLEAF); 14829ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 14839ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 14849ec7b004SRick Macklem if (error) { 14859ec7b004SRick Macklem vput(dp); 14869ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1487a9285ae5SZack Kirsch goto out; 14889ec7b004SRick Macklem } 14899ec7b004SRick Macklem if (!nd->nd_repstat) { 14909ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 14919ec7b004SRick Macklem } else { 14929ec7b004SRick Macklem vput(dp); 14939ec7b004SRick Macklem nfsvno_relpathbuf(&named); 14949ec7b004SRick Macklem } 14959ec7b004SRick Macklem if (dirp) { 14969ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) { 149790d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 149890d2dfabSRick Macklem NULL); 14999ec7b004SRick Macklem } else { 15009ec7b004SRick Macklem vrele(dirp); 15019ec7b004SRick Macklem dirp = NULL; 15029ec7b004SRick Macklem } 15039ec7b004SRick Macklem } 15049ec7b004SRick Macklem if (!nd->nd_repstat) { 15059ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 15069ec7b004SRick Macklem if (vnode_vtype(named.ni_vp) == VDIR) 15079ec7b004SRick Macklem nd->nd_repstat = nfsvno_rmdirsub(&named, 1, 15089ec7b004SRick Macklem nd->nd_cred, p, exp); 15099ec7b004SRick Macklem else 15109ec7b004SRick Macklem nd->nd_repstat = nfsvno_removesub(&named, 1, 15119ec7b004SRick Macklem nd->nd_cred, p, exp); 15129ec7b004SRick Macklem } else if (nd->nd_procnum == NFSPROC_RMDIR) { 15139ec7b004SRick Macklem nd->nd_repstat = nfsvno_rmdirsub(&named, 0, 15149ec7b004SRick Macklem nd->nd_cred, p, exp); 15159ec7b004SRick Macklem } else { 15169ec7b004SRick Macklem nd->nd_repstat = nfsvno_removesub(&named, 0, 15179ec7b004SRick Macklem nd->nd_cred, p, exp); 15189ec7b004SRick Macklem } 15199ec7b004SRick Macklem } 15209ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) { 15219ec7b004SRick Macklem if (dirp) { 152290d2dfabSRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, 152390d2dfabSRick Macklem NULL); 15249ec7b004SRick Macklem vrele(dirp); 15259ec7b004SRick Macklem } 15269ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 15279ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 15289ec7b004SRick Macklem &diraft); 15299ec7b004SRick Macklem } else if (!nd->nd_repstat) { 15309ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 15319ec7b004SRick Macklem *tl++ = newnfs_false; 15329ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 15339ec7b004SRick Macklem tl += 2; 15349ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 15359ec7b004SRick Macklem } 15369ec7b004SRick Macklem } 1537a9285ae5SZack Kirsch 1538a9285ae5SZack Kirsch out: 1539a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1540a9285ae5SZack Kirsch return (error); 15419ec7b004SRick Macklem } 15429ec7b004SRick Macklem 15439ec7b004SRick Macklem /* 15449ec7b004SRick Macklem * nfs rename service 15459ec7b004SRick Macklem */ 1546b9cc3262SRyan Moeller int 15479ec7b004SRick Macklem nfsrvd_rename(struct nfsrv_descript *nd, int isdgram, 1548af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t todp, struct nfsexstuff *exp, struct nfsexstuff *toexp) 15499ec7b004SRick Macklem { 15509ec7b004SRick Macklem u_int32_t *tl; 1551a9285ae5SZack Kirsch int error = 0, fdirfor_ret = 1, fdiraft_ret = 1; 15529ec7b004SRick Macklem int tdirfor_ret = 1, tdiraft_ret = 1; 15539ec7b004SRick Macklem struct nameidata fromnd, tond; 15549ec7b004SRick Macklem vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL; 15559ec7b004SRick Macklem struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft; 15569ec7b004SRick Macklem struct nfsexstuff tnes; 15579ec7b004SRick Macklem struct nfsrvfh tfh; 15589ec7b004SRick Macklem char *bufp, *tbufp = NULL; 15599ec7b004SRick Macklem u_long *hashp; 15606b3dfc6aSRick Macklem fhandle_t fh; 1561af444b18SEdward Tomasz Napierala struct thread *p = curthread; 15629ec7b004SRick Macklem 15639ec7b004SRick Macklem if (nd->nd_repstat) { 15649ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 15659ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 1566a9285ae5SZack Kirsch goto out; 15679ec7b004SRick Macklem } 15689ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV2)) 156990d2dfabSRick Macklem fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL); 15709ec7b004SRick Macklem tond.ni_cnd.cn_nameiop = 0; 15719ec7b004SRick Macklem tond.ni_startdir = NULL; 15729ec7b004SRick Macklem NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART); 15739ec7b004SRick Macklem nfsvno_setpathbuf(&fromnd, &bufp, &hashp); 15749ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen); 15759ec7b004SRick Macklem if (error) { 15769ec7b004SRick Macklem vput(dp); 15779ec7b004SRick Macklem if (todp) 15789ec7b004SRick Macklem vrele(todp); 15799ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 1580a9285ae5SZack Kirsch goto out; 15819ec7b004SRick Macklem } 158225bfde79SXin LI /* 158325bfde79SXin LI * Unlock dp in this code section, so it is unlocked before 158425bfde79SXin LI * tdp gets locked. This avoids a potential LOR if tdp is the 158525bfde79SXin LI * parent directory of dp. 158625bfde79SXin LI */ 15879ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 15889ec7b004SRick Macklem tdp = todp; 15899ec7b004SRick Macklem tnes = *toexp; 159025bfde79SXin LI if (dp != tdp) { 1591b249ce48SMateusz Guzik NFSVOPUNLOCK(dp); 159290d2dfabSRick Macklem /* Might lock tdp. */ 159390d2dfabSRick Macklem tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0, 159490d2dfabSRick Macklem NULL); 159525bfde79SXin LI } else { 159690d2dfabSRick Macklem tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1, 159790d2dfabSRick Macklem NULL); 1598b249ce48SMateusz Guzik NFSVOPUNLOCK(dp); 159925bfde79SXin LI } 16009ec7b004SRick Macklem } else { 16016b3dfc6aSRick Macklem tfh.nfsrvfh_len = 0; 16029ec7b004SRick Macklem error = nfsrv_mtofh(nd, &tfh); 16036b3dfc6aSRick Macklem if (error == 0) 16046b3dfc6aSRick Macklem error = nfsvno_getfh(dp, &fh, p); 16059ec7b004SRick Macklem if (error) { 16069ec7b004SRick Macklem vput(dp); 16079ec7b004SRick Macklem /* todp is always NULL except NFSv4 */ 16089ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 1609a9285ae5SZack Kirsch goto out; 16109ec7b004SRick Macklem } 16116b3dfc6aSRick Macklem 16126b3dfc6aSRick Macklem /* If this is the same file handle, just VREF() the vnode. */ 16136b3dfc6aSRick Macklem if (tfh.nfsrvfh_len == NFSX_MYFH && 16146b3dfc6aSRick Macklem !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) { 16156b3dfc6aSRick Macklem VREF(dp); 16166b3dfc6aSRick Macklem tdp = dp; 16176b3dfc6aSRick Macklem tnes = *exp; 161890d2dfabSRick Macklem tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1, 161990d2dfabSRick Macklem NULL); 1620b249ce48SMateusz Guzik NFSVOPUNLOCK(dp); 16216b3dfc6aSRick Macklem } else { 1622b249ce48SMateusz Guzik NFSVOPUNLOCK(dp); 16236b3dfc6aSRick Macklem nd->nd_cred->cr_uid = nd->nd_saveduid; 16246b3dfc6aSRick Macklem nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL, 16255edc9102SEdward Tomasz Napierala 0); /* Locks tdp. */ 16266b3dfc6aSRick Macklem if (tdp) { 162790d2dfabSRick Macklem tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, 162890d2dfabSRick Macklem p, 1, NULL); 1629b249ce48SMateusz Guzik NFSVOPUNLOCK(tdp); 16309ec7b004SRick Macklem } 16319ec7b004SRick Macklem } 16326b3dfc6aSRick Macklem } 16339ec7b004SRick Macklem NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART); 16349ec7b004SRick Macklem nfsvno_setpathbuf(&tond, &tbufp, &hashp); 16359ec7b004SRick Macklem if (!nd->nd_repstat) { 16369ec7b004SRick Macklem error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen); 16379ec7b004SRick Macklem if (error) { 16388974bc2fSRick Macklem if (tdp) 16399ec7b004SRick Macklem vrele(tdp); 164025bfde79SXin LI vrele(dp); 16419ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 16429ec7b004SRick Macklem nfsvno_relpathbuf(&tond); 1643a9285ae5SZack Kirsch goto out; 16449ec7b004SRick Macklem } 16459ec7b004SRick Macklem } 16469ec7b004SRick Macklem if (nd->nd_repstat) { 16479ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 16489ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 16499ec7b004SRick Macklem &fdiraft); 16509ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 16519ec7b004SRick Macklem &tdiraft); 16529ec7b004SRick Macklem } 16538974bc2fSRick Macklem if (tdp) 16549ec7b004SRick Macklem vrele(tdp); 165525bfde79SXin LI vrele(dp); 16569ec7b004SRick Macklem nfsvno_relpathbuf(&fromnd); 16579ec7b004SRick Macklem nfsvno_relpathbuf(&tond); 1658a9285ae5SZack Kirsch goto out; 16599ec7b004SRick Macklem } 16609ec7b004SRick Macklem 16619ec7b004SRick Macklem /* 16629ec7b004SRick Macklem * Done parsing, now down to business. 16639ec7b004SRick Macklem */ 166425bfde79SXin LI nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp); 16659ec7b004SRick Macklem if (nd->nd_repstat) { 16669ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 16679ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 16689ec7b004SRick Macklem &fdiraft); 16699ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 16709ec7b004SRick Macklem &tdiraft); 16719ec7b004SRick Macklem } 16729ec7b004SRick Macklem if (fdirp) 16739ec7b004SRick Macklem vrele(fdirp); 16748974bc2fSRick Macklem if (tdp) 16759ec7b004SRick Macklem vrele(tdp); 16769ec7b004SRick Macklem nfsvno_relpathbuf(&tond); 1677a9285ae5SZack Kirsch goto out; 16789ec7b004SRick Macklem } 16799ec7b004SRick Macklem if (vnode_vtype(fromnd.ni_vp) == VDIR) 16809ec7b004SRick Macklem tond.ni_cnd.cn_flags |= WILLBEDIR; 16819ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp); 16829ec7b004SRick Macklem nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat, 16839ec7b004SRick Macklem nd->nd_flag, nd->nd_cred, p); 16849ec7b004SRick Macklem if (fdirp) 168590d2dfabSRick Macklem fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL); 16869ec7b004SRick Macklem if (tdirp) 168790d2dfabSRick Macklem tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL); 16889ec7b004SRick Macklem if (fdirp) 16899ec7b004SRick Macklem vrele(fdirp); 16909ec7b004SRick Macklem if (tdirp) 16919ec7b004SRick Macklem vrele(tdirp); 16929ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 16939ec7b004SRick Macklem nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 16949ec7b004SRick Macklem nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 16959ec7b004SRick Macklem } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 16969ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED); 16979ec7b004SRick Macklem *tl++ = newnfs_false; 16989ec7b004SRick Macklem txdr_hyper(fdirfor.na_filerev, tl); 16999ec7b004SRick Macklem tl += 2; 17009ec7b004SRick Macklem txdr_hyper(fdiraft.na_filerev, tl); 17019ec7b004SRick Macklem tl += 2; 17029ec7b004SRick Macklem *tl++ = newnfs_false; 17039ec7b004SRick Macklem txdr_hyper(tdirfor.na_filerev, tl); 17049ec7b004SRick Macklem tl += 2; 17059ec7b004SRick Macklem txdr_hyper(tdiraft.na_filerev, tl); 17069ec7b004SRick Macklem } 1707a9285ae5SZack Kirsch 1708a9285ae5SZack Kirsch out: 1709a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1710a9285ae5SZack Kirsch return (error); 17119ec7b004SRick Macklem } 17129ec7b004SRick Macklem 17139ec7b004SRick Macklem /* 17149ec7b004SRick Macklem * nfs link service 17159ec7b004SRick Macklem */ 1716b9cc3262SRyan Moeller int 17179ec7b004SRick Macklem nfsrvd_link(struct nfsrv_descript *nd, int isdgram, 1718af444b18SEdward Tomasz Napierala vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp) 17199ec7b004SRick Macklem { 17209ec7b004SRick Macklem struct nameidata named; 17219ec7b004SRick Macklem u_int32_t *tl; 17229ec7b004SRick Macklem int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1; 17239ec7b004SRick Macklem vnode_t dirp = NULL, dp = NULL; 17249ec7b004SRick Macklem struct nfsvattr dirfor, diraft, at; 17259ec7b004SRick Macklem struct nfsexstuff tnes; 17269ec7b004SRick Macklem struct nfsrvfh dfh; 17279ec7b004SRick Macklem char *bufp; 17289ec7b004SRick Macklem u_long *hashp; 1729af444b18SEdward Tomasz Napierala struct thread *p = curthread; 17309ec7b004SRick Macklem 17319ec7b004SRick Macklem if (nd->nd_repstat) { 17329ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 17339ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1734a9285ae5SZack Kirsch goto out; 17359ec7b004SRick Macklem } 1736b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 17379ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) { 17389ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) 17399ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 17409ec7b004SRick Macklem else 17419ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 17429ec7b004SRick Macklem if (tovp) 17439ec7b004SRick Macklem vrele(tovp); 17449ec7b004SRick Macklem } 17459ec7b004SRick Macklem if (!nd->nd_repstat) { 17469ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV4) { 17479ec7b004SRick Macklem dp = tovp; 17489ec7b004SRick Macklem tnes = *toexp; 17499ec7b004SRick Macklem } else { 17509ec7b004SRick Macklem error = nfsrv_mtofh(nd, &dfh); 17519ec7b004SRick Macklem if (error) { 17529ec7b004SRick Macklem vrele(vp); 17539ec7b004SRick Macklem /* tovp is always NULL unless NFSv4 */ 1754a9285ae5SZack Kirsch goto out; 17559ec7b004SRick Macklem } 17565edc9102SEdward Tomasz Napierala nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0); 17579ec7b004SRick Macklem if (dp) 1758b249ce48SMateusz Guzik NFSVOPUNLOCK(dp); 17599ec7b004SRick Macklem } 17609ec7b004SRick Macklem } 1761f61786cbSRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 17626c21f6edSKonstantin Belousov LOCKPARENT | SAVENAME | NOCACHE); 17639ec7b004SRick Macklem if (!nd->nd_repstat) { 17649ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 17659ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 17669ec7b004SRick Macklem if (error) { 17679ec7b004SRick Macklem vrele(vp); 17688974bc2fSRick Macklem if (dp) 17699ec7b004SRick Macklem vrele(dp); 17709ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1771a9285ae5SZack Kirsch goto out; 17729ec7b004SRick Macklem } 17739ec7b004SRick Macklem if (!nd->nd_repstat) { 17749ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes, 17759ec7b004SRick Macklem p, &dirp); 17769ec7b004SRick Macklem } else { 17779ec7b004SRick Macklem if (dp) 17789ec7b004SRick Macklem vrele(dp); 17799ec7b004SRick Macklem nfsvno_relpathbuf(&named); 17809ec7b004SRick Macklem } 17819ec7b004SRick Macklem } 17829ec7b004SRick Macklem if (dirp) { 17839ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 17849ec7b004SRick Macklem vrele(dirp); 17859ec7b004SRick Macklem dirp = NULL; 17869ec7b004SRick Macklem } else { 178790d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 178890d2dfabSRick Macklem NULL); 17899ec7b004SRick Macklem } 17909ec7b004SRick Macklem } 17919ec7b004SRick Macklem if (!nd->nd_repstat) 17929ec7b004SRick Macklem nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp); 17939ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 179490d2dfabSRick Macklem getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL); 17959ec7b004SRick Macklem if (dirp) { 179690d2dfabSRick Macklem diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 17979ec7b004SRick Macklem vrele(dirp); 17989ec7b004SRick Macklem } 17999ec7b004SRick Macklem vrele(vp); 18009ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 18019ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 18029ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 18039ec7b004SRick Macklem } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 18049ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 18059ec7b004SRick Macklem *tl++ = newnfs_false; 18069ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 18079ec7b004SRick Macklem tl += 2; 18089ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 18099ec7b004SRick Macklem } 1810a9285ae5SZack Kirsch 1811a9285ae5SZack Kirsch out: 1812a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1813a9285ae5SZack Kirsch return (error); 18149ec7b004SRick Macklem } 18159ec7b004SRick Macklem 18169ec7b004SRick Macklem /* 18179ec7b004SRick Macklem * nfs symbolic link service 18189ec7b004SRick Macklem */ 1819b9cc3262SRyan Moeller int 18209ec7b004SRick Macklem nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram, 1821af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 18229ec7b004SRick Macklem { 18239ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 18249ec7b004SRick Macklem struct nameidata named; 1825a9285ae5SZack Kirsch int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 18269ec7b004SRick Macklem vnode_t dirp = NULL; 18279ec7b004SRick Macklem char *bufp, *pathcp = NULL; 18289ec7b004SRick Macklem u_long *hashp; 1829af444b18SEdward Tomasz Napierala struct thread *p = curthread; 18309ec7b004SRick Macklem 18319ec7b004SRick Macklem if (nd->nd_repstat) { 18329ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1833a9285ae5SZack Kirsch goto out; 18349ec7b004SRick Macklem } 18359ec7b004SRick Macklem if (vpp) 18369ec7b004SRick Macklem *vpp = NULL; 18379ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 18389ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 18396c21f6edSKonstantin Belousov LOCKPARENT | SAVESTART | NOCACHE); 18409ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 18419ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 18429ec7b004SRick Macklem if (!error && !nd->nd_repstat) 18439ec7b004SRick Macklem error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen); 18449ec7b004SRick Macklem if (error) { 18459ec7b004SRick Macklem vrele(dp); 18469ec7b004SRick Macklem nfsvno_relpathbuf(&named); 1847a9285ae5SZack Kirsch goto out; 18489ec7b004SRick Macklem } 18499ec7b004SRick Macklem if (!nd->nd_repstat) { 18509ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 18519ec7b004SRick Macklem } else { 18529ec7b004SRick Macklem vrele(dp); 18539ec7b004SRick Macklem nfsvno_relpathbuf(&named); 18549ec7b004SRick Macklem } 18559ec7b004SRick Macklem if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 18569ec7b004SRick Macklem vrele(dirp); 18579ec7b004SRick Macklem dirp = NULL; 18589ec7b004SRick Macklem } 18599ec7b004SRick Macklem 18609ec7b004SRick Macklem /* 18619ec7b004SRick Macklem * And call nfsrvd_symlinksub() to do the common code. It will 18629ec7b004SRick Macklem * return EBADRPC upon a parsing error, 0 otherwise. 18639ec7b004SRick Macklem */ 18649ec7b004SRick Macklem if (!nd->nd_repstat) { 18659ec7b004SRick Macklem if (dirp != NULL) 186690d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 186790d2dfabSRick Macklem NULL); 18689ec7b004SRick Macklem nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 18699ec7b004SRick Macklem &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp, 18709ec7b004SRick Macklem pathcp, pathlen); 18719ec7b004SRick Macklem } else if (dirp != NULL) { 187290d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); 18739ec7b004SRick Macklem vrele(dirp); 18749ec7b004SRick Macklem } 18759ec7b004SRick Macklem if (pathcp) 1876222daa42SConrad Meyer free(pathcp, M_TEMP); 18779ec7b004SRick Macklem 18789ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 18799ec7b004SRick Macklem if (!nd->nd_repstat) { 18809ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 18819ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 18829ec7b004SRick Macklem } 18839ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 18849ec7b004SRick Macklem } 1885a9285ae5SZack Kirsch 1886a9285ae5SZack Kirsch out: 1887a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 1888a9285ae5SZack Kirsch return (error); 18899ec7b004SRick Macklem } 18909ec7b004SRick Macklem 18919ec7b004SRick Macklem /* 18929ec7b004SRick Macklem * Common code for creating a symbolic link. 18939ec7b004SRick Macklem */ 18949ec7b004SRick Macklem static void 18959ec7b004SRick Macklem nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 18969ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 18979ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 18989ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, 18999ec7b004SRick Macklem NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 19009ec7b004SRick Macklem int pathlen) 19019ec7b004SRick Macklem { 19029ec7b004SRick Macklem u_int32_t *tl; 19039ec7b004SRick Macklem 19049ec7b004SRick Macklem nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen, 19059ec7b004SRick Macklem !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp); 19069ec7b004SRick Macklem if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) { 19079ec7b004SRick Macklem nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp); 19089ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 19099ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p); 19109ec7b004SRick Macklem if (!nd->nd_repstat) 19119ec7b004SRick Macklem nd->nd_repstat = nfsvno_getattr(ndp->ni_vp, 191290d2dfabSRick Macklem nvap, nd, p, 1, NULL); 19139ec7b004SRick Macklem } 191481f78d99SRick Macklem if (vpp != NULL && nd->nd_repstat == 0) { 1915b249ce48SMateusz Guzik NFSVOPUNLOCK(ndp->ni_vp); 19169ec7b004SRick Macklem *vpp = ndp->ni_vp; 191781f78d99SRick Macklem } else 19189ec7b004SRick Macklem vput(ndp->ni_vp); 19199ec7b004SRick Macklem } 19209ec7b004SRick Macklem if (dirp) { 192190d2dfabSRick Macklem *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL); 19229ec7b004SRick Macklem vrele(dirp); 19239ec7b004SRick Macklem } 19249ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 19259ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 19269ec7b004SRick Macklem *tl++ = newnfs_false; 19279ec7b004SRick Macklem txdr_hyper(dirforp->na_filerev, tl); 19289ec7b004SRick Macklem tl += 2; 19299ec7b004SRick Macklem txdr_hyper(diraftp->na_filerev, tl); 19309ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, attrbitp); 19319ec7b004SRick Macklem } 1932a9285ae5SZack Kirsch 1933a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 19349ec7b004SRick Macklem } 19359ec7b004SRick Macklem 19369ec7b004SRick Macklem /* 19379ec7b004SRick Macklem * nfs mkdir service 19389ec7b004SRick Macklem */ 1939b9cc3262SRyan Moeller int 19409ec7b004SRick Macklem nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram, 1941af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 19429ec7b004SRick Macklem { 19439ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 19449ec7b004SRick Macklem struct nameidata named; 19459ec7b004SRick Macklem u_int32_t *tl; 1946a9285ae5SZack Kirsch int error = 0, dirfor_ret = 1, diraft_ret = 1; 19479ec7b004SRick Macklem vnode_t dirp = NULL; 19489ec7b004SRick Macklem char *bufp; 19499ec7b004SRick Macklem u_long *hashp; 1950af444b18SEdward Tomasz Napierala struct thread *p = curthread; 19519ec7b004SRick Macklem 19529ec7b004SRick Macklem if (nd->nd_repstat) { 19539ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1954a9285ae5SZack Kirsch goto out; 19559ec7b004SRick Macklem } 1956f61786cbSRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 19576c21f6edSKonstantin Belousov LOCKPARENT | SAVENAME | NOCACHE); 19589ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 19599ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1960a9285ae5SZack Kirsch if (error) 1961a9285ae5SZack Kirsch goto nfsmout; 19629ec7b004SRick Macklem if (!nd->nd_repstat) { 19639ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 19649ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 1965d8a5961fSMarcelo Araujo error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p); 1966a9285ae5SZack Kirsch if (error) 1967a9285ae5SZack Kirsch goto nfsmout; 19689ec7b004SRick Macklem } else { 19699ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 19709ec7b004SRick Macklem nva.na_mode = nfstov_mode(*tl++); 19719ec7b004SRick Macklem } 19729ec7b004SRick Macklem } 19739ec7b004SRick Macklem if (!nd->nd_repstat) { 19749ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 19759ec7b004SRick Macklem } else { 19769ec7b004SRick Macklem vrele(dp); 19779ec7b004SRick Macklem nfsvno_relpathbuf(&named); 19789ec7b004SRick Macklem } 19799ec7b004SRick Macklem if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 19809ec7b004SRick Macklem vrele(dirp); 19819ec7b004SRick Macklem dirp = NULL; 19829ec7b004SRick Macklem } 19839ec7b004SRick Macklem if (nd->nd_repstat) { 19849ec7b004SRick Macklem if (dirp != NULL) { 198590d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 198690d2dfabSRick Macklem NULL); 19879ec7b004SRick Macklem vrele(dirp); 19889ec7b004SRick Macklem } 19899ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 19909ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 19919ec7b004SRick Macklem &diraft); 1992a9285ae5SZack Kirsch goto out; 19939ec7b004SRick Macklem } 19949ec7b004SRick Macklem if (dirp != NULL) 199590d2dfabSRick Macklem dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); 19969ec7b004SRick Macklem 19979ec7b004SRick Macklem /* 19989ec7b004SRick Macklem * Call nfsrvd_mkdirsub() for the code common to V4 as well. 19999ec7b004SRick Macklem */ 20009ec7b004SRick Macklem nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft, 20019ec7b004SRick Macklem &diraft_ret, NULL, NULL, p, exp); 20029ec7b004SRick Macklem 20039ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 20049ec7b004SRick Macklem if (!nd->nd_repstat) { 20059ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 20069ec7b004SRick Macklem nfsrv_postopattr(nd, 0, &nva); 20079ec7b004SRick Macklem } 20089ec7b004SRick Macklem nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 20099ec7b004SRick Macklem } else if (!nd->nd_repstat) { 20109ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 20119ec7b004SRick Macklem nfsrv_fillattr(nd, &nva); 20129ec7b004SRick Macklem } 2013a9285ae5SZack Kirsch 2014a9285ae5SZack Kirsch out: 2015a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 20169ec7b004SRick Macklem return (0); 20179ec7b004SRick Macklem nfsmout: 20189ec7b004SRick Macklem vrele(dp); 20199ec7b004SRick Macklem nfsvno_relpathbuf(&named); 2020a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 20219ec7b004SRick Macklem return (error); 20229ec7b004SRick Macklem } 20239ec7b004SRick Macklem 20249ec7b004SRick Macklem /* 20259ec7b004SRick Macklem * Code common to mkdir for V2,3 and 4. 20269ec7b004SRick Macklem */ 20279ec7b004SRick Macklem static void 20289ec7b004SRick Macklem nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 20299ec7b004SRick Macklem struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 20309ec7b004SRick Macklem vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 20319ec7b004SRick Macklem int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 20329ec7b004SRick Macklem NFSPROC_T *p, struct nfsexstuff *exp) 20339ec7b004SRick Macklem { 20349ec7b004SRick Macklem vnode_t vp; 20359ec7b004SRick Macklem u_int32_t *tl; 20369ec7b004SRick Macklem 20379ec7b004SRick Macklem NFSVNO_SETATTRVAL(nvap, type, VDIR); 20389ec7b004SRick Macklem nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid, 20399ec7b004SRick Macklem nd->nd_cred, p, exp); 20409ec7b004SRick Macklem if (!nd->nd_repstat) { 20419ec7b004SRick Macklem vp = ndp->ni_vp; 20429ec7b004SRick Macklem nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp); 20439ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 20449ec7b004SRick Macklem if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 204590d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1, 204690d2dfabSRick Macklem NULL); 20479ec7b004SRick Macklem if (vpp && !nd->nd_repstat) { 2048b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 20499ec7b004SRick Macklem *vpp = vp; 20509ec7b004SRick Macklem } else { 20519ec7b004SRick Macklem vput(vp); 20529ec7b004SRick Macklem } 20539ec7b004SRick Macklem } 20549ec7b004SRick Macklem if (dirp) { 205590d2dfabSRick Macklem *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL); 20569ec7b004SRick Macklem vrele(dirp); 20579ec7b004SRick Macklem } 20589ec7b004SRick Macklem if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 20599ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 20609ec7b004SRick Macklem *tl++ = newnfs_false; 20619ec7b004SRick Macklem txdr_hyper(dirforp->na_filerev, tl); 20629ec7b004SRick Macklem tl += 2; 20639ec7b004SRick Macklem txdr_hyper(diraftp->na_filerev, tl); 20649ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, attrbitp); 20659ec7b004SRick Macklem } 2066a9285ae5SZack Kirsch 2067a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 20689ec7b004SRick Macklem } 20699ec7b004SRick Macklem 20709ec7b004SRick Macklem /* 20719ec7b004SRick Macklem * nfs commit service 20729ec7b004SRick Macklem */ 2073b9cc3262SRyan Moeller int 20749ec7b004SRick Macklem nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram, 2075af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 20769ec7b004SRick Macklem { 20779ec7b004SRick Macklem struct nfsvattr bfor, aft; 20789ec7b004SRick Macklem u_int32_t *tl; 20799ec7b004SRick Macklem int error = 0, for_ret = 1, aft_ret = 1, cnt; 20809ec7b004SRick Macklem u_int64_t off; 2081af444b18SEdward Tomasz Napierala struct thread *p = curthread; 20829ec7b004SRick Macklem 20839ec7b004SRick Macklem if (nd->nd_repstat) { 20849ec7b004SRick Macklem nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 2085a9285ae5SZack Kirsch goto out; 20869ec7b004SRick Macklem } 2087d8a5961fSMarcelo Araujo 2088d8a5961fSMarcelo Araujo /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */ 2089d8a5961fSMarcelo Araujo if (vp->v_type != VREG) { 2090d8a5961fSMarcelo Araujo if (nd->nd_flag & ND_NFSV3) 2091d8a5961fSMarcelo Araujo error = NFSERR_NOTSUPP; 2092d8a5961fSMarcelo Araujo else 2093d8a5961fSMarcelo Araujo error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL; 2094d8a5961fSMarcelo Araujo goto nfsmout; 2095d8a5961fSMarcelo Araujo } 20969ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2097d8a5961fSMarcelo Araujo 20989ec7b004SRick Macklem /* 20999ec7b004SRick Macklem * XXX At this time VOP_FSYNC() does not accept offset and byte 21009ec7b004SRick Macklem * count parameters, so these arguments are useless (someday maybe). 21019ec7b004SRick Macklem */ 21029ec7b004SRick Macklem off = fxdr_hyper(tl); 21039ec7b004SRick Macklem tl += 2; 21049ec7b004SRick Macklem cnt = fxdr_unsigned(int, *tl); 21059ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 210690d2dfabSRick Macklem for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL); 21079ec7b004SRick Macklem nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p); 21089ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) { 210990d2dfabSRick Macklem aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL); 21109ec7b004SRick Macklem nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 21119ec7b004SRick Macklem } 21129ec7b004SRick Macklem vput(vp); 21139ec7b004SRick Macklem if (!nd->nd_repstat) { 21149ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 21159ec7b004SRick Macklem *tl++ = txdr_unsigned(nfsboottime.tv_sec); 21169ec7b004SRick Macklem *tl = txdr_unsigned(nfsboottime.tv_usec); 21179ec7b004SRick Macklem } 2118a9285ae5SZack Kirsch 2119a9285ae5SZack Kirsch out: 2120a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 21219ec7b004SRick Macklem return (0); 21229ec7b004SRick Macklem nfsmout: 21239ec7b004SRick Macklem vput(vp); 2124a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 21259ec7b004SRick Macklem return (error); 21269ec7b004SRick Macklem } 21279ec7b004SRick Macklem 21289ec7b004SRick Macklem /* 21299ec7b004SRick Macklem * nfs statfs service 21309ec7b004SRick Macklem */ 2131b9cc3262SRyan Moeller int 21329ec7b004SRick Macklem nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram, 2133af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 21349ec7b004SRick Macklem { 21359ec7b004SRick Macklem struct statfs *sf; 21369ec7b004SRick Macklem u_int32_t *tl; 21379ec7b004SRick Macklem int getret = 1; 21389ec7b004SRick Macklem struct nfsvattr at; 21399ec7b004SRick Macklem u_quad_t tval; 2140af444b18SEdward Tomasz Napierala struct thread *p = curthread; 21419ec7b004SRick Macklem 21422f304845SKonstantin Belousov sf = NULL; 21439ec7b004SRick Macklem if (nd->nd_repstat) { 21449ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 2145a9285ae5SZack Kirsch goto out; 21469ec7b004SRick Macklem } 21472f304845SKonstantin Belousov sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 2148dfd233edSAttilio Rao nd->nd_repstat = nfsvno_statfs(vp, sf); 214990d2dfabSRick Macklem getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); 21509ec7b004SRick Macklem vput(vp); 21519ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV3) 21529ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 21539ec7b004SRick Macklem if (nd->nd_repstat) 2154a9285ae5SZack Kirsch goto out; 21559ec7b004SRick Macklem if (nd->nd_flag & ND_NFSV2) { 21569ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS); 21579ec7b004SRick Macklem *tl++ = txdr_unsigned(NFS_V2MAXDATA); 21589ec7b004SRick Macklem *tl++ = txdr_unsigned(sf->f_bsize); 21599ec7b004SRick Macklem *tl++ = txdr_unsigned(sf->f_blocks); 21609ec7b004SRick Macklem *tl++ = txdr_unsigned(sf->f_bfree); 21619ec7b004SRick Macklem *tl = txdr_unsigned(sf->f_bavail); 21629ec7b004SRick Macklem } else { 21639ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS); 21649ec7b004SRick Macklem tval = (u_quad_t)sf->f_blocks; 21659ec7b004SRick Macklem tval *= (u_quad_t)sf->f_bsize; 21669ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 21679ec7b004SRick Macklem tval = (u_quad_t)sf->f_bfree; 21689ec7b004SRick Macklem tval *= (u_quad_t)sf->f_bsize; 21699ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 21709ec7b004SRick Macklem tval = (u_quad_t)sf->f_bavail; 21719ec7b004SRick Macklem tval *= (u_quad_t)sf->f_bsize; 21729ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 21739ec7b004SRick Macklem tval = (u_quad_t)sf->f_files; 21749ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 21759ec7b004SRick Macklem tval = (u_quad_t)sf->f_ffree; 21769ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 21779ec7b004SRick Macklem tval = (u_quad_t)sf->f_ffree; 21789ec7b004SRick Macklem txdr_hyper(tval, tl); tl += 2; 21799ec7b004SRick Macklem *tl = 0; 21809ec7b004SRick Macklem } 2181a9285ae5SZack Kirsch 2182a9285ae5SZack Kirsch out: 21832f304845SKonstantin Belousov free(sf, M_STATFS); 2184a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 21859ec7b004SRick Macklem return (0); 21869ec7b004SRick Macklem } 21879ec7b004SRick Macklem 21889ec7b004SRick Macklem /* 21899ec7b004SRick Macklem * nfs fsinfo service 21909ec7b004SRick Macklem */ 2191b9cc3262SRyan Moeller int 21929ec7b004SRick Macklem nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram, 2193af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 21949ec7b004SRick Macklem { 21959ec7b004SRick Macklem u_int32_t *tl; 21969ec7b004SRick Macklem struct nfsfsinfo fs; 21979ec7b004SRick Macklem int getret = 1; 21989ec7b004SRick Macklem struct nfsvattr at; 2199af444b18SEdward Tomasz Napierala struct thread *p = curthread; 22009ec7b004SRick Macklem 22019ec7b004SRick Macklem if (nd->nd_repstat) { 22029ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 2203a9285ae5SZack Kirsch goto out; 22049ec7b004SRick Macklem } 220590d2dfabSRick Macklem getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); 22069ec7b004SRick Macklem nfsvno_getfs(&fs, isdgram); 22079ec7b004SRick Macklem vput(vp); 22089ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 22099ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO); 22109ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_rtmax); 22119ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_rtpref); 22129ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_rtmult); 22139ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_wtmax); 22149ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_wtpref); 22159ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_wtmult); 22169ec7b004SRick Macklem *tl++ = txdr_unsigned(fs.fs_dtpref); 22179ec7b004SRick Macklem txdr_hyper(fs.fs_maxfilesize, tl); 22189ec7b004SRick Macklem tl += 2; 22199ec7b004SRick Macklem txdr_nfsv3time(&fs.fs_timedelta, tl); 22209ec7b004SRick Macklem tl += 2; 22219ec7b004SRick Macklem *tl = txdr_unsigned(fs.fs_properties); 2222a9285ae5SZack Kirsch 2223a9285ae5SZack Kirsch out: 2224a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 22259ec7b004SRick Macklem return (0); 22269ec7b004SRick Macklem } 22279ec7b004SRick Macklem 22289ec7b004SRick Macklem /* 22299ec7b004SRick Macklem * nfs pathconf service 22309ec7b004SRick Macklem */ 2231b9cc3262SRyan Moeller int 22329ec7b004SRick Macklem nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram, 2233af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 22349ec7b004SRick Macklem { 22359ec7b004SRick Macklem struct nfsv3_pathconf *pc; 22369ec7b004SRick Macklem int getret = 1; 2237b1288166SJohn Baldwin long linkmax, namemax, chownres, notrunc; 22389ec7b004SRick Macklem struct nfsvattr at; 2239af444b18SEdward Tomasz Napierala struct thread *p = curthread; 22409ec7b004SRick Macklem 22419ec7b004SRick Macklem if (nd->nd_repstat) { 22429ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 2243a9285ae5SZack Kirsch goto out; 22449ec7b004SRick Macklem } 22459ec7b004SRick Macklem nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax, 22469ec7b004SRick Macklem nd->nd_cred, p); 22479ec7b004SRick Macklem if (!nd->nd_repstat) 22489ec7b004SRick Macklem nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax, 22499ec7b004SRick Macklem nd->nd_cred, p); 22509ec7b004SRick Macklem if (!nd->nd_repstat) 22519ec7b004SRick Macklem nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED, 22529ec7b004SRick Macklem &chownres, nd->nd_cred, p); 22539ec7b004SRick Macklem if (!nd->nd_repstat) 22549ec7b004SRick Macklem nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc, 22559ec7b004SRick Macklem nd->nd_cred, p); 225690d2dfabSRick Macklem getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); 22579ec7b004SRick Macklem vput(vp); 22589ec7b004SRick Macklem nfsrv_postopattr(nd, getret, &at); 22599ec7b004SRick Macklem if (!nd->nd_repstat) { 22609ec7b004SRick Macklem NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); 22619ec7b004SRick Macklem pc->pc_linkmax = txdr_unsigned(linkmax); 22629ec7b004SRick Macklem pc->pc_namemax = txdr_unsigned(namemax); 22639ec7b004SRick Macklem pc->pc_notrunc = txdr_unsigned(notrunc); 22649ec7b004SRick Macklem pc->pc_chownrestricted = txdr_unsigned(chownres); 22659ec7b004SRick Macklem 22669ec7b004SRick Macklem /* 22679ec7b004SRick Macklem * These should probably be supported by VOP_PATHCONF(), but 22689ec7b004SRick Macklem * until msdosfs is exportable (why would you want to?), the 22699ec7b004SRick Macklem * Unix defaults should be ok. 22709ec7b004SRick Macklem */ 22719ec7b004SRick Macklem pc->pc_caseinsensitive = newnfs_false; 22729ec7b004SRick Macklem pc->pc_casepreserving = newnfs_true; 22739ec7b004SRick Macklem } 2274a9285ae5SZack Kirsch 2275a9285ae5SZack Kirsch out: 2276a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 22779ec7b004SRick Macklem return (0); 22789ec7b004SRick Macklem } 22799ec7b004SRick Macklem 22809ec7b004SRick Macklem /* 22819ec7b004SRick Macklem * nfsv4 lock service 22829ec7b004SRick Macklem */ 2283b9cc3262SRyan Moeller int 22849ec7b004SRick Macklem nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram, 2285af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 22869ec7b004SRick Macklem { 22879ec7b004SRick Macklem u_int32_t *tl; 22889ec7b004SRick Macklem int i; 22899ec7b004SRick Macklem struct nfsstate *stp = NULL; 22909ec7b004SRick Macklem struct nfslock *lop; 22919ec7b004SRick Macklem struct nfslockconflict cf; 22929ec7b004SRick Macklem int error = 0; 22939ec7b004SRick Macklem u_short flags = NFSLCK_LOCK, lflags; 22949ec7b004SRick Macklem u_int64_t offset, len; 22959ec7b004SRick Macklem nfsv4stateid_t stateid; 22969ec7b004SRick Macklem nfsquad_t clientid; 2297af444b18SEdward Tomasz Napierala struct thread *p = curthread; 22989ec7b004SRick Macklem 22999ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 23009ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 23019ec7b004SRick Macklem switch (i) { 23029ec7b004SRick Macklem case NFSV4LOCKT_READW: 23039ec7b004SRick Macklem flags |= NFSLCK_BLOCKING; 23049ec7b004SRick Macklem case NFSV4LOCKT_READ: 23059ec7b004SRick Macklem lflags = NFSLCK_READ; 23069ec7b004SRick Macklem break; 23079ec7b004SRick Macklem case NFSV4LOCKT_WRITEW: 23089ec7b004SRick Macklem flags |= NFSLCK_BLOCKING; 23099ec7b004SRick Macklem case NFSV4LOCKT_WRITE: 23109ec7b004SRick Macklem lflags = NFSLCK_WRITE; 23119ec7b004SRick Macklem break; 23129ec7b004SRick Macklem default: 23139ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 23149ec7b004SRick Macklem goto nfsmout; 231574b8d63dSPedro F. Giffuni } 23169ec7b004SRick Macklem if (*tl++ == newnfs_true) 23179ec7b004SRick Macklem flags |= NFSLCK_RECLAIM; 23189ec7b004SRick Macklem offset = fxdr_hyper(tl); 23199ec7b004SRick Macklem tl += 2; 23209ec7b004SRick Macklem len = fxdr_hyper(tl); 23219ec7b004SRick Macklem tl += 2; 23229ec7b004SRick Macklem if (*tl == newnfs_true) 23239ec7b004SRick Macklem flags |= NFSLCK_OPENTOLOCK; 23249ec7b004SRick Macklem if (flags & NFSLCK_OPENTOLOCK) { 23259ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID); 23269ec7b004SRick Macklem i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED))); 23272a45247cSRick Macklem if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 23282a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 23292a45247cSRick Macklem goto nfsmout; 23302a45247cSRick Macklem } 2331222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate) + i, 23329ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 23339ec7b004SRick Macklem stp->ls_ownerlen = i; 23349ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 23359ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(int, *tl++); 23369ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 23379ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 23389ec7b004SRick Macklem NFSX_STATEIDOTHER); 23399ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 234090d2dfabSRick Macklem 234190d2dfabSRick Macklem /* 234290d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set 234390d2dfabSRick Macklem * the stateid to the current stateid, if it is set. 234490d2dfabSRick Macklem */ 234590d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 && 234690d2dfabSRick Macklem stp->ls_stateid.seqid == 1 && 234790d2dfabSRick Macklem stp->ls_stateid.other[0] == 0 && 234890d2dfabSRick Macklem stp->ls_stateid.other[1] == 0 && 234990d2dfabSRick Macklem stp->ls_stateid.other[2] == 0) { 235090d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 235190d2dfabSRick Macklem stp->ls_stateid = nd->nd_curstateid; 235290d2dfabSRick Macklem stp->ls_stateid.seqid = 0; 235390d2dfabSRick Macklem } else { 235490d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 235590d2dfabSRick Macklem goto nfsmout; 235690d2dfabSRick Macklem } 235790d2dfabSRick Macklem } 235890d2dfabSRick Macklem 23599ec7b004SRick Macklem stp->ls_opentolockseq = fxdr_unsigned(int, *tl++); 23609ec7b004SRick Macklem clientid.lval[0] = *tl++; 23619ec7b004SRick Macklem clientid.lval[1] = *tl++; 2362c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2363c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2364c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2365c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2366c59e4cc3SRick Macklem printf("EEK3 multiple clids\n"); 23679ec7b004SRick Macklem } else { 2368c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2369c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 23709ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 23719ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 23729ec7b004SRick Macklem } 23739ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 23749ec7b004SRick Macklem if (error) 23759ec7b004SRick Macklem goto nfsmout; 23769ec7b004SRick Macklem } else { 23779ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 2378222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate), 23799ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 23809ec7b004SRick Macklem stp->ls_ownerlen = 0; 23819ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 23829ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 23839ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 23849ec7b004SRick Macklem NFSX_STATEIDOTHER); 23859ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 238690d2dfabSRick Macklem 238790d2dfabSRick Macklem /* 238890d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set 238990d2dfabSRick Macklem * the stateid to the current stateid, if it is set. 239090d2dfabSRick Macklem */ 239190d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 && 239290d2dfabSRick Macklem stp->ls_stateid.seqid == 1 && 239390d2dfabSRick Macklem stp->ls_stateid.other[0] == 0 && 239490d2dfabSRick Macklem stp->ls_stateid.other[1] == 0 && 239590d2dfabSRick Macklem stp->ls_stateid.other[2] == 0) { 239690d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 239790d2dfabSRick Macklem stp->ls_stateid = nd->nd_curstateid; 239890d2dfabSRick Macklem stp->ls_stateid.seqid = 0; 239990d2dfabSRick Macklem } else { 240090d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 240190d2dfabSRick Macklem goto nfsmout; 240290d2dfabSRick Macklem } 240390d2dfabSRick Macklem } 240490d2dfabSRick Macklem 24059ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(int, *tl); 24069ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 24079ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 2408c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2409c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2410c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2411c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2412c59e4cc3SRick Macklem printf("EEK4 multiple clids\n"); 24139ec7b004SRick Macklem } else { 2414c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2415c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 24169ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 24179ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 24189ec7b004SRick Macklem } 24199ec7b004SRick Macklem } 2420222daa42SConrad Meyer lop = malloc(sizeof (struct nfslock), 24219ec7b004SRick Macklem M_NFSDLOCK, M_WAITOK); 24229ec7b004SRick Macklem lop->lo_first = offset; 24239ec7b004SRick Macklem if (len == NFS64BITSSET) { 24249ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 24259ec7b004SRick Macklem } else { 24269ec7b004SRick Macklem lop->lo_end = offset + len; 24279ec7b004SRick Macklem if (lop->lo_end <= lop->lo_first) 24289ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 24299ec7b004SRick Macklem } 24309ec7b004SRick Macklem lop->lo_flags = lflags; 24319ec7b004SRick Macklem stp->ls_flags = flags; 24329ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 24339ec7b004SRick Macklem 24349ec7b004SRick Macklem /* 24359ec7b004SRick Macklem * Do basic access checking. 24369ec7b004SRick Macklem */ 24379ec7b004SRick Macklem if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 24389ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 24399ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 24409ec7b004SRick Macklem else 24419ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 24429ec7b004SRick Macklem } 24439ec7b004SRick Macklem if (!nd->nd_repstat) { 24449ec7b004SRick Macklem if (lflags & NFSLCK_WRITE) { 24458da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 24469ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 24478da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 24489ec7b004SRick Macklem } else { 24498da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, 24509ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 24518da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 24529ec7b004SRick Macklem if (nd->nd_repstat) 24538da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 24549ec7b004SRick Macklem nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 24558da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 24569ec7b004SRick Macklem } 24579ec7b004SRick Macklem } 24589ec7b004SRick Macklem 24599ec7b004SRick Macklem /* 24609ec7b004SRick Macklem * We call nfsrv_lockctrl() even if nd_repstat set, so that the 24619ec7b004SRick Macklem * seqid# gets updated. nfsrv_lockctrl() will return the value 24629ec7b004SRick Macklem * of nd_repstat, if it gets that far. 24639ec7b004SRick Macklem */ 24649ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 24659ec7b004SRick Macklem &stateid, exp, nd, p); 24669ec7b004SRick Macklem if (lop) 2467222daa42SConrad Meyer free(lop, M_NFSDLOCK); 24689ec7b004SRick Macklem if (stp) 2469222daa42SConrad Meyer free(stp, M_NFSDSTATE); 24709ec7b004SRick Macklem if (!nd->nd_repstat) { 247190d2dfabSRick Macklem /* For NFSv4.1, set the Current StateID. */ 247290d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 247390d2dfabSRick Macklem nd->nd_curstateid = stateid; 247490d2dfabSRick Macklem nd->nd_flag |= ND_CURSTATEID; 247590d2dfabSRick Macklem } 24769ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 24779ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 24789ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 24799ec7b004SRick Macklem } else if (nd->nd_repstat == NFSERR_DENIED) { 24809ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 24819ec7b004SRick Macklem txdr_hyper(cf.cl_first, tl); 24829ec7b004SRick Macklem tl += 2; 24839ec7b004SRick Macklem if (cf.cl_end == NFS64BITSSET) 24849ec7b004SRick Macklem len = NFS64BITSSET; 24859ec7b004SRick Macklem else 24869ec7b004SRick Macklem len = cf.cl_end - cf.cl_first; 24879ec7b004SRick Macklem txdr_hyper(len, tl); 24889ec7b004SRick Macklem tl += 2; 24899ec7b004SRick Macklem if (cf.cl_flags == NFSLCK_WRITE) 24909ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 24919ec7b004SRick Macklem else 24929ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 24939ec7b004SRick Macklem *tl++ = stateid.other[0]; 24949ec7b004SRick Macklem *tl = stateid.other[1]; 24959ec7b004SRick Macklem (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 24969ec7b004SRick Macklem } 24979ec7b004SRick Macklem vput(vp); 2498a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 24999ec7b004SRick Macklem return (0); 25009ec7b004SRick Macklem nfsmout: 25019ec7b004SRick Macklem vput(vp); 25029ec7b004SRick Macklem if (stp) 2503222daa42SConrad Meyer free(stp, M_NFSDSTATE); 2504a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 25059ec7b004SRick Macklem return (error); 25069ec7b004SRick Macklem } 25079ec7b004SRick Macklem 25089ec7b004SRick Macklem /* 25099ec7b004SRick Macklem * nfsv4 lock test service 25109ec7b004SRick Macklem */ 2511b9cc3262SRyan Moeller int 25129ec7b004SRick Macklem nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram, 2513af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 25149ec7b004SRick Macklem { 25159ec7b004SRick Macklem u_int32_t *tl; 25169ec7b004SRick Macklem int i; 25179ec7b004SRick Macklem struct nfsstate *stp = NULL; 25189ec7b004SRick Macklem struct nfslock lo, *lop = &lo; 25199ec7b004SRick Macklem struct nfslockconflict cf; 25209ec7b004SRick Macklem int error = 0; 25219ec7b004SRick Macklem nfsv4stateid_t stateid; 25229ec7b004SRick Macklem nfsquad_t clientid; 25239ec7b004SRick Macklem u_int64_t len; 2524af444b18SEdward Tomasz Napierala struct thread *p = curthread; 25259ec7b004SRick Macklem 25269ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 25279ec7b004SRick Macklem i = fxdr_unsigned(int, *(tl + 7)); 25282a45247cSRick Macklem if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 25292a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 25302a45247cSRick Macklem goto nfsmout; 25312a45247cSRick Macklem } 2532222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate) + i, 25339ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 25349ec7b004SRick Macklem stp->ls_ownerlen = i; 25359ec7b004SRick Macklem stp->ls_op = NULL; 25369ec7b004SRick Macklem stp->ls_flags = NFSLCK_TEST; 25379ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 25389ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 25399ec7b004SRick Macklem switch (i) { 25409ec7b004SRick Macklem case NFSV4LOCKT_READW: 25419ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 25429ec7b004SRick Macklem case NFSV4LOCKT_READ: 25439ec7b004SRick Macklem lo.lo_flags = NFSLCK_READ; 25449ec7b004SRick Macklem break; 25459ec7b004SRick Macklem case NFSV4LOCKT_WRITEW: 25469ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 25479ec7b004SRick Macklem case NFSV4LOCKT_WRITE: 25489ec7b004SRick Macklem lo.lo_flags = NFSLCK_WRITE; 25499ec7b004SRick Macklem break; 25509ec7b004SRick Macklem default: 25519ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 25529ec7b004SRick Macklem goto nfsmout; 255374b8d63dSPedro F. Giffuni } 25549ec7b004SRick Macklem lo.lo_first = fxdr_hyper(tl); 25559ec7b004SRick Macklem tl += 2; 25569ec7b004SRick Macklem len = fxdr_hyper(tl); 25579ec7b004SRick Macklem if (len == NFS64BITSSET) { 25589ec7b004SRick Macklem lo.lo_end = NFS64BITSSET; 25599ec7b004SRick Macklem } else { 25609ec7b004SRick Macklem lo.lo_end = lo.lo_first + len; 25619ec7b004SRick Macklem if (lo.lo_end <= lo.lo_first) 25629ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 25639ec7b004SRick Macklem } 25649ec7b004SRick Macklem tl += 2; 25659ec7b004SRick Macklem clientid.lval[0] = *tl++; 25669ec7b004SRick Macklem clientid.lval[1] = *tl; 2567c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2568c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2569c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2570c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2571c59e4cc3SRick Macklem printf("EEK5 multiple clids\n"); 25729ec7b004SRick Macklem } else { 2573c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2574c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 25759ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 25769ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 25779ec7b004SRick Macklem } 25789ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 25799ec7b004SRick Macklem if (error) 25809ec7b004SRick Macklem goto nfsmout; 25819ec7b004SRick Macklem if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 25829ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 25839ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 25849ec7b004SRick Macklem else 25859ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 25869ec7b004SRick Macklem } 25879ec7b004SRick Macklem if (!nd->nd_repstat) 25889ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 25899ec7b004SRick Macklem &stateid, exp, nd, p); 25909ec7b004SRick Macklem if (nd->nd_repstat) { 25919ec7b004SRick Macklem if (nd->nd_repstat == NFSERR_DENIED) { 25929ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 25939ec7b004SRick Macklem txdr_hyper(cf.cl_first, tl); 25949ec7b004SRick Macklem tl += 2; 25959ec7b004SRick Macklem if (cf.cl_end == NFS64BITSSET) 25969ec7b004SRick Macklem len = NFS64BITSSET; 25979ec7b004SRick Macklem else 25989ec7b004SRick Macklem len = cf.cl_end - cf.cl_first; 25999ec7b004SRick Macklem txdr_hyper(len, tl); 26009ec7b004SRick Macklem tl += 2; 26019ec7b004SRick Macklem if (cf.cl_flags == NFSLCK_WRITE) 26029ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 26039ec7b004SRick Macklem else 26049ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 26059ec7b004SRick Macklem *tl++ = stp->ls_stateid.other[0]; 26069ec7b004SRick Macklem *tl = stp->ls_stateid.other[1]; 26079ec7b004SRick Macklem (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 26089ec7b004SRick Macklem } 26099ec7b004SRick Macklem } 26109ec7b004SRick Macklem vput(vp); 26115ecc225fSConrad Meyer if (stp) 2612222daa42SConrad Meyer free(stp, M_NFSDSTATE); 2613a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 26149ec7b004SRick Macklem return (0); 26159ec7b004SRick Macklem nfsmout: 26169ec7b004SRick Macklem vput(vp); 26179ec7b004SRick Macklem if (stp) 2618222daa42SConrad Meyer free(stp, M_NFSDSTATE); 2619a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 26209ec7b004SRick Macklem return (error); 26219ec7b004SRick Macklem } 26229ec7b004SRick Macklem 26239ec7b004SRick Macklem /* 26249ec7b004SRick Macklem * nfsv4 unlock service 26259ec7b004SRick Macklem */ 2626b9cc3262SRyan Moeller int 26279ec7b004SRick Macklem nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram, 2628af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 26299ec7b004SRick Macklem { 26309ec7b004SRick Macklem u_int32_t *tl; 26319ec7b004SRick Macklem int i; 26329ec7b004SRick Macklem struct nfsstate *stp; 26339ec7b004SRick Macklem struct nfslock *lop; 26349ec7b004SRick Macklem int error = 0; 26359ec7b004SRick Macklem nfsv4stateid_t stateid; 26369ec7b004SRick Macklem nfsquad_t clientid; 26379ec7b004SRick Macklem u_int64_t len; 2638af444b18SEdward Tomasz Napierala struct thread *p = curthread; 26399ec7b004SRick Macklem 26409ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID); 2641222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate), 26429ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 2643222daa42SConrad Meyer lop = malloc(sizeof (struct nfslock), 26449ec7b004SRick Macklem M_NFSDLOCK, M_WAITOK); 26459ec7b004SRick Macklem stp->ls_flags = NFSLCK_UNLOCK; 26469ec7b004SRick Macklem lop->lo_flags = NFSLCK_UNLOCK; 26479ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 26489ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 26499ec7b004SRick Macklem switch (i) { 26509ec7b004SRick Macklem case NFSV4LOCKT_READW: 26519ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 26529ec7b004SRick Macklem case NFSV4LOCKT_READ: 26539ec7b004SRick Macklem break; 26549ec7b004SRick Macklem case NFSV4LOCKT_WRITEW: 26559ec7b004SRick Macklem stp->ls_flags |= NFSLCK_BLOCKING; 26569ec7b004SRick Macklem case NFSV4LOCKT_WRITE: 26579ec7b004SRick Macklem break; 26589ec7b004SRick Macklem default: 26599ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 26602a45247cSRick Macklem free(stp, M_NFSDSTATE); 26612a45247cSRick Macklem free(lop, M_NFSDLOCK); 26629ec7b004SRick Macklem goto nfsmout; 266374b8d63dSPedro F. Giffuni } 26649ec7b004SRick Macklem stp->ls_ownerlen = 0; 26659ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 26669ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(int, *tl++); 26679ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 26689ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 26699ec7b004SRick Macklem NFSX_STATEIDOTHER); 26709ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 267190d2dfabSRick Macklem 267290d2dfabSRick Macklem /* 267390d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 267490d2dfabSRick Macklem * stateid to the current stateid, if it is set. 267590d2dfabSRick Macklem */ 267690d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 267790d2dfabSRick Macklem stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 267890d2dfabSRick Macklem stp->ls_stateid.other[2] == 0) { 267990d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 268090d2dfabSRick Macklem stp->ls_stateid = nd->nd_curstateid; 268190d2dfabSRick Macklem stp->ls_stateid.seqid = 0; 268290d2dfabSRick Macklem } else { 268390d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 268490d2dfabSRick Macklem goto nfsmout; 268590d2dfabSRick Macklem } 268690d2dfabSRick Macklem } 268790d2dfabSRick Macklem 26889ec7b004SRick Macklem lop->lo_first = fxdr_hyper(tl); 26899ec7b004SRick Macklem tl += 2; 26909ec7b004SRick Macklem len = fxdr_hyper(tl); 26919ec7b004SRick Macklem if (len == NFS64BITSSET) { 26929ec7b004SRick Macklem lop->lo_end = NFS64BITSSET; 26939ec7b004SRick Macklem } else { 26949ec7b004SRick Macklem lop->lo_end = lop->lo_first + len; 26959ec7b004SRick Macklem if (lop->lo_end <= lop->lo_first) 26969ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 26979ec7b004SRick Macklem } 26989ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 26999ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 2700c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2701c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2702c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2703c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2704c59e4cc3SRick Macklem printf("EEK6 multiple clids\n"); 27059ec7b004SRick Macklem } else { 2706c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2707c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 27089ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 27099ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 27109ec7b004SRick Macklem } 27119ec7b004SRick Macklem if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 27129ec7b004SRick Macklem if (vnode_vtype(vp) == VDIR) 27139ec7b004SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 27149ec7b004SRick Macklem else 27159ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 27169ec7b004SRick Macklem } 27179ec7b004SRick Macklem /* 27189ec7b004SRick Macklem * Call nfsrv_lockctrl() even if nd_repstat is set, so that the 27199ec7b004SRick Macklem * seqid# gets incremented. nfsrv_lockctrl() will return the 27209ec7b004SRick Macklem * value of nd_repstat, if it gets that far. 27219ec7b004SRick Macklem */ 27229ec7b004SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 27239ec7b004SRick Macklem &stateid, exp, nd, p); 27249ec7b004SRick Macklem if (stp) 2725222daa42SConrad Meyer free(stp, M_NFSDSTATE); 27269ec7b004SRick Macklem if (lop) 2727222daa42SConrad Meyer free(lop, M_NFSDLOCK); 27289ec7b004SRick Macklem if (!nd->nd_repstat) { 27299ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 27309ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 27319ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 27329ec7b004SRick Macklem } 27339ec7b004SRick Macklem nfsmout: 27349ec7b004SRick Macklem vput(vp); 2735a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 27369ec7b004SRick Macklem return (error); 27379ec7b004SRick Macklem } 27389ec7b004SRick Macklem 27399ec7b004SRick Macklem /* 27409ec7b004SRick Macklem * nfsv4 open service 27419ec7b004SRick Macklem */ 2742b9cc3262SRyan Moeller int 27439ec7b004SRick Macklem nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram, 2744af444b18SEdward Tomasz Napierala vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp) 27459ec7b004SRick Macklem { 27469ec7b004SRick Macklem u_int32_t *tl; 2747c59e4cc3SRick Macklem int i, retext; 27489ec7b004SRick Macklem struct nfsstate *stp = NULL; 2749b0b7d978SRick Macklem int error = 0, create, claim, exclusive_flag = 0, override; 27509ec7b004SRick Macklem u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask; 27519ec7b004SRick Macklem int how = NFSCREATE_UNCHECKED; 2752086f6e0cSRick Macklem int32_t cverf[2], tverf[2] = { 0, 0 }; 27539ec7b004SRick Macklem vnode_t vp = NULL, dirp = NULL; 27549ec7b004SRick Macklem struct nfsvattr nva, dirfor, diraft; 27559ec7b004SRick Macklem struct nameidata named; 27569ec7b004SRick Macklem nfsv4stateid_t stateid, delegstateid; 27579ec7b004SRick Macklem nfsattrbit_t attrbits; 27589ec7b004SRick Macklem nfsquad_t clientid; 27599ec7b004SRick Macklem char *bufp = NULL; 27609ec7b004SRick Macklem u_long *hashp; 27619ec7b004SRick Macklem NFSACL_T *aclp = NULL; 2762af444b18SEdward Tomasz Napierala struct thread *p = curthread; 27639ec7b004SRick Macklem 27649ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 2765c3e22f83SRick Macklem aclp = acl_alloc(M_WAITOK); 27669ec7b004SRick Macklem aclp->acl_cnt = 0; 27679ec7b004SRick Macklem #endif 27689ec7b004SRick Macklem NFSZERO_ATTRBIT(&attrbits); 27699ec7b004SRick Macklem named.ni_startdir = NULL; 27709ec7b004SRick Macklem named.ni_cnd.cn_nameiop = 0; 27719ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 27729ec7b004SRick Macklem i = fxdr_unsigned(int, *(tl + 5)); 27732a45247cSRick Macklem if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 27742a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 2775a9285ae5SZack Kirsch goto nfsmout; 27762a45247cSRick Macklem } 2777222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate) + i, 27789ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 27799ec7b004SRick Macklem stp->ls_ownerlen = i; 27809ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 27819ec7b004SRick Macklem stp->ls_flags = NFSLCK_OPEN; 27829ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 27839ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 27849ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 2785c59e4cc3SRick Macklem retext = 0; 2786c59e4cc3SRick Macklem if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG | 2787c59e4cc3SRick Macklem NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) { 2788c59e4cc3SRick Macklem retext = 1; 2789c59e4cc3SRick Macklem /* For now, ignore these. */ 2790c59e4cc3SRick Macklem i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG); 2791c59e4cc3SRick Macklem switch (i & NFSV4OPEN_WANTDELEGMASK) { 2792c59e4cc3SRick Macklem case NFSV4OPEN_WANTANYDELEG: 2793c59e4cc3SRick Macklem stp->ls_flags |= (NFSLCK_WANTRDELEG | 2794c59e4cc3SRick Macklem NFSLCK_WANTWDELEG); 2795c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2796c59e4cc3SRick Macklem break; 2797c59e4cc3SRick Macklem case NFSV4OPEN_WANTREADDELEG: 2798c59e4cc3SRick Macklem stp->ls_flags |= NFSLCK_WANTRDELEG; 2799c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2800c59e4cc3SRick Macklem break; 2801c59e4cc3SRick Macklem case NFSV4OPEN_WANTWRITEDELEG: 2802c59e4cc3SRick Macklem stp->ls_flags |= NFSLCK_WANTWDELEG; 2803c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2804c59e4cc3SRick Macklem break; 2805c59e4cc3SRick Macklem case NFSV4OPEN_WANTNODELEG: 2806c59e4cc3SRick Macklem stp->ls_flags |= NFSLCK_WANTNODELEG; 2807c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2808c59e4cc3SRick Macklem break; 2809c59e4cc3SRick Macklem case NFSV4OPEN_WANTCANCEL: 2810c59e4cc3SRick Macklem printf("NFSv4: ignore Open WantCancel\n"); 2811c59e4cc3SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 2812c59e4cc3SRick Macklem break; 2813c59e4cc3SRick Macklem default: 2814c59e4cc3SRick Macklem /* nd_repstat will be set to NFSERR_INVAL below. */ 2815c59e4cc3SRick Macklem break; 281674b8d63dSPedro F. Giffuni } 2817c59e4cc3SRick Macklem } 28189ec7b004SRick Macklem switch (i) { 28199ec7b004SRick Macklem case NFSV4OPEN_ACCESSREAD: 28209ec7b004SRick Macklem stp->ls_flags |= NFSLCK_READACCESS; 28219ec7b004SRick Macklem break; 28229ec7b004SRick Macklem case NFSV4OPEN_ACCESSWRITE: 28239ec7b004SRick Macklem stp->ls_flags |= NFSLCK_WRITEACCESS; 28249ec7b004SRick Macklem break; 28259ec7b004SRick Macklem case NFSV4OPEN_ACCESSBOTH: 28269ec7b004SRick Macklem stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 28279ec7b004SRick Macklem break; 28289ec7b004SRick Macklem default: 28299ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 283074b8d63dSPedro F. Giffuni } 28319ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 28329ec7b004SRick Macklem switch (i) { 28339ec7b004SRick Macklem case NFSV4OPEN_DENYNONE: 28349ec7b004SRick Macklem break; 28359ec7b004SRick Macklem case NFSV4OPEN_DENYREAD: 28369ec7b004SRick Macklem stp->ls_flags |= NFSLCK_READDENY; 28379ec7b004SRick Macklem break; 28389ec7b004SRick Macklem case NFSV4OPEN_DENYWRITE: 28399ec7b004SRick Macklem stp->ls_flags |= NFSLCK_WRITEDENY; 28409ec7b004SRick Macklem break; 28419ec7b004SRick Macklem case NFSV4OPEN_DENYBOTH: 28429ec7b004SRick Macklem stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 28439ec7b004SRick Macklem break; 28449ec7b004SRick Macklem default: 28459ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 284674b8d63dSPedro F. Giffuni } 28479ec7b004SRick Macklem clientid.lval[0] = *tl++; 28489ec7b004SRick Macklem clientid.lval[1] = *tl; 2849c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2850c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2851c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 2852c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 2853c59e4cc3SRick Macklem printf("EEK7 multiple clids\n"); 28549ec7b004SRick Macklem } else { 2855c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 2856c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 28579ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 28589ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 28599ec7b004SRick Macklem } 28609ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2861a9285ae5SZack Kirsch if (error) 2862a9285ae5SZack Kirsch goto nfsmout; 28639ec7b004SRick Macklem NFSVNO_ATTRINIT(&nva); 28649ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 28659ec7b004SRick Macklem create = fxdr_unsigned(int, *tl); 28669ec7b004SRick Macklem if (!nd->nd_repstat) 286790d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL); 28689ec7b004SRick Macklem if (create == NFSV4OPEN_CREATE) { 28699ec7b004SRick Macklem nva.na_type = VREG; 28709ec7b004SRick Macklem nva.na_mode = 0; 28719ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 28729ec7b004SRick Macklem how = fxdr_unsigned(int, *tl); 28739ec7b004SRick Macklem switch (how) { 28749ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 28759ec7b004SRick Macklem case NFSCREATE_GUARDED: 2876d8a5961fSMarcelo Araujo error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p); 2877a9285ae5SZack Kirsch if (error) 2878a9285ae5SZack Kirsch goto nfsmout; 28799ec7b004SRick Macklem /* 28809ec7b004SRick Macklem * If the na_gid being set is the same as that of 28819ec7b004SRick Macklem * the directory it is going in, clear it, since 28829ec7b004SRick Macklem * that is what will be set by default. This allows 28839ec7b004SRick Macklem * a user that isn't in that group to do the create. 28849ec7b004SRick Macklem */ 28859ec7b004SRick Macklem if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) && 28869ec7b004SRick Macklem nva.na_gid == dirfor.na_gid) 28879ec7b004SRick Macklem NFSVNO_UNSET(&nva, gid); 28889ec7b004SRick Macklem if (!nd->nd_repstat) 28899ec7b004SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 28909ec7b004SRick Macklem break; 28919ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 28929ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2893086f6e0cSRick Macklem cverf[0] = *tl++; 2894086f6e0cSRick Macklem cverf[1] = *tl; 28959ec7b004SRick Macklem break; 2896c59e4cc3SRick Macklem case NFSCREATE_EXCLUSIVE41: 2897c59e4cc3SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2898c59e4cc3SRick Macklem cverf[0] = *tl++; 2899c59e4cc3SRick Macklem cverf[1] = *tl; 2900b4645807SRick Macklem error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p); 2901c59e4cc3SRick Macklem if (error != 0) 2902c59e4cc3SRick Macklem goto nfsmout; 2903c59e4cc3SRick Macklem if (NFSISSET_ATTRBIT(&attrbits, 2904c59e4cc3SRick Macklem NFSATTRBIT_TIMEACCESSSET)) 2905c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_INVAL; 2906c59e4cc3SRick Macklem /* 2907c59e4cc3SRick Macklem * If the na_gid being set is the same as that of 2908c59e4cc3SRick Macklem * the directory it is going in, clear it, since 2909c59e4cc3SRick Macklem * that is what will be set by default. This allows 2910c59e4cc3SRick Macklem * a user that isn't in that group to do the create. 2911c59e4cc3SRick Macklem */ 2912c59e4cc3SRick Macklem if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) && 2913c59e4cc3SRick Macklem nva.na_gid == dirfor.na_gid) 2914c59e4cc3SRick Macklem NFSVNO_UNSET(&nva, gid); 2915c59e4cc3SRick Macklem if (nd->nd_repstat == 0) 2916c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2917c59e4cc3SRick Macklem break; 29189ec7b004SRick Macklem default: 29199ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 2920a9285ae5SZack Kirsch goto nfsmout; 292174b8d63dSPedro F. Giffuni } 29229ec7b004SRick Macklem } else if (create != NFSV4OPEN_NOCREATE) { 29239ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 2924a9285ae5SZack Kirsch goto nfsmout; 29259ec7b004SRick Macklem } 29269ec7b004SRick Macklem 29279ec7b004SRick Macklem /* 29289ec7b004SRick Macklem * Now, handle the claim, which usually includes looking up a 29299ec7b004SRick Macklem * name in the directory referenced by dp. The exception is 29309ec7b004SRick Macklem * NFSV4OPEN_CLAIMPREVIOUS. 29319ec7b004SRick Macklem */ 29329ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 29339ec7b004SRick Macklem claim = fxdr_unsigned(int, *tl); 29349ec7b004SRick Macklem if (claim == NFSV4OPEN_CLAIMDELEGATECUR) { 29359ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 29369ec7b004SRick Macklem stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 29379ec7b004SRick Macklem NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 29389ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGCUR; 29399ec7b004SRick Macklem } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 29409ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGPREV; 29419ec7b004SRick Macklem } 29429ec7b004SRick Macklem if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR 29439ec7b004SRick Macklem || claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 29449ec7b004SRick Macklem if (!nd->nd_repstat && create == NFSV4OPEN_CREATE && 29459ec7b004SRick Macklem claim != NFSV4OPEN_CLAIMNULL) 29469ec7b004SRick Macklem nd->nd_repstat = NFSERR_INVAL; 29479ec7b004SRick Macklem if (nd->nd_repstat) { 29489ec7b004SRick Macklem nd->nd_repstat = nfsrv_opencheck(clientid, 29499ec7b004SRick Macklem &stateid, stp, NULL, nd, p, nd->nd_repstat); 2950a9285ae5SZack Kirsch goto nfsmout; 29519ec7b004SRick Macklem } 29529ec7b004SRick Macklem if (create == NFSV4OPEN_CREATE) 29539ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 29546c21f6edSKonstantin Belousov LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE); 29559ec7b004SRick Macklem else 29569ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 29579ec7b004SRick Macklem LOCKLEAF | SAVESTART); 29589ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 29599ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 29609ec7b004SRick Macklem if (error) { 29619ec7b004SRick Macklem vrele(dp); 29629ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 29639ec7b004SRick Macklem acl_free(aclp); 29649ec7b004SRick Macklem #endif 2965222daa42SConrad Meyer free(stp, M_NFSDSTATE); 29669ec7b004SRick Macklem nfsvno_relpathbuf(&named); 2967a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 29689ec7b004SRick Macklem return (error); 29699ec7b004SRick Macklem } 29709ec7b004SRick Macklem if (!nd->nd_repstat) { 29719ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, 29729ec7b004SRick Macklem p, &dirp); 29739ec7b004SRick Macklem } else { 29749ec7b004SRick Macklem vrele(dp); 29759ec7b004SRick Macklem nfsvno_relpathbuf(&named); 29769ec7b004SRick Macklem } 29779ec7b004SRick Macklem if (create == NFSV4OPEN_CREATE) { 29789ec7b004SRick Macklem switch (how) { 29799ec7b004SRick Macklem case NFSCREATE_UNCHECKED: 29809ec7b004SRick Macklem if (named.ni_vp) { 29819ec7b004SRick Macklem /* 29829ec7b004SRick Macklem * Clear the setable attribute bits, except 29839ec7b004SRick Macklem * for Size, if it is being truncated. 29849ec7b004SRick Macklem */ 29859ec7b004SRick Macklem NFSZERO_ATTRBIT(&attrbits); 29869ec7b004SRick Macklem if (NFSVNO_ISSETSIZE(&nva)) 29879ec7b004SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, 29889ec7b004SRick Macklem NFSATTRBIT_SIZE); 29899ec7b004SRick Macklem } 29909ec7b004SRick Macklem break; 29919ec7b004SRick Macklem case NFSCREATE_GUARDED: 29929ec7b004SRick Macklem if (named.ni_vp && !nd->nd_repstat) 29939ec7b004SRick Macklem nd->nd_repstat = EEXIST; 29949ec7b004SRick Macklem break; 29959ec7b004SRick Macklem case NFSCREATE_EXCLUSIVE: 29969ec7b004SRick Macklem exclusive_flag = 1; 29979ec7b004SRick Macklem if (!named.ni_vp) 29989ec7b004SRick Macklem nva.na_mode = 0; 2999c59e4cc3SRick Macklem break; 3000c59e4cc3SRick Macklem case NFSCREATE_EXCLUSIVE41: 3001c59e4cc3SRick Macklem exclusive_flag = 1; 3002c59e4cc3SRick Macklem break; 300374b8d63dSPedro F. Giffuni } 30049ec7b004SRick Macklem } 30059ec7b004SRick Macklem nfsvno_open(nd, &named, clientid, &stateid, stp, 30069ec7b004SRick Macklem &exclusive_flag, &nva, cverf, create, aclp, &attrbits, 300701c27978SEdward Tomasz Napierala nd->nd_cred, exp, &vp); 3008c59e4cc3SRick Macklem } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim == 3009c59e4cc3SRick Macklem NFSV4OPEN_CLAIMFH) { 3010c59e4cc3SRick Macklem if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 30119ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 30129ec7b004SRick Macklem i = fxdr_unsigned(int, *tl); 30139ec7b004SRick Macklem switch (i) { 30149ec7b004SRick Macklem case NFSV4OPEN_DELEGATEREAD: 30159ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGREAD; 30169ec7b004SRick Macklem break; 30179ec7b004SRick Macklem case NFSV4OPEN_DELEGATEWRITE: 30189ec7b004SRick Macklem stp->ls_flags |= NFSLCK_DELEGWRITE; 30199ec7b004SRick Macklem case NFSV4OPEN_DELEGATENONE: 30209ec7b004SRick Macklem break; 30219ec7b004SRick Macklem default: 30229ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 3023a9285ae5SZack Kirsch goto nfsmout; 302474b8d63dSPedro F. Giffuni } 30259ec7b004SRick Macklem stp->ls_flags |= NFSLCK_RECLAIM; 3026c59e4cc3SRick Macklem } else { 3027c59e4cc3SRick Macklem /* CLAIM_NULL_FH */ 3028c59e4cc3SRick Macklem if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE) 3029c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_INVAL; 3030c59e4cc3SRick Macklem } 30319ec7b004SRick Macklem vp = dp; 303298f234f3SZack Kirsch NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 3033abd80ddbSMateusz Guzik if (!VN_IS_DOOMED(vp)) 3034629fa50eSRick Macklem nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, 3035629fa50eSRick Macklem stp, vp, nd, p, nd->nd_repstat); 3036629fa50eSRick Macklem else 3037629fa50eSRick Macklem nd->nd_repstat = NFSERR_PERM; 30389ec7b004SRick Macklem } else { 30399ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 3040a9285ae5SZack Kirsch goto nfsmout; 30419ec7b004SRick Macklem } 30429ec7b004SRick Macklem 30439ec7b004SRick Macklem /* 30449ec7b004SRick Macklem * Do basic access checking. 30459ec7b004SRick Macklem */ 30469ec7b004SRick Macklem if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 3047de67b496SRick Macklem /* 3048de67b496SRick Macklem * The IETF working group decided that this is the correct 3049de67b496SRick Macklem * error return for all non-regular files. 3050de67b496SRick Macklem */ 3051d8a5961fSMarcelo Araujo nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK; 30529ec7b004SRick Macklem } 3053b0b7d978SRick Macklem 3054b0b7d978SRick Macklem /* 3055b0b7d978SRick Macklem * If the Open is being done for a file that already exists, apply 3056b0b7d978SRick Macklem * normal permission checking including for the file owner, if 3057b0b7d978SRick Macklem * vfs.nfsd.v4openaccess is set. 3058b0b7d978SRick Macklem * Previously, the owner was always allowed to open the file to 3059b0b7d978SRick Macklem * be consistent with the NFS tradition of always allowing the 3060b0b7d978SRick Macklem * owner of the file to write to the file regardless of permissions. 3061b0b7d978SRick Macklem * It now appears that the Linux client expects the owner 3062b0b7d978SRick Macklem * permissions to be checked for opens that are not creating the 3063b0b7d978SRick Macklem * file. I believe the correct approach is to use the Access 3064b0b7d978SRick Macklem * operation's results to be consistent with NFSv3, but that is 3065b0b7d978SRick Macklem * not what the current Linux client appears to be doing. 3066b0b7d978SRick Macklem * Since both the Linux and OpenSolaris NFSv4 servers do this check, 3067b0b7d978SRick Macklem * I have enabled it by default. 3068b0b7d978SRick Macklem * If this semantic change causes a problem, it can be disabled by 3069b0b7d978SRick Macklem * setting the sysctl vfs.nfsd.v4openaccess to 0 to re-enable the 3070b0b7d978SRick Macklem * previous semantics. 3071b0b7d978SRick Macklem */ 3072b0b7d978SRick Macklem if (nfsrv_openaccess && create == NFSV4OPEN_NOCREATE) 3073b0b7d978SRick Macklem override = NFSACCCHK_NOOVERRIDE; 3074b0b7d978SRick Macklem else 3075b0b7d978SRick Macklem override = NFSACCCHK_ALLOWOWNER; 30769ec7b004SRick Macklem if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS)) 30778da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, 3078b0b7d978SRick Macklem exp, p, override, NFSACCCHK_VPISLOCKED, NULL); 30799ec7b004SRick Macklem if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) { 30808da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, 3081b0b7d978SRick Macklem exp, p, override, NFSACCCHK_VPISLOCKED, NULL); 30829ec7b004SRick Macklem if (nd->nd_repstat) 30838da45f2cSRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 3084b0b7d978SRick Macklem nd->nd_cred, exp, p, override, 30858da45f2cSRick Macklem NFSACCCHK_VPISLOCKED, NULL); 30869ec7b004SRick Macklem } 30879ec7b004SRick Macklem 3088086f6e0cSRick Macklem if (!nd->nd_repstat) { 308990d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 3090086f6e0cSRick Macklem if (!nd->nd_repstat) { 3091086f6e0cSRick Macklem tverf[0] = nva.na_atime.tv_sec; 3092086f6e0cSRick Macklem tverf[1] = nva.na_atime.tv_nsec; 3093086f6e0cSRick Macklem } 3094086f6e0cSRick Macklem } 3095086f6e0cSRick Macklem if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] || 3096086f6e0cSRick Macklem cverf[1] != tverf[1])) 30979ec7b004SRick Macklem nd->nd_repstat = EEXIST; 30989ec7b004SRick Macklem /* 30999ec7b004SRick Macklem * Do the open locking/delegation stuff. 31009ec7b004SRick Macklem */ 31019ec7b004SRick Macklem if (!nd->nd_repstat) 31029ec7b004SRick Macklem nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid, 31039ec7b004SRick Macklem &delegstateid, &rflags, exp, p, nva.na_filerev); 31049ec7b004SRick Macklem 31059ec7b004SRick Macklem /* 31069ec7b004SRick Macklem * vp must be unlocked before the call to nfsvno_getattr(dirp,...) 31079ec7b004SRick Macklem * below, to avoid a deadlock with the lookup in nfsvno_namei() above. 31089ec7b004SRick Macklem * (ie: Leave the NFSVOPUNLOCK() about here.) 31099ec7b004SRick Macklem */ 31109ec7b004SRick Macklem if (vp) 3111b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 31129ec7b004SRick Macklem if (stp) 3113222daa42SConrad Meyer free(stp, M_NFSDSTATE); 31149ec7b004SRick Macklem if (!nd->nd_repstat && dirp) 311590d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 31169ec7b004SRick Macklem if (!nd->nd_repstat) { 311790d2dfabSRick Macklem /* For NFSv4.1, set the Current StateID. */ 311890d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 311990d2dfabSRick Macklem nd->nd_curstateid = stateid; 312090d2dfabSRick Macklem nd->nd_flag |= ND_CURSTATEID; 312190d2dfabSRick Macklem } 31229ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 31239ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 31249ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 31259ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 31269ec7b004SRick Macklem if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 31279ec7b004SRick Macklem *tl++ = newnfs_true; 31289ec7b004SRick Macklem *tl++ = 0; 31299ec7b004SRick Macklem *tl++ = 0; 31309ec7b004SRick Macklem *tl++ = 0; 31319ec7b004SRick Macklem *tl++ = 0; 31329ec7b004SRick Macklem } else { 31339ec7b004SRick Macklem *tl++ = newnfs_false; /* Since dirp is not locked */ 31349ec7b004SRick Macklem txdr_hyper(dirfor.na_filerev, tl); 31359ec7b004SRick Macklem tl += 2; 31369ec7b004SRick Macklem txdr_hyper(diraft.na_filerev, tl); 31379ec7b004SRick Macklem tl += 2; 31389ec7b004SRick Macklem } 31399ec7b004SRick Macklem *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS); 31409ec7b004SRick Macklem (void) nfsrv_putattrbit(nd, &attrbits); 31419ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 31429ec7b004SRick Macklem if (rflags & NFSV4OPEN_READDELEGATE) 31439ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD); 31449ec7b004SRick Macklem else if (rflags & NFSV4OPEN_WRITEDELEGATE) 31459ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE); 3146c59e4cc3SRick Macklem else if (retext != 0) { 3147c59e4cc3SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT); 31485d54f186SRick Macklem if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) { 31495d54f186SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 31505d54f186SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 31515d54f186SRick Macklem } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) { 31525d54f186SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 31535d54f186SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE); 31545d54f186SRick Macklem } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) { 3155c59e4cc3SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3156c59e4cc3SRick Macklem *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION); 3157c59e4cc3SRick Macklem *tl = newnfs_false; 3158c59e4cc3SRick Macklem } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) { 3159c59e4cc3SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3160c59e4cc3SRick Macklem *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE); 3161c59e4cc3SRick Macklem *tl = newnfs_false; 3162c59e4cc3SRick Macklem } else { 3163c59e4cc3SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3164c59e4cc3SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 3165c59e4cc3SRick Macklem } 3166c59e4cc3SRick Macklem } else 31679ec7b004SRick Macklem *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE); 31689ec7b004SRick Macklem if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) { 31699ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED); 31709ec7b004SRick Macklem *tl++ = txdr_unsigned(delegstateid.seqid); 31719ec7b004SRick Macklem NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl, 31729ec7b004SRick Macklem NFSX_STATEIDOTHER); 31739ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 31749ec7b004SRick Macklem if (rflags & NFSV4OPEN_RECALL) 31759ec7b004SRick Macklem *tl = newnfs_true; 31769ec7b004SRick Macklem else 31779ec7b004SRick Macklem *tl = newnfs_false; 31789ec7b004SRick Macklem if (rflags & NFSV4OPEN_WRITEDELEGATE) { 31799ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 31809ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE); 31819ec7b004SRick Macklem txdr_hyper(nva.na_size, tl); 31829ec7b004SRick Macklem } 31839ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 31849ec7b004SRick Macklem *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE); 31859ec7b004SRick Macklem *tl++ = txdr_unsigned(0x0); 31869ec7b004SRick Macklem acemask = NFSV4ACE_ALLFILESMASK; 31879ec7b004SRick Macklem if (nva.na_mode & S_IRUSR) 31889ec7b004SRick Macklem acemask |= NFSV4ACE_READMASK; 31899ec7b004SRick Macklem if (nva.na_mode & S_IWUSR) 31909ec7b004SRick Macklem acemask |= NFSV4ACE_WRITEMASK; 31919ec7b004SRick Macklem if (nva.na_mode & S_IXUSR) 31929ec7b004SRick Macklem acemask |= NFSV4ACE_EXECUTEMASK; 31939ec7b004SRick Macklem *tl = txdr_unsigned(acemask); 31949ec7b004SRick Macklem (void) nfsm_strtom(nd, "OWNER@", 6); 31959ec7b004SRick Macklem } 31969ec7b004SRick Macklem *vpp = vp; 31979ec7b004SRick Macklem } else if (vp) { 31989ec7b004SRick Macklem vrele(vp); 31999ec7b004SRick Macklem } 32009ec7b004SRick Macklem if (dirp) 32019ec7b004SRick Macklem vrele(dirp); 32029ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 32039ec7b004SRick Macklem acl_free(aclp); 32049ec7b004SRick Macklem #endif 3205a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 32069ec7b004SRick Macklem return (0); 32079ec7b004SRick Macklem nfsmout: 32089ec7b004SRick Macklem vrele(dp); 32099ec7b004SRick Macklem #ifdef NFS4_ACL_EXTATTR_NAME 32109ec7b004SRick Macklem acl_free(aclp); 32119ec7b004SRick Macklem #endif 32129ec7b004SRick Macklem if (stp) 3213222daa42SConrad Meyer free(stp, M_NFSDSTATE); 3214a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 32159ec7b004SRick Macklem return (error); 32169ec7b004SRick Macklem } 32179ec7b004SRick Macklem 32189ec7b004SRick Macklem /* 32199ec7b004SRick Macklem * nfsv4 close service 32209ec7b004SRick Macklem */ 3221b9cc3262SRyan Moeller int 32229ec7b004SRick Macklem nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram, 3223af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 32249ec7b004SRick Macklem { 32259ec7b004SRick Macklem u_int32_t *tl; 32269ec7b004SRick Macklem struct nfsstate st, *stp = &st; 322790d2dfabSRick Macklem int error = 0, writeacc; 32289ec7b004SRick Macklem nfsv4stateid_t stateid; 32299ec7b004SRick Macklem nfsquad_t clientid; 323090d2dfabSRick Macklem struct nfsvattr na; 3231af444b18SEdward Tomasz Napierala struct thread *p = curthread; 32329ec7b004SRick Macklem 32339ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 32349ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 32359ec7b004SRick Macklem stp->ls_ownerlen = 0; 32369ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 32379ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 32389ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 32399ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 32409ec7b004SRick Macklem NFSX_STATEIDOTHER); 324190d2dfabSRick Macklem 324290d2dfabSRick Macklem /* 324390d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 324490d2dfabSRick Macklem * stateid to the current stateid, if it is set. 324590d2dfabSRick Macklem */ 324690d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 324790d2dfabSRick Macklem stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 324890d2dfabSRick Macklem stp->ls_stateid.other[2] == 0) { 324990d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) 325090d2dfabSRick Macklem stp->ls_stateid = nd->nd_curstateid; 325190d2dfabSRick Macklem else { 325290d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 325390d2dfabSRick Macklem goto nfsmout; 325490d2dfabSRick Macklem } 325590d2dfabSRick Macklem } 325690d2dfabSRick Macklem 32579ec7b004SRick Macklem stp->ls_flags = NFSLCK_CLOSE; 32589ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 32599ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 3260c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3261c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3262c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3263c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3264c59e4cc3SRick Macklem printf("EEK8 multiple clids\n"); 32659ec7b004SRick Macklem } else { 3266c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3267c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 32689ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 32699ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 32709ec7b004SRick Macklem } 327190d2dfabSRick Macklem nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, 327290d2dfabSRick Macklem &writeacc); 327390d2dfabSRick Macklem /* For pNFS, update the attributes. */ 327490d2dfabSRick Macklem if (writeacc != 0 || nfsrv_pnfsatime != 0) 327590d2dfabSRick Macklem nfsrv_updatemdsattr(vp, &na, p); 32769ec7b004SRick Macklem vput(vp); 32779ec7b004SRick Macklem if (!nd->nd_repstat) { 327890d2dfabSRick Macklem /* 327990d2dfabSRick Macklem * If the stateid that has been closed is the current stateid, 328090d2dfabSRick Macklem * unset it. 328190d2dfabSRick Macklem */ 328290d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0 && 328390d2dfabSRick Macklem stateid.other[0] == nd->nd_curstateid.other[0] && 328490d2dfabSRick Macklem stateid.other[1] == nd->nd_curstateid.other[1] && 328590d2dfabSRick Macklem stateid.other[2] == nd->nd_curstateid.other[2]) 328690d2dfabSRick Macklem nd->nd_flag &= ~ND_CURSTATEID; 32879ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 32889ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 32899ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 32909ec7b004SRick Macklem } 3291a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 32929ec7b004SRick Macklem return (0); 32939ec7b004SRick Macklem nfsmout: 32949ec7b004SRick Macklem vput(vp); 3295a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 32969ec7b004SRick Macklem return (error); 32979ec7b004SRick Macklem } 32989ec7b004SRick Macklem 32999ec7b004SRick Macklem /* 33009ec7b004SRick Macklem * nfsv4 delegpurge service 33019ec7b004SRick Macklem */ 3302b9cc3262SRyan Moeller int 33039ec7b004SRick Macklem nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram, 3304af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 33059ec7b004SRick Macklem { 33069ec7b004SRick Macklem u_int32_t *tl; 33079ec7b004SRick Macklem int error = 0; 33089ec7b004SRick Macklem nfsquad_t clientid; 3309af444b18SEdward Tomasz Napierala struct thread *p = curthread; 33109ec7b004SRick Macklem 3311c9aad40fSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3312b1cfc0d9SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3313a9285ae5SZack Kirsch goto nfsmout; 3314b1cfc0d9SRick Macklem } 33159ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 33169ec7b004SRick Macklem clientid.lval[0] = *tl++; 33179ec7b004SRick Macklem clientid.lval[1] = *tl; 3318c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3319c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3320c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3321c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3322c59e4cc3SRick Macklem printf("EEK9 multiple clids\n"); 33239ec7b004SRick Macklem } else { 3324c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3325c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 33269ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 33279ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 33289ec7b004SRick Macklem } 3329c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL, 333090d2dfabSRick Macklem NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL); 33319ec7b004SRick Macklem nfsmout: 3332a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 33339ec7b004SRick Macklem return (error); 33349ec7b004SRick Macklem } 33359ec7b004SRick Macklem 33369ec7b004SRick Macklem /* 33379ec7b004SRick Macklem * nfsv4 delegreturn service 33389ec7b004SRick Macklem */ 3339b9cc3262SRyan Moeller int 33409ec7b004SRick Macklem nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram, 3341af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 33429ec7b004SRick Macklem { 33439ec7b004SRick Macklem u_int32_t *tl; 334490d2dfabSRick Macklem int error = 0, writeacc; 33459ec7b004SRick Macklem nfsv4stateid_t stateid; 33469ec7b004SRick Macklem nfsquad_t clientid; 334790d2dfabSRick Macklem struct nfsvattr na; 3348af444b18SEdward Tomasz Napierala struct thread *p = curthread; 33499ec7b004SRick Macklem 33509ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 33519ec7b004SRick Macklem stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 33529ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER); 33539ec7b004SRick Macklem clientid.lval[0] = stateid.other[0]; 33549ec7b004SRick Macklem clientid.lval[1] = stateid.other[1]; 3355c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3356c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3357c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3358c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3359c59e4cc3SRick Macklem printf("EEK10 multiple clids\n"); 33609ec7b004SRick Macklem } else { 3361c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3362c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 33639ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 33649ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 33659ec7b004SRick Macklem } 3366c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp, 336790d2dfabSRick Macklem NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc); 336890d2dfabSRick Macklem /* For pNFS, update the attributes. */ 336990d2dfabSRick Macklem if (writeacc != 0 || nfsrv_pnfsatime != 0) 337090d2dfabSRick Macklem nfsrv_updatemdsattr(vp, &na, p); 33719ec7b004SRick Macklem nfsmout: 33729ec7b004SRick Macklem vput(vp); 3373a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 33749ec7b004SRick Macklem return (error); 33759ec7b004SRick Macklem } 33769ec7b004SRick Macklem 33779ec7b004SRick Macklem /* 33789ec7b004SRick Macklem * nfsv4 get file handle service 33799ec7b004SRick Macklem */ 3380b9cc3262SRyan Moeller int 33819ec7b004SRick Macklem nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram, 3382af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 33839ec7b004SRick Macklem { 33849ec7b004SRick Macklem fhandle_t fh; 3385af444b18SEdward Tomasz Napierala struct thread *p = curthread; 33869ec7b004SRick Macklem 33879ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 33889ec7b004SRick Macklem vput(vp); 33899ec7b004SRick Macklem if (!nd->nd_repstat) 33909ec7b004SRick Macklem (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 3391a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 33929ec7b004SRick Macklem return (0); 33939ec7b004SRick Macklem } 33949ec7b004SRick Macklem 33959ec7b004SRick Macklem /* 33969ec7b004SRick Macklem * nfsv4 open confirm service 33979ec7b004SRick Macklem */ 3398b9cc3262SRyan Moeller int 33999ec7b004SRick Macklem nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram, 3400af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 34019ec7b004SRick Macklem { 34029ec7b004SRick Macklem u_int32_t *tl; 34039ec7b004SRick Macklem struct nfsstate st, *stp = &st; 34049ec7b004SRick Macklem int error = 0; 34059ec7b004SRick Macklem nfsv4stateid_t stateid; 34069ec7b004SRick Macklem nfsquad_t clientid; 3407af444b18SEdward Tomasz Napierala struct thread *p = curthread; 34089ec7b004SRick Macklem 3409c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3410c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3411c59e4cc3SRick Macklem goto nfsmout; 3412c59e4cc3SRick Macklem } 34139ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 34149ec7b004SRick Macklem stp->ls_ownerlen = 0; 34159ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 34169ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 34179ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 34189ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 34199ec7b004SRick Macklem NFSX_STATEIDOTHER); 34209ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 34219ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl); 34229ec7b004SRick Macklem stp->ls_flags = NFSLCK_CONFIRM; 34239ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 34249ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 3425c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3426c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3427c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3428c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3429c59e4cc3SRick Macklem printf("EEK11 multiple clids\n"); 34309ec7b004SRick Macklem } else { 3431c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3432c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 34339ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 34349ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 34359ec7b004SRick Macklem } 343690d2dfabSRick Macklem nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, 343790d2dfabSRick Macklem NULL); 34389ec7b004SRick Macklem if (!nd->nd_repstat) { 34399ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 34409ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 34419ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 34429ec7b004SRick Macklem } 34439ec7b004SRick Macklem nfsmout: 34449ec7b004SRick Macklem vput(vp); 3445a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 34469ec7b004SRick Macklem return (error); 34479ec7b004SRick Macklem } 34489ec7b004SRick Macklem 34499ec7b004SRick Macklem /* 34509ec7b004SRick Macklem * nfsv4 open downgrade service 34519ec7b004SRick Macklem */ 3452b9cc3262SRyan Moeller int 34539ec7b004SRick Macklem nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram, 3454af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 34559ec7b004SRick Macklem { 34569ec7b004SRick Macklem u_int32_t *tl; 34579ec7b004SRick Macklem int i; 34589ec7b004SRick Macklem struct nfsstate st, *stp = &st; 34599ec7b004SRick Macklem int error = 0; 34609ec7b004SRick Macklem nfsv4stateid_t stateid; 34619ec7b004SRick Macklem nfsquad_t clientid; 3462af444b18SEdward Tomasz Napierala struct thread *p = curthread; 34639ec7b004SRick Macklem 3464d8a5961fSMarcelo Araujo /* opendowngrade can only work on a file object.*/ 3465d8a5961fSMarcelo Araujo if (vp->v_type != VREG) { 3466d8a5961fSMarcelo Araujo error = NFSERR_INVAL; 3467d8a5961fSMarcelo Araujo goto nfsmout; 3468d8a5961fSMarcelo Araujo } 34699ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 34709ec7b004SRick Macklem stp->ls_ownerlen = 0; 34719ec7b004SRick Macklem stp->ls_op = nd->nd_rp; 34729ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 34739ec7b004SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 34749ec7b004SRick Macklem NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 34759ec7b004SRick Macklem NFSX_STATEIDOTHER); 34769ec7b004SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 347790d2dfabSRick Macklem 347890d2dfabSRick Macklem /* 347990d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 348090d2dfabSRick Macklem * stateid to the current stateid, if it is set. 348190d2dfabSRick Macklem */ 348290d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 348390d2dfabSRick Macklem stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 348490d2dfabSRick Macklem stp->ls_stateid.other[2] == 0) { 348590d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) 348690d2dfabSRick Macklem stp->ls_stateid = nd->nd_curstateid; 348790d2dfabSRick Macklem else { 348890d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 348990d2dfabSRick Macklem goto nfsmout; 349090d2dfabSRick Macklem } 349190d2dfabSRick Macklem } 349290d2dfabSRick Macklem 34939ec7b004SRick Macklem stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 34949ec7b004SRick Macklem i = fxdr_unsigned(int, *tl++); 34956269d663SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 34966269d663SRick Macklem i &= ~NFSV4OPEN_WANTDELEGMASK; 34979ec7b004SRick Macklem switch (i) { 34989ec7b004SRick Macklem case NFSV4OPEN_ACCESSREAD: 34999ec7b004SRick Macklem stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE); 35009ec7b004SRick Macklem break; 35019ec7b004SRick Macklem case NFSV4OPEN_ACCESSWRITE: 35029ec7b004SRick Macklem stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); 35039ec7b004SRick Macklem break; 35049ec7b004SRick Macklem case NFSV4OPEN_ACCESSBOTH: 35059ec7b004SRick Macklem stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS | 35069ec7b004SRick Macklem NFSLCK_DOWNGRADE); 35079ec7b004SRick Macklem break; 35089ec7b004SRick Macklem default: 35096269d663SRick Macklem nd->nd_repstat = NFSERR_INVAL; 351074b8d63dSPedro F. Giffuni } 35119ec7b004SRick Macklem i = fxdr_unsigned(int, *tl); 35129ec7b004SRick Macklem switch (i) { 35139ec7b004SRick Macklem case NFSV4OPEN_DENYNONE: 35149ec7b004SRick Macklem break; 35159ec7b004SRick Macklem case NFSV4OPEN_DENYREAD: 35169ec7b004SRick Macklem stp->ls_flags |= NFSLCK_READDENY; 35179ec7b004SRick Macklem break; 35189ec7b004SRick Macklem case NFSV4OPEN_DENYWRITE: 35199ec7b004SRick Macklem stp->ls_flags |= NFSLCK_WRITEDENY; 35209ec7b004SRick Macklem break; 35219ec7b004SRick Macklem case NFSV4OPEN_DENYBOTH: 35229ec7b004SRick Macklem stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 35239ec7b004SRick Macklem break; 35249ec7b004SRick Macklem default: 35256269d663SRick Macklem nd->nd_repstat = NFSERR_INVAL; 352674b8d63dSPedro F. Giffuni } 35279ec7b004SRick Macklem 35289ec7b004SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0]; 35299ec7b004SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1]; 3530c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3531c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3532c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3533c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3534c59e4cc3SRick Macklem printf("EEK12 multiple clids\n"); 35359ec7b004SRick Macklem } else { 3536c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3537c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 35389ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 35399ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 35409ec7b004SRick Macklem } 35419ec7b004SRick Macklem if (!nd->nd_repstat) 35429ec7b004SRick Macklem nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, 354390d2dfabSRick Macklem nd, p, NULL); 35449ec7b004SRick Macklem if (!nd->nd_repstat) { 354590d2dfabSRick Macklem /* For NFSv4.1, set the Current StateID. */ 354690d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 354790d2dfabSRick Macklem nd->nd_curstateid = stateid; 354890d2dfabSRick Macklem nd->nd_flag |= ND_CURSTATEID; 354990d2dfabSRick Macklem } 35509ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 35519ec7b004SRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 35529ec7b004SRick Macklem NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 35539ec7b004SRick Macklem } 35549ec7b004SRick Macklem nfsmout: 35559ec7b004SRick Macklem vput(vp); 3556a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 35579ec7b004SRick Macklem return (error); 35589ec7b004SRick Macklem } 35599ec7b004SRick Macklem 35609ec7b004SRick Macklem /* 35619ec7b004SRick Macklem * nfsv4 renew lease service 35629ec7b004SRick Macklem */ 3563b9cc3262SRyan Moeller int 35649ec7b004SRick Macklem nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram, 3565af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 35669ec7b004SRick Macklem { 35679ec7b004SRick Macklem u_int32_t *tl; 35689ec7b004SRick Macklem int error = 0; 35699ec7b004SRick Macklem nfsquad_t clientid; 3570af444b18SEdward Tomasz Napierala struct thread *p = curthread; 35719ec7b004SRick Macklem 3572c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3573c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3574c59e4cc3SRick Macklem goto nfsmout; 3575c59e4cc3SRick Macklem } 3576c9aad40fSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3577b1cfc0d9SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3578a9285ae5SZack Kirsch goto nfsmout; 3579b1cfc0d9SRick Macklem } 35809ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 35819ec7b004SRick Macklem clientid.lval[0] = *tl++; 35829ec7b004SRick Macklem clientid.lval[1] = *tl; 3583c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3584c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3585c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 3586c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 3587c59e4cc3SRick Macklem printf("EEK13 multiple clids\n"); 35889ec7b004SRick Macklem } else { 3589c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 3590c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 35919ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 35929ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 35939ec7b004SRick Macklem } 35949ec7b004SRick Macklem nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW), 3595c59e4cc3SRick Macklem NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p); 35969ec7b004SRick Macklem nfsmout: 3597a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 35989ec7b004SRick Macklem return (error); 35999ec7b004SRick Macklem } 36009ec7b004SRick Macklem 36019ec7b004SRick Macklem /* 36029ec7b004SRick Macklem * nfsv4 security info service 36039ec7b004SRick Macklem */ 3604b9cc3262SRyan Moeller int 36059ec7b004SRick Macklem nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram, 3606af444b18SEdward Tomasz Napierala vnode_t dp, struct nfsexstuff *exp) 36079ec7b004SRick Macklem { 36089ec7b004SRick Macklem u_int32_t *tl; 36099ec7b004SRick Macklem int len; 36109ec7b004SRick Macklem struct nameidata named; 36119ec7b004SRick Macklem vnode_t dirp = NULL, vp; 36129ec7b004SRick Macklem struct nfsrvfh fh; 36139ec7b004SRick Macklem struct nfsexstuff retnes; 36149ec7b004SRick Macklem u_int32_t *sizp; 3615a9285ae5SZack Kirsch int error = 0, savflag, i; 36169ec7b004SRick Macklem char *bufp; 36179ec7b004SRick Macklem u_long *hashp; 3618af444b18SEdward Tomasz Napierala struct thread *p = curthread; 36199ec7b004SRick Macklem 36209ec7b004SRick Macklem /* 36219ec7b004SRick Macklem * All this just to get the export flags for the name. 36229ec7b004SRick Macklem */ 36239ec7b004SRick Macklem NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 36249ec7b004SRick Macklem LOCKLEAF | SAVESTART); 36259ec7b004SRick Macklem nfsvno_setpathbuf(&named, &bufp, &hashp); 36269ec7b004SRick Macklem error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 36279ec7b004SRick Macklem if (error) { 36289ec7b004SRick Macklem vput(dp); 36299ec7b004SRick Macklem nfsvno_relpathbuf(&named); 3630a9285ae5SZack Kirsch goto out; 36319ec7b004SRick Macklem } 36329ec7b004SRick Macklem if (!nd->nd_repstat) { 36339ec7b004SRick Macklem nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 36349ec7b004SRick Macklem } else { 36359ec7b004SRick Macklem vput(dp); 36369ec7b004SRick Macklem nfsvno_relpathbuf(&named); 36379ec7b004SRick Macklem } 36389ec7b004SRick Macklem if (dirp) 36399ec7b004SRick Macklem vrele(dirp); 36409ec7b004SRick Macklem if (nd->nd_repstat) 3641a9285ae5SZack Kirsch goto out; 36429ec7b004SRick Macklem vrele(named.ni_startdir); 36439ec7b004SRick Macklem nfsvno_relpathbuf(&named); 36449ec7b004SRick Macklem fh.nfsrvfh_len = NFSX_MYFH; 36459ec7b004SRick Macklem vp = named.ni_vp; 36469ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 36479ec7b004SRick Macklem vput(vp); 36489ec7b004SRick Macklem savflag = nd->nd_flag; 36499ec7b004SRick Macklem if (!nd->nd_repstat) { 36505edc9102SEdward Tomasz Napierala nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0); 36519ec7b004SRick Macklem if (vp) 36529ec7b004SRick Macklem vput(vp); 36539ec7b004SRick Macklem } 36549ec7b004SRick Macklem nd->nd_flag = savflag; 36559ec7b004SRick Macklem if (nd->nd_repstat) 3656a9285ae5SZack Kirsch goto out; 36579ec7b004SRick Macklem 36589ec7b004SRick Macklem /* 36599ec7b004SRick Macklem * Finally have the export flags for name, so we can create 36609ec7b004SRick Macklem * the security info. 36619ec7b004SRick Macklem */ 36629ec7b004SRick Macklem len = 0; 36639ec7b004SRick Macklem NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED); 366498ad4453SRick Macklem for (i = 0; i < retnes.nes_numsecflavor; i++) { 366598ad4453SRick Macklem if (retnes.nes_secflavors[i] == AUTH_SYS) { 36669ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 36679ec7b004SRick Macklem *tl = txdr_unsigned(RPCAUTH_UNIX); 36689ec7b004SRick Macklem len++; 366998ad4453SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 36709ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 36719ec7b004SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_GSS); 36729ec7b004SRick Macklem (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 36739ec7b004SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 36749ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 36759ec7b004SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 367698ad4453SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 36779ec7b004SRick Macklem len++; 367898ad4453SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 367998ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 368098ad4453SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_GSS); 368198ad4453SRick Macklem (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 368298ad4453SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 368398ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 368498ad4453SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 368598ad4453SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 368698ad4453SRick Macklem len++; 368798ad4453SRick Macklem } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 368898ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 368998ad4453SRick Macklem *tl++ = txdr_unsigned(RPCAUTH_GSS); 369098ad4453SRick Macklem (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 369198ad4453SRick Macklem nfsgss_mechlist[KERBV_MECH].len); 369298ad4453SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 369398ad4453SRick Macklem *tl++ = txdr_unsigned(GSS_KERBV_QOP); 369498ad4453SRick Macklem *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 369598ad4453SRick Macklem len++; 369698ad4453SRick Macklem } 36979ec7b004SRick Macklem } 36989ec7b004SRick Macklem *sizp = txdr_unsigned(len); 3699a9285ae5SZack Kirsch 3700a9285ae5SZack Kirsch out: 3701a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 3702a9285ae5SZack Kirsch return (error); 37039ec7b004SRick Macklem } 37049ec7b004SRick Macklem 37059ec7b004SRick Macklem /* 37069ec7b004SRick Macklem * nfsv4 set client id service 37079ec7b004SRick Macklem */ 3708b9cc3262SRyan Moeller int 37099ec7b004SRick Macklem nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, 3710af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 37119ec7b004SRick Macklem { 37129ec7b004SRick Macklem u_int32_t *tl; 37139ec7b004SRick Macklem int i; 37149ec7b004SRick Macklem int error = 0, idlen; 37159ec7b004SRick Macklem struct nfsclient *clp = NULL; 3716ed2f1001SRick Macklem #ifdef INET 3717ed2f1001SRick Macklem struct sockaddr_in *rin; 3718ed2f1001SRick Macklem #endif 3719ed2f1001SRick Macklem #ifdef INET6 3720ed2f1001SRick Macklem struct sockaddr_in6 *rin6; 3721ed2f1001SRick Macklem #endif 3722ed2f1001SRick Macklem #if defined(INET) || defined(INET6) 3723ed2f1001SRick Macklem u_char *ucp, *ucp2; 3724ed2f1001SRick Macklem #endif 3725ed2f1001SRick Macklem u_char *verf, *addrbuf; 37269ec7b004SRick Macklem nfsquad_t clientid, confirm; 3727af444b18SEdward Tomasz Napierala struct thread *p = curthread; 37289ec7b004SRick Macklem 3729c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3730c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3731c59e4cc3SRick Macklem goto nfsmout; 3732c59e4cc3SRick Macklem } 3733c9aad40fSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 37349ec7b004SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3735a9285ae5SZack Kirsch goto out; 37369ec7b004SRick Macklem } 37379ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 37389ec7b004SRick Macklem verf = (u_char *)tl; 37399ec7b004SRick Macklem tl += (NFSX_VERF / NFSX_UNSIGNED); 37409ec7b004SRick Macklem i = fxdr_unsigned(int, *tl); 37419ec7b004SRick Macklem if (i > NFSV4_OPAQUELIMIT || i <= 0) { 37429ec7b004SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 3743a9285ae5SZack Kirsch goto nfsmout; 37449ec7b004SRick Macklem } 37459ec7b004SRick Macklem idlen = i; 37469ec7b004SRick Macklem if (nd->nd_flag & ND_GSS) 37479ec7b004SRick Macklem i += nd->nd_princlen; 37481f54e596SRick Macklem clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 37491f54e596SRick Macklem M_ZERO); 37501f54e596SRick Macklem clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 37511f54e596SRick Macklem nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 37529ec7b004SRick Macklem NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3753ed2f1001SRick Macklem /* Allocated large enough for an AF_INET or AF_INET6 socket. */ 3754ed2f1001SRick Macklem clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, 3755b97b91b5SConrad Meyer M_WAITOK | M_ZERO); 37569ec7b004SRick Macklem clp->lc_req.nr_cred = NULL; 37579ec7b004SRick Macklem NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 37589ec7b004SRick Macklem clp->lc_idlen = idlen; 37599ec7b004SRick Macklem error = nfsrv_mtostr(nd, clp->lc_id, idlen); 37609ec7b004SRick Macklem if (error) 37619ec7b004SRick Macklem goto nfsmout; 37629ec7b004SRick Macklem if (nd->nd_flag & ND_GSS) { 37639ec7b004SRick Macklem clp->lc_flags = LCL_GSS; 37649ec7b004SRick Macklem if (nd->nd_flag & ND_GSSINTEGRITY) 37659ec7b004SRick Macklem clp->lc_flags |= LCL_GSSINTEGRITY; 37669ec7b004SRick Macklem else if (nd->nd_flag & ND_GSSPRIVACY) 37679ec7b004SRick Macklem clp->lc_flags |= LCL_GSSPRIVACY; 37689ec7b004SRick Macklem } else { 37699ec7b004SRick Macklem clp->lc_flags = 0; 37709ec7b004SRick Macklem } 37719ec7b004SRick Macklem if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) { 37729ec7b004SRick Macklem clp->lc_flags |= LCL_NAME; 37739ec7b004SRick Macklem clp->lc_namelen = nd->nd_princlen; 37749ec7b004SRick Macklem clp->lc_name = &clp->lc_id[idlen]; 37759ec7b004SRick Macklem NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 37769ec7b004SRick Macklem } else { 37779ec7b004SRick Macklem clp->lc_uid = nd->nd_cred->cr_uid; 37789ec7b004SRick Macklem clp->lc_gid = nd->nd_cred->cr_gid; 37799ec7b004SRick Macklem } 37809ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 37819ec7b004SRick Macklem clp->lc_program = fxdr_unsigned(u_int32_t, *tl); 37829ec7b004SRick Macklem error = nfsrv_getclientipaddr(nd, clp); 37839ec7b004SRick Macklem if (error) 37849ec7b004SRick Macklem goto nfsmout; 37859ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 37869ec7b004SRick Macklem clp->lc_callback = fxdr_unsigned(u_int32_t, *tl); 37879ec7b004SRick Macklem 37889ec7b004SRick Macklem /* 37899ec7b004SRick Macklem * nfsrv_setclient() does the actual work of adding it to the 37909ec7b004SRick Macklem * client list. If there is no error, the structure has been 37919ec7b004SRick Macklem * linked into the client list and clp should no longer be used 37929ec7b004SRick Macklem * here. When an error is returned, it has not been linked in, 37939ec7b004SRick Macklem * so it should be free'd. 37949ec7b004SRick Macklem */ 37959ec7b004SRick Macklem nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 37969ec7b004SRick Macklem if (nd->nd_repstat == NFSERR_CLIDINUSE) { 3797ed2f1001SRick Macklem /* 3798ed2f1001SRick Macklem * 8 is the maximum length of the port# string. 3799ed2f1001SRick Macklem */ 3800ed2f1001SRick Macklem addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK); 3801ed2f1001SRick Macklem switch (clp->lc_req.nr_nam->sa_family) { 3802ed2f1001SRick Macklem #ifdef INET 3803ed2f1001SRick Macklem case AF_INET: 38049ec7b004SRick Macklem if (clp->lc_flags & LCL_TCPCALLBACK) 38059ec7b004SRick Macklem (void) nfsm_strtom(nd, "tcp", 3); 38069ec7b004SRick Macklem else 38079ec7b004SRick Macklem (void) nfsm_strtom(nd, "udp", 3); 3808ed2f1001SRick Macklem rin = (struct sockaddr_in *)clp->lc_req.nr_nam; 3809ed2f1001SRick Macklem ucp = (u_char *)&rin->sin_addr.s_addr; 3810ed2f1001SRick Macklem ucp2 = (u_char *)&rin->sin_port; 38119ec7b004SRick Macklem sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff, 38129ec7b004SRick Macklem ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff, 38139ec7b004SRick Macklem ucp2[0] & 0xff, ucp2[1] & 0xff); 3814ed2f1001SRick Macklem break; 3815ed2f1001SRick Macklem #endif 3816ed2f1001SRick Macklem #ifdef INET6 3817ed2f1001SRick Macklem case AF_INET6: 3818ed2f1001SRick Macklem if (clp->lc_flags & LCL_TCPCALLBACK) 3819ed2f1001SRick Macklem (void) nfsm_strtom(nd, "tcp6", 4); 3820ed2f1001SRick Macklem else 3821ed2f1001SRick Macklem (void) nfsm_strtom(nd, "udp6", 4); 3822ed2f1001SRick Macklem rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam; 3823ed2f1001SRick Macklem ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf, 3824ed2f1001SRick Macklem INET6_ADDRSTRLEN); 3825ed2f1001SRick Macklem if (ucp != NULL) 3826ed2f1001SRick Macklem i = strlen(ucp); 3827ed2f1001SRick Macklem else 3828ed2f1001SRick Macklem i = 0; 3829ed2f1001SRick Macklem ucp2 = (u_char *)&rin6->sin6_port; 3830ed2f1001SRick Macklem sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff, 3831ed2f1001SRick Macklem ucp2[1] & 0xff); 3832ed2f1001SRick Macklem break; 3833ed2f1001SRick Macklem #endif 3834ed2f1001SRick Macklem } 38359ec7b004SRick Macklem (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf)); 3836ed2f1001SRick Macklem free(addrbuf, M_TEMP); 38379ec7b004SRick Macklem } 38389ec7b004SRick Macklem if (clp) { 3839b97b91b5SConrad Meyer free(clp->lc_req.nr_nam, M_SONAME); 38409ec7b004SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 38411f54e596SRick Macklem free(clp->lc_stateid, M_NFSDCLIENT); 38421f54e596SRick Macklem free(clp, M_NFSDCLIENT); 38439ec7b004SRick Macklem } 38449ec7b004SRick Macklem if (!nd->nd_repstat) { 38459ec7b004SRick Macklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); 38469ec7b004SRick Macklem *tl++ = clientid.lval[0]; 38479ec7b004SRick Macklem *tl++ = clientid.lval[1]; 38489ec7b004SRick Macklem *tl++ = confirm.lval[0]; 38499ec7b004SRick Macklem *tl = confirm.lval[1]; 38509ec7b004SRick Macklem } 3851a9285ae5SZack Kirsch 3852a9285ae5SZack Kirsch out: 3853a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 38549ec7b004SRick Macklem return (0); 38559ec7b004SRick Macklem nfsmout: 38569ec7b004SRick Macklem if (clp) { 3857b97b91b5SConrad Meyer free(clp->lc_req.nr_nam, M_SONAME); 38589ec7b004SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 38591f54e596SRick Macklem free(clp->lc_stateid, M_NFSDCLIENT); 38601f54e596SRick Macklem free(clp, M_NFSDCLIENT); 38619ec7b004SRick Macklem } 3862a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 38639ec7b004SRick Macklem return (error); 38649ec7b004SRick Macklem } 38659ec7b004SRick Macklem 38669ec7b004SRick Macklem /* 38679ec7b004SRick Macklem * nfsv4 set client id confirm service 38689ec7b004SRick Macklem */ 3869b9cc3262SRyan Moeller int 38709ec7b004SRick Macklem nfsrvd_setclientidcfrm(struct nfsrv_descript *nd, 3871af444b18SEdward Tomasz Napierala __unused int isdgram, __unused vnode_t vp, 38729ec7b004SRick Macklem __unused struct nfsexstuff *exp) 38739ec7b004SRick Macklem { 38749ec7b004SRick Macklem u_int32_t *tl; 38759ec7b004SRick Macklem int error = 0; 38769ec7b004SRick Macklem nfsquad_t clientid, confirm; 3877af444b18SEdward Tomasz Napierala struct thread *p = curthread; 38789ec7b004SRick Macklem 3879c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3880c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3881c59e4cc3SRick Macklem goto nfsmout; 3882c59e4cc3SRick Macklem } 3883c9aad40fSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 38849ec7b004SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3885a9285ae5SZack Kirsch goto nfsmout; 38869ec7b004SRick Macklem } 38879ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER); 38889ec7b004SRick Macklem clientid.lval[0] = *tl++; 38899ec7b004SRick Macklem clientid.lval[1] = *tl++; 38909ec7b004SRick Macklem confirm.lval[0] = *tl++; 38919ec7b004SRick Macklem confirm.lval[1] = *tl; 38929ec7b004SRick Macklem 38939ec7b004SRick Macklem /* 38949ec7b004SRick Macklem * nfsrv_getclient() searches the client list for a match and 38959ec7b004SRick Macklem * returns the appropriate NFSERR status. 38969ec7b004SRick Macklem */ 38979ec7b004SRick Macklem nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW), 3898c59e4cc3SRick Macklem NULL, NULL, confirm, 0, nd, p); 38999ec7b004SRick Macklem nfsmout: 3900a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 39019ec7b004SRick Macklem return (error); 39029ec7b004SRick Macklem } 39039ec7b004SRick Macklem 39049ec7b004SRick Macklem /* 39059ec7b004SRick Macklem * nfsv4 verify service 39069ec7b004SRick Macklem */ 3907b9cc3262SRyan Moeller int 39089ec7b004SRick Macklem nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, 3909af444b18SEdward Tomasz Napierala vnode_t vp, __unused struct nfsexstuff *exp) 39109ec7b004SRick Macklem { 39119ec7b004SRick Macklem int error = 0, ret, fhsize = NFSX_MYFH; 39129ec7b004SRick Macklem struct nfsvattr nva; 39132f304845SKonstantin Belousov struct statfs *sf; 39149ec7b004SRick Macklem struct nfsfsinfo fs; 39159ec7b004SRick Macklem fhandle_t fh; 3916af444b18SEdward Tomasz Napierala struct thread *p = curthread; 39179ec7b004SRick Macklem 39182f304845SKonstantin Belousov sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 391990d2dfabSRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 39209ec7b004SRick Macklem if (!nd->nd_repstat) 39212f304845SKonstantin Belousov nd->nd_repstat = nfsvno_statfs(vp, sf); 39229ec7b004SRick Macklem if (!nd->nd_repstat) 39239ec7b004SRick Macklem nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 39249ec7b004SRick Macklem if (!nd->nd_repstat) { 39259ec7b004SRick Macklem nfsvno_getfs(&fs, isdgram); 39269ec7b004SRick Macklem error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL, 39272f304845SKonstantin Belousov sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred); 39289ec7b004SRick Macklem if (!error) { 39299ec7b004SRick Macklem if (nd->nd_procnum == NFSV4OP_NVERIFY) { 39309ec7b004SRick Macklem if (ret == 0) 39319ec7b004SRick Macklem nd->nd_repstat = NFSERR_SAME; 39329ec7b004SRick Macklem else if (ret != NFSERR_NOTSAME) 39339ec7b004SRick Macklem nd->nd_repstat = ret; 39349ec7b004SRick Macklem } else if (ret) 39359ec7b004SRick Macklem nd->nd_repstat = ret; 39369ec7b004SRick Macklem } 39379ec7b004SRick Macklem } 39389ec7b004SRick Macklem vput(vp); 39392f304845SKonstantin Belousov free(sf, M_STATFS); 3940a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 39419ec7b004SRick Macklem return (error); 39429ec7b004SRick Macklem } 39439ec7b004SRick Macklem 39449ec7b004SRick Macklem /* 39459ec7b004SRick Macklem * nfs openattr rpc 39469ec7b004SRick Macklem */ 3947b9cc3262SRyan Moeller int 39489ec7b004SRick Macklem nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram, 39499ec7b004SRick Macklem vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp, 3950af444b18SEdward Tomasz Napierala __unused struct nfsexstuff *exp) 39519ec7b004SRick Macklem { 39529ec7b004SRick Macklem u_int32_t *tl; 39538014c971SRick Macklem int error = 0, createdir __unused; 39549ec7b004SRick Macklem 39559ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 39569ec7b004SRick Macklem createdir = fxdr_unsigned(int, *tl); 39579ec7b004SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 39589ec7b004SRick Macklem nfsmout: 39599ec7b004SRick Macklem vrele(dp); 3960a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 39619ec7b004SRick Macklem return (error); 39629ec7b004SRick Macklem } 39639ec7b004SRick Macklem 39649ec7b004SRick Macklem /* 39659ec7b004SRick Macklem * nfsv4 release lock owner service 39669ec7b004SRick Macklem */ 3967b9cc3262SRyan Moeller int 39689ec7b004SRick Macklem nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram, 3969af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 39709ec7b004SRick Macklem { 39719ec7b004SRick Macklem u_int32_t *tl; 39729ec7b004SRick Macklem struct nfsstate *stp = NULL; 39739ec7b004SRick Macklem int error = 0, len; 39749ec7b004SRick Macklem nfsquad_t clientid; 3975af444b18SEdward Tomasz Napierala struct thread *p = curthread; 39769ec7b004SRick Macklem 3977c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 3978c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 3979c59e4cc3SRick Macklem goto nfsmout; 3980c59e4cc3SRick Macklem } 3981c9aad40fSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3982b1cfc0d9SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 3983a9285ae5SZack Kirsch goto nfsmout; 3984b1cfc0d9SRick Macklem } 39859ec7b004SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 39869ec7b004SRick Macklem len = fxdr_unsigned(int, *(tl + 2)); 39872a45247cSRick Macklem if (len <= 0 || len > NFSV4_OPAQUELIMIT) { 39882a45247cSRick Macklem nd->nd_repstat = NFSERR_BADXDR; 3989a9285ae5SZack Kirsch goto nfsmout; 39902a45247cSRick Macklem } 3991222daa42SConrad Meyer stp = malloc(sizeof (struct nfsstate) + len, 39929ec7b004SRick Macklem M_NFSDSTATE, M_WAITOK); 39939ec7b004SRick Macklem stp->ls_ownerlen = len; 39949ec7b004SRick Macklem stp->ls_op = NULL; 39959ec7b004SRick Macklem stp->ls_flags = NFSLCK_RELEASE; 39969ec7b004SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 39979ec7b004SRick Macklem clientid.lval[0] = *tl++; 39989ec7b004SRick Macklem clientid.lval[1] = *tl; 3999c59e4cc3SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 4000c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 4001c59e4cc3SRick Macklem clientid.qval = nd->nd_clientid.qval; 4002c59e4cc3SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 4003c59e4cc3SRick Macklem printf("EEK14 multiple clids\n"); 40049ec7b004SRick Macklem } else { 4005c59e4cc3SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 4006c59e4cc3SRick Macklem printf("EEK! no clientid from session\n"); 40079ec7b004SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 40089ec7b004SRick Macklem nd->nd_clientid.qval = clientid.qval; 40099ec7b004SRick Macklem } 40109ec7b004SRick Macklem error = nfsrv_mtostr(nd, stp->ls_owner, len); 40119ec7b004SRick Macklem if (error) 40129ec7b004SRick Macklem goto nfsmout; 40139ec7b004SRick Macklem nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p); 4014222daa42SConrad Meyer free(stp, M_NFSDSTATE); 4015a9285ae5SZack Kirsch 4016a9285ae5SZack Kirsch NFSEXITCODE2(0, nd); 40179ec7b004SRick Macklem return (0); 40189ec7b004SRick Macklem nfsmout: 40199ec7b004SRick Macklem if (stp) 4020222daa42SConrad Meyer free(stp, M_NFSDSTATE); 4021a9285ae5SZack Kirsch NFSEXITCODE2(error, nd); 40229ec7b004SRick Macklem return (error); 40239ec7b004SRick Macklem } 4024c59e4cc3SRick Macklem 4025c59e4cc3SRick Macklem /* 4026c59e4cc3SRick Macklem * nfsv4 exchange_id service 4027c59e4cc3SRick Macklem */ 4028b9cc3262SRyan Moeller int 4029c59e4cc3SRick Macklem nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram, 4030af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4031c59e4cc3SRick Macklem { 4032c59e4cc3SRick Macklem uint32_t *tl; 4033c59e4cc3SRick Macklem int error = 0, i, idlen; 4034c59e4cc3SRick Macklem struct nfsclient *clp = NULL; 4035c59e4cc3SRick Macklem nfsquad_t clientid, confirm; 4036c59e4cc3SRick Macklem uint8_t *verf; 4037c59e4cc3SRick Macklem uint32_t sp4type, v41flags; 4038c59e4cc3SRick Macklem uint64_t owner_minor; 4039c59e4cc3SRick Macklem struct timespec verstime; 4040ed2f1001SRick Macklem #ifdef INET 4041ed2f1001SRick Macklem struct sockaddr_in *sin, *rin; 4042ed2f1001SRick Macklem #endif 4043ed2f1001SRick Macklem #ifdef INET6 4044ed2f1001SRick Macklem struct sockaddr_in6 *sin6, *rin6; 4045ed2f1001SRick Macklem #endif 4046af444b18SEdward Tomasz Napierala struct thread *p = curthread; 4047c59e4cc3SRick Macklem 4048c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4049c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 4050c59e4cc3SRick Macklem goto nfsmout; 4051c59e4cc3SRick Macklem } 4052c59e4cc3SRick Macklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 4053c59e4cc3SRick Macklem verf = (uint8_t *)tl; 4054c59e4cc3SRick Macklem tl += (NFSX_VERF / NFSX_UNSIGNED); 4055c59e4cc3SRick Macklem i = fxdr_unsigned(int, *tl); 4056c59e4cc3SRick Macklem if (i > NFSV4_OPAQUELIMIT || i <= 0) { 4057c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 4058c59e4cc3SRick Macklem goto nfsmout; 4059c59e4cc3SRick Macklem } 4060c59e4cc3SRick Macklem idlen = i; 4061c59e4cc3SRick Macklem if (nd->nd_flag & ND_GSS) 4062c59e4cc3SRick Macklem i += nd->nd_princlen; 40631f54e596SRick Macklem clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 40641f54e596SRick Macklem M_ZERO); 40651f54e596SRick Macklem clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 40661f54e596SRick Macklem nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 4067c59e4cc3SRick Macklem NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 4068ed2f1001SRick Macklem /* Allocated large enough for an AF_INET or AF_INET6 socket. */ 4069ed2f1001SRick Macklem clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, 4070b97b91b5SConrad Meyer M_WAITOK | M_ZERO); 4071ed2f1001SRick Macklem switch (nd->nd_nam->sa_family) { 4072ed2f1001SRick Macklem #ifdef INET 4073ed2f1001SRick Macklem case AF_INET: 4074ed2f1001SRick Macklem rin = (struct sockaddr_in *)clp->lc_req.nr_nam; 4075ed2f1001SRick Macklem sin = (struct sockaddr_in *)nd->nd_nam; 4076ed2f1001SRick Macklem rin->sin_family = AF_INET; 4077ed2f1001SRick Macklem rin->sin_len = sizeof(struct sockaddr_in); 4078ed2f1001SRick Macklem rin->sin_port = 0; 4079ed2f1001SRick Macklem rin->sin_addr.s_addr = sin->sin_addr.s_addr; 4080ed2f1001SRick Macklem break; 4081ed2f1001SRick Macklem #endif 4082ed2f1001SRick Macklem #ifdef INET6 4083ed2f1001SRick Macklem case AF_INET6: 4084ed2f1001SRick Macklem rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam; 4085ed2f1001SRick Macklem sin6 = (struct sockaddr_in6 *)nd->nd_nam; 4086ed2f1001SRick Macklem rin6->sin6_family = AF_INET6; 4087ed2f1001SRick Macklem rin6->sin6_len = sizeof(struct sockaddr_in6); 4088ed2f1001SRick Macklem rin6->sin6_port = 0; 4089ed2f1001SRick Macklem rin6->sin6_addr = sin6->sin6_addr; 4090ed2f1001SRick Macklem break; 4091ed2f1001SRick Macklem #endif 4092ed2f1001SRick Macklem } 4093c59e4cc3SRick Macklem clp->lc_req.nr_cred = NULL; 4094c59e4cc3SRick Macklem NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 4095c59e4cc3SRick Macklem clp->lc_idlen = idlen; 4096c59e4cc3SRick Macklem error = nfsrv_mtostr(nd, clp->lc_id, idlen); 4097c59e4cc3SRick Macklem if (error != 0) 4098c59e4cc3SRick Macklem goto nfsmout; 4099c59e4cc3SRick Macklem if ((nd->nd_flag & ND_GSS) != 0) { 4100c59e4cc3SRick Macklem clp->lc_flags = LCL_GSS | LCL_NFSV41; 4101c59e4cc3SRick Macklem if ((nd->nd_flag & ND_GSSINTEGRITY) != 0) 4102c59e4cc3SRick Macklem clp->lc_flags |= LCL_GSSINTEGRITY; 4103c59e4cc3SRick Macklem else if ((nd->nd_flag & ND_GSSPRIVACY) != 0) 4104c59e4cc3SRick Macklem clp->lc_flags |= LCL_GSSPRIVACY; 4105c59e4cc3SRick Macklem } else 4106c59e4cc3SRick Macklem clp->lc_flags = LCL_NFSV41; 4107c057a378SRick Macklem if ((nd->nd_flag & ND_NFSV42) != 0) 4108c057a378SRick Macklem clp->lc_flags |= LCL_NFSV42; 4109c59e4cc3SRick Macklem if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) { 4110c59e4cc3SRick Macklem clp->lc_flags |= LCL_NAME; 4111c59e4cc3SRick Macklem clp->lc_namelen = nd->nd_princlen; 4112c59e4cc3SRick Macklem clp->lc_name = &clp->lc_id[idlen]; 4113c59e4cc3SRick Macklem NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 4114c59e4cc3SRick Macklem } else { 4115c59e4cc3SRick Macklem clp->lc_uid = nd->nd_cred->cr_uid; 4116c59e4cc3SRick Macklem clp->lc_gid = nd->nd_cred->cr_gid; 4117c59e4cc3SRick Macklem } 4118c59e4cc3SRick Macklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4119c59e4cc3SRick Macklem v41flags = fxdr_unsigned(uint32_t, *tl++); 4120c59e4cc3SRick Macklem if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR | 4121c59e4cc3SRick Macklem NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS | 4122c59e4cc3SRick Macklem NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) { 4123c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_INVAL; 4124c59e4cc3SRick Macklem goto nfsmout; 4125c59e4cc3SRick Macklem } 4126c59e4cc3SRick Macklem if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0) 4127c59e4cc3SRick Macklem confirm.lval[1] = 1; 4128c59e4cc3SRick Macklem else 4129c59e4cc3SRick Macklem confirm.lval[1] = 0; 413090d2dfabSRick Macklem if (nfsrv_devidcnt == 0) 413190d2dfabSRick Macklem v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS; 413290d2dfabSRick Macklem else 413390d2dfabSRick Macklem v41flags = NFSV4EXCH_USEPNFSMDS; 4134c59e4cc3SRick Macklem sp4type = fxdr_unsigned(uint32_t, *tl); 4135c59e4cc3SRick Macklem if (sp4type != NFSV4EXCH_SP4NONE) { 4136c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 4137c59e4cc3SRick Macklem goto nfsmout; 4138c59e4cc3SRick Macklem } 4139c59e4cc3SRick Macklem 4140c59e4cc3SRick Macklem /* 4141c59e4cc3SRick Macklem * nfsrv_setclient() does the actual work of adding it to the 4142c59e4cc3SRick Macklem * client list. If there is no error, the structure has been 4143c59e4cc3SRick Macklem * linked into the client list and clp should no longer be used 4144c59e4cc3SRick Macklem * here. When an error is returned, it has not been linked in, 4145c59e4cc3SRick Macklem * so it should be free'd. 4146c59e4cc3SRick Macklem */ 4147c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 4148c59e4cc3SRick Macklem if (clp != NULL) { 4149b97b91b5SConrad Meyer free(clp->lc_req.nr_nam, M_SONAME); 4150c59e4cc3SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 41511f54e596SRick Macklem free(clp->lc_stateid, M_NFSDCLIENT); 4152c59e4cc3SRick Macklem free(clp, M_NFSDCLIENT); 4153c59e4cc3SRick Macklem } 4154c59e4cc3SRick Macklem if (nd->nd_repstat == 0) { 4155c59e4cc3SRick Macklem if (confirm.lval[1] != 0) 4156c59e4cc3SRick Macklem v41flags |= NFSV4EXCH_CONFIRMEDR; 4157c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED); 4158c59e4cc3SRick Macklem *tl++ = clientid.lval[0]; /* ClientID */ 4159c59e4cc3SRick Macklem *tl++ = clientid.lval[1]; 4160c59e4cc3SRick Macklem *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */ 4161c59e4cc3SRick Macklem *tl++ = txdr_unsigned(v41flags); /* Exch flags */ 4162c59e4cc3SRick Macklem *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */ 4163c59e4cc3SRick Macklem owner_minor = 0; /* Owner */ 4164c59e4cc3SRick Macklem txdr_hyper(owner_minor, tl); /* Minor */ 4165c59e4cc3SRick Macklem (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid, 4166c59e4cc3SRick Macklem strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */ 41678932a483SRick Macklem (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid, 41688932a483SRick Macklem strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Scope */ 41698932a483SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4170c59e4cc3SRick Macklem *tl = txdr_unsigned(1); 4171c59e4cc3SRick Macklem (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 4172c59e4cc3SRick Macklem (void)nfsm_strtom(nd, version, strlen(version)); 4173c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 4174c59e4cc3SRick Macklem verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 4175c59e4cc3SRick Macklem verstime.tv_nsec = 0; 4176c59e4cc3SRick Macklem txdr_nfsv4time(&verstime, tl); 4177c59e4cc3SRick Macklem } 4178c59e4cc3SRick Macklem NFSEXITCODE2(0, nd); 4179c59e4cc3SRick Macklem return (0); 4180c59e4cc3SRick Macklem nfsmout: 4181c59e4cc3SRick Macklem if (clp != NULL) { 4182b97b91b5SConrad Meyer free(clp->lc_req.nr_nam, M_SONAME); 4183c59e4cc3SRick Macklem NFSFREEMUTEX(&clp->lc_req.nr_mtx); 41841f54e596SRick Macklem free(clp->lc_stateid, M_NFSDCLIENT); 4185c59e4cc3SRick Macklem free(clp, M_NFSDCLIENT); 4186c59e4cc3SRick Macklem } 4187c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4188c59e4cc3SRick Macklem return (error); 4189c59e4cc3SRick Macklem } 4190c59e4cc3SRick Macklem 4191c59e4cc3SRick Macklem /* 4192c59e4cc3SRick Macklem * nfsv4 create session service 4193c59e4cc3SRick Macklem */ 4194b9cc3262SRyan Moeller int 4195c59e4cc3SRick Macklem nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram, 4196af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4197c59e4cc3SRick Macklem { 4198c59e4cc3SRick Macklem uint32_t *tl; 4199c59e4cc3SRick Macklem int error = 0; 4200c59e4cc3SRick Macklem nfsquad_t clientid, confirm; 4201c59e4cc3SRick Macklem struct nfsdsession *sep = NULL; 4202c59e4cc3SRick Macklem uint32_t rdmacnt; 4203af444b18SEdward Tomasz Napierala struct thread *p = curthread; 4204c59e4cc3SRick Macklem 4205c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4206c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 4207c59e4cc3SRick Macklem goto nfsmout; 4208c59e4cc3SRick Macklem } 4209c59e4cc3SRick Macklem sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession), 4210c59e4cc3SRick Macklem M_NFSDSESSION, M_WAITOK | M_ZERO); 4211c59e4cc3SRick Macklem sep->sess_refcnt = 1; 4212c59e4cc3SRick Macklem mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF); 4213c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 4214c59e4cc3SRick Macklem clientid.lval[0] = *tl++; 4215c59e4cc3SRick Macklem clientid.lval[1] = *tl++; 4216c59e4cc3SRick Macklem confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++); 4217c59e4cc3SRick Macklem sep->sess_crflags = fxdr_unsigned(uint32_t, *tl); 4218c59e4cc3SRick Macklem /* Persistent sessions and RDMA are not supported. */ 4219c59e4cc3SRick Macklem sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN; 4220c59e4cc3SRick Macklem 4221c59e4cc3SRick Macklem /* Fore channel attributes. */ 4222c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4223c59e4cc3SRick Macklem tl++; /* Header pad always 0. */ 4224c59e4cc3SRick Macklem sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++); 422590d2dfabSRick Macklem if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) { 422690d2dfabSRick Macklem sep->sess_maxreq = sb_max_adj - NFS_MAXXDR; 422790d2dfabSRick Macklem printf("Consider increasing kern.ipc.maxsockbuf\n"); 422890d2dfabSRick Macklem } 4229c59e4cc3SRick Macklem sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++); 423090d2dfabSRick Macklem if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) { 423190d2dfabSRick Macklem sep->sess_maxresp = sb_max_adj - NFS_MAXXDR; 423290d2dfabSRick Macklem printf("Consider increasing kern.ipc.maxsockbuf\n"); 423390d2dfabSRick Macklem } 4234c59e4cc3SRick Macklem sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++); 4235c59e4cc3SRick Macklem sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++); 4236c59e4cc3SRick Macklem sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++); 4237c59e4cc3SRick Macklem if (sep->sess_maxslots > NFSV4_SLOTS) 4238c59e4cc3SRick Macklem sep->sess_maxslots = NFSV4_SLOTS; 4239c59e4cc3SRick Macklem rdmacnt = fxdr_unsigned(uint32_t, *tl); 4240c59e4cc3SRick Macklem if (rdmacnt > 1) { 4241c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 4242c59e4cc3SRick Macklem goto nfsmout; 4243c59e4cc3SRick Macklem } else if (rdmacnt == 1) 4244c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4245c59e4cc3SRick Macklem 4246c59e4cc3SRick Macklem /* Back channel attributes. */ 4247c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4248c59e4cc3SRick Macklem tl++; /* Header pad always 0. */ 4249c59e4cc3SRick Macklem sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++); 4250c59e4cc3SRick Macklem sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++); 4251c59e4cc3SRick Macklem sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++); 4252c59e4cc3SRick Macklem sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++); 4253c59e4cc3SRick Macklem sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++); 4254c59e4cc3SRick Macklem rdmacnt = fxdr_unsigned(uint32_t, *tl); 4255c59e4cc3SRick Macklem if (rdmacnt > 1) { 4256c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 4257c59e4cc3SRick Macklem goto nfsmout; 4258c59e4cc3SRick Macklem } else if (rdmacnt == 1) 4259c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4260c59e4cc3SRick Macklem 4261c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4262c59e4cc3SRick Macklem sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl); 4263c59e4cc3SRick Macklem 4264c59e4cc3SRick Macklem /* 4265c59e4cc3SRick Macklem * nfsrv_getclient() searches the client list for a match and 4266c59e4cc3SRick Macklem * returns the appropriate NFSERR status. 4267c59e4cc3SRick Macklem */ 4268c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW, 4269c59e4cc3SRick Macklem NULL, sep, confirm, sep->sess_cbprogram, nd, p); 4270c59e4cc3SRick Macklem if (nd->nd_repstat == 0) { 4271c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4272c59e4cc3SRick Macklem NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID); 4273c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED); 4274c59e4cc3SRick Macklem *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */ 4275c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_crflags); 4276c59e4cc3SRick Macklem 4277c59e4cc3SRick Macklem /* Fore channel attributes. */ 4278c59e4cc3SRick Macklem *tl++ = 0; 4279c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxreq); 4280c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxresp); 4281c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxrespcached); 4282c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxops); 4283c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_maxslots); 4284c59e4cc3SRick Macklem *tl++ = txdr_unsigned(1); 4285c59e4cc3SRick Macklem *tl++ = txdr_unsigned(0); /* No RDMA. */ 4286c59e4cc3SRick Macklem 4287c59e4cc3SRick Macklem /* Back channel attributes. */ 4288c59e4cc3SRick Macklem *tl++ = 0; 4289c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbmaxreq); 4290c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbmaxresp); 4291c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached); 4292c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbmaxops); 4293c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots); 4294c59e4cc3SRick Macklem *tl++ = txdr_unsigned(1); 4295c59e4cc3SRick Macklem *tl = txdr_unsigned(0); /* No RDMA. */ 4296c59e4cc3SRick Macklem } 4297c59e4cc3SRick Macklem nfsmout: 4298c59e4cc3SRick Macklem if (nd->nd_repstat != 0 && sep != NULL) 4299c59e4cc3SRick Macklem free(sep, M_NFSDSESSION); 4300c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4301c59e4cc3SRick Macklem return (error); 4302c59e4cc3SRick Macklem } 4303c59e4cc3SRick Macklem 4304c59e4cc3SRick Macklem /* 4305c59e4cc3SRick Macklem * nfsv4 sequence service 4306c59e4cc3SRick Macklem */ 4307b9cc3262SRyan Moeller int 4308c59e4cc3SRick Macklem nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram, 4309af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4310c59e4cc3SRick Macklem { 4311c59e4cc3SRick Macklem uint32_t *tl; 4312c59e4cc3SRick Macklem uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid; 4313c59e4cc3SRick Macklem int cache_this, error = 0; 4314af444b18SEdward Tomasz Napierala struct thread *p = curthread; 4315c59e4cc3SRick Macklem 4316c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4317c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 4318c59e4cc3SRick Macklem goto nfsmout; 4319c59e4cc3SRick Macklem } 4320c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID); 4321c59e4cc3SRick Macklem NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID); 4322c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 4323c59e4cc3SRick Macklem sequenceid = fxdr_unsigned(uint32_t, *tl++); 4324c59e4cc3SRick Macklem nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++); 4325c59e4cc3SRick Macklem highest_slotid = fxdr_unsigned(uint32_t, *tl++); 4326c59e4cc3SRick Macklem if (*tl == newnfs_true) 4327c59e4cc3SRick Macklem cache_this = 1; 4328c59e4cc3SRick Macklem else 4329c59e4cc3SRick Macklem cache_this = 0; 4330c59e4cc3SRick Macklem nd->nd_flag |= ND_HASSEQUENCE; 4331c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid, 4332c59e4cc3SRick Macklem &target_highest_slotid, cache_this, &sflags, p); 4333c59e4cc3SRick Macklem if (nd->nd_repstat == 0) { 4334c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4335c59e4cc3SRick Macklem NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID); 4336c59e4cc3SRick Macklem NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 4337c59e4cc3SRick Macklem *tl++ = txdr_unsigned(sequenceid); 4338c59e4cc3SRick Macklem *tl++ = txdr_unsigned(nd->nd_slotid); 4339c59e4cc3SRick Macklem *tl++ = txdr_unsigned(highest_slotid); 4340c59e4cc3SRick Macklem *tl++ = txdr_unsigned(target_highest_slotid); 4341c59e4cc3SRick Macklem *tl = txdr_unsigned(sflags); 4342c59e4cc3SRick Macklem } 4343c59e4cc3SRick Macklem nfsmout: 4344c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4345c59e4cc3SRick Macklem return (error); 4346c59e4cc3SRick Macklem } 4347c59e4cc3SRick Macklem 4348c59e4cc3SRick Macklem /* 4349c59e4cc3SRick Macklem * nfsv4 reclaim complete service 4350c59e4cc3SRick Macklem */ 4351b9cc3262SRyan Moeller int 4352c59e4cc3SRick Macklem nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram, 4353af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4354c59e4cc3SRick Macklem { 4355c59e4cc3SRick Macklem uint32_t *tl; 4356a3e709cdSRick Macklem int error = 0, onefs; 4357c59e4cc3SRick Macklem 4358c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4359c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 4360c59e4cc3SRick Macklem goto nfsmout; 4361c59e4cc3SRick Macklem } 4362c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4363a3e709cdSRick Macklem /* 4364a3e709cdSRick Macklem * I believe that a ReclaimComplete with rca_one_fs == TRUE is only 4365a3e709cdSRick Macklem * to be used after a file system has been transferred to a different 4366a3e709cdSRick Macklem * file server. However, RFC5661 is somewhat vague w.r.t. this and 4367a3e709cdSRick Macklem * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs 4368a3e709cdSRick Macklem * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE. 4369a3e709cdSRick Macklem * Therefore, just ignore the rca_one_fs == TRUE operation and return 4370a3e709cdSRick Macklem * NFS_OK without doing anything. 4371a3e709cdSRick Macklem */ 4372a3e709cdSRick Macklem onefs = 0; 4373c59e4cc3SRick Macklem if (*tl == newnfs_true) 4374a3e709cdSRick Macklem onefs = 1; 4375a3e709cdSRick Macklem nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs); 4376c59e4cc3SRick Macklem nfsmout: 4377c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4378c59e4cc3SRick Macklem return (error); 4379c59e4cc3SRick Macklem } 4380c59e4cc3SRick Macklem 4381c59e4cc3SRick Macklem /* 4382c59e4cc3SRick Macklem * nfsv4 destroy clientid service 4383c59e4cc3SRick Macklem */ 4384b9cc3262SRyan Moeller int 4385c59e4cc3SRick Macklem nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram, 4386af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4387c59e4cc3SRick Macklem { 4388c59e4cc3SRick Macklem uint32_t *tl; 4389c59e4cc3SRick Macklem nfsquad_t clientid; 4390c59e4cc3SRick Macklem int error = 0; 4391af444b18SEdward Tomasz Napierala struct thread *p = curthread; 4392c59e4cc3SRick Macklem 4393c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4394c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 4395c59e4cc3SRick Macklem goto nfsmout; 4396c59e4cc3SRick Macklem } 4397c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4398c59e4cc3SRick Macklem clientid.lval[0] = *tl++; 4399c59e4cc3SRick Macklem clientid.lval[1] = *tl; 4400c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_destroyclient(clientid, p); 4401c59e4cc3SRick Macklem nfsmout: 4402c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4403c59e4cc3SRick Macklem return (error); 4404c59e4cc3SRick Macklem } 4405c59e4cc3SRick Macklem 4406c59e4cc3SRick Macklem /* 44079442a64eSRick Macklem * nfsv4 bind connection to session service 44089442a64eSRick Macklem */ 4409b9cc3262SRyan Moeller int 44109442a64eSRick Macklem nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram, 4411af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 44129442a64eSRick Macklem { 44139442a64eSRick Macklem uint32_t *tl; 44149442a64eSRick Macklem uint8_t sessid[NFSX_V4SESSIONID]; 44159442a64eSRick Macklem int error = 0, foreaft; 44169442a64eSRick Macklem 44179442a64eSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 44189442a64eSRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 44199442a64eSRick Macklem goto nfsmout; 44209442a64eSRick Macklem } 44219442a64eSRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED); 44229442a64eSRick Macklem NFSBCOPY(tl, sessid, NFSX_V4SESSIONID); 44239442a64eSRick Macklem tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); 44249442a64eSRick Macklem foreaft = fxdr_unsigned(int, *tl++); 44259442a64eSRick Macklem if (*tl == newnfs_true) { 44269442a64eSRick Macklem /* RDMA is not supported. */ 44279442a64eSRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 44289442a64eSRick Macklem goto nfsmout; 44299442a64eSRick Macklem } 44309442a64eSRick Macklem 44319442a64eSRick Macklem nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft); 44329442a64eSRick Macklem if (nd->nd_repstat == 0) { 44339442a64eSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 * 44349442a64eSRick Macklem NFSX_UNSIGNED); 44359442a64eSRick Macklem NFSBCOPY(sessid, tl, NFSX_V4SESSIONID); 44369442a64eSRick Macklem tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); 44379442a64eSRick Macklem *tl++ = txdr_unsigned(foreaft); 44389442a64eSRick Macklem *tl = newnfs_false; 44399442a64eSRick Macklem } 44409442a64eSRick Macklem nfsmout: 44419442a64eSRick Macklem NFSEXITCODE2(error, nd); 44429442a64eSRick Macklem return (error); 44439442a64eSRick Macklem } 44449442a64eSRick Macklem 44459442a64eSRick Macklem /* 4446c59e4cc3SRick Macklem * nfsv4 destroy session service 4447c59e4cc3SRick Macklem */ 4448b9cc3262SRyan Moeller int 4449c59e4cc3SRick Macklem nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram, 4450af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4451c59e4cc3SRick Macklem { 4452c59e4cc3SRick Macklem uint8_t *cp, sessid[NFSX_V4SESSIONID]; 4453c59e4cc3SRick Macklem int error = 0; 4454c59e4cc3SRick Macklem 4455c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4456c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 4457c59e4cc3SRick Macklem goto nfsmout; 4458c59e4cc3SRick Macklem } 4459c59e4cc3SRick Macklem NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID); 4460c59e4cc3SRick Macklem NFSBCOPY(cp, sessid, NFSX_V4SESSIONID); 4461c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_destroysession(nd, sessid); 4462c59e4cc3SRick Macklem nfsmout: 4463c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 4464c59e4cc3SRick Macklem return (error); 4465c59e4cc3SRick Macklem } 4466c59e4cc3SRick Macklem 4467c59e4cc3SRick Macklem /* 4468c59e4cc3SRick Macklem * nfsv4 free stateid service 4469c59e4cc3SRick Macklem */ 4470b9cc3262SRyan Moeller int 4471c59e4cc3SRick Macklem nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram, 4472af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 4473c59e4cc3SRick Macklem { 4474c59e4cc3SRick Macklem uint32_t *tl; 4475c59e4cc3SRick Macklem nfsv4stateid_t stateid; 4476c59e4cc3SRick Macklem int error = 0; 4477af444b18SEdward Tomasz Napierala struct thread *p = curthread; 4478c59e4cc3SRick Macklem 4479c59e4cc3SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4480c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 4481c59e4cc3SRick Macklem goto nfsmout; 4482c59e4cc3SRick Macklem } 4483c59e4cc3SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 4484c59e4cc3SRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4485c59e4cc3SRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 448690d2dfabSRick Macklem 448790d2dfabSRick Macklem /* 448890d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 448990d2dfabSRick Macklem * stateid to the current stateid, if it is set. 449090d2dfabSRick Macklem */ 449190d2dfabSRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 449290d2dfabSRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 449390d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 449490d2dfabSRick Macklem stateid = nd->nd_curstateid; 449590d2dfabSRick Macklem stateid.seqid = 0; 449690d2dfabSRick Macklem } else { 449790d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 449890d2dfabSRick Macklem goto nfsmout; 449990d2dfabSRick Macklem } 450090d2dfabSRick Macklem } 450190d2dfabSRick Macklem 4502c59e4cc3SRick Macklem nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p); 450390d2dfabSRick Macklem 450490d2dfabSRick Macklem /* If the current stateid has been free'd, unset it. */ 450590d2dfabSRick Macklem if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 && 450690d2dfabSRick Macklem stateid.other[0] == nd->nd_curstateid.other[0] && 450790d2dfabSRick Macklem stateid.other[1] == nd->nd_curstateid.other[1] && 450890d2dfabSRick Macklem stateid.other[2] == nd->nd_curstateid.other[2]) 450990d2dfabSRick Macklem nd->nd_flag &= ~ND_CURSTATEID; 451090d2dfabSRick Macklem nfsmout: 451190d2dfabSRick Macklem NFSEXITCODE2(error, nd); 451290d2dfabSRick Macklem return (error); 451390d2dfabSRick Macklem } 451490d2dfabSRick Macklem 451590d2dfabSRick Macklem /* 451690d2dfabSRick Macklem * nfsv4 layoutget service 451790d2dfabSRick Macklem */ 4518b9cc3262SRyan Moeller int 451990d2dfabSRick Macklem nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram, 4520af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 452190d2dfabSRick Macklem { 452290d2dfabSRick Macklem uint32_t *tl; 452390d2dfabSRick Macklem nfsv4stateid_t stateid; 452490d2dfabSRick Macklem int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose; 452590d2dfabSRick Macklem uint64_t offset, len, minlen; 452690d2dfabSRick Macklem char *layp; 4527af444b18SEdward Tomasz Napierala struct thread *p = curthread; 452890d2dfabSRick Macklem 452990d2dfabSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 453090d2dfabSRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 453190d2dfabSRick Macklem goto nfsmout; 453290d2dfabSRick Macklem } 453390d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 453490d2dfabSRick Macklem NFSX_STATEID); 453590d2dfabSRick Macklem tl++; /* Signal layout available. Ignore for now. */ 453690d2dfabSRick Macklem layouttype = fxdr_unsigned(int, *tl++); 453790d2dfabSRick Macklem iomode = fxdr_unsigned(int, *tl++); 453890d2dfabSRick Macklem offset = fxdr_hyper(tl); tl += 2; 453990d2dfabSRick Macklem len = fxdr_hyper(tl); tl += 2; 454090d2dfabSRick Macklem minlen = fxdr_hyper(tl); tl += 2; 454190d2dfabSRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 454290d2dfabSRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 454390d2dfabSRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 454490d2dfabSRick Macklem maxcnt = fxdr_unsigned(int, *tl); 454590d2dfabSRick Macklem NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n", 454690d2dfabSRick Macklem layouttype, iomode, (uintmax_t)offset, (uintmax_t)len, 454790d2dfabSRick Macklem (uintmax_t)minlen); 454890d2dfabSRick Macklem if (len < minlen || 454990d2dfabSRick Macklem (minlen != UINT64_MAX && offset + minlen < offset) || 455090d2dfabSRick Macklem (len != UINT64_MAX && offset + len < offset)) { 455190d2dfabSRick Macklem nd->nd_repstat = NFSERR_INVAL; 455290d2dfabSRick Macklem goto nfsmout; 455390d2dfabSRick Macklem } 455490d2dfabSRick Macklem 455590d2dfabSRick Macklem /* 455690d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 455790d2dfabSRick Macklem * stateid to the current stateid, if it is set. 455890d2dfabSRick Macklem */ 455990d2dfabSRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 456090d2dfabSRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 456190d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 456290d2dfabSRick Macklem stateid = nd->nd_curstateid; 456390d2dfabSRick Macklem stateid.seqid = 0; 456490d2dfabSRick Macklem } else { 456590d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 456690d2dfabSRick Macklem goto nfsmout; 456790d2dfabSRick Macklem } 456890d2dfabSRick Macklem } 456990d2dfabSRick Macklem 457090d2dfabSRick Macklem layp = NULL; 457190d2dfabSRick Macklem if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1) 457290d2dfabSRick Macklem layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK); 457390d2dfabSRick Macklem else if (layouttype == NFSLAYOUT_FLEXFILE) 457490d2dfabSRick Macklem layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP, 457590d2dfabSRick Macklem M_WAITOK); 457690d2dfabSRick Macklem else 457790d2dfabSRick Macklem nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE; 457890d2dfabSRick Macklem if (layp != NULL) 457990d2dfabSRick Macklem nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype, 458090d2dfabSRick Macklem &iomode, &offset, &len, minlen, &stateid, maxcnt, 458190d2dfabSRick Macklem &retonclose, &layoutlen, layp, nd->nd_cred, p); 458290d2dfabSRick Macklem NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat, 458390d2dfabSRick Macklem layoutlen); 458490d2dfabSRick Macklem if (nd->nd_repstat == 0) { 458590d2dfabSRick Macklem /* For NFSv4.1, set the Current StateID. */ 458690d2dfabSRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) { 458790d2dfabSRick Macklem nd->nd_curstateid = stateid; 458890d2dfabSRick Macklem nd->nd_flag |= ND_CURSTATEID; 458990d2dfabSRick Macklem } 459090d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID + 459190d2dfabSRick Macklem 2 * NFSX_HYPER); 459290d2dfabSRick Macklem *tl++ = txdr_unsigned(retonclose); 459390d2dfabSRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 459490d2dfabSRick Macklem NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER); 459590d2dfabSRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 459690d2dfabSRick Macklem *tl++ = txdr_unsigned(1); /* Only returns one layout. */ 459790d2dfabSRick Macklem txdr_hyper(offset, tl); tl += 2; 459890d2dfabSRick Macklem txdr_hyper(len, tl); tl += 2; 459990d2dfabSRick Macklem *tl++ = txdr_unsigned(iomode); 460090d2dfabSRick Macklem *tl = txdr_unsigned(layouttype); 460190d2dfabSRick Macklem nfsm_strtom(nd, layp, layoutlen); 460290d2dfabSRick Macklem } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) { 460390d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 460490d2dfabSRick Macklem *tl = newnfs_false; 460590d2dfabSRick Macklem } 460690d2dfabSRick Macklem free(layp, M_TEMP); 460790d2dfabSRick Macklem nfsmout: 460890d2dfabSRick Macklem vput(vp); 460990d2dfabSRick Macklem NFSEXITCODE2(error, nd); 461090d2dfabSRick Macklem return (error); 461190d2dfabSRick Macklem } 461290d2dfabSRick Macklem 461390d2dfabSRick Macklem /* 461490d2dfabSRick Macklem * nfsv4 layoutcommit service 461590d2dfabSRick Macklem */ 4616b9cc3262SRyan Moeller int 461790d2dfabSRick Macklem nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram, 4618af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 461990d2dfabSRick Macklem { 462090d2dfabSRick Macklem uint32_t *tl; 462190d2dfabSRick Macklem nfsv4stateid_t stateid; 462290d2dfabSRick Macklem int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim; 462390d2dfabSRick Macklem int hasnewsize; 4624f808cf72SRick Macklem uint64_t offset, len, newoff = 0, newsize; 462590d2dfabSRick Macklem struct timespec newmtime; 462690d2dfabSRick Macklem char *layp; 4627af444b18SEdward Tomasz Napierala struct thread *p = curthread; 462890d2dfabSRick Macklem 462990d2dfabSRick Macklem layp = NULL; 463090d2dfabSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 463190d2dfabSRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 463290d2dfabSRick Macklem goto nfsmout; 463390d2dfabSRick Macklem } 463490d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER + 463590d2dfabSRick Macklem NFSX_STATEID); 463690d2dfabSRick Macklem offset = fxdr_hyper(tl); tl += 2; 463790d2dfabSRick Macklem len = fxdr_hyper(tl); tl += 2; 463890d2dfabSRick Macklem reclaim = fxdr_unsigned(int, *tl++); 463990d2dfabSRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 464090d2dfabSRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 464190d2dfabSRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 464290d2dfabSRick Macklem /* 464390d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set the 464490d2dfabSRick Macklem * stateid to the current stateid, if it is set. 464590d2dfabSRick Macklem */ 464690d2dfabSRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 464790d2dfabSRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 464890d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 464990d2dfabSRick Macklem stateid = nd->nd_curstateid; 465090d2dfabSRick Macklem stateid.seqid = 0; 465190d2dfabSRick Macklem } else { 465290d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 465390d2dfabSRick Macklem goto nfsmout; 465490d2dfabSRick Macklem } 465590d2dfabSRick Macklem } 465690d2dfabSRick Macklem 465790d2dfabSRick Macklem hasnewoff = fxdr_unsigned(int, *tl); 465890d2dfabSRick Macklem if (hasnewoff != 0) { 465990d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 466090d2dfabSRick Macklem newoff = fxdr_hyper(tl); tl += 2; 466190d2dfabSRick Macklem } else 466290d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 466390d2dfabSRick Macklem hasnewmtime = fxdr_unsigned(int, *tl); 466490d2dfabSRick Macklem if (hasnewmtime != 0) { 466590d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED); 466690d2dfabSRick Macklem fxdr_nfsv4time(tl, &newmtime); 466790d2dfabSRick Macklem tl += (NFSX_V4TIME / NFSX_UNSIGNED); 466890d2dfabSRick Macklem } else 466990d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 467090d2dfabSRick Macklem layouttype = fxdr_unsigned(int, *tl++); 467190d2dfabSRick Macklem maxcnt = fxdr_unsigned(int, *tl); 467290d2dfabSRick Macklem if (maxcnt > 0) { 467390d2dfabSRick Macklem layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK); 467490d2dfabSRick Macklem error = nfsrv_mtostr(nd, layp, maxcnt); 467590d2dfabSRick Macklem if (error != 0) 467690d2dfabSRick Macklem goto nfsmout; 467790d2dfabSRick Macklem } 467890d2dfabSRick Macklem nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff, 467990d2dfabSRick Macklem newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid, 468090d2dfabSRick Macklem maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p); 468190d2dfabSRick Macklem NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat); 468290d2dfabSRick Macklem if (nd->nd_repstat == 0) { 468390d2dfabSRick Macklem if (hasnewsize != 0) { 468490d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); 468590d2dfabSRick Macklem *tl++ = newnfs_true; 468690d2dfabSRick Macklem txdr_hyper(newsize, tl); 468790d2dfabSRick Macklem } else { 468890d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 468990d2dfabSRick Macklem *tl = newnfs_false; 469090d2dfabSRick Macklem } 469190d2dfabSRick Macklem } 469290d2dfabSRick Macklem nfsmout: 469390d2dfabSRick Macklem free(layp, M_TEMP); 469490d2dfabSRick Macklem vput(vp); 469590d2dfabSRick Macklem NFSEXITCODE2(error, nd); 469690d2dfabSRick Macklem return (error); 469790d2dfabSRick Macklem } 469890d2dfabSRick Macklem 469990d2dfabSRick Macklem /* 470090d2dfabSRick Macklem * nfsv4 layoutreturn service 470190d2dfabSRick Macklem */ 4702b9cc3262SRyan Moeller int 470390d2dfabSRick Macklem nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram, 4704af444b18SEdward Tomasz Napierala vnode_t vp, struct nfsexstuff *exp) 470590d2dfabSRick Macklem { 470690d2dfabSRick Macklem uint32_t *tl, *layp; 470790d2dfabSRick Macklem nfsv4stateid_t stateid; 470890d2dfabSRick Macklem int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim; 470990d2dfabSRick Macklem uint64_t offset, len; 4710af444b18SEdward Tomasz Napierala struct thread *p = curthread; 471190d2dfabSRick Macklem 471290d2dfabSRick Macklem layp = NULL; 471390d2dfabSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 471490d2dfabSRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 471590d2dfabSRick Macklem goto nfsmout; 471690d2dfabSRick Macklem } 471790d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 471890d2dfabSRick Macklem reclaim = *tl++; 471990d2dfabSRick Macklem layouttype = fxdr_unsigned(int, *tl++); 472090d2dfabSRick Macklem iomode = fxdr_unsigned(int, *tl++); 472190d2dfabSRick Macklem kind = fxdr_unsigned(int, *tl); 472290d2dfabSRick Macklem NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim, 472390d2dfabSRick Macklem layouttype, iomode, kind); 472490d2dfabSRick Macklem if (kind == NFSV4LAYOUTRET_FILE) { 472590d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 472690d2dfabSRick Macklem NFSX_UNSIGNED); 472790d2dfabSRick Macklem offset = fxdr_hyper(tl); tl += 2; 472890d2dfabSRick Macklem len = fxdr_hyper(tl); tl += 2; 472990d2dfabSRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 473090d2dfabSRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 473190d2dfabSRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 473290d2dfabSRick Macklem 473390d2dfabSRick Macklem /* 473490d2dfabSRick Macklem * For the special stateid of other all 0s and seqid == 1, set 473590d2dfabSRick Macklem * the stateid to the current stateid, if it is set. 473690d2dfabSRick Macklem */ 473790d2dfabSRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 473890d2dfabSRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 473990d2dfabSRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 474090d2dfabSRick Macklem stateid = nd->nd_curstateid; 474190d2dfabSRick Macklem stateid.seqid = 0; 474290d2dfabSRick Macklem } else { 474390d2dfabSRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 474490d2dfabSRick Macklem goto nfsmout; 474590d2dfabSRick Macklem } 474690d2dfabSRick Macklem } 474790d2dfabSRick Macklem 474890d2dfabSRick Macklem maxcnt = fxdr_unsigned(int, *tl); 474990d2dfabSRick Macklem if (maxcnt > 0) { 475090d2dfabSRick Macklem layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK); 475190d2dfabSRick Macklem error = nfsrv_mtostr(nd, (char *)layp, maxcnt); 475290d2dfabSRick Macklem if (error != 0) 475390d2dfabSRick Macklem goto nfsmout; 475490d2dfabSRick Macklem } 475590d2dfabSRick Macklem } else { 475690d2dfabSRick Macklem if (reclaim == newnfs_true) { 475790d2dfabSRick Macklem nd->nd_repstat = NFSERR_INVAL; 475890d2dfabSRick Macklem goto nfsmout; 475990d2dfabSRick Macklem } 476090d2dfabSRick Macklem offset = len = 0; 476190d2dfabSRick Macklem maxcnt = 0; 476290d2dfabSRick Macklem } 476390d2dfabSRick Macklem nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode, 476490d2dfabSRick Macklem offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd, 476590d2dfabSRick Macklem nd->nd_cred, p); 476690d2dfabSRick Macklem NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat, 476790d2dfabSRick Macklem fnd); 476890d2dfabSRick Macklem if (nd->nd_repstat == 0) { 476990d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 477090d2dfabSRick Macklem if (fnd != 0) { 477190d2dfabSRick Macklem *tl = newnfs_true; 477290d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_STATEID); 477390d2dfabSRick Macklem *tl++ = txdr_unsigned(stateid.seqid); 477490d2dfabSRick Macklem NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER); 477590d2dfabSRick Macklem } else 477690d2dfabSRick Macklem *tl = newnfs_false; 477790d2dfabSRick Macklem } 477890d2dfabSRick Macklem nfsmout: 477990d2dfabSRick Macklem free(layp, M_TEMP); 478090d2dfabSRick Macklem vput(vp); 478190d2dfabSRick Macklem NFSEXITCODE2(error, nd); 478290d2dfabSRick Macklem return (error); 478390d2dfabSRick Macklem } 478490d2dfabSRick Macklem 478590d2dfabSRick Macklem /* 4786c057a378SRick Macklem * nfsv4 layout error service 4787c057a378SRick Macklem */ 4788b9cc3262SRyan Moeller int 4789c057a378SRick Macklem nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram, 4790c057a378SRick Macklem vnode_t vp, struct nfsexstuff *exp) 4791c057a378SRick Macklem { 4792c057a378SRick Macklem uint32_t *tl; 4793c057a378SRick Macklem nfsv4stateid_t stateid; 4794c057a378SRick Macklem int cnt, error = 0, i, stat; 4795c057a378SRick Macklem int opnum __unused; 4796c057a378SRick Macklem char devid[NFSX_V4DEVICEID]; 4797c057a378SRick Macklem uint64_t offset, len; 4798c057a378SRick Macklem 4799c057a378SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4800c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 4801c057a378SRick Macklem goto nfsmout; 4802c057a378SRick Macklem } 4803c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 4804c057a378SRick Macklem NFSX_UNSIGNED); 4805c057a378SRick Macklem offset = fxdr_hyper(tl); tl += 2; 4806c057a378SRick Macklem len = fxdr_hyper(tl); tl += 2; 4807c057a378SRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4808c057a378SRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4809c057a378SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4810c057a378SRick Macklem cnt = fxdr_unsigned(int, *tl); 4811c057a378SRick Macklem NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset, 4812c057a378SRick Macklem (uintmax_t)len, cnt); 4813c057a378SRick Macklem /* 4814c057a378SRick Macklem * For the special stateid of other all 0s and seqid == 1, set 4815c057a378SRick Macklem * the stateid to the current stateid, if it is set. 4816c057a378SRick Macklem */ 4817c057a378SRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 4818c057a378SRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 4819c057a378SRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4820c057a378SRick Macklem stateid = nd->nd_curstateid; 4821c057a378SRick Macklem stateid.seqid = 0; 4822c057a378SRick Macklem } else { 4823c057a378SRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 4824c057a378SRick Macklem goto nfsmout; 4825c057a378SRick Macklem } 4826c057a378SRick Macklem } 4827c057a378SRick Macklem 4828c057a378SRick Macklem /* 4829c057a378SRick Macklem * Ignore offset, len and stateid for now. 4830c057a378SRick Macklem */ 4831c057a378SRick Macklem for (i = 0; i < cnt; i++) { 4832c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 * 4833c057a378SRick Macklem NFSX_UNSIGNED); 4834c057a378SRick Macklem NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 4835c057a378SRick Macklem tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 4836c057a378SRick Macklem stat = fxdr_unsigned(int, *tl++); 4837c057a378SRick Macklem opnum = fxdr_unsigned(int, *tl); 4838c057a378SRick Macklem NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat); 4839c057a378SRick Macklem /* 4840c057a378SRick Macklem * Except for NFSERR_ACCES and NFSERR_STALE errors, 4841c057a378SRick Macklem * disable the mirror. 4842c057a378SRick Macklem */ 4843c057a378SRick Macklem if (stat != NFSERR_ACCES && stat != NFSERR_STALE) 4844c057a378SRick Macklem nfsrv_delds(devid, curthread); 4845c057a378SRick Macklem } 4846c057a378SRick Macklem nfsmout: 4847c057a378SRick Macklem vput(vp); 4848c057a378SRick Macklem NFSEXITCODE2(error, nd); 4849c057a378SRick Macklem return (error); 4850c057a378SRick Macklem } 4851c057a378SRick Macklem 4852c057a378SRick Macklem /* 4853c057a378SRick Macklem * nfsv4 layout stats service 4854c057a378SRick Macklem */ 4855b9cc3262SRyan Moeller int 4856c057a378SRick Macklem nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram, 4857c057a378SRick Macklem vnode_t vp, struct nfsexstuff *exp) 4858c057a378SRick Macklem { 4859c057a378SRick Macklem uint32_t *tl; 4860c057a378SRick Macklem nfsv4stateid_t stateid; 4861c057a378SRick Macklem int cnt, error = 0; 4862c057a378SRick Macklem int layouttype __unused; 4863c057a378SRick Macklem char devid[NFSX_V4DEVICEID] __unused; 4864c057a378SRick Macklem uint64_t offset, len, readcount, readbytes, writecount, writebytes 4865c057a378SRick Macklem __unused; 4866c057a378SRick Macklem 4867c057a378SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4868c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 4869c057a378SRick Macklem goto nfsmout; 4870c057a378SRick Macklem } 4871c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID + 4872c057a378SRick Macklem NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED); 4873c057a378SRick Macklem offset = fxdr_hyper(tl); tl += 2; 4874c057a378SRick Macklem len = fxdr_hyper(tl); tl += 2; 4875c057a378SRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4876c057a378SRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4877c057a378SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4878c057a378SRick Macklem readcount = fxdr_hyper(tl); tl += 2; 4879c057a378SRick Macklem readbytes = fxdr_hyper(tl); tl += 2; 4880c057a378SRick Macklem writecount = fxdr_hyper(tl); tl += 2; 4881c057a378SRick Macklem writebytes = fxdr_hyper(tl); tl += 2; 4882c057a378SRick Macklem NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 4883c057a378SRick Macklem tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 4884c057a378SRick Macklem layouttype = fxdr_unsigned(int, *tl++); 4885c057a378SRick Macklem cnt = fxdr_unsigned(int, *tl); 4886c057a378SRick Macklem error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1); 4887c057a378SRick Macklem if (error != 0) 4888c057a378SRick Macklem goto nfsmout; 4889c057a378SRick Macklem NFSD_DEBUG(4, "layoutstats cnt=%d\n", cnt); 4890c057a378SRick Macklem /* 4891c057a378SRick Macklem * For the special stateid of other all 0s and seqid == 1, set 4892c057a378SRick Macklem * the stateid to the current stateid, if it is set. 4893c057a378SRick Macklem */ 4894c057a378SRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 4895c057a378SRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 4896c057a378SRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4897c057a378SRick Macklem stateid = nd->nd_curstateid; 4898c057a378SRick Macklem stateid.seqid = 0; 4899c057a378SRick Macklem } else { 4900c057a378SRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 4901c057a378SRick Macklem goto nfsmout; 4902c057a378SRick Macklem } 4903c057a378SRick Macklem } 4904c057a378SRick Macklem 4905c057a378SRick Macklem /* 4906c057a378SRick Macklem * No use for the stats for now. 4907c057a378SRick Macklem */ 4908c057a378SRick Macklem nfsmout: 4909c057a378SRick Macklem vput(vp); 4910c057a378SRick Macklem NFSEXITCODE2(error, nd); 4911c057a378SRick Macklem return (error); 4912c057a378SRick Macklem } 4913c057a378SRick Macklem 4914c057a378SRick Macklem /* 4915c057a378SRick Macklem * nfsv4 io_advise service 4916c057a378SRick Macklem */ 4917b9cc3262SRyan Moeller int 4918c057a378SRick Macklem nfsrvd_ioadvise(struct nfsrv_descript *nd, __unused int isdgram, 4919c057a378SRick Macklem vnode_t vp, struct nfsexstuff *exp) 4920c057a378SRick Macklem { 4921c057a378SRick Macklem uint32_t *tl; 4922c057a378SRick Macklem nfsv4stateid_t stateid; 4923c057a378SRick Macklem nfsattrbit_t hints; 4924c057a378SRick Macklem int error = 0, ret; 4925c057a378SRick Macklem off_t offset, len; 4926c057a378SRick Macklem 4927c057a378SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4928c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 4929c057a378SRick Macklem goto nfsmout; 4930c057a378SRick Macklem } 4931c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); 4932c057a378SRick Macklem stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4933c057a378SRick Macklem NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4934c057a378SRick Macklem tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4935c057a378SRick Macklem offset = fxdr_hyper(tl); tl += 2; 4936c057a378SRick Macklem len = fxdr_hyper(tl); 4937c057a378SRick Macklem error = nfsrv_getattrbits(nd, &hints, NULL, NULL); 4938c057a378SRick Macklem if (error != 0) 4939c057a378SRick Macklem goto nfsmout; 4940c057a378SRick Macklem /* 4941c057a378SRick Macklem * For the special stateid of other all 0s and seqid == 1, set 4942c057a378SRick Macklem * the stateid to the current stateid, if it is set. 4943c057a378SRick Macklem */ 4944c057a378SRick Macklem if (stateid.seqid == 1 && stateid.other[0] == 0 && 4945c057a378SRick Macklem stateid.other[1] == 0 && stateid.other[2] == 0) { 4946c057a378SRick Macklem if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4947c057a378SRick Macklem stateid = nd->nd_curstateid; 4948c057a378SRick Macklem stateid.seqid = 0; 4949c057a378SRick Macklem } else { 4950c057a378SRick Macklem nd->nd_repstat = NFSERR_BADSTATEID; 4951c057a378SRick Macklem goto nfsmout; 4952c057a378SRick Macklem } 4953c057a378SRick Macklem } 4954c057a378SRick Macklem 4955c057a378SRick Macklem if (offset < 0) { 4956c057a378SRick Macklem nd->nd_repstat = NFSERR_INVAL; 4957c057a378SRick Macklem goto nfsmout; 4958c057a378SRick Macklem } 4959c057a378SRick Macklem if (len < 0) 4960c057a378SRick Macklem len = 0; 4961c057a378SRick Macklem if (vp->v_type != VREG) { 4962c057a378SRick Macklem if (vp->v_type == VDIR) 4963c057a378SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 4964c057a378SRick Macklem else 4965c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGTYPE; 4966c057a378SRick Macklem goto nfsmout; 4967c057a378SRick Macklem } 4968c057a378SRick Macklem 4969c057a378SRick Macklem /* 4970c057a378SRick Macklem * For now, we can only handle WILLNEED and DONTNEED and don't use 4971c057a378SRick Macklem * the stateid. 4972c057a378SRick Macklem */ 4973c057a378SRick Macklem if ((NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED) && 4974c057a378SRick Macklem !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED)) || 4975c057a378SRick Macklem (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED) && 4976c057a378SRick Macklem !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED))) { 4977b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 4978c057a378SRick Macklem if (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED)) { 4979c057a378SRick Macklem ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_WILLNEED); 4980c057a378SRick Macklem NFSZERO_ATTRBIT(&hints); 4981c057a378SRick Macklem if (ret == 0) 4982c057a378SRick Macklem NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED); 4983c057a378SRick Macklem else 4984c057a378SRick Macklem NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 4985c057a378SRick Macklem } else { 4986c057a378SRick Macklem ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_DONTNEED); 4987c057a378SRick Macklem NFSZERO_ATTRBIT(&hints); 4988c057a378SRick Macklem if (ret == 0) 4989c057a378SRick Macklem NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED); 4990c057a378SRick Macklem else 4991c057a378SRick Macklem NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 4992c057a378SRick Macklem } 4993c057a378SRick Macklem vrele(vp); 4994c057a378SRick Macklem } else { 4995c057a378SRick Macklem NFSZERO_ATTRBIT(&hints); 4996c057a378SRick Macklem NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 4997c057a378SRick Macklem vput(vp); 4998c057a378SRick Macklem } 4999c057a378SRick Macklem nfsrv_putattrbit(nd, &hints); 5000c057a378SRick Macklem NFSEXITCODE2(error, nd); 5001c057a378SRick Macklem return (error); 5002c057a378SRick Macklem nfsmout: 5003c057a378SRick Macklem vput(vp); 5004c057a378SRick Macklem NFSEXITCODE2(error, nd); 5005c057a378SRick Macklem return (error); 5006c057a378SRick Macklem } 5007c057a378SRick Macklem 5008c057a378SRick Macklem /* 500990d2dfabSRick Macklem * nfsv4 getdeviceinfo service 501090d2dfabSRick Macklem */ 5011b9cc3262SRyan Moeller int 501290d2dfabSRick Macklem nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram, 5013af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 501490d2dfabSRick Macklem { 501590d2dfabSRick Macklem uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP]; 501690d2dfabSRick Macklem int cnt, devaddrlen, error = 0, i, layouttype; 501790d2dfabSRick Macklem char devid[NFSX_V4DEVICEID], *devaddr; 501890d2dfabSRick Macklem time_t dev_time; 501990d2dfabSRick Macklem 502090d2dfabSRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 502190d2dfabSRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 502290d2dfabSRick Macklem goto nfsmout; 502390d2dfabSRick Macklem } 502490d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID); 502590d2dfabSRick Macklem NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 502690d2dfabSRick Macklem tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 502790d2dfabSRick Macklem layouttype = fxdr_unsigned(int, *tl++); 502890d2dfabSRick Macklem maxcnt = fxdr_unsigned(uint32_t, *tl++); 502990d2dfabSRick Macklem cnt = fxdr_unsigned(int, *tl); 503090d2dfabSRick Macklem NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype, 503190d2dfabSRick Macklem maxcnt, cnt); 503290d2dfabSRick Macklem if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) { 503390d2dfabSRick Macklem nd->nd_repstat = NFSERR_INVAL; 503490d2dfabSRick Macklem goto nfsmout; 503590d2dfabSRick Macklem } 503690d2dfabSRick Macklem if (cnt > 0) { 503790d2dfabSRick Macklem NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED); 503890d2dfabSRick Macklem for (i = 0; i < cnt; i++) 503990d2dfabSRick Macklem notify[i] = fxdr_unsigned(uint32_t, *tl++); 504090d2dfabSRick Macklem } 504190d2dfabSRick Macklem for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++) 504290d2dfabSRick Macklem notify[i] = 0; 504390d2dfabSRick Macklem 504490d2dfabSRick Macklem /* 504590d2dfabSRick Macklem * Check that the device id is not stale. Device ids are recreated 504690d2dfabSRick Macklem * each time the nfsd threads are restarted. 504790d2dfabSRick Macklem */ 504890d2dfabSRick Macklem NFSBCOPY(devid, &dev_time, sizeof(dev_time)); 504990d2dfabSRick Macklem if (dev_time != nfsdev_time) { 505090d2dfabSRick Macklem nd->nd_repstat = NFSERR_NOENT; 505190d2dfabSRick Macklem goto nfsmout; 505290d2dfabSRick Macklem } 505390d2dfabSRick Macklem 505490d2dfabSRick Macklem /* Look for the device id. */ 505590d2dfabSRick Macklem nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt, 505690d2dfabSRick Macklem notify, &devaddrlen, &devaddr); 505790d2dfabSRick Macklem NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat); 505890d2dfabSRick Macklem if (nd->nd_repstat == 0) { 505990d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 506090d2dfabSRick Macklem *tl = txdr_unsigned(layouttype); 506190d2dfabSRick Macklem nfsm_strtom(nd, devaddr, devaddrlen); 506290d2dfabSRick Macklem cnt = 0; 506390d2dfabSRick Macklem for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) { 506490d2dfabSRick Macklem if (notify[i] != 0) 506590d2dfabSRick Macklem cnt = i + 1; 506690d2dfabSRick Macklem } 506790d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED); 506890d2dfabSRick Macklem *tl++ = txdr_unsigned(cnt); 506990d2dfabSRick Macklem for (i = 0; i < cnt; i++) 507090d2dfabSRick Macklem *tl++ = txdr_unsigned(notify[i]); 507190d2dfabSRick Macklem } else if (nd->nd_repstat == NFSERR_TOOSMALL) { 507290d2dfabSRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 507390d2dfabSRick Macklem *tl = txdr_unsigned(maxcnt); 507490d2dfabSRick Macklem } 5075c59e4cc3SRick Macklem nfsmout: 5076c59e4cc3SRick Macklem NFSEXITCODE2(error, nd); 5077c59e4cc3SRick Macklem return (error); 5078c59e4cc3SRick Macklem } 5079c59e4cc3SRick Macklem 5080c59e4cc3SRick Macklem /* 50815d4835e4SRick Macklem * nfsv4 test stateid service 50825d4835e4SRick Macklem */ 5083b9cc3262SRyan Moeller int 50845d4835e4SRick Macklem nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram, 5085af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 50865d4835e4SRick Macklem { 50875d4835e4SRick Macklem uint32_t *tl; 50885d4835e4SRick Macklem nfsv4stateid_t *stateidp = NULL, *tstateidp; 50895d4835e4SRick Macklem int cnt, error = 0, i, ret; 5090af444b18SEdward Tomasz Napierala struct thread *p = curthread; 50915d4835e4SRick Macklem 50925d4835e4SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 50935d4835e4SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 50945d4835e4SRick Macklem goto nfsmout; 50955d4835e4SRick Macklem } 50965d4835e4SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 50975d4835e4SRick Macklem cnt = fxdr_unsigned(int, *tl); 50985d4835e4SRick Macklem if (cnt <= 0 || cnt > 1024) { 50995d4835e4SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 51005d4835e4SRick Macklem goto nfsmout; 51015d4835e4SRick Macklem } 51025d4835e4SRick Macklem stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK); 51035d4835e4SRick Macklem tstateidp = stateidp; 51045d4835e4SRick Macklem for (i = 0; i < cnt; i++) { 51055d4835e4SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 51065d4835e4SRick Macklem tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 51075d4835e4SRick Macklem NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER); 51085d4835e4SRick Macklem tstateidp++; 51095d4835e4SRick Macklem } 51105d4835e4SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 51115d4835e4SRick Macklem *tl = txdr_unsigned(cnt); 51125d4835e4SRick Macklem tstateidp = stateidp; 51135d4835e4SRick Macklem for (i = 0; i < cnt; i++) { 51145d4835e4SRick Macklem ret = nfsrv_teststateid(nd, tstateidp, p); 51155d4835e4SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 51165d4835e4SRick Macklem *tl = txdr_unsigned(ret); 51175d4835e4SRick Macklem tstateidp++; 51185d4835e4SRick Macklem } 51195d4835e4SRick Macklem nfsmout: 51205d4835e4SRick Macklem free(stateidp, M_TEMP); 51215d4835e4SRick Macklem NFSEXITCODE2(error, nd); 51225d4835e4SRick Macklem return (error); 51235d4835e4SRick Macklem } 51245d4835e4SRick Macklem 51255d4835e4SRick Macklem /* 5126c057a378SRick Macklem * nfs allocate service 5127c057a378SRick Macklem */ 5128b9cc3262SRyan Moeller int 5129c057a378SRick Macklem nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram, 5130c057a378SRick Macklem vnode_t vp, struct nfsexstuff *exp) 5131c057a378SRick Macklem { 5132c057a378SRick Macklem uint32_t *tl; 5133c057a378SRick Macklem struct nfsvattr forat; 5134c057a378SRick Macklem int error = 0, forat_ret = 1, gotproxystateid; 5135c057a378SRick Macklem off_t off, len; 5136c057a378SRick Macklem struct nfsstate st, *stp = &st; 5137c057a378SRick Macklem struct nfslock lo, *lop = &lo; 5138c057a378SRick Macklem nfsv4stateid_t stateid; 5139c057a378SRick Macklem nfsquad_t clientid; 5140c057a378SRick Macklem nfsattrbit_t attrbits; 5141c057a378SRick Macklem 5142c057a378SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 5143c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 5144c057a378SRick Macklem goto nfsmout; 5145c057a378SRick Macklem } 5146c057a378SRick Macklem gotproxystateid = 0; 5147c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); 5148c057a378SRick Macklem stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 5149c057a378SRick Macklem lop->lo_flags = NFSLCK_WRITE; 5150c057a378SRick Macklem stp->ls_ownerlen = 0; 5151c057a378SRick Macklem stp->ls_op = NULL; 5152c057a378SRick Macklem stp->ls_uid = nd->nd_cred->cr_uid; 5153c057a378SRick Macklem stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 5154c057a378SRick Macklem clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 5155c057a378SRick Macklem clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 5156c057a378SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 5157c057a378SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 5158c057a378SRick Macklem clientid.qval = nd->nd_clientid.qval; 5159c057a378SRick Macklem else if (nd->nd_clientid.qval != clientid.qval) 5160c057a378SRick Macklem printf("EEK2 multiple clids\n"); 5161c057a378SRick Macklem } else { 5162c057a378SRick Macklem if ((nd->nd_flag & ND_NFSV41) != 0) 5163c057a378SRick Macklem printf("EEK! no clientid from session\n"); 5164c057a378SRick Macklem nd->nd_flag |= ND_IMPLIEDCLID; 5165c057a378SRick Macklem nd->nd_clientid.qval = clientid.qval; 5166c057a378SRick Macklem } 5167c057a378SRick Macklem stp->ls_stateid.other[2] = *tl++; 5168c057a378SRick Macklem /* 5169c057a378SRick Macklem * Don't allow this to be done for a DS. 5170c057a378SRick Macklem */ 5171c057a378SRick Macklem if ((nd->nd_flag & ND_DSSERVER) != 0) 5172c057a378SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 5173c057a378SRick Macklem /* However, allow the proxy stateid. */ 5174c057a378SRick Macklem if (stp->ls_stateid.seqid == 0xffffffff && 5175c057a378SRick Macklem stp->ls_stateid.other[0] == 0x55555555 && 5176c057a378SRick Macklem stp->ls_stateid.other[1] == 0x55555555 && 5177c057a378SRick Macklem stp->ls_stateid.other[2] == 0x55555555) 5178c057a378SRick Macklem gotproxystateid = 1; 5179c057a378SRick Macklem off = fxdr_hyper(tl); tl += 2; 5180c057a378SRick Macklem lop->lo_first = off; 5181c057a378SRick Macklem len = fxdr_hyper(tl); 5182c057a378SRick Macklem lop->lo_end = off + len; 5183c057a378SRick Macklem /* 5184c057a378SRick Macklem * Paranoia, just in case it wraps around, which shouldn't 5185c057a378SRick Macklem * ever happen anyhow. 5186c057a378SRick Macklem */ 5187c057a378SRick Macklem if (nd->nd_repstat == 0 && (lop->lo_end < lop->lo_first || len <= 0)) 5188c057a378SRick Macklem nd->nd_repstat = NFSERR_INVAL; 5189c057a378SRick Macklem 5190c057a378SRick Macklem if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG) 5191c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGTYPE; 5192c057a378SRick Macklem NFSZERO_ATTRBIT(&attrbits); 5193c057a378SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5194c057a378SRick Macklem forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits); 5195c057a378SRick Macklem if (nd->nd_repstat == 0) 5196c057a378SRick Macklem nd->nd_repstat = forat_ret; 5197c057a378SRick Macklem if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid || 5198c057a378SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) 5199c057a378SRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, 5200c057a378SRick Macklem curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5201c057a378SRick Macklem NULL); 5202c057a378SRick Macklem if (nd->nd_repstat == 0 && gotproxystateid == 0) 5203c057a378SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 5204c057a378SRick Macklem &stateid, exp, nd, curthread); 5205c057a378SRick Macklem 5206c057a378SRick Macklem if (nd->nd_repstat == 0) 5207c057a378SRick Macklem nd->nd_repstat = nfsvno_allocate(vp, off, len, nd->nd_cred, 5208c057a378SRick Macklem curthread); 5209c057a378SRick Macklem vput(vp); 5210c057a378SRick Macklem NFSEXITCODE2(0, nd); 5211c057a378SRick Macklem return (0); 5212c057a378SRick Macklem nfsmout: 5213c057a378SRick Macklem vput(vp); 5214c057a378SRick Macklem NFSEXITCODE2(error, nd); 5215c057a378SRick Macklem return (error); 5216c057a378SRick Macklem } 5217c057a378SRick Macklem 5218c057a378SRick Macklem /* 5219c057a378SRick Macklem * nfs copy service 5220c057a378SRick Macklem */ 5221b9cc3262SRyan Moeller int 5222c057a378SRick Macklem nfsrvd_copy_file_range(struct nfsrv_descript *nd, __unused int isdgram, 5223c057a378SRick Macklem vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp) 5224c057a378SRick Macklem { 5225c057a378SRick Macklem uint32_t *tl; 5226c057a378SRick Macklem struct nfsvattr at; 5227c057a378SRick Macklem int cnt, error = 0, ret; 5228c057a378SRick Macklem off_t inoff, outoff; 5229c057a378SRick Macklem uint64_t len; 5230c057a378SRick Macklem size_t xfer; 5231c057a378SRick Macklem struct nfsstate inst, outst, *instp = &inst, *outstp = &outst; 5232c057a378SRick Macklem struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo; 5233c057a378SRick Macklem nfsquad_t clientid; 5234c057a378SRick Macklem nfsv4stateid_t stateid; 5235c057a378SRick Macklem nfsattrbit_t attrbits; 5236c057a378SRick Macklem void *rl_rcookie, *rl_wcookie; 5237c057a378SRick Macklem 5238c057a378SRick Macklem rl_rcookie = rl_wcookie = NULL; 5239c057a378SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 5240c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 5241c057a378SRick Macklem goto nfsmout; 5242c057a378SRick Macklem } 5243c057a378SRick Macklem if (nfsrv_devidcnt > 0) { 5244c057a378SRick Macklem /* 5245c057a378SRick Macklem * For a pNFS server, reply NFSERR_NOTSUPP so that the client 5246c057a378SRick Macklem * will do the copy via I/O on the DS(s). 5247c057a378SRick Macklem */ 5248c057a378SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 5249c057a378SRick Macklem goto nfsmout; 5250c057a378SRick Macklem } 5251c057a378SRick Macklem if (vp == tovp) { 5252c057a378SRick Macklem /* Copying a byte range within the same file is not allowed. */ 5253c057a378SRick Macklem nd->nd_repstat = NFSERR_INVAL; 5254c057a378SRick Macklem goto nfsmout; 5255c057a378SRick Macklem } 5256c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER + 5257c057a378SRick Macklem 3 * NFSX_UNSIGNED); 5258c057a378SRick Macklem instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS); 5259c057a378SRick Macklem inlop->lo_flags = NFSLCK_READ; 5260c057a378SRick Macklem instp->ls_ownerlen = 0; 5261c057a378SRick Macklem instp->ls_op = NULL; 5262c057a378SRick Macklem instp->ls_uid = nd->nd_cred->cr_uid; 5263c057a378SRick Macklem instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5264c057a378SRick Macklem clientid.lval[0] = instp->ls_stateid.other[0] = *tl++; 5265c057a378SRick Macklem clientid.lval[1] = instp->ls_stateid.other[1] = *tl++; 5266c057a378SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) 5267c057a378SRick Macklem clientid.qval = nd->nd_clientid.qval; 5268c057a378SRick Macklem instp->ls_stateid.other[2] = *tl++; 5269c057a378SRick Macklem outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 5270c057a378SRick Macklem outlop->lo_flags = NFSLCK_WRITE; 5271c057a378SRick Macklem outstp->ls_ownerlen = 0; 5272c057a378SRick Macklem outstp->ls_op = NULL; 5273c057a378SRick Macklem outstp->ls_uid = nd->nd_cred->cr_uid; 5274c057a378SRick Macklem outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5275c057a378SRick Macklem outstp->ls_stateid.other[0] = *tl++; 5276c057a378SRick Macklem outstp->ls_stateid.other[1] = *tl++; 5277c057a378SRick Macklem outstp->ls_stateid.other[2] = *tl++; 5278c057a378SRick Macklem inoff = fxdr_hyper(tl); tl += 2; 5279c057a378SRick Macklem inlop->lo_first = inoff; 5280c057a378SRick Macklem outoff = fxdr_hyper(tl); tl += 2; 5281c057a378SRick Macklem outlop->lo_first = outoff; 5282c057a378SRick Macklem len = fxdr_hyper(tl); tl += 2; 5283c057a378SRick Macklem if (len == 0) { 5284c057a378SRick Macklem /* len == 0 means to EOF. */ 5285c057a378SRick Macklem inlop->lo_end = OFF_MAX; 5286c057a378SRick Macklem outlop->lo_end = OFF_MAX; 5287c057a378SRick Macklem } else { 5288c057a378SRick Macklem inlop->lo_end = inlop->lo_first + len; 5289c057a378SRick Macklem outlop->lo_end = outlop->lo_first + len; 5290c057a378SRick Macklem } 5291c057a378SRick Macklem 5292c057a378SRick Macklem /* 5293c057a378SRick Macklem * At this time only consecutive, synchronous copy is supported, 5294c057a378SRick Macklem * so ca_consecutive and ca_synchronous can be ignored. 5295c057a378SRick Macklem */ 5296c057a378SRick Macklem tl += 2; 5297c057a378SRick Macklem 5298c057a378SRick Macklem cnt = fxdr_unsigned(int, *tl); 5299c057a378SRick Macklem if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0) 5300c057a378SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 5301c057a378SRick Macklem if (nd->nd_repstat == 0 && (inoff > OFF_MAX || outoff > OFF_MAX || 5302c057a378SRick Macklem inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX || 5303c057a378SRick Macklem inlop->lo_end < inlop->lo_first || outlop->lo_end < 5304c057a378SRick Macklem outlop->lo_first)) 5305c057a378SRick Macklem nd->nd_repstat = NFSERR_INVAL; 5306c057a378SRick Macklem 5307c057a378SRick Macklem if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG) 5308c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGTYPE; 5309c057a378SRick Macklem 5310c057a378SRick Macklem /* Check permissions for the input file. */ 5311c057a378SRick Macklem NFSZERO_ATTRBIT(&attrbits); 5312c057a378SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5313c057a378SRick Macklem ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits); 5314c057a378SRick Macklem if (nd->nd_repstat == 0) 5315c057a378SRick Macklem nd->nd_repstat = ret; 5316c057a378SRick Macklem if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 5317c057a378SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) 5318c057a378SRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, 5319c057a378SRick Macklem curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5320c057a378SRick Macklem NULL); 5321c057a378SRick Macklem if (nd->nd_repstat == 0) 5322c057a378SRick Macklem nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL, 5323c057a378SRick Macklem clientid, &stateid, exp, nd, curthread); 5324b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 5325c057a378SRick Macklem if (nd->nd_repstat != 0) 5326c057a378SRick Macklem goto out; 5327c057a378SRick Macklem 5328c057a378SRick Macklem error = NFSVOPLOCK(tovp, LK_SHARED); 5329c057a378SRick Macklem if (error != 0) 5330c057a378SRick Macklem goto out; 5331c057a378SRick Macklem if (vnode_vtype(tovp) != VREG) 5332c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGTYPE; 5333c057a378SRick Macklem 5334c057a378SRick Macklem /* For the output file, we only need the Owner attribute. */ 5335c057a378SRick Macklem ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits); 5336c057a378SRick Macklem if (nd->nd_repstat == 0) 5337c057a378SRick Macklem nd->nd_repstat = ret; 5338c057a378SRick Macklem if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 5339c057a378SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) 5340c057a378SRick Macklem nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp, 5341c057a378SRick Macklem curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5342c057a378SRick Macklem NULL); 5343c057a378SRick Macklem if (nd->nd_repstat == 0) 5344c057a378SRick Macklem nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL, 5345c057a378SRick Macklem clientid, &stateid, toexp, nd, curthread); 5346b249ce48SMateusz Guzik NFSVOPUNLOCK(tovp); 5347c057a378SRick Macklem 5348c057a378SRick Macklem /* Range lock the byte ranges for both invp and outvp. */ 5349c057a378SRick Macklem if (nd->nd_repstat == 0) { 5350c057a378SRick Macklem for (;;) { 5351c057a378SRick Macklem if (len == 0) { 5352c057a378SRick Macklem rl_wcookie = vn_rangelock_wlock(tovp, outoff, 5353c057a378SRick Macklem OFF_MAX); 5354c057a378SRick Macklem rl_rcookie = vn_rangelock_tryrlock(vp, inoff, 5355c057a378SRick Macklem OFF_MAX); 5356c057a378SRick Macklem } else { 5357c057a378SRick Macklem rl_wcookie = vn_rangelock_wlock(tovp, outoff, 5358c057a378SRick Macklem outoff + len); 5359c057a378SRick Macklem rl_rcookie = vn_rangelock_tryrlock(vp, inoff, 5360c057a378SRick Macklem inoff + len); 5361c057a378SRick Macklem } 5362c057a378SRick Macklem if (rl_rcookie != NULL) 5363c057a378SRick Macklem break; 5364c057a378SRick Macklem vn_rangelock_unlock(tovp, rl_wcookie); 5365c057a378SRick Macklem if (len == 0) 5366c057a378SRick Macklem rl_rcookie = vn_rangelock_rlock(vp, inoff, 5367c057a378SRick Macklem OFF_MAX); 5368c057a378SRick Macklem else 5369c057a378SRick Macklem rl_rcookie = vn_rangelock_rlock(vp, inoff, 5370c057a378SRick Macklem inoff + len); 5371c057a378SRick Macklem vn_rangelock_unlock(vp, rl_rcookie); 5372c057a378SRick Macklem } 5373c057a378SRick Macklem 5374c057a378SRick Macklem error = NFSVOPLOCK(vp, LK_SHARED); 5375c057a378SRick Macklem if (error == 0) { 5376c057a378SRick Macklem ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL); 5377c057a378SRick Macklem if (ret == 0) { 5378c057a378SRick Macklem /* 5379c057a378SRick Macklem * Since invp is range locked, na_size should 5380c057a378SRick Macklem * not change. 5381c057a378SRick Macklem */ 5382c057a378SRick Macklem if (len == 0 && at.na_size > inoff) { 5383c057a378SRick Macklem /* 5384c057a378SRick Macklem * If len == 0, set it based on invp's 5385c057a378SRick Macklem * size. If offset is past EOF, just 5386c057a378SRick Macklem * leave len == 0. 5387c057a378SRick Macklem */ 5388c057a378SRick Macklem len = at.na_size - inoff; 5389c057a378SRick Macklem } else if (nfsrv_linux42server == 0 && 5390c057a378SRick Macklem inoff + len > at.na_size) { 5391c057a378SRick Macklem /* 5392c057a378SRick Macklem * RFC-7862 says that NFSERR_INVAL must 5393c057a378SRick Macklem * be returned when inoff + len exceeds 5394c057a378SRick Macklem * the file size, however the NFSv4.2 5395c057a378SRick Macklem * Linux client likes to do this, so 5396c057a378SRick Macklem * only check if nfsrv_linux42server 5397c057a378SRick Macklem * is not set. 5398c057a378SRick Macklem */ 5399c057a378SRick Macklem nd->nd_repstat = NFSERR_INVAL; 5400c057a378SRick Macklem } 5401c057a378SRick Macklem } 5402b249ce48SMateusz Guzik NFSVOPUNLOCK(vp); 5403c057a378SRick Macklem if (ret != 0 && nd->nd_repstat == 0) 5404c057a378SRick Macklem nd->nd_repstat = ret; 5405c057a378SRick Macklem } else if (nd->nd_repstat == 0) 5406c057a378SRick Macklem nd->nd_repstat = error; 5407c057a378SRick Macklem } 5408c057a378SRick Macklem 5409c057a378SRick Macklem /* 5410c057a378SRick Macklem * Do the actual copy to an upper limit of vfs.nfs.maxcopyrange. 5411c057a378SRick Macklem * This limit is applied to ensure that the RPC replies in a 5412c057a378SRick Macklem * reasonable time. 5413c057a378SRick Macklem */ 5414c057a378SRick Macklem if (len > nfs_maxcopyrange) 5415c057a378SRick Macklem xfer = nfs_maxcopyrange; 5416c057a378SRick Macklem else 5417c057a378SRick Macklem xfer = len; 5418c057a378SRick Macklem if (nd->nd_repstat == 0) { 5419c057a378SRick Macklem nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff, 5420c057a378SRick Macklem &xfer, 0, nd->nd_cred, nd->nd_cred, NULL); 5421c057a378SRick Macklem if (nd->nd_repstat == 0) 5422c057a378SRick Macklem len = xfer; 5423c057a378SRick Macklem } 5424c057a378SRick Macklem 5425c057a378SRick Macklem /* Unlock the ranges. */ 5426c057a378SRick Macklem if (rl_rcookie != NULL) 5427c057a378SRick Macklem vn_rangelock_unlock(vp, rl_rcookie); 5428c057a378SRick Macklem if (rl_wcookie != NULL) 5429c057a378SRick Macklem vn_rangelock_unlock(tovp, rl_wcookie); 5430c057a378SRick Macklem 5431c057a378SRick Macklem if (nd->nd_repstat == 0) { 5432c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER + 5433c057a378SRick Macklem NFSX_VERF); 5434c057a378SRick Macklem *tl++ = txdr_unsigned(0); /* No callback ids. */ 5435c057a378SRick Macklem txdr_hyper(len, tl); tl += 2; 5436c057a378SRick Macklem *tl++ = txdr_unsigned(NFSWRITE_UNSTABLE); 5437c057a378SRick Macklem *tl++ = txdr_unsigned(nfsboottime.tv_sec); 5438c057a378SRick Macklem *tl++ = txdr_unsigned(nfsboottime.tv_usec); 5439c057a378SRick Macklem *tl++ = newnfs_true; 5440c057a378SRick Macklem *tl = newnfs_true; 5441c057a378SRick Macklem } 5442c057a378SRick Macklem out: 5443c057a378SRick Macklem vrele(vp); 5444c057a378SRick Macklem vrele(tovp); 5445c057a378SRick Macklem NFSEXITCODE2(error, nd); 5446c057a378SRick Macklem return (error); 5447c057a378SRick Macklem nfsmout: 5448c057a378SRick Macklem vput(vp); 5449c057a378SRick Macklem vrele(tovp); 5450c057a378SRick Macklem NFSEXITCODE2(error, nd); 5451c057a378SRick Macklem return (error); 5452c057a378SRick Macklem } 5453c057a378SRick Macklem 5454c057a378SRick Macklem /* 5455c057a378SRick Macklem * nfs seek service 5456c057a378SRick Macklem */ 5457b9cc3262SRyan Moeller int 5458c057a378SRick Macklem nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram, 5459c057a378SRick Macklem vnode_t vp, struct nfsexstuff *exp) 5460c057a378SRick Macklem { 5461c057a378SRick Macklem uint32_t *tl; 5462c057a378SRick Macklem struct nfsvattr at; 5463c057a378SRick Macklem int content, error = 0; 5464c057a378SRick Macklem off_t off; 5465c057a378SRick Macklem u_long cmd; 5466c057a378SRick Macklem nfsattrbit_t attrbits; 5467c057a378SRick Macklem bool eof; 5468c057a378SRick Macklem 5469c057a378SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 5470c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 5471c057a378SRick Macklem goto nfsmout; 5472c057a378SRick Macklem } 5473c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED); 5474c057a378SRick Macklem /* Ignore the stateid for now. */ 5475c057a378SRick Macklem tl += (NFSX_STATEID / NFSX_UNSIGNED); 5476c057a378SRick Macklem off = fxdr_hyper(tl); tl += 2; 5477c057a378SRick Macklem content = fxdr_unsigned(int, *tl); 5478c057a378SRick Macklem if (content == NFSV4CONTENT_DATA) 5479c057a378SRick Macklem cmd = FIOSEEKDATA; 5480c057a378SRick Macklem else if (content == NFSV4CONTENT_HOLE) 5481c057a378SRick Macklem cmd = FIOSEEKHOLE; 5482c057a378SRick Macklem else 5483c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 5484c057a378SRick Macklem if (nd->nd_repstat == 0 && vnode_vtype(vp) == VDIR) 5485c057a378SRick Macklem nd->nd_repstat = NFSERR_ISDIR; 5486c057a378SRick Macklem if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG) 5487c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGTYPE; 5488c057a378SRick Macklem if (nd->nd_repstat == 0 && off < 0) 5489c057a378SRick Macklem nd->nd_repstat = NFSERR_NXIO; 5490c057a378SRick Macklem if (nd->nd_repstat == 0) { 5491c057a378SRick Macklem /* Check permissions for the input file. */ 5492c057a378SRick Macklem NFSZERO_ATTRBIT(&attrbits); 5493c057a378SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5494c057a378SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1, 5495c057a378SRick Macklem &attrbits); 5496c057a378SRick Macklem } 5497c057a378SRick Macklem if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 5498c057a378SRick Macklem NFSVNO_EXSTRICTACCESS(exp))) 5499c057a378SRick Macklem nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, 5500c057a378SRick Macklem curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5501c057a378SRick Macklem NULL); 5502c057a378SRick Macklem if (nd->nd_repstat != 0) 5503c057a378SRick Macklem goto nfsmout; 5504c057a378SRick Macklem 5505c057a378SRick Macklem /* nfsvno_seek() unlocks and vrele()s the vp. */ 5506c057a378SRick Macklem nd->nd_repstat = nfsvno_seek(nd, vp, cmd, &off, content, &eof, 5507c057a378SRick Macklem nd->nd_cred, curthread); 5508c057a378SRick Macklem if (nd->nd_repstat == 0 && eof && content == NFSV4CONTENT_DATA && 5509c057a378SRick Macklem nfsrv_linux42server != 0) 5510c057a378SRick Macklem nd->nd_repstat = NFSERR_NXIO; 5511c057a378SRick Macklem if (nd->nd_repstat == 0) { 5512c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); 5513c057a378SRick Macklem if (eof) 5514c057a378SRick Macklem *tl++ = newnfs_true; 5515c057a378SRick Macklem else 5516c057a378SRick Macklem *tl++ = newnfs_false; 5517c057a378SRick Macklem txdr_hyper(off, tl); 5518c057a378SRick Macklem } 5519c057a378SRick Macklem NFSEXITCODE2(error, nd); 5520c057a378SRick Macklem return (error); 5521c057a378SRick Macklem nfsmout: 5522c057a378SRick Macklem vput(vp); 5523c057a378SRick Macklem NFSEXITCODE2(error, nd); 5524c057a378SRick Macklem return (error); 5525c057a378SRick Macklem } 5526c057a378SRick Macklem 5527c057a378SRick Macklem /* 5528c057a378SRick Macklem * nfs get extended attribute service 5529c057a378SRick Macklem */ 5530b9cc3262SRyan Moeller int 5531c057a378SRick Macklem nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram, 5532c057a378SRick Macklem vnode_t vp, __unused struct nfsexstuff *exp) 5533c057a378SRick Macklem { 5534c057a378SRick Macklem uint32_t *tl; 5535ae070589SRick Macklem struct mbuf *mp = NULL, *mpend = NULL; 5536c057a378SRick Macklem int error, len; 5537c057a378SRick Macklem char *name; 5538c057a378SRick Macklem struct thread *p = curthread; 5539c057a378SRick Macklem 5540c057a378SRick Macklem error = 0; 5541c057a378SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 5542c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 5543c057a378SRick Macklem goto nfsmout; 5544c057a378SRick Macklem } 5545c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5546c057a378SRick Macklem len = fxdr_unsigned(int, *tl); 5547c057a378SRick Macklem if (len <= 0) { 5548c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 5549c057a378SRick Macklem goto nfsmout; 5550c057a378SRick Macklem } 5551c057a378SRick Macklem if (len > EXTATTR_MAXNAMELEN) { 5552c057a378SRick Macklem nd->nd_repstat = NFSERR_NOXATTR; 5553c057a378SRick Macklem goto nfsmout; 5554c057a378SRick Macklem } 5555c057a378SRick Macklem name = malloc(len + 1, M_TEMP, M_WAITOK); 5556c057a378SRick Macklem nd->nd_repstat = nfsrv_mtostr(nd, name, len); 5557c057a378SRick Macklem if (nd->nd_repstat == 0) 5558c057a378SRick Macklem nd->nd_repstat = nfsvno_getxattr(vp, name, nd->nd_maxresp, 5559c057a378SRick Macklem nd->nd_cred, p, &mp, &mpend, &len); 5560c057a378SRick Macklem if (nd->nd_repstat == ENOATTR) 5561c057a378SRick Macklem nd->nd_repstat = NFSERR_NOXATTR; 5562c057a378SRick Macklem else if (nd->nd_repstat == EOPNOTSUPP) 5563c057a378SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 5564c057a378SRick Macklem if (nd->nd_repstat == 0) { 5565c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5566c057a378SRick Macklem *tl = txdr_unsigned(len); 5567fb8ed4c5SRick Macklem if (len > 0) { 55689f6624d3SRick Macklem nd->nd_mb->m_next = mp; 5569c057a378SRick Macklem nd->nd_mb = mpend; 55709f6624d3SRick Macklem nd->nd_bpos = mtod(mpend, caddr_t) + mpend->m_len; 5571c057a378SRick Macklem } 5572fb8ed4c5SRick Macklem } 5573c057a378SRick Macklem free(name, M_TEMP); 5574c057a378SRick Macklem 5575c057a378SRick Macklem nfsmout: 5576c057a378SRick Macklem if (nd->nd_repstat == 0) 5577c057a378SRick Macklem nd->nd_repstat = error; 5578c057a378SRick Macklem vput(vp); 5579c057a378SRick Macklem NFSEXITCODE2(0, nd); 5580c057a378SRick Macklem return (0); 5581c057a378SRick Macklem } 5582c057a378SRick Macklem 5583c057a378SRick Macklem /* 5584c057a378SRick Macklem * nfs set extended attribute service 5585c057a378SRick Macklem */ 5586b9cc3262SRyan Moeller int 5587c057a378SRick Macklem nfsrvd_setxattr(struct nfsrv_descript *nd, __unused int isdgram, 5588c057a378SRick Macklem vnode_t vp, __unused struct nfsexstuff *exp) 5589c057a378SRick Macklem { 5590c057a378SRick Macklem uint32_t *tl; 5591c057a378SRick Macklem struct nfsvattr ova, nva; 5592c057a378SRick Macklem nfsattrbit_t attrbits; 5593c057a378SRick Macklem int error, len, opt; 5594c057a378SRick Macklem char *name; 5595c057a378SRick Macklem size_t siz; 5596c057a378SRick Macklem struct thread *p = curthread; 5597c057a378SRick Macklem 5598c057a378SRick Macklem error = 0; 5599c057a378SRick Macklem name = NULL; 5600c057a378SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 5601c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 5602c057a378SRick Macklem goto nfsmout; 5603c057a378SRick Macklem } 5604c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5605c057a378SRick Macklem opt = fxdr_unsigned(int, *tl++); 5606c057a378SRick Macklem len = fxdr_unsigned(int, *tl); 5607c057a378SRick Macklem if (len <= 0) { 5608c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 5609c057a378SRick Macklem goto nfsmout; 5610c057a378SRick Macklem } 5611c057a378SRick Macklem if (len > EXTATTR_MAXNAMELEN) { 5612c057a378SRick Macklem nd->nd_repstat = NFSERR_NOXATTR; 5613c057a378SRick Macklem goto nfsmout; 5614c057a378SRick Macklem } 5615c057a378SRick Macklem name = malloc(len + 1, M_TEMP, M_WAITOK); 5616c057a378SRick Macklem error = nfsrv_mtostr(nd, name, len); 5617c057a378SRick Macklem if (error != 0) 5618c057a378SRick Macklem goto nfsmout; 5619c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5620c057a378SRick Macklem len = fxdr_unsigned(int, *tl); 5621fb8ed4c5SRick Macklem if (len < 0 || len > IOSIZE_MAX) { 5622c057a378SRick Macklem nd->nd_repstat = NFSERR_XATTR2BIG; 5623c057a378SRick Macklem goto nfsmout; 5624c057a378SRick Macklem } 5625c057a378SRick Macklem switch (opt) { 5626c057a378SRick Macklem case NFSV4SXATTR_CREATE: 5627c057a378SRick Macklem error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL, 5628c057a378SRick Macklem &siz, nd->nd_cred, p); 5629c057a378SRick Macklem if (error != ENOATTR) 5630c057a378SRick Macklem nd->nd_repstat = NFSERR_EXIST; 5631c057a378SRick Macklem error = 0; 5632c057a378SRick Macklem break; 5633c057a378SRick Macklem case NFSV4SXATTR_REPLACE: 5634c057a378SRick Macklem error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL, 5635c057a378SRick Macklem &siz, nd->nd_cred, p); 5636c057a378SRick Macklem if (error != 0) 5637c057a378SRick Macklem nd->nd_repstat = NFSERR_NOXATTR; 5638c057a378SRick Macklem break; 5639c057a378SRick Macklem case NFSV4SXATTR_EITHER: 5640c057a378SRick Macklem break; 5641c057a378SRick Macklem default: 5642c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 5643c057a378SRick Macklem } 5644c057a378SRick Macklem if (nd->nd_repstat != 0) 5645c057a378SRick Macklem goto nfsmout; 5646c057a378SRick Macklem 5647c057a378SRick Macklem /* Now, do the Set Extended attribute, with Change before and after. */ 5648c057a378SRick Macklem NFSZERO_ATTRBIT(&attrbits); 5649c057a378SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 5650c057a378SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits); 5651c057a378SRick Macklem if (nd->nd_repstat == 0) { 5652c057a378SRick Macklem nd->nd_repstat = nfsvno_setxattr(vp, name, len, nd->nd_md, 5653c057a378SRick Macklem nd->nd_dpos, nd->nd_cred, p); 5654c057a378SRick Macklem if (nd->nd_repstat == ENXIO) 5655c057a378SRick Macklem nd->nd_repstat = NFSERR_XATTR2BIG; 5656c057a378SRick Macklem } 5657fb8ed4c5SRick Macklem if (nd->nd_repstat == 0 && len > 0) 5658c057a378SRick Macklem nd->nd_repstat = nfsm_advance(nd, NFSM_RNDUP(len), -1); 5659c057a378SRick Macklem if (nd->nd_repstat == 0) 5660c057a378SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); 5661c057a378SRick Macklem if (nd->nd_repstat == 0) { 5662c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); 5663c057a378SRick Macklem *tl++ = newnfs_true; 5664c057a378SRick Macklem txdr_hyper(ova.na_filerev, tl); tl += 2; 5665c057a378SRick Macklem txdr_hyper(nva.na_filerev, tl); 5666c057a378SRick Macklem } 5667c057a378SRick Macklem 5668c057a378SRick Macklem nfsmout: 5669c057a378SRick Macklem free(name, M_TEMP); 5670c057a378SRick Macklem if (nd->nd_repstat == 0) 5671c057a378SRick Macklem nd->nd_repstat = error; 5672c057a378SRick Macklem vput(vp); 5673c057a378SRick Macklem NFSEXITCODE2(0, nd); 5674c057a378SRick Macklem return (0); 5675c057a378SRick Macklem } 5676c057a378SRick Macklem 5677c057a378SRick Macklem /* 5678c057a378SRick Macklem * nfs remove extended attribute service 5679c057a378SRick Macklem */ 5680b9cc3262SRyan Moeller int 5681c057a378SRick Macklem nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int isdgram, 5682c057a378SRick Macklem vnode_t vp, __unused struct nfsexstuff *exp) 5683c057a378SRick Macklem { 5684c057a378SRick Macklem uint32_t *tl; 5685c057a378SRick Macklem struct nfsvattr ova, nva; 5686c057a378SRick Macklem nfsattrbit_t attrbits; 5687c057a378SRick Macklem int error, len; 5688c057a378SRick Macklem char *name; 5689c057a378SRick Macklem struct thread *p = curthread; 5690c057a378SRick Macklem 5691c057a378SRick Macklem error = 0; 5692c057a378SRick Macklem name = NULL; 5693c057a378SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 5694c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 5695c057a378SRick Macklem goto nfsmout; 5696c057a378SRick Macklem } 5697c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5698c057a378SRick Macklem len = fxdr_unsigned(int, *tl); 5699c057a378SRick Macklem if (len <= 0) { 5700c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 5701c057a378SRick Macklem goto nfsmout; 5702c057a378SRick Macklem } 5703c057a378SRick Macklem if (len > EXTATTR_MAXNAMELEN) { 5704c057a378SRick Macklem nd->nd_repstat = NFSERR_NOXATTR; 5705c057a378SRick Macklem goto nfsmout; 5706c057a378SRick Macklem } 5707c057a378SRick Macklem name = malloc(len + 1, M_TEMP, M_WAITOK); 5708c057a378SRick Macklem error = nfsrv_mtostr(nd, name, len); 5709c057a378SRick Macklem if (error != 0) 5710c057a378SRick Macklem goto nfsmout; 5711c057a378SRick Macklem 5712c057a378SRick Macklem if ((nd->nd_flag & ND_IMPLIEDCLID) == 0) { 5713c057a378SRick Macklem printf("EEK! nfsrvd_rmxattr: no implied clientid\n"); 5714c057a378SRick Macklem error = NFSERR_NOXATTR; 5715c057a378SRick Macklem goto nfsmout; 5716c057a378SRick Macklem } 5717c057a378SRick Macklem /* 5718c057a378SRick Macklem * Now, do the Remove Extended attribute, with Change before and 5719c057a378SRick Macklem * after. 5720c057a378SRick Macklem */ 5721c057a378SRick Macklem NFSZERO_ATTRBIT(&attrbits); 5722c057a378SRick Macklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 5723c057a378SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits); 5724c057a378SRick Macklem if (nd->nd_repstat == 0) { 5725c057a378SRick Macklem nd->nd_repstat = nfsvno_rmxattr(nd, vp, name, nd->nd_cred, p); 5726c057a378SRick Macklem if (nd->nd_repstat == ENOATTR) 5727c057a378SRick Macklem nd->nd_repstat = NFSERR_NOXATTR; 5728c057a378SRick Macklem } 5729c057a378SRick Macklem if (nd->nd_repstat == 0) 5730c057a378SRick Macklem nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); 5731c057a378SRick Macklem if (nd->nd_repstat == 0) { 57320bda1dddSRick Macklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); 57330bda1dddSRick Macklem *tl++ = newnfs_true; 5734c057a378SRick Macklem txdr_hyper(ova.na_filerev, tl); tl += 2; 5735c057a378SRick Macklem txdr_hyper(nva.na_filerev, tl); 5736c057a378SRick Macklem } 5737c057a378SRick Macklem 5738c057a378SRick Macklem nfsmout: 5739c057a378SRick Macklem free(name, M_TEMP); 5740c057a378SRick Macklem if (nd->nd_repstat == 0) 5741c057a378SRick Macklem nd->nd_repstat = error; 5742c057a378SRick Macklem vput(vp); 5743c057a378SRick Macklem NFSEXITCODE2(0, nd); 5744c057a378SRick Macklem return (0); 5745c057a378SRick Macklem } 5746c057a378SRick Macklem 5747c057a378SRick Macklem /* 5748c057a378SRick Macklem * nfs list extended attribute service 5749c057a378SRick Macklem */ 5750b9cc3262SRyan Moeller int 5751c057a378SRick Macklem nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram, 5752c057a378SRick Macklem vnode_t vp, __unused struct nfsexstuff *exp) 5753c057a378SRick Macklem { 5754c057a378SRick Macklem uint32_t cnt, *tl, len, len2, i, pos, retlen; 5755c057a378SRick Macklem int error; 5756c057a378SRick Macklem uint64_t cookie, cookie2; 5757c057a378SRick Macklem u_char *buf; 5758c057a378SRick Macklem bool eof; 5759c057a378SRick Macklem struct thread *p = curthread; 5760c057a378SRick Macklem 5761c057a378SRick Macklem error = 0; 5762c057a378SRick Macklem buf = NULL; 5763c057a378SRick Macklem if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 5764c057a378SRick Macklem nd->nd_repstat = NFSERR_WRONGSEC; 5765c057a378SRick Macklem goto nfsmout; 5766c057a378SRick Macklem } 5767c057a378SRick Macklem NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 5768c057a378SRick Macklem /* 5769c057a378SRick Macklem * The cookie doesn't need to be in net byte order, but FreeBSD 5770c057a378SRick Macklem * does so to make it more readable in packet traces. 5771c057a378SRick Macklem */ 5772c057a378SRick Macklem cookie = fxdr_hyper(tl); tl += 2; 5773c057a378SRick Macklem len = fxdr_unsigned(uint32_t, *tl); 5774c057a378SRick Macklem if (len == 0 || cookie >= IOSIZE_MAX) { 5775c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 5776c057a378SRick Macklem goto nfsmout; 5777c057a378SRick Macklem } 5778c057a378SRick Macklem if (len > nd->nd_maxresp - NFS_MAXXDR) 5779c057a378SRick Macklem len = nd->nd_maxresp - NFS_MAXXDR; 5780c057a378SRick Macklem len2 = len; 5781c057a378SRick Macklem nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf, 5782c057a378SRick Macklem &len, &eof); 5783c057a378SRick Macklem if (nd->nd_repstat == EOPNOTSUPP) 5784c057a378SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 5785c057a378SRick Macklem if (nd->nd_repstat == 0) { 5786c057a378SRick Macklem cookie2 = cookie + len; 5787c057a378SRick Macklem if (cookie2 < cookie) 5788c057a378SRick Macklem nd->nd_repstat = NFSERR_BADXDR; 5789c057a378SRick Macklem } 5790c057a378SRick Macklem if (nd->nd_repstat == 0) { 5791c057a378SRick Macklem /* Now copy the entries out. */ 5792c057a378SRick Macklem retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED; 5793c057a378SRick Macklem if (len == 0 && retlen <= len2) { 5794c057a378SRick Macklem /* The cookie was at eof. */ 5795c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * 5796c057a378SRick Macklem NFSX_UNSIGNED); 5797c057a378SRick Macklem txdr_hyper(cookie2, tl); tl += 2; 5798c057a378SRick Macklem *tl++ = txdr_unsigned(0); 5799c057a378SRick Macklem *tl = newnfs_true; 5800c057a378SRick Macklem goto nfsmout; 5801c057a378SRick Macklem } 5802c057a378SRick Macklem 5803c057a378SRick Macklem /* Sanity check the cookie. */ 5804c057a378SRick Macklem for (pos = 0; pos < len; pos += (i + 1)) { 5805c057a378SRick Macklem if (pos == cookie) 5806c057a378SRick Macklem break; 5807c057a378SRick Macklem i = buf[pos]; 5808c057a378SRick Macklem } 5809c057a378SRick Macklem if (pos != cookie) { 5810c057a378SRick Macklem nd->nd_repstat = NFSERR_INVAL; 5811c057a378SRick Macklem goto nfsmout; 5812c057a378SRick Macklem } 5813c057a378SRick Macklem 5814c057a378SRick Macklem /* Loop around copying the entrie(s) out. */ 5815c057a378SRick Macklem cnt = 0; 5816c057a378SRick Macklem len -= cookie; 5817c057a378SRick Macklem i = buf[pos]; 5818c057a378SRick Macklem while (i < len && len2 >= retlen + NFSM_RNDUP(i) + 5819c057a378SRick Macklem NFSX_UNSIGNED) { 5820c057a378SRick Macklem if (cnt == 0) { 5821c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 5822c057a378SRick Macklem NFSX_UNSIGNED); 5823c057a378SRick Macklem txdr_hyper(cookie2, tl); tl += 2; 5824c057a378SRick Macklem } 5825c057a378SRick Macklem retlen += nfsm_strtom(nd, &buf[pos + 1], i); 5826c057a378SRick Macklem len -= (i + 1); 5827c057a378SRick Macklem pos += (i + 1); 5828c057a378SRick Macklem i = buf[pos]; 5829c057a378SRick Macklem cnt++; 5830c057a378SRick Macklem } 5831c057a378SRick Macklem /* 5832c057a378SRick Macklem * eof is set true/false by nfsvno_listxattr(), but if we 5833c057a378SRick Macklem * can't copy all entries returned by nfsvno_listxattr(), 5834c057a378SRick Macklem * we are not at eof. 5835c057a378SRick Macklem */ 5836c057a378SRick Macklem if (len > 0) 5837c057a378SRick Macklem eof = false; 5838c057a378SRick Macklem if (cnt > 0) { 5839c057a378SRick Macklem /* *tl is set above. */ 5840c057a378SRick Macklem *tl = txdr_unsigned(cnt); 5841c057a378SRick Macklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5842c057a378SRick Macklem if (eof) 5843c057a378SRick Macklem *tl = newnfs_true; 5844c057a378SRick Macklem else 5845c057a378SRick Macklem *tl = newnfs_false; 5846c057a378SRick Macklem } else 5847c057a378SRick Macklem nd->nd_repstat = NFSERR_TOOSMALL; 5848c057a378SRick Macklem } 5849c057a378SRick Macklem 5850c057a378SRick Macklem nfsmout: 5851c057a378SRick Macklem free(buf, M_TEMP); 5852c057a378SRick Macklem if (nd->nd_repstat == 0) 5853c057a378SRick Macklem nd->nd_repstat = error; 5854c057a378SRick Macklem vput(vp); 5855c057a378SRick Macklem NFSEXITCODE2(0, nd); 5856c057a378SRick Macklem return (0); 5857c057a378SRick Macklem } 5858c057a378SRick Macklem 5859c057a378SRick Macklem /* 5860c59e4cc3SRick Macklem * nfsv4 service not supported 5861c59e4cc3SRick Macklem */ 5862b9cc3262SRyan Moeller int 5863c59e4cc3SRick Macklem nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram, 5864af444b18SEdward Tomasz Napierala __unused vnode_t vp, __unused struct nfsexstuff *exp) 5865c59e4cc3SRick Macklem { 5866c59e4cc3SRick Macklem 5867c59e4cc3SRick Macklem nd->nd_repstat = NFSERR_NOTSUPP; 5868c59e4cc3SRick Macklem NFSEXITCODE2(0, nd); 5869c59e4cc3SRick Macklem return (0); 5870c59e4cc3SRick Macklem } 5871c59e4cc3SRick Macklem 5872