From 1c4cb5237701bb138f9cce29036773086253f839 Mon Sep 17 00:00:00 2001 From: Krishna Srinivas Date: Wed, 12 Sep 2012 12:36:49 +0530 Subject: ACLv3 - Access Control Lists V3 Change-Id: I43e544d6cdeac5e3880141477461e7c22cbf6e91 BUG: 847622 Signed-off-by: Krishna Srinivas Reviewed-on: http://review.gluster.org/4045 Reviewed-by: Kaleb KEITHLEY Tested-by: Gluster Build System Reviewed-by: Anand Avati --- rpc/xdr/src/Makefile.am | 4 +- rpc/xdr/src/acl.x | 48 +++ rpc/xdr/src/acl3-xdr.c | 94 +++++ rpc/xdr/src/acl3-xdr.h | 107 ++++++ rpc/xdr/src/msg-nfs3.c | 29 ++ rpc/xdr/src/msg-nfs3.h | 13 + tests/bugs/bug-847622.t | 25 ++ xlators/nfs/server/src/Makefile.am | 3 +- xlators/nfs/server/src/acl3.c | 621 ++++++++++++++++++++++++++++++++++ xlators/nfs/server/src/acl3.h | 30 ++ xlators/nfs/server/src/nfs-fops.c | 89 +++++ xlators/nfs/server/src/nfs-fops.h | 9 + xlators/nfs/server/src/nfs-generics.c | 16 + xlators/nfs/server/src/nfs-generics.h | 10 + xlators/nfs/server/src/nfs.c | 8 + xlators/nfs/server/src/nfs3.h | 15 +- 16 files changed, 1117 insertions(+), 4 deletions(-) create mode 100644 rpc/xdr/src/acl.x create mode 100644 rpc/xdr/src/acl3-xdr.c create mode 100644 rpc/xdr/src/acl3-xdr.h create mode 100755 tests/bugs/bug-847622.t create mode 100644 xlators/nfs/server/src/acl3.c create mode 100644 xlators/nfs/server/src/acl3.h diff --git a/rpc/xdr/src/Makefile.am b/rpc/xdr/src/Makefile.am index 7d3d00093..949e75e8d 100644 --- a/rpc/xdr/src/Makefile.am +++ b/rpc/xdr/src/Makefile.am @@ -14,7 +14,7 @@ libgfxdr_la_SOURCES = xdr-generic.c rpc-common-xdr.c \ glusterd1-xdr.c \ portmap-xdr.c \ nlm4-xdr.c xdr-nfs3.c msg-nfs3.c nsm-xdr.c \ - nlmcbk-xdr.c + nlmcbk-xdr.c acl3-xdr.c noinst_HEADERS = xdr-generic.h rpc-common-xdr.h \ glusterfs3-xdr.h glusterfs3.h \ @@ -22,4 +22,4 @@ noinst_HEADERS = xdr-generic.h rpc-common-xdr.h \ glusterd1-xdr.h \ portmap-xdr.h \ nlm4-xdr.h xdr-nfs3.h msg-nfs3.h nsm-xdr.h \ - nlmcbk-xdr.h + nlmcbk-xdr.h acl3-xdr.h diff --git a/rpc/xdr/src/acl.x b/rpc/xdr/src/acl.x new file mode 100644 index 000000000..6cf4f1d3b --- /dev/null +++ b/rpc/xdr/src/acl.x @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2012 Red Hat, Inc. + * This file is part of GlusterFS. + * + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + + +struct aclentry { + int type; + int uid; + int perm; +}; + +struct getaclargs { + netobj fh; + int mask; +}; + +struct getaclreply { + int status; + int attr_follows; + struct fattr3 attr; + int mask; + int aclcount; + struct aclentry aclentry<>; + int daclcount; + struct aclentry daclentry<>; +}; + +struct setaclargs { + netobj fh; + int mask; + int aclcount; + struct aclentry aclentry<>; + int daclcount; + struct aclentry daclentry<>; +}; + +struct setaclreply { + int status; + int attr_follows; + struct fattr3 attr; +}; + diff --git a/rpc/xdr/src/acl3-xdr.c b/rpc/xdr/src/acl3-xdr.c new file mode 100644 index 000000000..8fbaeff16 --- /dev/null +++ b/rpc/xdr/src/acl3-xdr.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2012 Red Hat, Inc. + * This file is part of GlusterFS. + * + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "acl3-xdr.h" + +bool_t +xdr_aclentry (XDR *xdrs, aclentry *objp) +{ + if (!xdr_int (xdrs, &objp->type)) + return FALSE; + if (!xdr_int (xdrs, &objp->uid)) + return FALSE; + if (!xdr_int (xdrs, &objp->perm)) + return FALSE; + return TRUE; +} + +bool_t +xdr_getaclargs (XDR *xdrs, getaclargs *objp) +{ + if (!xdr_netobj (xdrs, &objp->fh)) + return FALSE; + if (!xdr_int (xdrs, &objp->mask)) + return FALSE; + return TRUE; +} + +bool_t +xdr_getaclreply (XDR *xdrs, getaclreply *objp) +{ + if (!xdr_int (xdrs, &objp->status)) + return FALSE; + if (!xdr_int (xdrs, &objp->attr_follows)) + return FALSE; + if (!xdr_fattr3 (xdrs, &objp->attr)) + return FALSE; + if (!xdr_int (xdrs, &objp->mask)) + return FALSE; + if (!xdr_int (xdrs, &objp->aclcount)) + return FALSE; + if (!xdr_array (xdrs, (char **)&objp->aclentry.aclentry_val, (u_int *) &objp->aclentry.aclentry_len, ~0, + sizeof (aclentry), (xdrproc_t) xdr_aclentry)) + return FALSE; + if (!xdr_int (xdrs, &objp->daclcount)) + return FALSE; + if (!xdr_array (xdrs, (char **)&objp->daclentry.daclentry_val, (u_int *) &objp->daclentry.daclentry_len, ~0, + sizeof (aclentry), (xdrproc_t) xdr_aclentry)) + return FALSE; + return TRUE; +} + +bool_t +xdr_setaclargs (XDR *xdrs, setaclargs *objp) +{ + if (!xdr_netobj (xdrs, &objp->fh)) + return FALSE; + if (!xdr_int (xdrs, &objp->mask)) + return FALSE; + if (!xdr_int (xdrs, &objp->aclcount)) + return FALSE; + if (!xdr_array (xdrs, (char **)&objp->aclentry.aclentry_val, (u_int *) &objp->aclentry.aclentry_len, ~0, + sizeof (aclentry), (xdrproc_t) xdr_aclentry)) + return FALSE; + if (!xdr_int (xdrs, &objp->daclcount)) + return FALSE; + if (!xdr_array (xdrs, (char **)&objp->daclentry.daclentry_val, (u_int *) &objp->daclentry.daclentry_len, ~0, + sizeof (aclentry), (xdrproc_t) xdr_aclentry)) + return FALSE; + return TRUE; +} + +bool_t +xdr_setaclreply (XDR *xdrs, setaclreply *objp) +{ + if (!xdr_int (xdrs, &objp->status)) + return FALSE; + if (!xdr_int (xdrs, &objp->attr_follows)) + return FALSE; + if (!xdr_fattr3 (xdrs, &objp->attr)) + return FALSE; + return TRUE; +} diff --git a/rpc/xdr/src/acl3-xdr.h b/rpc/xdr/src/acl3-xdr.h new file mode 100644 index 000000000..7cebaed69 --- /dev/null +++ b/rpc/xdr/src/acl3-xdr.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2012 Red Hat, Inc. + * This file is part of GlusterFS. + * + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#ifndef _ACL_H_RPCGEN +#define _ACL_H_RPCGEN + +#include +#include "xdr-nfs3.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +struct aclentry { + int type; + int uid; + int perm; +}; +typedef struct aclentry aclentry; + +struct getaclargs { + netobj fh; + int mask; +}; +typedef struct getaclargs getaclargs; + +struct getaclreply { + int status; + int attr_follows; + struct fattr3 attr; + int mask; + int aclcount; + struct { + u_int aclentry_len; + struct aclentry *aclentry_val; + } aclentry; + int daclcount; + struct { + u_int daclentry_len; + struct aclentry *daclentry_val; + } daclentry; +}; +typedef struct getaclreply getaclreply; + +struct setaclargs { + netobj fh; + int mask; + int aclcount; + struct { + u_int aclentry_len; + struct aclentry *aclentry_val; + } aclentry; + int daclcount; + struct { + u_int daclentry_len; + struct aclentry *daclentry_val; + } daclentry; +}; +typedef struct setaclargs setaclargs; + +struct setaclreply { + int status; + int attr_follows; + struct fattr3 attr; +}; +typedef struct setaclreply setaclreply; + +#define ACL3_NULL 0 +#define ACL3_GETACL 1 +#define ACL3_SETACL 2 +#define ACL3_PROC_COUNT 3 +/* the xdr functions */ + +#if defined(__STDC__) || defined(__cplusplus) +extern bool_t xdr_aclentry (XDR *, aclentry*); +extern bool_t xdr_getaclargs (XDR *, getaclargs*); +extern bool_t xdr_getaclreply (XDR *, getaclreply*); +extern bool_t xdr_setaclargs (XDR *, setaclargs*); +extern bool_t xdr_setaclreply (XDR *, setaclreply*); + +#else /* K&R C */ +extern bool_t xdr_aclentry (); +extern bool_t xdr_getaclargs (); +extern bool_t xdr_getaclreply (); +extern bool_t xdr_setaclargs (); +extern bool_t xdr_setaclreply (); + +#endif /* K&R C */ + +#ifdef __cplusplus +} +#endif + +#endif /* !_ACL_H_RPCGEN */ diff --git a/rpc/xdr/src/msg-nfs3.c b/rpc/xdr/src/msg-nfs3.c index 97e62040d..6cdb5d37e 100644 --- a/rpc/xdr/src/msg-nfs3.c +++ b/rpc/xdr/src/msg-nfs3.c @@ -541,3 +541,32 @@ xdr_to_nlm4_freeallargs (struct iovec inmsg, nlm4_freeallargs *args) return xdr_to_generic (inmsg, (void*)args, (xdrproc_t)xdr_nlm4_freeallargs); } + +ssize_t +xdr_to_getaclargs (struct iovec inmsg, getaclargs *args) +{ + return xdr_to_generic (inmsg, (void *) args, + (xdrproc_t)xdr_getaclargs); +} + +ssize_t +xdr_to_setaclargs (struct iovec inmsg, setaclargs *args) +{ + return xdr_to_generic (inmsg, (void *) args, + (xdrproc_t)xdr_setaclargs); +} + +ssize_t +xdr_serialize_getaclreply (struct iovec inmsg, getaclreply *res) +{ + return xdr_serialize_generic (inmsg, (void *) res, + (xdrproc_t)xdr_getaclreply); +} + +ssize_t +xdr_serialize_setaclreply (struct iovec inmsg, setaclreply *res) +{ + return xdr_serialize_generic (inmsg, (void *) res, + (xdrproc_t)xdr_setaclreply); +} + diff --git a/rpc/xdr/src/msg-nfs3.h b/rpc/xdr/src/msg-nfs3.h index 8df777c6c..b8e2c9694 100644 --- a/rpc/xdr/src/msg-nfs3.h +++ b/rpc/xdr/src/msg-nfs3.h @@ -18,6 +18,7 @@ #include "xdr-nfs3.h" #include "nlm4-xdr.h" +#include "acl3-xdr.h" #include #include @@ -208,4 +209,16 @@ xdr_to_nlm4_res (struct iovec inmsg, nlm4_res *args); extern ssize_t xdr_to_nlm4_freeallargs (struct iovec inmsg, nlm4_freeallargs *args); +extern ssize_t +xdr_to_getaclargs (struct iovec inmsg, getaclargs *args); + +extern ssize_t +xdr_to_setaclargs (struct iovec inmsg, setaclargs *args); + +extern ssize_t +xdr_serialize_getaclreply (struct iovec inmsg, getaclreply *res); + +extern ssize_t +xdr_serialize_setaclreply (struct iovec inmsg, setaclreply *res); + #endif diff --git a/tests/bugs/bug-847622.t b/tests/bugs/bug-847622.t new file mode 100755 index 000000000..138499527 --- /dev/null +++ b/tests/bugs/bug-847622.t @@ -0,0 +1,25 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 $H0:$B0/brick0 +TEST $CLI volume start $V0 + +sleep 5 + +TEST mount -t nfs -o vers=3,nolock $H0:/$V0 $N0 +cd $N0 + +# simple getfacl setfacl commands +TEST touch testfile +TEST setfacl -m u:14:r testfile +TEST getfacl testfile + +cd +TEST umount $N0 +cleanup + diff --git a/xlators/nfs/server/src/Makefile.am b/xlators/nfs/server/src/Makefile.am index e22489606..42f1ab5d2 100644 --- a/xlators/nfs/server/src/Makefile.am +++ b/xlators/nfs/server/src/Makefile.am @@ -4,11 +4,12 @@ nfsrpclibdir = $(top_srcdir)/rpc/rpc-lib/src server_la_LDFLAGS = -module -avoidversion server_la_SOURCES = nfs.c nfs-common.c nfs-fops.c nfs-inodes.c \ nfs-generics.c mount3.c nfs3-fh.c nfs3.c nfs3-helpers.c nlm4.c \ - nlmcbk_svc.c mount3udp_svc.c + nlmcbk_svc.c mount3udp_svc.c acl3.c server_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la noinst_HEADERS = nfs.h nfs-common.h nfs-fops.h nfs-inodes.h nfs-generics.h \ mount3.h nfs3-fh.h nfs3.h nfs3-helpers.h nfs-mem-types.h nlm4.h + acl3.h AM_CPPFLAGS = $(GF_CPPFLAGS) \ -DLIBDIR=\"$(libdir)/glusterfs/$(PACKAGE_VERSION)/auth\" \ diff --git a/xlators/nfs/server/src/acl3.c b/xlators/nfs/server/src/acl3.c new file mode 100644 index 000000000..46431a475 --- /dev/null +++ b/xlators/nfs/server/src/acl3.c @@ -0,0 +1,621 @@ +/* + * Copyright (c) 2012 Red Hat, Inc. + * This file is part of GlusterFS. + * + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "defaults.h" +#include "rpcsvc.h" +#include "dict.h" +#include "xlator.h" +#include "nfs.h" +#include "mem-pool.h" +#include "logging.h" +#include "nfs-fops.h" +#include "inode.h" +#include "nfs3.h" +#include "nfs-mem-types.h" +#include "nfs3-helpers.h" +#include "nfs3-fh.h" +#include "nfs-generics.h" +#include "acl3.h" + + +typedef ssize_t (*acl3_serializer) (struct iovec outmsg, void *args); + +extern void nfs3_call_state_wipe (nfs3_call_state_t *cs); + +extern nfs3_call_state_t * +nfs3_call_state_init (struct nfs3_state *s, rpcsvc_request_t *req, xlator_t *v); + +extern int +nfs3_fh_validate (struct nfs3_fh *fh); + +extern fattr3 +nfs3_stat_to_fattr3 (struct iatt *buf); + +#define acl3_validate_nfs3_state(request, state, status, label, retval) \ + do { \ + state = rpcsvc_request_program_private (request); \ + if (!state) { \ + gf_log (GF_ACL, GF_LOG_ERROR, "NFSv3 state " \ + "missing from RPC request"); \ + rpcsvc_request_seterr (req, SYSTEM_ERR); \ + status = NFS3ERR_SERVERFAULT; \ + goto label; \ + } \ + } while (0); \ + +#define acl3_validate_gluster_fh(handle, status, errlabel) \ + do { \ + if (!nfs3_fh_validate (handle)) { \ + status = NFS3ERR_SERVERFAULT; \ + goto errlabel; \ + } \ + } while (0) \ + + +extern xlator_t * +nfs3_fh_to_xlator (struct nfs3_state *nfs3, struct nfs3_fh *fh); + +#define acl3_map_fh_to_volume(nfs3state, handle, req, volume, status, label) \ + do { \ + char exportid[256], gfid[256]; \ + rpc_transport_t *trans = NULL; \ + volume = nfs3_fh_to_xlator ((nfs3state), handle); \ + if (!volume) { \ + uuid_unparse (handle->exportid, exportid); \ + uuid_unparse (handle->gfid, gfid); \ + trans = rpcsvc_request_transport (req); \ + gf_log (GF_ACL, GF_LOG_ERROR, "Failed to map " \ + "FH to vol: client=%s, exportid=%s, gfid=%s",\ + trans->peerinfo.identifier, exportid, \ + gfid); \ + gf_log (GF_ACL, GF_LOG_ERROR, \ + "Stale nfs client %s must be trying to "\ + "connect to a deleted volume, please " \ + "unmount it.", trans->peerinfo.identifier);\ + status = NFS3ERR_STALE; \ + goto label; \ + } else { \ + gf_log (GF_ACL, GF_LOG_TRACE, "FH to Volume: %s"\ + ,volume->name); \ + rpcsvc_request_set_private (req, volume); \ + } \ + } while (0); \ + +#define acl3_volume_started_check(nfs3state, vlm, rtval, erlbl) \ + do { \ + if ((!nfs_subvolume_started (nfs_state (nfs3state->nfsx), vlm))){\ + gf_log (GF_ACL, GF_LOG_ERROR, "Volume is disabled: %s",\ + vlm->name); \ + rtval = RPCSVC_ACTOR_IGNORE; \ + goto erlbl; \ + } \ + } while (0) \ + +#define acl3_check_fh_resolve_status(cst, nfstat, erlabl) \ + do { \ + xlator_t *xlatorp = NULL; \ + char buf[256], gfid[256]; \ + rpc_transport_t *trans = NULL; \ + if ((cst)->resolve_ret < 0) { \ + trans = rpcsvc_request_transport (cst->req); \ + xlatorp = nfs3_fh_to_xlator (cst->nfs3state, \ + &cst->resolvefh); \ + uuid_unparse (cst->resolvefh.gfid, gfid); \ + sprintf (buf, "(%s) %s : %s", trans->peerinfo.identifier,\ + xlatorp ? xlatorp->name : "ERR", gfid); \ + gf_log (GF_ACL, GF_LOG_ERROR, "Unable to resolve FH"\ + ": %s", buf); \ + nfstat = nfs3_errno_to_nfsstat3 (cst->resolve_errno);\ + goto erlabl; \ + } \ + } while (0) \ + +#define acl3_handle_call_state_init(nfs3state, calls, rq, v, opstat, errlabel)\ + do { \ + calls = nfs3_call_state_init ((nfs3state), (rq), v); \ + if (!calls) { \ + gf_log (GF_NLM, GF_LOG_ERROR, "Failed to " \ + "init call state"); \ + opstat = nlm4_failed; \ + rpcsvc_request_seterr (req, SYSTEM_ERR); \ + goto errlabel; \ + } \ + } while (0) \ + + +int +acl3svc_submit_reply (rpcsvc_request_t *req, void *arg, acl3_serializer sfunc) +{ + struct iovec outmsg = {0, }; + struct iobuf *iob = NULL; + struct nfs3_state *nfs3 = NULL; + int ret = -1; + struct iobref *iobref = NULL; + + if (!req) + return -1; + + nfs3 = (struct nfs3_state *)rpcsvc_request_program_private (req); + if (!nfs3) { + gf_log (GF_ACL, GF_LOG_ERROR, "mount state not found"); + goto ret; + } + + /* First, get the io buffer into which the reply in arg will + * be serialized. + */ + iob = iobuf_get (nfs3->iobpool); + if (!iob) { + gf_log (GF_ACL, GF_LOG_ERROR, "Failed to get iobuf"); + goto ret; + } + + iobuf_to_iovec (iob, &outmsg); + /* Use the given serializer to translate the give C structure in arg + * to XDR format which will be written into the buffer in outmsg. + */ + outmsg.iov_len = sfunc (outmsg, arg); + + iobref = iobref_new (); + if (iobref == NULL) { + gf_log (GF_ACL, GF_LOG_ERROR, "Failed to get iobref"); + goto ret; + } + + iobref_add (iobref, iob); + + /* Then, submit the message for transmission. */ + ret = rpcsvc_submit_message (req, &outmsg, 1, NULL, 0, iobref); + if (ret == -1) { + gf_log (GF_ACL, GF_LOG_ERROR, "Reply submission failed"); + goto ret; + } + + ret = 0; +ret: + if (iob) + iobuf_unref (iob); + if (iobref) + iobref_unref (iobref); + + return ret; +} + + +int +acl3svc_null (rpcsvc_request_t *req) +{ + struct iovec dummyvec = {0, }; + + if (!req) { + gf_log (GF_ACL, GF_LOG_ERROR, "Got NULL request!"); + return 0; + } + rpcsvc_submit_generic (req, &dummyvec, 1, NULL, 0, NULL); + return 0; +} + +int +acl3_getacl_reply (nfs3_call_state_t *cs, getaclreply *reply) +{ + acl3svc_submit_reply (cs->req, (void *)reply, + (acl3_serializer)xdr_serialize_getaclreply); + return 0; +} + + +int +acl3_getacl_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata) +{ + nfsstat3 stat = NFS3ERR_SERVERFAULT; + nfs3_call_state_t *cs = NULL; + data_t *data = NULL; + int *p = NULL; + int i = 0; + getaclreply *getaclreply = NULL; + + cs = frame->local; + if (op_ret == -1) { + stat = nfs3_errno_to_nfsstat3 (op_errno); + goto err; + } + + getaclreply = &cs->args.getaclreply; + getaclreply->aclentry.aclentry_val = cs->aclentry; + getaclreply->daclentry.daclentry_val = cs->daclentry; + + /* FIXME: use posix_acl_from_xattr() */ + data = dict_get (dict, "system.posix_acl_access"); + if (data && (p = data_to_bin (data))) { + /* POSIX_ACL_XATTR_VERSION */ + p++; + while ((char *)p < (data->data + data->len)) { + getaclreply->aclentry.aclentry_val[i].type = *(*(short **)&p)++; + getaclreply->aclentry.aclentry_val[i].perm = *(*(short **)&p)++; + getaclreply->aclentry.aclentry_val[i].uid = *(*(int **)&p)++; + i++; + } + getaclreply->aclcount = getaclreply->aclentry.aclentry_len = i; + } + i = 0; + + data = dict_get (dict, "system.posix_acl_default"); + if (data && (p = data_to_bin (data))) { + /* POSIX_ACL_XATTR_VERSION */ + p++; + while ((char *)p < (data->data + data->len)) { + getaclreply->daclentry.daclentry_val[i].type = *(*(short **)&p)++; + getaclreply->daclentry.daclentry_val[i].perm = *(*(short **)&p)++; + getaclreply->daclentry.daclentry_val[i].uid = *(*(int **)&p)++; + i++; + } + getaclreply->daclcount = getaclreply->daclentry.daclentry_len = i; + } + + acl3_getacl_reply (cs, getaclreply); + nfs3_call_state_wipe (cs); + return 0; + +err: + getaclreply->status = stat; + acl3_getacl_reply (cs, getaclreply); + nfs3_call_state_wipe (cs); + return 0; +} + +int +acl3_stat_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *buf, + dict_t *xdata) +{ + nfsstat3 stat = NFS3ERR_SERVERFAULT; + nfs3_call_state_t *cs = NULL; + getaclreply *getaclreply = NULL; + int ret = -1; + nfs_user_t nfu = {0, }; + + cs = frame->local; + if (op_ret == -1) { + stat = nfs3_errno_to_nfsstat3 (op_errno); + goto err; + } + + getaclreply = &cs->args.getaclreply; + + getaclreply->attr_follows = 1; + getaclreply->attr = nfs3_stat_to_fattr3 (buf); + getaclreply->mask = 0xf; + nfs_request_user_init (&nfu, cs->req); + ret = nfs_getxattr (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, NULL, NULL, + acl3_getacl_cbk, cs); + if (ret == -1) { + stat = nfs3_errno_to_nfsstat3 (op_errno); + goto err; + } + return 0; +err: + getaclreply->status = stat; + acl3_getacl_reply (cs, getaclreply); + nfs3_call_state_wipe (cs); + return 0; +} + + +int +acl3_getacl_resume (void *carg) +{ + int ret = -1; + nfs3_call_state_t *cs = NULL; + nfsstat3 stat = NFS3ERR_SERVERFAULT; + nfs_user_t nfu = {0, }; + + if (!carg) + return ret; + + cs = (nfs3_call_state_t *)carg; + acl3_check_fh_resolve_status (cs, stat, acl3err); + nfs_request_user_init (&nfu, cs->req); + + ret = nfs_stat (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + acl3_stat_cbk, cs); + stat = -ret; +acl3err: + if (ret < 0) { + gf_log (GF_ACL, GF_LOG_ERROR, "unable to open_and_resume"); + cs->args.getaclreply.status = nfs3_errno_to_nfsstat3 (stat); + acl3_getacl_reply (cs, &cs->args.getaclreply); + nfs3_call_state_wipe (cs); + } + + return ret; +} + + +int +acl3svc_getacl (rpcsvc_request_t *req) +{ + xlator_t *vol = NULL; + struct nfs_state *nfs = NULL; + nfs3_state_t *nfs3 = NULL; + nfs3_call_state_t *cs = NULL; + int ret = RPCSVC_ACTOR_ERROR; + nfsstat3 stat = NFS3ERR_SERVERFAULT; + struct nfs3_fh fh, *fhp = NULL; + getaclargs getaclargs; + + if (!req) + return ret; + + acl3_validate_nfs3_state (req, nfs3, stat, rpcerr, ret); + nfs = nfs_state (nfs3->nfsx); + memset (&getaclargs, 0, sizeof (getaclargs)); + getaclargs.fh.n_bytes = (char *)&fh; + if (xdr_to_getaclargs(req->msg[0], &getaclargs) <= 0) { + gf_log (GF_ACL, GF_LOG_ERROR, "Error decoding args"); + rpcsvc_request_seterr (req, GARBAGE_ARGS); + goto rpcerr; + } + fhp = &fh; + acl3_validate_gluster_fh (&fh, stat, acl3err); + acl3_map_fh_to_volume (nfs->nfs3state, fhp, req, + vol, stat, acl3err); + acl3_handle_call_state_init (nfs->nfs3state, cs, req, + vol, stat, rpcerr); + + cs->vol = vol; + acl3_volume_started_check (nfs3, vol, ret, rpcerr); + + ret = nfs3_fh_resolve_and_resume (cs, fhp, + NULL, acl3_getacl_resume); + +acl3err: + if (ret < 0) { + gf_log (GF_ACL, GF_LOG_ERROR, "unable to resolve and resume"); + cs->args.getaclreply.status = stat; + acl3_getacl_reply (cs, &cs->args.getaclreply); + nfs3_call_state_wipe (cs); + return 0; + } + +rpcerr: + return ret; +} + +int +acl3_setacl_cbk (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, int32_t op_errno, + dict_t *xdata) +{ + nfs3_call_state_t *cs = NULL; + cs = frame->local; + if (op_ret < 0) { + cs->args.setaclreply.status = nfs3_errno_to_nfsstat3 (op_errno); + } + + acl3svc_submit_reply (cs->req, (void *)&cs->args.setaclreply, + (acl3_serializer)xdr_serialize_setaclreply); + return 0; +} + +int +acl3_setacl_resume (void *carg) +{ + int ret = -1; + nfs3_call_state_t *cs = NULL; + nfsstat3 stat = NFS3ERR_SERVERFAULT; + nfs_user_t nfu = {0, }; + dict_t *xattr = NULL; + + if (!carg) + return ret; + + cs = (nfs3_call_state_t *)carg; + acl3_check_fh_resolve_status (cs, stat, acl3err); + nfs_request_user_init (&nfu, cs->req); + xattr = dict_new(); + if (cs->aclcount) + ret = dict_set_static_bin (xattr, "system.posix_acl_access", cs->aclxattr, + cs->aclcount * 8 + 4); + if (cs->daclcount) + ret = dict_set_static_bin (xattr, "system.posix_acl_default", cs->daclxattr, + cs->daclcount * 8 + 4); + + ret = nfs_setxattr (cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, xattr, + 0, NULL, acl3_setacl_cbk, cs); + dict_unref (xattr); + +acl3err: + if (ret < 0) { + stat = -ret; + gf_log (GF_ACL, GF_LOG_ERROR, "unable to open_and_resume"); + cs->args.setaclreply.status = nfs3_errno_to_nfsstat3 (stat); + acl3svc_submit_reply (cs->req, (void *)&cs->args.setaclreply, + (acl3_serializer)xdr_serialize_setaclreply); + nfs3_call_state_wipe (cs); + } + + return ret; +} + + +int +acl3svc_setacl (rpcsvc_request_t *req) +{ + xlator_t *vol = NULL; + struct nfs_state *nfs = NULL; + nfs3_state_t *nfs3 = NULL; + nfs3_call_state_t *cs = NULL; + int ret = RPCSVC_ACTOR_ERROR; + nfsstat3 stat = NFS3ERR_SERVERFAULT; + struct nfs3_fh fh; + struct nfs3_fh *fhp = NULL; + setaclargs setaclargs; + aclentry aclentry[NFS_ACL_MAX_ENTRIES]; + struct aclentry daclentry[NFS_ACL_MAX_ENTRIES]; + int *p = NULL, i = 0; + + if (!req) + return ret; + + acl3_validate_nfs3_state (req, nfs3, stat, rpcerr, ret); + nfs = nfs_state (nfs3->nfsx); + memset (&setaclargs, 0, sizeof (setaclargs)); + memset (&fh, 0, sizeof (fh)); + setaclargs.fh.n_bytes = (char *)&fh; + setaclargs.aclentry.aclentry_val = aclentry; + setaclargs.daclentry.daclentry_val = daclentry; + if (xdr_to_setaclargs(req->msg[0], &setaclargs) <= 0) { + gf_log (GF_ACL, GF_LOG_ERROR, "Error decoding args"); + rpcsvc_request_seterr (req, GARBAGE_ARGS); + goto rpcerr; + } + fhp = &fh; + acl3_validate_gluster_fh (fhp, stat, acl3err); + acl3_map_fh_to_volume (nfs->nfs3state, fhp, req, + vol, stat, acl3err); + acl3_handle_call_state_init (nfs->nfs3state, cs, req, + vol, stat, rpcerr); + + cs->vol = vol; + acl3_volume_started_check (nfs3, vol, ret, rpcerr); + + cs->aclcount = setaclargs.aclcount; + cs->daclcount = setaclargs.daclcount; + + if ((cs->aclcount > NFS_ACL_MAX_ENTRIES) || + (cs->daclcount > NFS_ACL_MAX_ENTRIES)) + goto acl3err; + /* FIXME: use posix_acl_to_xattr() */ + p = (int *)cs->aclxattr; + *(*(int **)&p)++ = POSIX_ACL_XATTR_VERSION; + for (i = 0; i < cs->aclcount; i++) { + *(*(short **)&p)++ = aclentry[i].type; + *(*(short **)&p)++ = aclentry[i].perm; + *(*(int **)&p)++ = aclentry[i].uid; + } + p = (int *)cs->daclxattr; + *(*(int **)&p)++ = POSIX_ACL_XATTR_VERSION; + for (i = 0; i < cs->daclcount; i++) { + *(*(short **)&p)++ = daclentry[i].type; + *(*(short **)&p)++ = daclentry[i].perm; + *(*(int **)&p)++ = daclentry[i].uid; + } + + + ret = nfs3_fh_resolve_and_resume (cs, fhp, + NULL, acl3_setacl_resume); + +acl3err: + if (ret < 0) { + gf_log (GF_ACL, GF_LOG_ERROR, "unable to resolve and resume"); + cs->args.setaclreply.status = stat; + acl3svc_submit_reply (cs->req, (void *)&cs->args.setaclreply, + (acl3_serializer)xdr_serialize_setaclreply); + nfs3_call_state_wipe (cs); + return 0; + } + +rpcerr: + if (ret < 0) + nfs3_call_state_wipe (cs); + + return ret; +} + + + + +rpcsvc_actor_t acl3svc_actors[ACL3_PROC_COUNT] = { + {"NULL", ACL3_NULL, acl3svc_null, NULL, 0}, + {"GETACL", ACL3_GETACL, acl3svc_getacl, NULL, 0}, + {"SETACL", ACL3_SETACL, acl3svc_setacl, NULL, 0}, +}; + +rpcsvc_program_t acl3prog = { + .progname = "ACL3", + .prognum = ACL_PROGRAM, + .progver = ACL_V3, + .progport = GF_NFS3_PORT, + .actors = acl3svc_actors, + .numactors = ACL3_PROC_COUNT, + .min_auth = AUTH_NULL, +}; + +rpcsvc_program_t * +acl3svc_init(xlator_t *nfsx) +{ + struct nfs3_state *ns = NULL; + struct nfs_state *nfs = NULL; + dict_t *options = NULL; + int ret = -1; + char *portstr = NULL; + + nfs = (struct nfs_state*)nfsx->private; + + ns = nfs->nfs3state; + if (!ns) { + gf_log (GF_ACL, GF_LOG_ERROR, "ACL3 init failed"); + goto err; + } + acl3prog.private = ns; + + options = dict_new (); + + ret = gf_asprintf (&portstr, "%d", GF_ACL3_PORT); + if (ret == -1) + goto err; + + ret = dict_set_dynstr (options, "transport.socket.listen-port", + portstr); + if (ret == -1) + goto err; + ret = dict_set_str (options, "transport-type", "socket"); + if (ret == -1) { + gf_log (GF_ACL, GF_LOG_ERROR, "dict_set_str error"); + goto err; + } + + if (nfs->allow_insecure) { + ret = dict_set_str (options, "rpc-auth-allow-insecure", "on"); + if (ret == -1) { + gf_log (GF_ACL, GF_LOG_ERROR, "dict_set_str error"); + goto err; + } + ret = dict_set_str (options, "rpc-auth.ports.insecure", "on"); + if (ret == -1) { + gf_log (GF_ACL, GF_LOG_ERROR, "dict_set_str error"); + goto err; + } + } + + ret = dict_set_str (options, "transport.address-family", "inet"); + if (ret == -1) { + gf_log (GF_ACL, GF_LOG_ERROR, "dict_set_str error"); + goto err; + } + + rpcsvc_create_listeners (nfs->rpcsvc, options, "ACL"); + if (ret == -1) { + gf_log (GF_ACL, GF_LOG_ERROR, "Unable to create listeners"); + dict_unref (options); + goto err; + } + + return &acl3prog; +err: + return NULL; +} diff --git a/xlators/nfs/server/src/acl3.h b/xlators/nfs/server/src/acl3.h new file mode 100644 index 000000000..b668723c8 --- /dev/null +++ b/xlators/nfs/server/src/acl3.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2012 Red Hat, Inc. + * This file is part of GlusterFS. + * + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + +#ifndef _ACL3_H +#define _ACL3_H + +#define GF_ACL3_PORT 38469 +#define GF_ACL GF_NFS"-ACL" + +#define ACL_PROGRAM 100227 +#define ACL_V3 3 + +#define ACL_USER_OBJ 0x1 +#define ACL_GROUP_OBJ 0x4 +#define ACL_OTHER_OBJ 0x20 + +#define POSIX_ACL_XATTR_VERSION 0x0002 +#define NFS_ACL_MAX_ENTRIES 1024 + +rpcsvc_program_t * +acl3svc_init(xlator_t *nfsx); + +#endif diff --git a/xlators/nfs/server/src/nfs-fops.c b/xlators/nfs/server/src/nfs-fops.c index 5a2cf2862..df09d22bb 100644 --- a/xlators/nfs/server/src/nfs-fops.c +++ b/xlators/nfs/server/src/nfs-fops.c @@ -1539,6 +1539,95 @@ err: return ret; } +int32_t +nfs_fop_getxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata) +{ + struct nfs_fop_local *nfl = NULL; + fop_getxattr_cbk_t progcbk = NULL; + + nfl_to_prog_data (nfl, progcbk, frame); + + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, dict, xdata); + + nfs_stack_destroy (nfl, frame); + return 0; +} + + +int +nfs_fop_getxattr (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, + char *name, dict_t *xdata, fop_getxattr_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!loc) || (!nfu)) + return ret; + + nfs_fop_handle_frame_create (frame, nfsx, nfu, ret, err); + nfs_fop_handle_local_init (frame, nfsx, nfl, cbk, local, ret, err); + + STACK_WIND_COOKIE (frame, nfs_fop_getxattr_cbk, xl, xl, xl->fops->getxattr, + loc, name, NULL); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (nfl, frame); + } + + return ret; +} + + +int32_t +nfs_fop_setxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + struct nfs_fop_local *nfl = NULL; + fop_setxattr_cbk_t progcbk = NULL; + + nfl_to_prog_data (nfl, progcbk, frame); + + if (progcbk) + progcbk (frame, cookie, this, op_ret, op_errno, xdata); + + nfs_stack_destroy (nfl, frame); + return 0; +} + + +int +nfs_fop_setxattr (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, + loc_t *loc, dict_t *dict, int32_t flags, dict_t *xdata, + fop_setxattr_cbk_t cbk, void *local) +{ + call_frame_t *frame = NULL; + int ret = -EFAULT; + struct nfs_fop_local *nfl = NULL; + + if ((!xl) || (!loc) || (!nfu)) + return ret; + + nfs_fop_handle_frame_create (frame, nfsx, nfu, ret, err); + nfs_fop_handle_local_init (frame, nfsx, nfl, cbk, local, ret, err); + + STACK_WIND_COOKIE (frame, nfs_fop_setxattr_cbk, xl, xl, xl->fops->setxattr, + loc, dict, flags, xdata); + ret = 0; +err: + if (ret < 0) { + if (frame) + nfs_stack_destroy (nfl, frame); + } + + return ret; +} + int32_t nfs_fop_truncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, diff --git a/xlators/nfs/server/src/nfs-fops.h b/xlators/nfs/server/src/nfs-fops.h index b82805939..3ada863de 100644 --- a/xlators/nfs/server/src/nfs-fops.h +++ b/xlators/nfs/server/src/nfs-fops.h @@ -245,4 +245,13 @@ extern int nfs_fop_lk (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, int cmd, struct gf_flock *flock, fop_lk_cbk_t cbk, void *local); +extern int +nfs_fop_getxattr (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, + char *name, dict_t *xdata, fop_getxattr_cbk_t cbk, void *local); + +extern int +nfs_fop_setxattr (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, + loc_t *loc, dict_t *dict, int32_t flags, dict_t *xdata, + fop_setxattr_cbk_t cbk, void *local); + #endif diff --git a/xlators/nfs/server/src/nfs-generics.c b/xlators/nfs/server/src/nfs-generics.c index 553cc7f39..7f79bba9b 100644 --- a/xlators/nfs/server/src/nfs-generics.c +++ b/xlators/nfs/server/src/nfs-generics.c @@ -165,6 +165,22 @@ nfs_lk (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, return nfs_fop_lk ( nfsx, xl, nfu, fd, cmd, flock, cbk, local); } +int +nfs_getxattr (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, + char *name, dict_t *xdata, fop_getxattr_cbk_t cbk, void *local) +{ + return nfs_fop_getxattr (nfsx, xl, nfu, loc, name, xdata, cbk, local); +} + +int +nfs_setxattr (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, + loc_t *loc, dict_t *dict, int32_t flags, dict_t *xdata, + fop_setxattr_cbk_t cbk, void *local) +{ + return nfs_fop_setxattr (nfsx, xl, nfu, loc, dict, flags, xdata, cbk, + local); +} + int nfs_fsync (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, int32_t datasync, fop_fsync_cbk_t cbk, void *local) diff --git a/xlators/nfs/server/src/nfs-generics.h b/xlators/nfs/server/src/nfs-generics.h index 11f191f5f..34e203a62 100644 --- a/xlators/nfs/server/src/nfs-generics.h +++ b/xlators/nfs/server/src/nfs-generics.h @@ -164,4 +164,14 @@ nfs_access (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *pathloc, extern int nfs_lk (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, fd_t *fd, int cmd, struct gf_flock *flock, fop_lk_cbk_t cbk, void *local); + +extern int +nfs_getxattr (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, loc_t *loc, + char *name, dict_t *xdata, fop_getxattr_cbk_t cbk, void *local); + +extern int +nfs_setxattr (xlator_t *nfsx, xlator_t *xl, nfs_user_t *nfu, + loc_t *loc, dict_t *dict, int32_t flags, dict_t *xdata, + fop_setxattr_cbk_t cbk, void *local); + #endif diff --git a/xlators/nfs/server/src/nfs.c b/xlators/nfs/server/src/nfs.c index 033d95213..8fa69af6b 100644 --- a/xlators/nfs/server/src/nfs.c +++ b/xlators/nfs/server/src/nfs.c @@ -42,6 +42,7 @@ #include "nfs3-helpers.h" #include "nlm4.h" #include "options.h" +#include "acl3.h" #define OPT_SERVER_AUX_GIDS "nfs.server-aux-gids" #define OPT_SERVER_GID_CACHE_TIMEOUT "nfs.server.aux-gid-timeout" @@ -186,6 +187,13 @@ nfs_add_all_initiators (struct nfs_state *nfs) } } + ret = nfs_add_initer (&nfs->versions, acl3svc_init); + if (ret == -1) { + gf_log (GF_NFS, GF_LOG_ERROR, "Failed to add protocol" + " initializer"); + goto ret; + } + ret = 0; ret: return ret; diff --git a/xlators/nfs/server/src/nfs3.h b/xlators/nfs/server/src/nfs3.h index 78eb01b60..111542bc6 100644 --- a/xlators/nfs/server/src/nfs3.h +++ b/xlators/nfs/server/src/nfs3.h @@ -35,7 +35,8 @@ #include "xdr-nfs3.h" #include "mem-pool.h" #include "nlm4.h" - +#include "acl3-xdr.h" +#include "acl3.h" #include #define GF_NFS3 GF_NFS"-nfsv3" @@ -155,6 +156,10 @@ typedef union args_ { nlm4_shareargs nlm4_shareargs; nlm4_shareres nlm4_shareres; nlm4_freeallargs nlm4_freeallargs; + getaclargs getaclargs; + setaclargs setaclargs; + getaclreply getaclreply; + setaclreply setaclreply; } args; @@ -234,6 +239,14 @@ struct nfs3_local { int monitor; rpc_transport_t *trans; call_frame_t *frame; + + /* ACL */ + aclentry aclentry[NFS_ACL_MAX_ENTRIES]; + aclentry daclentry[NFS_ACL_MAX_ENTRIES]; + int aclcount; + char aclxattr[NFS_ACL_MAX_ENTRIES*8 + 4]; + int daclcount; + char daclxattr[NFS_ACL_MAX_ENTRIES*8 + 4]; }; #define nfs3_is_revalidate_lookup(cst) ((cst)->lookuptype == GF_NFS3_REVALIDATE) -- cgit