diff options
| -rw-r--r-- | configure.ac | 3 | ||||
| -rw-r--r-- | xlators/Makefile.am | 2 | ||||
| -rw-r--r-- | xlators/storage/posix/src/posix.c | 5 | ||||
| -rw-r--r-- | xlators/system/Makefile.am | 1 | ||||
| -rw-r--r-- | xlators/system/posix-acl/Makefile.am | 1 | ||||
| -rw-r--r-- | xlators/system/posix-acl/src/Makefile.am | 13 | ||||
| -rw-r--r-- | xlators/system/posix-acl/src/posix-acl-xattr.c | 190 | ||||
| -rw-r--r-- | xlators/system/posix-acl/src/posix-acl-xattr.h | 52 | ||||
| -rw-r--r-- | xlators/system/posix-acl/src/posix-acl.c | 1792 | ||||
| -rw-r--r-- | xlators/system/posix-acl/src/posix-acl.h | 86 | 
10 files changed, 2144 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac index 16a9e9b3566..51bdab86384 100644 --- a/configure.ac +++ b/configure.ac @@ -105,6 +105,9 @@ AC_CONFIG_FILES([Makefile  		xlators/encryption/Makefile  		xlators/encryption/rot-13/Makefile  		xlators/encryption/rot-13/src/Makefile +                xlators/system/Makefile +                xlators/system/posix-acl/Makefile +                xlators/system/posix-acl/src/Makefile                  cli/Makefile                  cli/src/Makefile  		doc/Makefile diff --git a/xlators/Makefile.am b/xlators/Makefile.am index 4c94f5e44c1..b1643d26ca0 100644 --- a/xlators/Makefile.am +++ b/xlators/Makefile.am @@ -1,3 +1,3 @@ -SUBDIRS = cluster storage protocol performance debug features encryption mount nfs mgmt +SUBDIRS = cluster storage protocol performance debug features encryption mount nfs mgmt system  CLEANFILES = diff --git a/xlators/storage/posix/src/posix.c b/xlators/storage/posix/src/posix.c index 6121b5f5a1c..fd7f2e27cb8 100644 --- a/xlators/storage/posix/src/posix.c +++ b/xlators/storage/posix/src/posix.c @@ -4537,6 +4537,11 @@ init (xlator_t *this)                  }          } +        op_ret = sys_lgetxattr (dir_data->data, "system.posix_acl_access", +                                NULL, 0); +        if ((op_ret < 0) && (errno == ENOTSUP)) +                gf_log (this->name, GF_LOG_WARNING, +                        "Posix access control list is not supported.");          _private = GF_CALLOC (1, sizeof (*_private),                                gf_posix_mt_posix_private);          if (!_private) { diff --git a/xlators/system/Makefile.am b/xlators/system/Makefile.am new file mode 100644 index 00000000000..65aeea50f0c --- /dev/null +++ b/xlators/system/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = posix-acl
\ No newline at end of file diff --git a/xlators/system/posix-acl/Makefile.am b/xlators/system/posix-acl/Makefile.am new file mode 100644 index 00000000000..af437a64d6d --- /dev/null +++ b/xlators/system/posix-acl/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/xlators/system/posix-acl/src/Makefile.am b/xlators/system/posix-acl/src/Makefile.am new file mode 100644 index 00000000000..57ff27e70d5 --- /dev/null +++ b/xlators/system/posix-acl/src/Makefile.am @@ -0,0 +1,13 @@ +xlator_LTLIBRARIES = posix-acl.la +xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/system +posix_acl_la_LDFLAGS = -module -avoidversion +posix_acl_la_SOURCES = posix-acl.c posix-acl-xattr.c +posix_acl_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la + +noinst_HEADERS = posix-acl.h posix-acl-xattr.h + +AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -D$(GF_HOST_OS)\ +	-I$(top_srcdir)/libglusterfs/src -shared -nostartfiles $(GF_CFLAGS)\ +	-L$(xlatordir)/ + +CLEANFILES = diff --git a/xlators/system/posix-acl/src/posix-acl-xattr.c b/xlators/system/posix-acl/src/posix-acl-xattr.c new file mode 100644 index 00000000000..a473c3666b3 --- /dev/null +++ b/xlators/system/posix-acl/src/posix-acl-xattr.c @@ -0,0 +1,190 @@ +/* +  Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com> +  This file is part of GlusterFS. + +  GlusterFS is free software; you can redistribute it and/or modify +  it under the terms of the GNU Affero General Public License as published +  by the Free Software Foundation; either version 3 of the License, +  or (at your option) any later version. + +  GlusterFS is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Affero General Public License for more details. + +  You should have received a copy of the GNU Affero General Public License +  along with this program.  If not, see +  <http://www.gnu.org/licenses/>. +*/ + + +#include <stdio.h> +#include <stdlib.h> + +#include "posix-acl.h" +#include "posix-acl-xattr.h" + + +int +posix_ace_cmp (const void *val1, const void *val2) +{ +        const struct posix_ace *ace1 = NULL; +        const struct posix_ace *ace2 = NULL; +        int                     ret = 0; + +        ace1 = val1; +        ace2 = val2; + +        ret = (ace1->tag - ace2->tag); +        if (!ret) +                ret = (ace1->id - ace2->id); + +        return ret; +} + + +void +posix_acl_normalize (xlator_t *this, struct posix_acl *acl) +{ +        qsort (acl->entries, acl->count, sizeof (struct posix_ace *), +               posix_ace_cmp); +} + + +struct posix_acl * +posix_acl_from_xattr (xlator_t *this, const char *xattr_buf, int xattr_size) +{ +        struct posix_acl_xattr_header   *header = NULL; +        struct posix_acl_xattr_entry    *entry = NULL; +        struct posix_acl                *acl = NULL; +        struct posix_ace                *ace = NULL; +        int                              size = 0; +        int                              count = 0; +        int                              i = 0; + +        size = xattr_size; + +        if (size < sizeof (*header)) +                return NULL; + +        size -= sizeof (*header); + +        if (size % sizeof (*entry)) +                return NULL; + +        count = size / sizeof (*entry); + +        header = (struct posix_acl_xattr_header *) (xattr_buf); +        entry = (struct posix_acl_xattr_entry *) (header + 1); + +        if (header->version != htole32 (POSIX_ACL_VERSION)) +                return NULL; + +        acl = posix_acl_new (this, count); +        if (!acl) +                return NULL; + +        ace = acl->entries; + +        for (i = 0; i < count; i++) { +                ace->tag  = letoh16 (entry->tag); +                ace->perm = letoh16 (entry->perm); + +                switch (ace->tag) { +                case POSIX_ACL_USER_OBJ: +                case POSIX_ACL_GROUP_OBJ: +                case POSIX_ACL_MASK: +                case POSIX_ACL_OTHER: +                        ace->id = POSIX_ACL_UNDEFINED_ID; +                        break; + +                case POSIX_ACL_GROUP: +                case POSIX_ACL_USER: +                        ace->id = letoh32 (entry->id); +                        break; + +                default: +                        goto err; +                } + +                ace++; +                entry++; +        } + +        posix_acl_normalize (this, acl); + +        return acl; +err: +        posix_acl_destroy (this, acl); +        return NULL; +} + + +int +posix_acl_to_xattr (xlator_t *this, struct posix_acl *acl, char *xattr_buf, +                    int xattr_size) +{ +        int                             size = 0; +        struct posix_acl_xattr_header  *header = NULL; +        struct posix_acl_xattr_entry   *entry = NULL; +        struct posix_ace               *ace = NULL; +        int                             i = 0; + +        size = sizeof (*header) + (acl->count * sizeof (*entry)); + +        if (xattr_size < size) +                return size; + +        header = (struct posix_acl_xattr_header *) (xattr_buf); +        entry = (struct posix_acl_xattr_entry *) (header + 1); +        ace = acl->entries; + +        header->version = htole32 (POSIX_ACL_VERSION); + +        for (i = 0; i < acl->count; i++) { +                entry->tag   = htole16 (ace->tag); +                entry->perm  = htole16 (ace->perm); + +                switch (ace->tag) { +                case POSIX_ACL_USER: +                case POSIX_ACL_GROUP: +                        entry->id  = htole32 (ace->id); +                        break; +                default: +                        entry->id = POSIX_ACL_UNDEFINED_ID; +                        break; +                } + +                ace++; +                entry++; +        } + +        return 0; +} + + +int +posix_acl_matches_xattr (xlator_t *this, struct posix_acl *acl, const char *buf, +                         int size) +{ +        struct posix_acl  *acl2 = NULL; +        int                ret = 1; + +        acl2 = posix_acl_from_xattr (this, buf, size); +        if (!acl2) +                return 0; + +        if (acl->count != acl2->count) { +                ret = 0; +                goto out; +        } + +        if (memcmp (acl->entries, acl2->entries, +                    (acl->count * sizeof (struct posix_ace)))) +                ret = 0; +out: +        posix_acl_destroy (this, acl2); + +        return ret; +} + diff --git a/xlators/system/posix-acl/src/posix-acl-xattr.h b/xlators/system/posix-acl/src/posix-acl-xattr.h new file mode 100644 index 00000000000..008a55db438 --- /dev/null +++ b/xlators/system/posix-acl/src/posix-acl-xattr.h @@ -0,0 +1,52 @@ +/* +  Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com> +  This file is part of GlusterFS. + +  GlusterFS is free software; you can redistribute it and/or modify +  it under the terms of the GNU Affero General Public License as published +  by the Free Software Foundation; either version 3 of the License, +  or (at your option) any later version. + +  GlusterFS is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Affero General Public License for more details. + +  You should have received a copy of the GNU Affero General Public License +  along with this program.  If not, see +  <http://www.gnu.org/licenses/>. +*/ + + +#ifndef _POSIX_ACL_XATTR_H +#define _POSIX_ACL_XATTR_H + +#include <stdint.h> + +#include "common-utils.h" +#include "posix-acl.h" + +#define POSIX_ACL_ACCESS_XATTR "system.posix_acl_access" +#define POSIX_ACL_DEFAULT_XATTR "system.posix_acl_default" + +#define POSIX_ACL_VERSION 2  + +struct posix_acl_xattr_entry { +        uint16_t            tag; +        uint16_t            perm; +        uint32_t            id; +}; + +struct posix_acl_xattr_header { +        uint32_t                        version; +        struct posix_acl_xattr_entry    entries[0]; +}; + +struct posix_acl *posix_acl_from_xattr (xlator_t *this, const char *buf, int size); + +int posix_acl_to_xattr (xlator_t *this, struct posix_acl *acl, char *buf, int size); + +int posix_acl_matches_xattr (xlator_t *this, struct posix_acl *acl, const char *buf, int size); + + +#endif /* !_POSIX_ACL_XATTR_H */ diff --git a/xlators/system/posix-acl/src/posix-acl.c b/xlators/system/posix-acl/src/posix-acl.c new file mode 100644 index 00000000000..f05ed3f95f8 --- /dev/null +++ b/xlators/system/posix-acl/src/posix-acl.c @@ -0,0 +1,1792 @@ +/* +  Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com> +  This file is part of GlusterFS. + +  GlusterFS is free software; you can redistribute it and/or modify +  it under the terms of the GNU Affero General Public License as published +  by the Free Software Foundation; either version 3 of the License, +  or (at your option) any later version. + +  GlusterFS is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Affero General Public License for more details. + +  You should have received a copy of the GNU Affero General Public License +  along with this program.  If not, see +  <http://www.gnu.org/licenses/>. +*/ + + +#include <errno.h> + +#include "xlator.h" +#include "glusterfs.h" + +#include "posix-acl.h" +#include "posix-acl-xattr.h" + + +#define UINT64(ptr) ((uint64_t)((long)(ptr))) +#define PTR(num) ((void *)((long)(num))) + + +int +whitelisted_xattr (const char *key) +{ +        if (!key) +                return 0; + +        if (strcmp (POSIX_ACL_ACCESS_XATTR, key) == 0) +                return 1; +        if (strcmp (POSIX_ACL_DEFAULT_XATTR, key) == 0) +                return 1; +        return 0; +} + + +int +frame_is_user (call_frame_t *frame, uid_t uid) +{ +        return (frame->root->uid == uid); +} + + +int +frame_in_group (call_frame_t *frame, gid_t gid) +{ +        int  i = 0; + +        if (frame->root->gid == gid) +                return 1; + +        for (i = 0; i < frame->root->ngrps; i++) +                if (frame->root->groups[i] == gid) +                        return 1; +        return 0; +} + + +mode_t +posix_acl_access_set_mode (struct posix_acl *acl, struct posix_acl_ctx *ctx) +{ +        struct posix_ace  *ace = NULL; +        struct posix_ace  *group_ce = NULL; +        struct posix_ace  *mask_ce = NULL; +        int                count = 0; +        int                i = 0; +        mode_t             mode = 0; +        int                mask = 0; + +        count = acl->count; + +        ace = acl->entries; +        for (i = 0; i < count; i++) { +                switch (ace->tag) { +                case POSIX_ACL_USER_OBJ: +                        mask |= S_IRWXU; +                        mode |= (ace->perm << 6); +                        break; +                case POSIX_ACL_GROUP_OBJ: +                        group_ce = ace; +                        break; +                case POSIX_ACL_MASK: +                        mask_ce = ace; +                        break; +                case POSIX_ACL_OTHER: +                        mask |= S_IRWXO; +                        mode |= (ace->perm); +                        break; +                } +                ace++; +        } + +        if (mask_ce) { +                mask |= S_IRWXG; +                mode |= (mask_ce->perm << 3); +        } else { +                if (!group_ce) +                        goto out; +                mask |= S_IRWXG; +                mode |= (group_ce->perm << 3); +        } + +out: +        ctx->perm = (ctx->perm & ~mask) | mode; + +        return mode; +} + + +static int +sticky_permits (call_frame_t *frame, inode_t *parent, inode_t *inode) +{ +        struct posix_acl_ctx  *par = NULL; +        struct posix_acl_ctx  *ctx = NULL; + +        par = posix_acl_ctx_get (parent, frame->this); +        ctx = posix_acl_ctx_get (inode, frame->this); + +        if (frame_is_user (frame, 0)) +                return 1; + +        if (!(par->perm & S_ISVTX)) +                return 1; + +        if (frame_is_user (frame, par->uid)) +                return 1; + +        if (frame_is_user (frame, ctx->uid)) +                return 1; + +        return 0; +} + + +static int +acl_permits (call_frame_t *frame, inode_t *inode, int want) +{ +        int                     verdict = 0; +        int                     ret = 0; +        struct posix_acl       *acl = NULL; +        struct posix_ace       *ace = NULL; +        struct posix_acl_ctx   *ctx = NULL; +        struct posix_acl_conf  *conf = NULL; +        int                     i = 0; +        int                     perm = 0; +        int                     found = 0; + +        conf = frame->this->private; + +        ctx = posix_acl_ctx_get (inode, frame->this); +        if (!ctx) +                goto red; + +        if (frame->root->uid == 0) +                goto green; + +        ret = posix_acl_get (inode, frame->this, &acl, NULL); + +        if (!acl) { +                acl = posix_acl_ref (frame->this, conf->minimal_acl); +        } + +        ace = acl->entries; + +        for (i = 0; i < acl->count; i++) { +                switch (ace->tag) { +                case POSIX_ACL_USER_OBJ: +                        perm = ((ctx->perm & S_IRWXU) >> 6); +                        if (frame_is_user (frame, ctx->uid)) +                                goto perm_check; +                        break; +                case POSIX_ACL_USER: +                        perm = ace->perm; +                        if (frame_is_user (frame, ace->id)) +                                goto mask_check; +                        break; +                case POSIX_ACL_GROUP_OBJ: +                        perm = ((ctx->perm & S_IRWXG) >> 3); +                        if (frame_in_group (frame, ctx->gid)) { +                                found = 1; +                                if ((perm & want) == want) +                                        goto mask_check; +                        } +                        break; +                case POSIX_ACL_GROUP: +                        perm = ace->perm; +                        if (frame_in_group (frame, ace->id)) { +                                found = 1; +                                if ((perm & want) == want) +                                        goto mask_check; +                        } +                        break; +                case POSIX_ACL_MASK: +                        break; +                case POSIX_ACL_OTHER: +                        perm = (ctx->perm & S_IRWXO); +                        if (!found) +                                goto perm_check; +                        /* fall through */ +                default: +                        goto red; +                } + +                ace++; +        } + +mask_check: +        ace = acl->entries; + +        for (i = 0; i < acl->count; i++, ace++) { +                if (ace->tag != POSIX_ACL_MASK) +                        continue; +                if ((ace->perm & perm & want) == want) +                        goto green; +                goto red; +        } + +perm_check: +        if ((perm & want) == want) +                goto green; +        else +                goto red; + +green: +        verdict = 1; +        goto out; +red: +        verdict = 0; +out: +        if (acl) +                posix_acl_unref (frame->this, acl); + +        return verdict; +} + + +struct posix_acl_ctx * +posix_acl_ctx_get (inode_t *inode, xlator_t *this) +{ +        struct posix_acl_ctx *ctx = NULL; +        uint64_t              int_ctx = 0; +        int                   ret = 0; + +        ret = inode_ctx_get (inode, this, &int_ctx); +        if ((ret == 0) && (int_ctx)) +                return PTR(int_ctx); + +        ctx = CALLOC (1, sizeof (*ctx)); +        if (!ctx) +                return NULL; + +        ret = inode_ctx_put (inode, this, UINT64 (ctx)); + +        return ctx; +} + + +int +__posix_acl_set (inode_t *inode, xlator_t *this, struct posix_acl *acl_access, +                 struct posix_acl *acl_default) +{ +        int                    ret = 0; +        struct posix_acl_ctx  *ctx = NULL; + +        ctx = posix_acl_ctx_get (inode, this); +        if (!ctx) +                goto out; + +        ctx->acl_access = acl_access; +        ctx->acl_default = acl_default; + +out: +        return ret; +} + + +int +__posix_acl_get (inode_t *inode, xlator_t *this, struct posix_acl **acl_access_p, +                 struct posix_acl **acl_default_p) +{ +        int                    ret = 0; +        struct posix_acl_ctx  *ctx = NULL; + +        ctx = posix_acl_ctx_get (inode, this); +        if (!ctx) +                goto out; + +        if (acl_access_p) +                *acl_access_p = ctx->acl_access; +        if (acl_default_p) +                *acl_default_p = ctx->acl_default; + +out: +        return ret; +} + + +struct posix_acl * +posix_acl_new (xlator_t *this, int entrycnt) +{ +        struct posix_acl *acl = NULL; +        struct posix_ace *ace = NULL; + +        acl = CALLOC (1, sizeof (*acl) + (entrycnt * sizeof (*ace))); +        if (!acl) +                return NULL; + +        acl->count = entrycnt; + +        posix_acl_ref (this, acl); + +        return acl; +} + + +void +posix_acl_destroy (xlator_t *this, struct posix_acl *acl) +{ +        FREE (acl); + +        return; +} + + +struct posix_acl * +posix_acl_ref (xlator_t *this, struct posix_acl *acl) +{ +        struct posix_acl_conf  *conf = NULL; + +        conf = this->private; + +        LOCK(&conf->acl_lock); +        { +                acl->refcnt++; +        } +        UNLOCK(&conf->acl_lock); + +        return acl; +} + + +struct posix_acl * +posix_acl_dup (xlator_t *this, struct posix_acl *acl) +{ +        struct posix_acl_conf  *conf = NULL; +        struct posix_acl       *dup = NULL; + +        conf = this->private; + +        dup = posix_acl_new (this, acl->count); +        if (!dup) +                return NULL; + +        memcpy (dup->entries, acl->entries, +                sizeof (struct posix_ace) * acl->count); + +        return dup; +} + + +void +posix_acl_unref (xlator_t *this, struct posix_acl *acl) +{ +        struct posix_acl_conf  *conf = NULL; +        int                     refcnt = 0; + +        conf = this->private; + +        LOCK(&conf->acl_lock); +        { +                refcnt = --acl->refcnt; +        } +        UNLOCK(&conf->acl_lock); + +        if (!refcnt) +                posix_acl_destroy (this, acl); +} + + +int +posix_acl_set (inode_t *inode, xlator_t *this, struct posix_acl *acl_access, +               struct posix_acl *acl_default) +{ +        int                     ret = 0; +        int                     oldret = 0; +        struct posix_acl       *old_access = NULL; +        struct posix_acl       *old_default = NULL; +        struct posix_acl_conf  *conf = NULL; + +        conf = this->private; + +        LOCK(&conf->acl_lock); +        { +                oldret = __posix_acl_get (inode, this, &old_access, +                                          &old_default); +                if (acl_access) +                        acl_access->refcnt++; +                if (acl_default) +                        acl_default->refcnt++; + +                ret = __posix_acl_set (inode, this, acl_access, acl_default); +        } +        UNLOCK(&conf->acl_lock); + +        if (oldret == 0) { +                if (old_access) +                        posix_acl_unref (this, old_access); +                if (old_default) +                        posix_acl_unref (this, old_default); +        } + +        return ret; +} + + +int +posix_acl_get (inode_t *inode, xlator_t *this, struct posix_acl **acl_access_p, +               struct posix_acl **acl_default_p) +{ +        struct posix_acl_conf  *conf = NULL; +        struct posix_acl       *acl_access = NULL; +        struct posix_acl       *acl_default = NULL; +        int                     ret = 0; + +        conf = this->private; + +        LOCK(&conf->acl_lock); +        { +                ret = __posix_acl_get (inode, this, &acl_access, &acl_default); + +                if (ret != 0) +                        goto unlock; + +                if (acl_access && acl_access_p) +                        acl_access->refcnt++; +                if (acl_default && acl_default_p) +                        acl_default->refcnt++; +        } +unlock: +        UNLOCK(&conf->acl_lock); + +        if (acl_access_p) +                *acl_access_p = acl_access; +        if (acl_default_p) +                *acl_default_p = acl_default; + +        return ret; +} + + +mode_t +posix_acl_inherit_mode (struct posix_acl *acl, mode_t modein) +{ +        struct posix_ace       *ace = NULL; +        int                     count = 0; +        int                     i = 0; +        mode_t                  newmode = 0; +        mode_t                  mode = 0; +        struct posix_ace       *mask_ce = NULL; +        struct posix_ace       *group_ce = NULL; + +        newmode = mode = modein; + +        count = acl->count; + +        ace = acl->entries; +        for (i = 0; i < count; i++) { +                switch (ace->tag) { +                case POSIX_ACL_USER_OBJ: +                        ace->perm &= (mode >> 6) | ~S_IRWXO; +                        mode &= (ace->perm << 6) | ~S_IRWXU; +                        break; +                case POSIX_ACL_GROUP_OBJ: +                        group_ce = ace; +                        break; +                case POSIX_ACL_MASK: +                        mask_ce = ace; +                        break; +                case POSIX_ACL_OTHER: +                        ace->perm &= (mode) | ~S_IRWXO; +                        mode &= (ace->perm) | ~S_IRWXO; +                        break; +                } +                ace++; +        } + +        if (mask_ce) { +                mask_ce->perm &= (mode >> 3) | ~S_IRWXO; +                mode &= (mask_ce->perm << 3) | ~S_IRWXG; +        } else { +                group_ce->perm &= (mode >> 3) | ~S_IRWXO; +                mode &= (group_ce->perm << 3) | ~S_IRWXG; +        } + +        newmode = ((modein & S_IFMT) | (mode & (S_IRWXU|S_IRWXG|S_IRWXO))); + +        return newmode; +} + + +mode_t +posix_acl_inherit (xlator_t *this, loc_t *loc, dict_t *params, mode_t mode, +                   int is_dir) +{ +        int                    ret = 0; +        struct posix_acl      *par_default = NULL; +        struct posix_acl      *acl_default = NULL; +        struct posix_acl      *acl_access = NULL; +        struct posix_acl_ctx  *ctx = NULL; +        char                  *xattr_default = NULL; +        char                  *xattr_access = NULL; +        int                    size_default = 0; +        int                    size_access = 0; +        mode_t                 retmode = 0; + +        retmode = mode; + +        ret = posix_acl_get (loc->parent, this, NULL, &par_default); + +        if (!par_default) +                goto out; + +        ctx = posix_acl_ctx_get (loc->inode, this); + +        acl_access = posix_acl_dup (this, par_default); +        if (!acl_access) +                goto out; + +        retmode = posix_acl_inherit_mode (acl_access, mode); +        ctx->perm = retmode; + +        size_access = posix_acl_to_xattr (this, acl_access, NULL, 0); +        xattr_access = CALLOC (1, size_access); +        if (!xattr_access) { +                gf_log (this->name, GF_LOG_ERROR, "out of memory"); +                ret = -1; +                goto out; +        } +        posix_acl_to_xattr (this, acl_access, xattr_access, size_access); + +        ret = dict_set_bin (params, POSIX_ACL_ACCESS_XATTR, xattr_access, +                            size_access); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "out of memory"); +                ret = -1; +                goto out; +        } + +        if (!is_dir) +                goto set; + + +        acl_default = posix_acl_ref (this, par_default); + +        size_default = posix_acl_to_xattr (this, acl_default, NULL, 0); +        xattr_default = CALLOC (1, size_default); +        if (!xattr_default) { +                gf_log (this->name, GF_LOG_ERROR, "out of memory"); +                ret = -1; +                goto out; +        } +        posix_acl_to_xattr (this, acl_default, xattr_default, size_default); + +        ret = dict_set_bin (params, POSIX_ACL_DEFAULT_XATTR, xattr_default, +                            size_default); +        if (ret) { +                gf_log (this->name, GF_LOG_ERROR, "out of memory"); +                ret = -1; +                goto out; +        } + +set: +        ret = posix_acl_set (loc->inode, this, acl_access, acl_default); +        if (ret != 0) +                goto out; + +out: +        if (par_default) +                posix_acl_unref (this, par_default); +        if (acl_access) +                posix_acl_unref (this, acl_access); +        if (acl_default) +                posix_acl_unref (this, acl_default); + +        return retmode; +} + + +mode_t +posix_acl_inherit_dir (xlator_t *this, loc_t *loc, dict_t *params, mode_t mode) +{ +        mode_t  retmode = 0; + +        retmode = posix_acl_inherit (this, loc, params, mode, 1); + +        return retmode; +} + + +mode_t +posix_acl_inherit_file (xlator_t *this, loc_t *loc, dict_t *params, mode_t mode) +{ +        mode_t  retmode = 0; + +        retmode = posix_acl_inherit (this, loc, params, mode, 0); + +        return retmode; +} + + +int +posix_acl_ctx_update (inode_t *inode, xlator_t *this, struct iatt *buf) +{ +        struct posix_acl_ctx *ctx = NULL; +        int                   ret = 0; + +        ctx = posix_acl_ctx_get (inode, this); +        if (!ctx) { +                ret = -1; +                goto out; +        } + +        LOCK(&inode->lock); +        { +                ctx->uid   = buf->ia_uid; +                ctx->gid   = buf->ia_gid; +                ctx->perm  = st_mode_from_ia (buf->ia_prot, buf->ia_type); +        } +        UNLOCK(&inode->lock); +out: +        return ret; +} + + +int +posix_acl_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                      int op_ret, int op_errno, inode_t *inode, +                      struct iatt *buf, dict_t *xattr, struct iatt *postparent) +{ +        struct posix_acl     *acl_access = NULL; +        struct posix_acl     *acl_default = NULL; +        struct posix_acl     *old_access = NULL; +        struct posix_acl     *old_default = NULL; +        data_t               *data = NULL; +        int                   ret = 0; +        dict_t               *my_xattr = NULL; + +        if (op_ret != 0) +                goto unwind; + +        ret = posix_acl_get (inode, this, &old_access, &old_default); + +        data = dict_get (xattr, POSIX_ACL_ACCESS_XATTR); +        if (!data) +                goto acl_default; + +        if (old_access && +            posix_acl_matches_xattr (this, old_access, data->data, +                                     data->len)) { +                acl_access = posix_acl_ref (this, old_access); +        } else { +                acl_access = posix_acl_from_xattr (this, data->data, +                                                   data->len); +        } + +acl_default: +        data = dict_get (xattr, POSIX_ACL_DEFAULT_XATTR); +        if (!data) +                goto acl_set; + +        if (old_default && +            posix_acl_matches_xattr (this, old_default, data->data, +                                     data->len)) { +                acl_default = posix_acl_ref (this, old_default); +        } else { +                acl_default = posix_acl_from_xattr (this, data->data, +                                                    data->len); +        } + +acl_set: +        posix_acl_ctx_update (inode, this, buf); + +        ret = posix_acl_set (inode, this, acl_access, acl_default); + +unwind: +        my_xattr = frame->local; +        frame->local = NULL; +        STACK_UNWIND_STRICT (lookup, frame, op_ret, op_errno, inode, buf, xattr, +                             postparent); + +        if (acl_access) +                posix_acl_unref (this, acl_access); +        if (acl_default) +                posix_acl_unref (this, acl_default); +        if (old_access) +                posix_acl_unref (this, old_access); +        if (old_default) +                posix_acl_unref (this, old_default); +        if (my_xattr) +                dict_unref (my_xattr); + +        return 0; +} + + +int +posix_acl_lookup (call_frame_t *frame, xlator_t *this, loc_t *loc, +                  dict_t *xattr) +{ +        int      ret = 0; +        dict_t  *my_xattr = NULL; + +        if (!loc->parent) +                /* lookup of / is always permitted */ +                goto green; + +        if (acl_permits (frame, loc->parent, POSIX_ACL_EXECUTE)) +                goto green; +        else +                goto red; + +green: +        if (xattr) { +                my_xattr = dict_ref (xattr); +        } else { +                my_xattr = dict_new (); +        } + +        ret = dict_set_int8 (my_xattr, POSIX_ACL_ACCESS_XATTR, 0); +        ret = dict_set_int8 (my_xattr, POSIX_ACL_DEFAULT_XATTR, 0); + +        frame->local = my_xattr; +        STACK_WIND (frame, posix_acl_lookup_cbk, +                    FIRST_CHILD (this), FIRST_CHILD (this)->fops->lookup, +                    loc, my_xattr); +        return 0; +red: +        STACK_UNWIND_STRICT (lookup, frame, -1, EACCES, NULL, NULL, NULL, +                             NULL); + +        return 0; +} + + +int +posix_acl_access (call_frame_t *frame, xlator_t *this, loc_t *loc, int mask) +{ +        int  op_ret = 0; +        int  op_errno = 0; +        int  perm = 0; + + +        if (mask & R_OK) +                perm |= POSIX_ACL_READ; +        if (mask & W_OK) +                perm |= POSIX_ACL_WRITE; +        if (mask & X_OK) +                perm |= POSIX_ACL_EXECUTE; +        if (!perm) { +                op_ret = -1; +                op_errno = EINVAL; +                goto unwind; +        } + +        if (acl_permits (frame, loc->inode, perm)) { +                op_ret = 0; +                op_errno = 0; +        } else { +                op_ret = -1; +                op_errno = EACCES; +        } + +unwind: +        STACK_UNWIND_STRICT (access, frame, op_ret, op_errno); + +        return 0; +} + + +int +posix_acl_truncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                        int op_ret, int op_errno, struct iatt *prebuf, +                        struct iatt *postbuf) +{ +        STACK_UNWIND_STRICT (truncate, frame, op_ret, op_errno, prebuf, postbuf); + +        return 0; +} + + +int +posix_acl_truncate (call_frame_t *frame, xlator_t *this, loc_t *loc, off_t off) +{ +        if (acl_permits (frame, loc->inode, POSIX_ACL_WRITE)) +                goto green; +        else +                goto red; +green: +        STACK_WIND (frame, posix_acl_truncate_cbk, +                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->truncate, +                    loc, off); +        return 0; +red: +        STACK_UNWIND_STRICT (truncate, frame, -1, EACCES, NULL, NULL); +        return 0; +} + + +int +posix_acl_open_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                    int op_ret, int op_errno, fd_t *fd) +{ +        STACK_UNWIND_STRICT (open, frame, op_ret, op_errno, fd); + +        return 0; +} + + +int +posix_acl_open (call_frame_t *frame, xlator_t *this, loc_t *loc, int flags, +                fd_t *fd, int wbflags) +{ +        int perm = 0; + +        switch (flags & O_ACCMODE) { +        case O_RDONLY: +                perm = POSIX_ACL_READ; +                break; +        case O_WRONLY: +                perm = POSIX_ACL_WRITE; +                break; +        case O_RDWR: +                perm = POSIX_ACL_READ|POSIX_ACL_WRITE; +                break; +        } + +        if (acl_permits (frame, loc->inode, perm)) +                goto green; +        else +                goto red; +green: +        STACK_WIND (frame, posix_acl_open_cbk, +                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->open, +                    loc, flags, fd, wbflags); +        return 0; +red: +        STACK_UNWIND_STRICT (open, frame, -1, EACCES, NULL); +        return 0; +} + + + +int +posix_acl_opendir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                       int op_ret, int op_errno, fd_t *fd) +{ +        STACK_UNWIND_STRICT (opendir, frame, op_ret, op_errno, fd); + +        return 0; +} + + +int +posix_acl_opendir (call_frame_t *frame, xlator_t *this, loc_t *loc, fd_t *fd) +{ +        if (acl_permits (frame, loc->inode, POSIX_ACL_READ)) +                goto green; +        else +                goto red; +green: +        STACK_WIND (frame, posix_acl_opendir_cbk, +                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->opendir, +                    loc, fd); +        return 0; +red: +        STACK_UNWIND_STRICT (opendir, frame, -1, EACCES, NULL); +        return 0; +} + + +int +posix_acl_mkdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                     int op_ret, int op_errno, inode_t *inode, struct iatt *buf, +                     struct iatt *preparent, struct iatt *postparent) +{ +        if (op_ret != 0) +                goto unwind; + +        posix_acl_ctx_update (inode, this, buf); + +unwind: +        STACK_UNWIND_STRICT (mkdir, frame, op_ret, op_errno, inode, buf, +                             preparent, postparent); +        return 0; +} + + +int +posix_acl_mkdir (call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, +                 dict_t *params) +{ +        mode_t   newmode = 0; + +        newmode = mode; +        if (acl_permits (frame, loc->parent, POSIX_ACL_WRITE|POSIX_ACL_EXECUTE)) +                goto green; +        else +                goto red; +green: +        newmode = posix_acl_inherit_dir (this, loc, params, mode); + +        STACK_WIND (frame, posix_acl_mkdir_cbk, +                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->mkdir, +                    loc, newmode, params); +        return 0; +red: +        STACK_UNWIND_STRICT (mkdir, frame, -1, EACCES, NULL, NULL, NULL, NULL); +        return 0; +} + + +int +posix_acl_mknod_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                     int op_ret, int op_errno, inode_t *inode, struct iatt *buf, +                     struct iatt *preparent, struct iatt *postparent) +{ +        if (op_ret != 0) +                goto unwind; + +        posix_acl_ctx_update (inode, this, buf); + +unwind: +        STACK_UNWIND_STRICT (mknod, frame, op_ret, op_errno, inode, buf, +                             preparent, postparent); +        return 0; +} + + +int +posix_acl_mknod (call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, +                 dev_t rdev, dict_t *params) +{ +        mode_t  newmode = 0; + +        newmode = mode; +        if (acl_permits (frame, loc->parent, POSIX_ACL_WRITE|POSIX_ACL_EXECUTE)) +                goto green; +        else +                goto red; +green: +        newmode = posix_acl_inherit_file (this, loc, params, mode); + +        STACK_WIND (frame, posix_acl_mknod_cbk, +                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->mknod, +                    loc, newmode, rdev, params); +        return 0; +red: +        STACK_UNWIND_STRICT (mknod, frame, -1, EACCES, NULL, NULL, NULL, NULL); +        return 0; +} + + +int +posix_acl_create_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                      int op_ret, int op_errno, fd_t *fd, inode_t *inode, +                      struct iatt *buf, struct iatt *preparent, +                      struct iatt *postparent) +{ +        if (op_ret != 0) +                goto unwind; + +        posix_acl_ctx_update (inode, this, buf); + +unwind: +        STACK_UNWIND_STRICT (create, frame, op_ret, op_errno, fd, inode, buf, +                             preparent, postparent); +        return 0; +} + + +int +posix_acl_create (call_frame_t *frame, xlator_t *this, loc_t *loc, int flags, +                  mode_t mode, fd_t *fd, dict_t *params) +{ +        mode_t  newmode = 0; + +        newmode = mode; +        if (acl_permits (frame, loc->parent, POSIX_ACL_WRITE|POSIX_ACL_EXECUTE)) +                goto green; +        else +                goto red; +green: +        newmode = posix_acl_inherit_file (this, loc, params, mode); + +        STACK_WIND (frame, posix_acl_create_cbk, +                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->create, +                    loc, flags, newmode, fd, params); +        return 0; +red: +        STACK_UNWIND_STRICT (create, frame, -1, EACCES, NULL, NULL, NULL, NULL, NULL); +        return 0; +} + + +int +posix_acl_symlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                      int op_ret, int op_errno, inode_t *inode, +                      struct iatt *buf, struct iatt *preparent, +                      struct iatt *postparent) +{ +        if (op_ret != 0) +                goto unwind; + +        posix_acl_ctx_update (inode, this, buf); + +unwind: +        STACK_UNWIND_STRICT (symlink, frame, op_ret, op_errno, inode, buf, +                             preparent, postparent); +        return 0; +} + + +int +posix_acl_symlink (call_frame_t *frame, xlator_t *this, const char *linkname, +                   loc_t *loc, dict_t *params) +{ +        if (acl_permits (frame, loc->parent, POSIX_ACL_WRITE|POSIX_ACL_EXECUTE)) +                goto green; +        else +                goto red; +green: +        STACK_WIND (frame, posix_acl_symlink_cbk, +                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->symlink, +                    linkname, loc, params); +        return 0; +red: +        STACK_UNWIND_STRICT (symlink, frame, -1, EACCES, NULL, NULL, NULL, NULL); +        return 0; +} + + +int +posix_acl_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                      int op_ret, int op_errno, +                      struct iatt *preparent, struct iatt *postparent) +{ +        if (op_ret != 0) +                goto unwind; +unwind: +        STACK_UNWIND_STRICT (unlink, frame, op_ret, op_errno, +                             preparent, postparent); +        return 0; +} + + +int +posix_acl_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc) +{ +        if (!sticky_permits (frame, loc->parent, loc->inode)) +                goto red; + +        if (acl_permits (frame, loc->parent, POSIX_ACL_WRITE|POSIX_ACL_EXECUTE)) +                goto green; +        else +                goto red; +green: +        STACK_WIND (frame, posix_acl_unlink_cbk, +                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->unlink, +                    loc); +        return 0; +red: +        STACK_UNWIND_STRICT (unlink, frame, -1, EACCES, NULL, NULL); +        return 0; +} + + +int +posix_acl_rmdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                     int op_ret, int op_errno, +                     struct iatt *preparent, struct iatt *postparent) +{ +        if (op_ret != 0) +                goto unwind; +unwind: +        STACK_UNWIND_STRICT (rmdir, frame, op_ret, op_errno, +                             preparent, postparent); +        return 0; +} + + +int +posix_acl_rmdir (call_frame_t *frame, xlator_t *this, loc_t *loc, int flags) +{ +        if (!sticky_permits (frame, loc->parent, loc->inode)) +                goto red; + +        if (acl_permits (frame, loc->parent, POSIX_ACL_WRITE|POSIX_ACL_EXECUTE)) +                goto green; +        else +                goto red; +green: +        STACK_WIND (frame, posix_acl_rmdir_cbk, +                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->rmdir, +                    loc, flags); +        return 0; +red: +        STACK_UNWIND_STRICT (rmdir, frame, -1, EACCES, NULL, NULL); +        return 0; +} + + +int +posix_acl_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                      int op_ret, int op_errno, struct iatt *buf, +                      struct iatt *preoldparent, struct iatt *postoldparent, +                      struct iatt *prenewparent, struct iatt *postnewparent) +{ +        if (op_ret != 0) +                goto unwind; +unwind: +        STACK_UNWIND_STRICT (rename, frame, op_ret, op_errno, buf, +                             preoldparent, postoldparent, +                             prenewparent, postnewparent); +        return 0; +} + + +int +posix_acl_rename (call_frame_t *frame, xlator_t *this, loc_t *old, loc_t *new) +{ +        if (!acl_permits (frame, old->parent, POSIX_ACL_WRITE)) +                goto red; + +        if (!acl_permits (frame, new->parent, POSIX_ACL_WRITE)) +                goto red; + +        if (!sticky_permits (frame, old->parent, old->inode)) +                goto red; + +        if (new->inode) { +                if (!sticky_permits (frame, new->parent, new->inode)) +                        goto red; +        } + +        STACK_WIND (frame, posix_acl_rename_cbk, +                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->rename, +                    old, new); +        return 0; +red: +        STACK_UNWIND_STRICT (rename, frame, -1, EACCES, NULL, NULL, NULL, NULL, +                             NULL); +        return 0; +} + + +int +posix_acl_link_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                    int op_ret, int op_errno, inode_t *inode, struct iatt *buf, +                    struct iatt *preparent, struct iatt *postparent) +{ +        if (op_ret != 0) +                goto unwind; +unwind: +        STACK_UNWIND_STRICT (link, frame, op_ret, op_errno, inode, buf, +                             preparent, postparent); +        return 0; +} + + +int +posix_acl_link (call_frame_t *frame, xlator_t *this, loc_t *old, loc_t *new) +{ +        struct posix_acl_ctx *ctx = NULL; +        int                   op_errno = 0; + +        ctx = posix_acl_ctx_get (old->inode, this); +        if (!ctx) { +                op_errno = EIO; +                goto red; +        } + +        if (!acl_permits (frame, new->parent, POSIX_ACL_WRITE)) { +                op_errno = EACCES; +                goto red; +        } + +        STACK_WIND (frame, posix_acl_link_cbk, +                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->link, +                    old, new); +        return 0; +red: +        STACK_UNWIND_STRICT (link, frame, -1, op_errno, NULL, NULL, NULL, NULL); + +        return 0; +} + + +int +posix_acl_readdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                       int op_ret, int op_errno, gf_dirent_t *entries) +{ +        if (op_ret != 0) +                goto unwind; +unwind: +        STACK_UNWIND_STRICT (readdir, frame, op_ret, op_errno, entries); +        return 0; +} + + +int +posix_acl_readdir (call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, +                   off_t offset) +{ +        if (acl_permits (frame, fd->inode, POSIX_ACL_READ)) +                goto green; +        else +                goto red; +green: +        STACK_WIND (frame, posix_acl_readdir_cbk, +                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->readdir, +                    fd, size, offset); +        return 0; +red: +        STACK_UNWIND_STRICT (readdir, frame, -1, EACCES, NULL); + +        return 0; +} + + +int +posix_acl_readdirp_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                        int op_ret, int op_errno, gf_dirent_t *entries) +{ +        if (op_ret != 0) +                goto unwind; +unwind: +        STACK_UNWIND_STRICT (readdirp, frame, op_ret, op_errno, entries); +        return 0; +} + + +int +posix_acl_readdirp (call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, +                   off_t offset) +{ +        if (acl_permits (frame, fd->inode, POSIX_ACL_READ)) +                goto green; +        else +                goto red; +green: +        STACK_WIND (frame, posix_acl_readdirp_cbk, +                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->readdirp, +                    fd, size, offset); +        return 0; +red: +        STACK_UNWIND_STRICT (readdirp, frame, -1, EACCES, NULL); + +        return 0; +} + + +int +setattr_scrutiny (call_frame_t *frame, inode_t *inode, struct iatt *buf, +                  int valid) +{ +        struct posix_acl_ctx   *ctx = NULL; + +        if (frame->root->uid == 0) +                return 0; + +        ctx = posix_acl_ctx_get (inode, frame->this); +        if (!ctx) +                return EIO; + +        if (valid & GF_SET_ATTR_MODE) { +/* +       The effective UID of the calling process must match the  owner  of  the +       file,  or  the  process  must  be  privileged +*/ +                if (!frame_is_user (frame, ctx->uid)) +                        return EPERM; +/* +       If the calling process is not privileged  (Linux:  does  not  have  the +       CAP_FSETID  capability),  and  the group of the file does not match the +       effective group ID of the process or one  of  its  supplementary  group +       IDs,  the  S_ISGID  bit  will be turned off, but this will not cause an +       error to be returned. + +*/ +                if (!frame_in_group (frame, ctx->gid)) +                        buf->ia_prot.sgid = 0; +        } + +        if (valid & (GF_SET_ATTR_ATIME | GF_SET_ATTR_MTIME)) { +/* +       Changing timestamps is permitted when: either the process has appropri? +       ate  privileges,  or  the  effective  user ID equals the user ID of the +       file, or times is NULL and the process has  write  permission  for  the +       file. +*/ +                if (!frame_is_user (frame, ctx->uid) && +                    !acl_permits (frame, inode, POSIX_ACL_WRITE)) +                        return EACCES; +        } + +        if (valid & GF_SET_ATTR_UID) { +                if ((frame->root->uid != 0) && +                    (buf->ia_uid != ctx->uid)) +                        return EPERM; +        } + +        if (valid & GF_SET_ATTR_GID) { +                if (!frame_is_user (frame, ctx->uid)) +                        return EPERM; +                if (!frame_in_group (frame, buf->ia_gid)) +                        return EPERM; +        } + +        return 0; +} + + +int +posix_acl_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                       int op_ret, int op_errno, +                       struct iatt *prebuf, struct iatt *postbuf) +{ +        inode_t   *inode = NULL; + +        inode = frame->local; +        frame->local = NULL; + +        if (op_ret != 0) +                goto unwind; + +        posix_acl_ctx_update (inode, this, postbuf); + +unwind: +        STACK_UNWIND_STRICT (setattr, frame, op_ret, op_errno, prebuf, postbuf); +        return 0; +} + + +int +posix_acl_setattr (call_frame_t *frame, xlator_t *this, loc_t *loc, +                   struct iatt *buf, int valid) +{ +        int  op_errno = 0; + +        op_errno = setattr_scrutiny (frame, loc->inode, buf, valid); + +        if (op_errno) +                goto red; + +        frame->local = loc->inode; + +        STACK_WIND (frame, posix_acl_setattr_cbk, +                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->setattr, +                    loc, buf, valid); +        return 0; +red: +        STACK_UNWIND_STRICT (setattr, frame, -1, op_errno, NULL, NULL); + +        return 0; +} + + +int +posix_acl_fsetattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                        int op_ret, int op_errno, +                        struct iatt *prebuf, struct iatt *postbuf) +{ +        inode_t   *inode = NULL; + +        inode = frame->local; +        frame->local = NULL; + +        if (op_ret != 0) +                goto unwind; + +        posix_acl_ctx_update (inode, this, postbuf); + +unwind: +        STACK_UNWIND_STRICT (fsetattr, frame, op_ret, op_errno, prebuf, postbuf); +        return 0; +} + + +int +posix_acl_fsetattr (call_frame_t *frame, xlator_t *this, fd_t *fd, +                    struct iatt *buf, int valid) +{ +        int  op_errno = 0; + +        op_errno = setattr_scrutiny (frame, fd->inode, buf, valid); + +        if (op_errno) +                goto red; + +        frame->local = fd->inode; + +        STACK_WIND (frame, posix_acl_fsetattr_cbk, +                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->fsetattr, +                    fd, buf, valid); +        return 0; +red: +        STACK_UNWIND_STRICT (fsetattr, frame, -1, EACCES, NULL, NULL); + +        return 0; +} + + +int +setxattr_scrutiny (call_frame_t *frame, inode_t *inode, dict_t *xattr) +{ +        struct posix_acl_ctx   *ctx = NULL; +        int                     found = 0; + +        if (frame->root->uid == 0) +                return 0; + +        ctx = posix_acl_ctx_get (inode, frame->this); +        if (!ctx) +                return EIO; + +        if (dict_get (xattr, POSIX_ACL_ACCESS_XATTR)) { +                found = 1; +                if (!frame_is_user (frame, ctx->uid)) +                        return EPERM; +        } + +        if (dict_get (xattr, POSIX_ACL_DEFAULT_XATTR)) { +                found = 1; +                if (!frame_is_user (frame, ctx->uid)) +                        return EPERM; +        } + +        if (!found && !acl_permits (frame, inode, POSIX_ACL_WRITE)) +                return EACCES; + +        return 0; +} + + +struct posix_acl * +posix_acl_xattr_update (xlator_t *this, inode_t *inode, dict_t *xattr, +                        char *name, struct posix_acl *old) +{ +        struct  posix_acl      *acl = NULL; +        data_t                 *data = NULL; + +        data = dict_get (xattr, name); +        if (data) { +                acl = posix_acl_from_xattr (this, data->data, +                                            data->len); +        } + +        if (!acl && old) +                acl = posix_acl_ref (this, old); + +        return acl; +} + + +int +posix_acl_setxattr_update (xlator_t *this, inode_t *inode, dict_t *xattr) +{ +        struct posix_acl     *acl_access = NULL; +        struct posix_acl     *acl_default = NULL; +        struct posix_acl     *old_access = NULL; +        struct posix_acl     *old_default = NULL; +        struct posix_acl_ctx *ctx = NULL; +        int                   ret = 0; +        mode_t                mode = 0; + +        ctx = posix_acl_ctx_get (inode, this); +        if (!ctx) +                return -1; + +        ret = posix_acl_get (inode, this, &old_access, &old_default); + +        acl_access = posix_acl_xattr_update (this, inode, xattr, +                                             POSIX_ACL_ACCESS_XATTR, +                                             old_access); + +        acl_default = posix_acl_xattr_update (this, inode, xattr, +                                              POSIX_ACL_DEFAULT_XATTR, +                                              old_default); + +        ret = posix_acl_set (inode, this, acl_access, acl_default); + +        if (acl_access && acl_access != old_access) { +                mode = posix_acl_access_set_mode (acl_access, ctx); +        } + +        if (acl_access) +                posix_acl_unref (this, acl_access); +        if (acl_default) +                posix_acl_unref (this, acl_default); +        if (old_access) +                posix_acl_unref (this, old_access); +        if (old_default) +                posix_acl_unref (this, old_default); + +        return 0; +} + + +int +posix_acl_setxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                        int op_ret, int op_errno) +{ +        STACK_UNWIND_STRICT (setxattr, frame, op_ret, op_errno); + +        return 0; +} + + +int +posix_acl_setxattr (call_frame_t *frame, xlator_t *this, loc_t *loc, +                    dict_t *xattr, int flags) +{ +        int  op_errno = 0; + +        op_errno = setxattr_scrutiny (frame, loc->inode, xattr); + +        if (op_errno != 0) +                goto red; + +        posix_acl_setxattr_update (this, loc->inode, xattr); + +        STACK_WIND (frame, posix_acl_setxattr_cbk, +                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->setxattr, +                    loc, xattr, flags); +        return 0; +red: +        STACK_UNWIND_STRICT (setxattr, frame, -1, op_errno); + +        return 0; +} + + +int +posix_acl_fsetxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                         int op_ret, int op_errno) +{ +        STACK_UNWIND_STRICT (fsetxattr, frame, op_ret, op_errno); + +        return 0; +} + + +int +posix_acl_fsetxattr (call_frame_t *frame, xlator_t *this, fd_t *fd, +                     dict_t *xattr, int flags) +{ +        int  op_errno = 0; + +        op_errno = setxattr_scrutiny (frame, fd->inode, xattr); + +        if (op_errno != 0) +                goto red; + +        posix_acl_setxattr_update (this, fd->inode, xattr); + +        STACK_WIND (frame, posix_acl_fsetxattr_cbk, +                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->fsetxattr, +                    fd, xattr, flags); +        return 0; +red: +        STACK_UNWIND_STRICT (fsetxattr, frame, -1, op_errno); + +        return 0; +} + + +int +posix_acl_getxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                        int op_ret, int op_errno, dict_t *xattr) +{ +        STACK_UNWIND_STRICT (getxattr, frame, op_ret, op_errno, xattr); + +        return 0; +} + + +int +posix_acl_getxattr (call_frame_t *frame, xlator_t *this, loc_t *loc, +                    const char *name) +{ +        if (whitelisted_xattr (name)) +                goto green; + +        if (acl_permits (frame, loc->inode, POSIX_ACL_READ)) +                goto green; +        else +                goto red; +green: +        STACK_WIND (frame, posix_acl_getxattr_cbk, +                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->getxattr, +                    loc, name); +        return 0; +red: +        STACK_UNWIND_STRICT (getxattr, frame, -1, EACCES, NULL); + +        return 0; +} + + +int +posix_acl_fgetxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                         int op_ret, int op_errno, dict_t *xattr) +{ +        STACK_UNWIND_STRICT (fgetxattr, frame, op_ret, op_errno, xattr); + +        return 0; +} + + +int +posix_acl_fgetxattr (call_frame_t *frame, xlator_t *this, fd_t *fd, +                     const char *name) +{ +        if (whitelisted_xattr (name)) +                goto green; + +        if (acl_permits (frame, fd->inode, POSIX_ACL_READ)) +                goto green; +        else +                goto red; +green: +        STACK_WIND (frame, posix_acl_fgetxattr_cbk, +                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->fgetxattr, +                    fd, name); +        return 0; +red: +        STACK_UNWIND_STRICT (fgetxattr, frame, -1, EACCES, NULL); + +        return 0; +} + + +int +posix_acl_removexattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, +                           int op_ret, int op_errno) +{ +        STACK_UNWIND_STRICT (removexattr, frame, op_ret, op_errno); + +        return 0; +} + + +int +posix_acl_removexattr (call_frame_t *frame, xlator_t *this, loc_t *loc, +                       const char *name) +{ +        struct  posix_acl_ctx  *ctx = NULL; +        int                     op_errno = EACCES; + +        if (frame_is_user (frame, 0)) +                goto green; + +        ctx = posix_acl_ctx_get (loc->inode, this); +        if (!ctx) { +                op_errno = EIO; +                goto red; +        } + +        if (whitelisted_xattr (name)) { +                if (!frame_is_user (frame, ctx->uid)) { +                        op_errno = EPERM; +                        goto red; +                } +        } + +        if (acl_permits (frame, loc->inode, POSIX_ACL_WRITE)) +                goto green; +        else +                goto red; +green: +        STACK_WIND (frame, posix_acl_removexattr_cbk, +                    FIRST_CHILD(this), FIRST_CHILD(this)->fops->removexattr, +                    loc, name); +        return 0; +red: +        STACK_UNWIND_STRICT (removexattr, frame, -1, op_errno); + +        return 0; +} + + +int +posix_acl_forget (xlator_t *this, inode_t *inode) +{ +        struct posix_acl_ctx *ctx = NULL; + +        ctx = posix_acl_ctx_get (inode, this); +        if (!ctx) +                goto out; + +        if (ctx->acl_access) +                posix_acl_unref (this, ctx->acl_access); + +        if (ctx->acl_default) +                posix_acl_unref (this, ctx->acl_default); + +        FREE (ctx); +out: +        return 0; +} + + +int +init (xlator_t *this) +{ +        struct posix_acl_conf   *conf = NULL; +        struct posix_acl        *minacl = NULL; +        struct posix_ace        *minace = NULL; + +        conf = CALLOC (1, sizeof (*conf)); +        if (!conf) { +                gf_log (this->name, GF_LOG_ERROR, +                        "out of memory"); +                return -1; +        } + +        LOCK_INIT (&conf->acl_lock); + +        this->private = conf; + +        minacl = posix_acl_new (this, 3); +        if (!minacl) +                return -1; + +        minace = minacl->entries; +        minace[0].tag = POSIX_ACL_USER_OBJ; +        minace[1].tag = POSIX_ACL_GROUP_OBJ; +        minace[2].tag = POSIX_ACL_OTHER; + +        conf->minimal_acl = minacl; + +        return 0; +} + + +int +fini (xlator_t *this) +{ +        return 0; +} + + +struct xlator_fops fops = { +        .lookup           = posix_acl_lookup, +        .open             = posix_acl_open, +        .access           = posix_acl_access, +        .truncate         = posix_acl_truncate, +        .mkdir            = posix_acl_mkdir, +        .mknod            = posix_acl_mknod, +        .create           = posix_acl_create, +        .symlink          = posix_acl_symlink, +        .unlink           = posix_acl_unlink, +        .rmdir            = posix_acl_rmdir, +        .rename           = posix_acl_rename, +        .link             = posix_acl_link, +        .opendir          = posix_acl_opendir, +        .readdir          = posix_acl_readdir, +        .readdirp         = posix_acl_readdirp, +        .setattr          = posix_acl_setattr, +        .fsetattr         = posix_acl_fsetattr, +        .setxattr         = posix_acl_setxattr, +        .fsetxattr        = posix_acl_fsetxattr, +        .getxattr         = posix_acl_getxattr, +        .fgetxattr        = posix_acl_fgetxattr, +        .removexattr      = posix_acl_removexattr, +}; + + +struct xlator_cbks cbks = { +        .forget           = posix_acl_forget +}; diff --git a/xlators/system/posix-acl/src/posix-acl.h b/xlators/system/posix-acl/src/posix-acl.h new file mode 100644 index 00000000000..46b56d6f38c --- /dev/null +++ b/xlators/system/posix-acl/src/posix-acl.h @@ -0,0 +1,86 @@ +/* +  Copyright (c) 2011 Gluster, Inc. <http://www.gluster.com> +  This file is part of GlusterFS. + +  GlusterFS is free software; you can redistribute it and/or modify +  it under the terms of the GNU Affero General Public License as published +  by the Free Software Foundation; either version 3 of the License, +  or (at your option) any later version. + +  GlusterFS is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Affero General Public License for more details. + +  You should have received a copy of the GNU Affero General Public License +  along with this program.  If not, see +  <http://www.gnu.org/licenses/>. +*/ + + +#ifndef _POSIX_ACL_H +#define _POSIX_ACL_H + +#include <stdint.h> + +#include "xlator.h" +#include "common-utils.h" +#include "byte-order.h" + + +#define POSIX_ACL_READ                (0x04) +#define POSIX_ACL_WRITE               (0x02) +#define POSIX_ACL_EXECUTE             (0x01) + +#define POSIX_ACL_UNDEFINED_TAG       (0x00) +#define POSIX_ACL_USER_OBJ            (0x01) +#define POSIX_ACL_USER                (0x02) +#define POSIX_ACL_GROUP_OBJ           (0x04) +#define POSIX_ACL_GROUP               (0x08) +#define POSIX_ACL_MASK                (0x10) +#define POSIX_ACL_OTHER               (0x20) + +#define POSIX_ACL_UNDEFINED_ID        ((id_t)-1) + + +struct posix_ace { +        uint16_t     tag; +        uint16_t     perm; +        uint32_t     id; +}; + + +struct posix_acl { +        int               refcnt; +        int               count; +        struct posix_ace  entries[0]; +}; + + +struct posix_acl_ctx { +        uid_t             uid; +        gid_t             gid; +        mode_t            perm; +        struct posix_acl *acl_access; +        struct posix_acl *acl_default; +}; + + +struct posix_acl_conf { +        gf_lock_t         acl_lock; +        struct posix_acl *minimal_acl; +}; + + +struct posix_acl *posix_acl_new (xlator_t *this, int entry_count); +struct posix_acl *posix_acl_ref (xlator_t *this, struct posix_acl *acl); +void posix_acl_unref (xlator_t *this, struct posix_acl *acl); +void posix_acl_destroy (xlator_t *this, struct posix_acl *acl); +struct posix_acl_ctx *posix_acl_ctx_get (inode_t *inode, xlator_t *this); +int posix_acl_get (inode_t *inode, xlator_t *this, +                   struct posix_acl **acl_access_p, +                   struct posix_acl **acl_default_p); +int posix_acl_set (inode_t *inode, xlator_t *this, struct posix_acl *acl_access, +                   struct posix_acl *acl_default); + +#endif /* !_POSIX_ACL_H */  | 
