diff options
Diffstat (limited to 'xlators/nfs/server/src/acl3.c')
| -rw-r--r-- | xlators/nfs/server/src/acl3.c | 1332 |
1 files changed, 819 insertions, 513 deletions
diff --git a/xlators/nfs/server/src/acl3.c b/xlators/nfs/server/src/acl3.c index ed60775ab32..7e3bbf16086 100644 --- a/xlators/nfs/server/src/acl3.c +++ b/xlators/nfs/server/src/acl3.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Red Hat, Inc. <http://www.redhat.com> + * Copyright (c) 2012-2013 Red Hat, Inc. <http://www.redhat.com> * This file is part of GlusterFS. * * This file is licensed to you under your choice of the GNU Lesser @@ -8,620 +8,926 @@ * cases as published by the Free Software Foundation. */ -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include "defaults.h" +#include <glusterfs/defaults.h> #include "rpcsvc.h" -#include "dict.h" -#include "xlator.h" +#include <glusterfs/dict.h> +#include <glusterfs/xlator.h> #include "nfs.h" -#include "mem-pool.h" -#include "logging.h" +#include <glusterfs/mem-pool.h> +#include <glusterfs/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" +#include <glusterfs/byte-order.h> +#include <glusterfs/compat-errno.h> +#include "nfs-messages.h" + +static int +acl3_nfs_acl_to_xattr(aclentry *ace, void *xattrbuf, int aclcount, int defacl); +static int +acl3_nfs_acl_from_xattr(aclentry *ace, void *xattrbuf, int bufsize, int defacl); -typedef ssize_t (*acl3_serializer) (struct iovec outmsg, void *args); +typedef ssize_t (*acl3_serializer)(struct iovec outmsg, void *args); -extern void nfs3_call_state_wipe (nfs3_call_state_t *cs); +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); +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) \ - +nfs3_fh_validate(struct nfs3_fh *fh); + +extern void +nfs3_stat_to_fattr3(struct iatt *buf, fattr3 *fa); + +#define acl3_validate_nfs3_state(request, state, status, label, retval) \ + do { \ + state = rpcsvc_request_program_private(request); \ + if (!state) { \ + gf_msg(GF_ACL, GF_LOG_ERROR, errno, NFS_MSG_STATE_MISSING, \ + "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)) { \ + gf_msg(GF_ACL, GF_LOG_ERROR, EINVAL, NFS_MSG_BAD_HANDLE, \ + "Bad Handle"); \ + status = NFS3ERR_BADHANDLE; \ + 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_ACL, GF_LOG_ERROR, "Failed to " \ - "init call state"); \ - opstat = NFS3ERR_SERVERFAULT; \ - rpcsvc_request_seterr (req, SYSTEM_ERR); \ - goto errlabel; \ - } \ - } while (0) \ - +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) { \ + gf_uuid_unparse(handle->exportid, exportid); \ + gf_uuid_unparse(handle->gfid, gfid); \ + trans = rpcsvc_request_transport(req); \ + gf_msg(GF_ACL, GF_LOG_ERROR, 0, NFS_MSG_FH_TO_VOL_FAIL, \ + "Failed to map " \ + "FH to vol: client=%s, exportid=%s, gfid=%s", \ + trans->peerinfo.identifier, exportid, gfid); \ + gf_msg(GF_ACL, GF_LOG_ERROR, ESTALE, NFS_MSG_VOLUME_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_msg_trace(GF_ACL, 0, "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_msg(GF_ACL, GF_LOG_ERROR, 0, NFS_MSG_VOL_DISABLE, \ + "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[GF_UUID_BUF_SIZE]; \ + 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); \ + gf_uuid_unparse(cst->resolvefh.gfid, gfid); \ + snprintf(buf, sizeof(buf), "(%s) %s : %s", \ + trans->peerinfo.identifier, \ + xlatorp ? xlatorp->name : "ERR", gfid); \ + gf_msg(GF_ACL, GF_LOG_ERROR, cst->resolve_errno, \ + NFS_MSG_RESOLVE_FH_FAIL, \ + "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_msg(GF_ACL, GF_LOG_ERROR, 0, NFS_MSG_INIT_CALL_STAT_FAIL, \ + "Failed to " \ + "init call state"); \ + opstat = NFS3ERR_SERVERFAULT; \ + rpcsvc_request_seterr(req, SYSTEM_ERR); \ + goto errlabel; \ + } \ + } while (0) int -acl3svc_submit_reply (rpcsvc_request_t *req, void *arg, acl3_serializer sfunc) +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; + struct iovec outmsg = { + 0, + }; + struct iobuf *iob = NULL; + struct nfs3_state *nfs3 = NULL; + int ret = -1; + ssize_t msglen = 0; + struct iobref *iobref = NULL; + + if (!req) + return -1; + + nfs3 = (struct nfs3_state *)rpcsvc_request_program_private(req); + if (!nfs3) { + gf_msg(GF_ACL, GF_LOG_ERROR, EINVAL, NFS_MSG_MNT_STATE_NOT_FOUND, + "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_msg(GF_ACL, GF_LOG_ERROR, ENOMEM, NFS_MSG_NO_MEMORY, + "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. + */ + msglen = sfunc(outmsg, arg); + if (msglen < 0) { + gf_msg(GF_ACL, GF_LOG_ERROR, errno, NFS_MSG_ENCODE_MSG_FAIL, + "Failed to encode message"); + goto ret; + } + outmsg.iov_len = msglen; + + iobref = iobref_new(); + if (iobref == NULL) { + gf_msg(GF_ACL, GF_LOG_ERROR, ENOMEM, NFS_MSG_NO_MEMORY, + "Failed to get iobref"); + goto ret; + } + + ret = iobref_add(iobref, iob); + if (ret) { + gf_msg(GF_ACL, GF_LOG_ERROR, ENOMEM, NFS_MSG_NO_MEMORY, + "Failed to add iob to iobref"); + goto ret; + } + + /* Then, submit the message for transmission. */ + ret = rpcsvc_submit_message(req, &outmsg, 1, NULL, 0, iobref); + if (ret == -1) { + gf_msg(GF_ACL, GF_LOG_ERROR, errno, NFS_MSG_REP_SUBMIT_FAIL, + "Reply submission failed"); + goto ret; + } + + ret = 0; ret: - if (iob) - iobuf_unref (iob); - if (iobref) - iobref_unref (iobref); + if (iob) + iobuf_unref(iob); + if (iobref) + iobref_unref(iobref); - return ret; + return ret; } - int -acl3svc_null (rpcsvc_request_t *req) +acl3svc_null(rpcsvc_request_t *req) { - struct iovec dummyvec = {0, }; + 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); + if (!req) { + gf_msg(GF_ACL, GF_LOG_ERROR, EINVAL, NFS_MSG_INVALID_ENTRY, + "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) +acl3_getacl_reply(rpcsvc_request_t *req, getaclreply *reply) { - acl3svc_submit_reply (cs->req, (void *)reply, - (acl3_serializer)xdr_serialize_getaclreply); - return 0; + acl3svc_submit_reply(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) +acl3_setacl_reply(rpcsvc_request_t *req, setaclreply *reply) { - 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 (cs) - getaclreply = &cs->args.getaclreply; - - if (op_ret == -1) { - stat = nfs3_errno_to_nfsstat3 (op_errno); - goto err; - } + acl3svc_submit_reply(req, (void *)reply, + (acl3_serializer)xdr_serialize_setaclreply); + return 0; +} - 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_cbk: fetch and decode the ACL in the POSIX_ACL_ACCESS_XATTR + * + * The POSIX_ACL_ACCESS_XATTR can be set on files and directories. + */ +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; + getaclreply *getaclreply = NULL; + int aclcount = 0; + int defacl = 1; /* DEFAULT ACL */ + + if (!frame->local) { + gf_msg(GF_ACL, GF_LOG_ERROR, EINVAL, NFS_MSG_INVALID_ENTRY, + "Invalid argument, frame->local NULL"); + return -EINVAL; + } + cs = frame->local; + getaclreply = &cs->args.getaclreply; + if ((op_ret < 0) && (op_errno != ENODATA && op_errno != ENOATTR)) { + stat = nfs3_cbk_errno_status(op_ret, op_errno); + goto err; + } else if (!dict) { + /* no ACL has been set */ + stat = NFS3_OK; + goto err; + } + + getaclreply->aclentry.aclentry_val = cs->aclentry; + + /* getfacl: NFS USER ACL */ + data = dict_get(dict, POSIX_ACL_ACCESS_XATTR); + if (data && data->data) { + aclcount = acl3_nfs_acl_from_xattr(cs->aclentry, data->data, data->len, + !defacl); + if (aclcount < 0) { + gf_msg(GF_ACL, GF_LOG_ERROR, aclcount, NFS_MSG_GET_USER_ACL_FAIL, + "Failed to get USER ACL"); + stat = nfs3_errno_to_nfsstat3(-aclcount); + goto err; } + getaclreply->aclcount = aclcount; + getaclreply->aclentry.aclentry_len = aclcount; + } - acl3_getacl_reply (cs, getaclreply); - nfs3_call_state_wipe (cs); - return 0; + acl3_getacl_reply(cs->req, getaclreply); + nfs3_call_state_wipe(cs); + return 0; err: - if (getaclreply) - getaclreply->status = stat; - acl3_getacl_reply (cs, getaclreply); - nfs3_call_state_wipe (cs); - return 0; + if (getaclreply) + getaclreply->status = stat; + acl3_getacl_reply(cs->req, getaclreply); + nfs3_call_state_wipe(cs); + return 0; } +/* acl3_default_getacl_cbk: fetch and decode the ACL set in the + * POSIX_ACL_DEFAULT_XATTR xattr. + * + * The POSIX_ACL_DEFAULT_XATTR xattr is only set on directories, not on files. + * + * When done with POSIX_ACL_DEFAULT_XATTR, we also need to get and decode the + * ACL that can be set in POSIX_ACL_DEFAULT_XATTR. + */ 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) +acl3_default_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; - getaclreply *getaclreply = NULL; - int ret = -1; - nfs_user_t nfu = {0, }; - - cs = frame->local; - if (cs) - getaclreply = &cs->args.getaclreply; - - if (op_ret == -1) { - stat = nfs3_errno_to_nfsstat3 (op_errno); - goto err; + nfsstat3 stat = NFS3ERR_SERVERFAULT; + nfs3_call_state_t *cs = NULL; + data_t *data = NULL; + getaclreply *getaclreply = NULL; + int aclcount = 0; + int defacl = 1; /* DEFAULT ACL */ + nfs_user_t nfu = { + 0, + }; + int ret = -1; + + if (!frame->local) { + gf_msg(GF_ACL, GF_LOG_ERROR, EINVAL, NFS_MSG_INVALID_ENTRY, + "Invalid argument, frame->local NULL"); + return -EINVAL; + } + cs = frame->local; + getaclreply = &cs->args.getaclreply; + if ((op_ret < 0) && (op_errno != ENODATA && op_errno != ENOATTR)) { + stat = nfs3_cbk_errno_status(op_ret, op_errno); + goto err; + } else if (!dict) { + /* no ACL has been set */ + stat = NFS3_OK; + goto err; + } + + getaclreply->daclentry.daclentry_val = cs->daclentry; + + /* getfacl: NFS DEFAULT ACL */ + data = dict_get(dict, POSIX_ACL_DEFAULT_XATTR); + if (data && data->data) { + aclcount = acl3_nfs_acl_from_xattr(cs->daclentry, data->data, data->len, + defacl); + if (aclcount < 0) { + gf_msg(GF_ACL, GF_LOG_ERROR, aclcount, NFS_MSG_GET_DEF_ACL_FAIL, + "Failed to get DEFAULT ACL"); + stat = nfs3_errno_to_nfsstat3(-aclcount); + goto err; } - 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; + getaclreply->daclcount = aclcount; + getaclreply->daclentry.daclentry_len = aclcount; + } + + getaclreply->attr_follows = TRUE; + nfs_request_user_init(&nfu, cs->req); + ret = nfs_getxattr(cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + POSIX_ACL_ACCESS_XATTR, NULL, acl3_getacl_cbk, cs); + if (ret < 0) { + stat = nfs3_errno_to_nfsstat3(-ret); + goto err; + } + + return 0; + err: + if (getaclreply) getaclreply->status = stat; - acl3_getacl_reply (cs, getaclreply); - nfs3_call_state_wipe (cs); - return 0; + acl3_getacl_reply(cs->req, getaclreply); + nfs3_call_state_wipe(cs); + return 0; } - int -acl3_getacl_resume (void *carg) +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) { - int ret = -1; - nfs3_call_state_t *cs = NULL; - nfsstat3 stat = NFS3ERR_SERVERFAULT; - nfs_user_t nfu = {0, }; + nfsstat3 stat = NFS3ERR_SERVERFAULT; + nfs3_call_state_t *cs = NULL; + getaclreply *getaclreply = NULL; + int ret = -1; + nfs_user_t nfu = { + 0, + }; + uint64_t deviceid = 0; + + if (!frame->local) { + gf_msg(GF_ACL, GF_LOG_ERROR, EINVAL, NFS_MSG_INVALID_ENTRY, + "Invalid argument, frame->local NULL"); + return EINVAL; + } + + cs = frame->local; + getaclreply = &cs->args.getaclreply; + + if (op_ret == -1) { + stat = nfs3_cbk_errno_status(op_ret, op_errno); + goto err; + } + + /* Fill the attrs before xattrs */ + getaclreply->attr_follows = TRUE; + deviceid = nfs3_request_xlator_deviceid(cs->req); + nfs3_map_deviceid_to_statdev(buf, deviceid); + nfs3_stat_to_fattr3(buf, &(getaclreply->attr)); + + nfs_request_user_init(&nfu, cs->req); + if (buf->ia_type == IA_IFDIR) { + ret = nfs_getxattr(cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + POSIX_ACL_DEFAULT_XATTR, NULL, + acl3_default_getacl_cbk, cs); + } else { + ret = nfs_getxattr(cs->nfsx, cs->vol, &nfu, &cs->resolvedloc, + POSIX_ACL_ACCESS_XATTR, NULL, acl3_getacl_cbk, cs); + } + + if (ret < 0) { + stat = nfs3_errno_to_nfsstat3(-ret); + goto err; + } + + return 0; +err: + getaclreply->status = stat; + acl3_getacl_reply(cs->req, getaclreply); + nfs3_call_state_wipe(cs); + return 0; +} - if (!carg) - return ret; +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); + 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; + 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; + if (ret < 0) { + gf_msg(GF_ACL, GF_LOG_ERROR, stat, NFS_MSG_OPEN_FAIL, + "unable to open_and_resume"); + cs->args.getaclreply.status = nfs3_errno_to_nfsstat3(stat); + acl3_getacl_reply(cs->req, &cs->args.getaclreply); + nfs3_call_state_wipe(cs); + } + + return ret; } - int -acl3svc_getacl (rpcsvc_request_t *req) +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, acl3err); + 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; + getaclreply getaclreply; + + if (!req) + return ret; - ret = nfs3_fh_resolve_and_resume (cs, fhp, - NULL, acl3_getacl_resume); + acl3_validate_nfs3_state(req, nfs3, stat, rpcerr, ret); + nfs = nfs_state(nfs3->nfsx); + memset(&getaclargs, 0, sizeof(getaclargs)); + memset(&getaclreply, 0, sizeof(getaclreply)); + getaclargs.fh.n_bytes = (char *)&fh; + if (xdr_to_getaclargs(req->msg[0], &getaclargs) <= 0) { + gf_msg(GF_ACL, GF_LOG_ERROR, errno, NFS_MSG_ARGS_DECODE_ERROR, + "Error decoding args"); + rpcsvc_request_seterr(req, GARBAGE_ARGS); + goto rpcerr; + } + + /* Validate ACL mask */ + if (getaclargs.mask & ~(NFS_ACL | NFS_ACLCNT | NFS_DFACL | NFS_DFACLCNT)) { + stat = NFS3ERR_INVAL; + goto acl3err; + } + + fhp = &fh; + acl3_validate_gluster_fh(&fh, stat, acl3err); + acl3_map_fh_to_volume(nfs->nfs3state, fhp, req, vol, stat, acl3err); + acl3_volume_started_check(nfs3, vol, ret, rpcerr); + acl3_handle_call_state_init(nfs->nfs3state, cs, req, vol, stat, acl3err); + + cs->vol = vol; + cs->args.getaclreply.mask = getaclargs.mask; + + ret = nfs3_fh_resolve_and_resume(cs, fhp, NULL, acl3_getacl_resume); + stat = nfs3_errno_to_nfsstat3(-ret); acl3err: - if (ret < 0) { - gf_log (GF_ACL, GF_LOG_ERROR, "unable to resolve and resume"); - if (cs) { - cs->args.getaclreply.status = stat; - acl3_getacl_reply (cs, &cs->args.getaclreply); - nfs3_call_state_wipe (cs); - } - return 0; - } + if (ret < 0) { + gf_msg(GF_ACL, GF_LOG_ERROR, -ret, NFS_MSG_RESOLVE_ERROR, + "unable to resolve and resume"); + getaclreply.status = stat; + acl3_getacl_reply(req, &getaclreply); + nfs3_call_state_wipe(cs); + return 0; + } rpcerr: - return ret; + 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) +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); - } + nfs3_call_state_t *cs = NULL; + cs = frame->local; + if (op_ret < 0) { + nfsstat3 status = nfs3_cbk_errno_status(op_ret, op_errno); + cs->args.setaclreply.status = status; + } - acl3svc_submit_reply (cs->req, (void *)&cs->args.setaclreply, - (acl3_serializer)xdr_serialize_setaclreply); - return 0; + acl3_setacl_reply(cs->req, &cs->args.setaclreply); + + nfs3_call_state_wipe(cs); + + return 0; } int -acl3_setacl_resume (void *carg) +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); + 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 (xattr == NULL) { + gf_msg(GF_NLM, GF_LOG_ERROR, ENOMEM, NFS_MSG_GFID_DICT_CREATE_FAIL, + "dict allocation failed"); + goto acl3err; + } + + if (cs->aclcount) + ret = dict_set_static_bin(xattr, POSIX_ACL_ACCESS_XATTR, cs->aclxattr, + posix_acl_xattr_size(cs->aclcount)); + if (cs->daclcount) + ret = dict_set_static_bin(xattr, POSIX_ACL_DEFAULT_XATTR, cs->daclxattr, + posix_acl_xattr_size(cs->daclcount)); + + 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; + if (ret < 0) { + stat = -ret; + gf_msg(GF_ACL, GF_LOG_ERROR, stat, NFS_MSG_OPEN_FAIL, + "unable to open_and_resume"); + cs->args.setaclreply.status = nfs3_errno_to_nfsstat3(stat); + acl3_setacl_reply(cs->req, &cs->args.setaclreply); + nfs3_call_state_wipe(cs); + } + + return ret; } - int -acl3svc_setacl (rpcsvc_request_t *req) +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); + 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; + setaclreply setaclreply; + aclentry *daclentry = NULL; + aclentry *aclentry = NULL; + int aclerrno = 0; + int defacl = 1; + + if (!req) + return ret; + aclentry = GF_CALLOC(NFS_ACL_MAX_ENTRIES, sizeof(*aclentry), gf_nfs_mt_arr); + if (!aclentry) { + goto rpcerr; + } + daclentry = GF_CALLOC(NFS_ACL_MAX_ENTRIES, sizeof(*daclentry), + gf_nfs_mt_arr); + if (!daclentry) { + goto rpcerr; + } + + acl3_validate_nfs3_state(req, nfs3, stat, rpcerr, ret); + nfs = nfs_state(nfs3->nfsx); + memset(&setaclargs, 0, sizeof(setaclargs)); + memset(&setaclreply, 0, sizeof(setaclreply)); + 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_msg(GF_ACL, GF_LOG_ERROR, errno, NFS_MSG_ARGS_DECODE_ERROR, + "Error decoding args"); + rpcsvc_request_seterr(req, GARBAGE_ARGS); + goto rpcerr; + } + + /* Validate ACL mask */ + if (setaclargs.mask & ~(NFS_ACL | NFS_ACLCNT | NFS_DFACL | NFS_DFACLCNT)) { + stat = NFS3ERR_INVAL; + goto acl3err; + } + + fhp = &fh; + acl3_validate_gluster_fh(fhp, stat, acl3err); + acl3_map_fh_to_volume(nfs->nfs3state, fhp, req, vol, stat, acl3err); + acl3_volume_started_check(nfs3, vol, ret, rpcerr); + acl3_handle_call_state_init(nfs->nfs3state, cs, req, vol, stat, acl3err); + + cs->vol = vol; + cs->aclcount = setaclargs.aclcount; + cs->daclcount = setaclargs.daclcount; + + /* setfacl: NFS USER ACL */ + aclerrno = acl3_nfs_acl_to_xattr(aclentry, cs->aclxattr, cs->aclcount, + !defacl); + if (aclerrno < 0) { + gf_msg(GF_ACL, GF_LOG_ERROR, -aclerrno, NFS_MSG_SET_USER_ACL_FAIL, + "Failed to set USER ACL"); + stat = nfs3_errno_to_nfsstat3(-aclerrno); + goto acl3err; + } + + /* setfacl: NFS DEFAULT ACL */ + aclerrno = acl3_nfs_acl_to_xattr(daclentry, cs->daclxattr, cs->daclcount, + defacl); + if (aclerrno < 0) { + gf_msg(GF_ACL, GF_LOG_ERROR, -aclerrno, NFS_MSG_SET_DEF_ACL_FAIL, + "Failed to set DEFAULT ACL"); + stat = nfs3_errno_to_nfsstat3(-aclerrno); + goto acl3err; + } + + ret = nfs3_fh_resolve_and_resume(cs, fhp, NULL, acl3_setacl_resume); + stat = nfs3_errno_to_nfsstat3(-ret); 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; - } + if (ret < 0) { + gf_msg(GF_ACL, GF_LOG_ERROR, -ret, NFS_MSG_RESOLVE_ERROR, + "unable to resolve and resume"); + setaclreply.status = stat; + acl3_setacl_reply(req, &setaclreply); + nfs3_call_state_wipe(cs); + GF_FREE(aclentry); + GF_FREE(daclentry); + return 0; + } rpcerr: - if (ret < 0) - nfs3_call_state_wipe (cs); - - return ret; + if (ret < 0) + nfs3_call_state_wipe(cs); + if (aclentry) + GF_FREE(aclentry); + if (daclentry) + GF_FREE(daclentry); + 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}, +static rpcsvc_actor_t acl3svc_actors[ACL3_PROC_COUNT] = { + {"NULL", acl3svc_null, NULL, ACL3_NULL, DRC_NA, 0}, + {"GETACL", acl3svc_getacl, NULL, ACL3_GETACL, DRC_NA, 0}, + {"SETACL", acl3svc_setacl, NULL, ACL3_SETACL, DRC_NA, 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, +static rpcsvc_program_t acl3prog = { + .progname = "ACL3", + .prognum = ACL_PROGRAM, + .progver = ACLV3_VERSION, + .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; + struct nfs3_state *ns = NULL; + struct nfs_state *nfs = NULL; + dict_t *options = NULL; + int ret = -1; + static gf_boolean_t acl3_inited = _gf_false; + + /* Already inited */ + if (acl3_inited) + return &acl3prog; - ret = dict_set_dynstr (options, "transport.socket.listen-port", - portstr); - if (ret == -1) - goto err; - ret = dict_set_str (options, "transport-type", "socket"); + nfs = (struct nfs_state *)nfsx->private; + + ns = nfs->nfs3state; + if (!ns) { + gf_msg(GF_ACL, GF_LOG_ERROR, EINVAL, NFS_MSG_ACL_INIT_FAIL, + "ACL3 init failed"); + goto err; + } + acl3prog.private = ns; + + options = dict_new(); + if (options == NULL) { + gf_msg(GF_ACL, GF_LOG_ERROR, ENOMEM, NFS_MSG_GFID_DICT_CREATE_FAIL, + "dict allocation failed"); + goto err; + } + + ret = dict_set_str(options, "transport.socket.listen-port", GF_ACL3_PORT); + if (ret == -1) + goto err; + ret = dict_set_str(options, "transport-type", "socket"); + if (ret == -1) { + gf_msg(GF_ACL, GF_LOG_ERROR, errno, NFS_MSG_DICT_SET_FAILED, + "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; + gf_msg(GF_ACL, GF_LOG_ERROR, errno, NFS_MSG_DICT_SET_FAILED, + "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, "rpc-auth.ports.insecure", "on"); + if (ret == -1) { + gf_msg(GF_ACL, GF_LOG_ERROR, errno, NFS_MSG_DICT_SET_FAILED, + "dict_set_str error"); + goto err; } + } + + ret = dict_set_str(options, "transport.address-family", "inet"); + if (ret == -1) { + gf_msg(GF_ACL, GF_LOG_ERROR, errno, NFS_MSG_DICT_SET_FAILED, + "dict_set_str error"); + goto err; + } + + ret = rpcsvc_create_listeners(nfs->rpcsvc, options, "ACL"); + if (ret == -1) { + gf_msg(GF_ACL, GF_LOG_ERROR, errno, NFS_MSG_LISTENERS_CREATE_FAIL, + "Unable to create listeners"); + goto err; + } + + if (options) + dict_unref(options); + + acl3_inited = _gf_true; + return &acl3prog; +err: + if (options) + dict_unref(options); + return NULL; +} - 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; +static int +acl3_nfs_acl_to_xattr(aclentry *ace, /* ACL entries to be read */ + void *xattrbuf, /* XATTR buf to be populated */ + int aclcount, /* No of ACLs to be read */ + int defacl) /* 1 if DEFAULT ACL */ +{ + int idx = 0; + posix_acl_xattr_header *xheader = NULL; + posix_acl_xattr_entry *xentry = NULL; + + if ((!ace) || (!xattrbuf)) + return (-EINVAL); + + /* ACL count is ZERO, nothing to do */ + if (!aclcount) + return (0); + + if ((aclcount < 0) || (aclcount > NFS_ACL_MAX_ENTRIES)) + return (-EINVAL); + + xheader = (posix_acl_xattr_header *)(xattrbuf); + xentry = (posix_acl_xattr_entry *)(xheader + 1); + + /* + * For "default ACL", NFSv3 handles the 'type' differently + * i.e. by logical OR'ing 'type' with NFS_ACL_DEFAULT. + * Which the backend File system does not understand and + * that needs to be masked OFF. + */ + xheader->version = POSIX_ACL_XATTR_VERSION; + + for (idx = 0; idx < aclcount; idx++) { + xentry->tag = ace->type; + if (defacl) + xentry->tag &= ~NFS_ACL_DEFAULT; + xentry->perm = ace->perm; + + switch (xentry->tag) { + case POSIX_ACL_USER: + case POSIX_ACL_GROUP: + if (xentry->perm & ~S_IRWXO) + return (-EINVAL); + xentry->id = ace->uid; + break; + case POSIX_ACL_USER_OBJ: + case POSIX_ACL_GROUP_OBJ: + case POSIX_ACL_OTHER: + if (xentry->perm & ~S_IRWXO) + return (-EINVAL); + xentry->id = POSIX_ACL_UNDEFINED_ID; + break; + case POSIX_ACL_MASK: + /* Solaris sometimes sets additional bits in + * the mask. + */ + xentry->perm &= S_IRWXO; + xentry->id = POSIX_ACL_UNDEFINED_ID; + break; + default: + return (-EINVAL); } - 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; + xentry++; + ace++; + } + + /* SUCCESS */ + return (0); +} + +static int +acl3_nfs_acl_from_xattr(aclentry *ace, /* ACL entries to be filled */ + void *xattrbuf, /* XATTR buf to be read */ + int bufsize, /* Size of XATTR buffer */ + int defacl) /* 1 if DEFAULT ACL */ +{ + int idx = 0; + ssize_t aclcount = 0; + posix_acl_xattr_header *xheader = NULL; + posix_acl_xattr_entry *xentry = NULL; + + if ((!xattrbuf) || (!ace)) + return (-EINVAL); + + aclcount = posix_acl_xattr_count(bufsize); + if ((aclcount < 0) || (aclcount > NFS_ACL_MAX_ENTRIES)) + return (-EINVAL); + + xheader = (posix_acl_xattr_header *)(xattrbuf); + xentry = (posix_acl_xattr_entry *)(xheader + 1); + + /* Check for supported POSIX ACL xattr version */ + if (xheader->version != POSIX_ACL_XATTR_VERSION) + return (-ENOSYS); + + for (idx = 0; idx < (int)aclcount; idx++) { + ace->type = xentry->tag; + if (defacl) { + /* + * SET the NFS_ACL_DEFAULT flag for default + * ACL which was masked OFF during setfacl(). + */ + ace->type |= NFS_ACL_DEFAULT; + } + ace->perm = (xentry->perm & S_IRWXO); + + switch (xentry->tag) { + case POSIX_ACL_USER: + case POSIX_ACL_GROUP: + ace->uid = xentry->id; + break; + case POSIX_ACL_USER_OBJ: + case POSIX_ACL_GROUP_OBJ: + case POSIX_ACL_MASK: + case POSIX_ACL_OTHER: + ace->uid = POSIX_ACL_UNDEFINED_ID; + break; + default: + return (-EINVAL); } - return &acl3prog; -err: - return NULL; + xentry++; + ace++; + } + + /* SUCCESS: ACL count */ + return aclcount; } |
