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