[PATCH 1/2 v2] s3: vfs: generalize functions that set/get posix acl through xattr

Ira Cooper ira at wakeful.net
Thu Mar 24 01:21:19 UTC 2016


This is my untested attempt to fix Jeremy's questions.  (compiled, but not
tested.)

It also deals with the omission of a useful comment from vfs_glusterfs.c :).

I owe the code a once over, myself, and I'd like to test it, and make sure
everything is working right.

Cheers,

-Ira

On Wed, Mar 23, 2016 at 8:23 AM, Yan, Zheng <zyan at redhat.com> wrote:

> Move posix acl related code in vfs_glusterfs.c to a seperate module.
>
> Signed-off-by: "Yan, Zheng" <zyan at redhat.com>
> ---
>  source3/modules/vfs_glusterfs.c      | 522
> +----------------------------------
>  source3/modules/vfs_posixacl_xattr.c | 487
> ++++++++++++++++++++++++++++++++
>  source3/modules/vfs_posixacl_xattr.h |  46 +++
>  source3/modules/wscript_build        |   8 +
>  source3/wscript                      |   1 +
>  5 files changed, 548 insertions(+), 516 deletions(-)
>  create mode 100644 source3/modules/vfs_posixacl_xattr.c
>  create mode 100644 source3/modules/vfs_posixacl_xattr.h
>
> diff --git a/source3/modules/vfs_glusterfs.c
> b/source3/modules/vfs_glusterfs.c
> index e202672..f1ed66d 100644
> --- a/source3/modules/vfs_glusterfs.c
> +++ b/source3/modules/vfs_glusterfs.c
> @@ -44,6 +44,7 @@
>  #include "lib/tevent/tevent_internal.h"
>  #include "smbd/globals.h"
>  #include "lib/util/sys_rw.h"
> +#include "modules/vfs_posixacl_xattr.h"
>
>  #define DEFAULT_VOLFILE_SERVER "localhost"
>
> @@ -1262,517 +1263,6 @@ static int vfs_gluster_set_offline(struct
> vfs_handle_struct *handle,
>         return -1;
>  }
>
> -/*
> -  Gluster ACL Format:
> -
> -  Size = 4 (header) + N * 8 (entry)
> -
> -  Offset  Size    Field (Little Endian)
> -  -------------------------------------
> -  0-3     4-byte  Version
> -
> -  4-5     2-byte  Entry-1 tag
> -  6-7     2-byte  Entry-1 perm
> -  8-11    4-byte  Entry-1 id
> -
> -  12-13   2-byte  Entry-2 tag
> -  14-15   2-byte  Entry-2 perm
> -  16-19   4-byte  Entry-2 id
> -
> -  ...
> -
> - */
> -
> -/* header version */
> -#define GLUSTER_ACL_VERSION 2
> -
> -/* perm bits */
> -#define GLUSTER_ACL_READ    0x04
> -#define GLUSTER_ACL_WRITE   0x02
> -#define GLUSTER_ACL_EXECUTE 0x01
> -
> -/* tag values */
> -#define GLUSTER_ACL_UNDEFINED_TAG  0x00
> -#define GLUSTER_ACL_USER_OBJ       0x01
> -#define GLUSTER_ACL_USER           0x02
> -#define GLUSTER_ACL_GROUP_OBJ      0x04
> -#define GLUSTER_ACL_GROUP          0x08
> -#define GLUSTER_ACL_MASK           0x10
> -#define GLUSTER_ACL_OTHER          0x20
> -
> -#define GLUSTER_ACL_UNDEFINED_ID  (-1)
> -
> -#define GLUSTER_ACL_HEADER_SIZE    4
> -#define GLUSTER_ACL_ENTRY_SIZE     8
> -
> -#define GLUSTER_ACL_SIZE(n)       (GLUSTER_ACL_HEADER_SIZE + (n *
> GLUSTER_ACL_ENTRY_SIZE))
> -
> -static SMB_ACL_T mode_to_smb_acls(const struct stat *mode, TALLOC_CTX
> *mem_ctx)
> -{
> -       struct smb_acl_t *result;
> -       int count;
> -
> -       count = 3;
> -       result = sys_acl_init(mem_ctx);
> -       if (!result) {
> -               errno = ENOMEM;
> -               return NULL;
> -       }
> -
> -       result->acl = talloc_array(result, struct smb_acl_entry, count);
> -       if (!result->acl) {
> -               errno = ENOMEM;
> -               talloc_free(result);
> -               return NULL;
> -       }
> -
> -       result->count = count;
> -
> -       result->acl[0].a_type = SMB_ACL_USER_OBJ;
> -       result->acl[0].a_perm = (mode->st_mode & S_IRWXU) >> 6;;
> -
> -       result->acl[1].a_type = SMB_ACL_GROUP_OBJ;
> -       result->acl[1].a_perm = (mode->st_mode & S_IRWXG) >> 3;;
> -
> -       result->acl[2].a_type = SMB_ACL_OTHER;
> -       result->acl[2].a_perm = mode->st_mode & S_IRWXO;;
> -
> -       return result;
> -}
> -
> -static SMB_ACL_T gluster_to_smb_acl(const char *buf, size_t xattr_size,
> -                                   TALLOC_CTX *mem_ctx)
> -{
> -       int count;
> -       size_t size;
> -       struct smb_acl_entry *smb_ace;
> -       struct smb_acl_t *result;
> -       int i;
> -       int offset;
> -       uint16_t tag;
> -       uint16_t perm;
> -       uint32_t id;
> -
> -       size = xattr_size;
> -
> -       if (size < GLUSTER_ACL_HEADER_SIZE) {
> -               /* ACL should be at least as big as the header (4 bytes) */
> -               errno = EINVAL;
> -               return NULL;
> -       }
> -
> -       size -= GLUSTER_ACL_HEADER_SIZE; /* size of header = 4 bytes */
> -
> -       if (size % GLUSTER_ACL_ENTRY_SIZE) {
> -               /* Size of entries must strictly be a multiple of
> -                  size of an ACE (8 bytes)
> -               */
> -               errno = EINVAL;
> -               return NULL;
> -       }
> -
> -       count = size / GLUSTER_ACL_ENTRY_SIZE;
> -
> -       /* Version is the first 4 bytes of the ACL */
> -       if (IVAL(buf, 0) != GLUSTER_ACL_VERSION) {
> -               DEBUG(0, ("Unknown gluster ACL version: %d\n",
> -                         IVAL(buf, 0)));
> -               return NULL;
> -       }
> -       offset = GLUSTER_ACL_HEADER_SIZE;
> -
> -       result = sys_acl_init(mem_ctx);
> -       if (!result) {
> -               errno = ENOMEM;
> -               return NULL;
> -       }
> -
> -       result->acl = talloc_array(result, struct smb_acl_entry, count);
> -       if (!result->acl) {
> -               errno = ENOMEM;
> -               talloc_free(result);
> -               return NULL;
> -       }
> -
> -       result->count = count;
> -
> -       smb_ace = result->acl;
> -
> -       for (i = 0; i < count; i++) {
> -               /* TAG is the first 2 bytes of an entry */
> -               tag = SVAL(buf, offset);
> -               offset += 2;
> -
> -               /* PERM is the next 2 bytes of an entry */
> -               perm = SVAL(buf, offset);
> -               offset += 2;
> -
> -               /* ID is the last 4 bytes of an entry */
> -               id = IVAL(buf, offset);
> -               offset += 4;
> -
> -               switch(tag) {
> -               case GLUSTER_ACL_USER:
> -                       smb_ace->a_type = SMB_ACL_USER;
> -                       break;
> -               case GLUSTER_ACL_USER_OBJ:
> -                       smb_ace->a_type = SMB_ACL_USER_OBJ;
> -                       break;
> -               case GLUSTER_ACL_GROUP:
> -                       smb_ace->a_type = SMB_ACL_GROUP;
> -                       break;
> -               case GLUSTER_ACL_GROUP_OBJ:
> -                       smb_ace->a_type = SMB_ACL_GROUP_OBJ;
> -                       break;
> -               case GLUSTER_ACL_OTHER:
> -                       smb_ace->a_type = SMB_ACL_OTHER;
> -                       break;
> -               case GLUSTER_ACL_MASK:
> -                       smb_ace->a_type = SMB_ACL_MASK;
> -                       break;
> -               default:
> -                       DEBUG(0, ("unknown tag type %d\n", (unsigned int)
> tag));
> -                       return NULL;
> -               }
> -
> -
> -               switch(smb_ace->a_type) {
> -               case SMB_ACL_USER:
> -                       smb_ace->info.user.uid = id;
> -                       break;
> -               case SMB_ACL_GROUP:
> -                       smb_ace->info.group.gid = id;
> -                       break;
> -               default:
> -                       break;
> -               }
> -
> -               smb_ace->a_perm = 0;
> -               smb_ace->a_perm |=
> -                       ((perm & GLUSTER_ACL_READ) ? SMB_ACL_READ : 0);
> -               smb_ace->a_perm |=
> -                       ((perm & GLUSTER_ACL_WRITE) ? SMB_ACL_WRITE : 0);
> -               smb_ace->a_perm |=
> -                       ((perm & GLUSTER_ACL_EXECUTE) ? SMB_ACL_EXECUTE :
> 0);
> -
> -               smb_ace++;
> -       }
> -
> -       return result;
> -}
> -
> -
> -static int gluster_ace_cmp(const void *left, const void *right)
> -{
> -       int ret = 0;
> -       uint16_t tag_left, tag_right;
> -       uint32_t id_left, id_right;
> -
> -       /*
> -         Sorting precedence:
> -
> -          - Smaller TAG values must be earlier.
> -
> -          - Within same TAG, smaller identifiers must be earlier, E.g:
> -            UID 0 entry must be earlier than UID 200
> -            GID 17 entry must be earlier than GID 19
> -       */
> -
> -       /* TAG is the first element in the entry */
> -       tag_left = SVAL(left, 0);
> -       tag_right = SVAL(right, 0);
> -
> -       ret = (tag_left - tag_right);
> -       if (!ret) {
> -               /* ID is the third element in the entry, after two short
> -                  integers (tag and perm), i.e at offset 4.
> -               */
> -               id_left = IVAL(left, 4);
> -               id_right = IVAL(right, 4);
> -               ret = id_left - id_right;
> -       }
> -
> -       return ret;
> -}
> -
> -
> -static ssize_t smb_to_gluster_acl(SMB_ACL_T theacl, char *buf, size_t len)
> -{
> -       ssize_t size;
> -       struct smb_acl_entry *smb_ace;
> -       int i;
> -       int count;
> -       uint16_t tag;
> -       uint16_t perm;
> -       uint32_t id;
> -       int offset;
> -
> -       count = theacl->count;
> -
> -       size = GLUSTER_ACL_HEADER_SIZE + (count * GLUSTER_ACL_ENTRY_SIZE);
> -       if (!buf) {
> -               return size;
> -       }
> -
> -       if (len < size) {
> -               errno = ERANGE;
> -               return -1;
> -       }
> -
> -       smb_ace = theacl->acl;
> -
> -       /* Version is the first 4 bytes of the ACL */
> -       SIVAL(buf, 0, GLUSTER_ACL_VERSION);
> -       offset = GLUSTER_ACL_HEADER_SIZE;
> -
> -       for (i = 0; i < count; i++) {
> -               /* Calculate tag */
> -               switch(smb_ace->a_type) {
> -               case SMB_ACL_USER:
> -                       tag = GLUSTER_ACL_USER;
> -                       break;
> -               case SMB_ACL_USER_OBJ:
> -                       tag = GLUSTER_ACL_USER_OBJ;
> -                       break;
> -               case SMB_ACL_GROUP:
> -                       tag = GLUSTER_ACL_GROUP;
> -                       break;
> -               case SMB_ACL_GROUP_OBJ:
> -                       tag = GLUSTER_ACL_GROUP_OBJ;
> -                       break;
> -               case SMB_ACL_OTHER:
> -                       tag = GLUSTER_ACL_OTHER;
> -                       break;
> -               case SMB_ACL_MASK:
> -                       tag = GLUSTER_ACL_MASK;
> -                       break;
> -               default:
> -                       DEBUG(0, ("Unknown tag value %d\n",
> -                                 smb_ace->a_type));
> -                       errno = EINVAL;
> -                       return -1;
> -               }
> -
> -
> -               /* Calculate id */
> -               switch(smb_ace->a_type) {
> -               case SMB_ACL_USER:
> -                       id = smb_ace->info.user.uid;
> -                       break;
> -               case SMB_ACL_GROUP:
> -                       id = smb_ace->info.group.gid;
> -                       break;
> -               default:
> -                       id = GLUSTER_ACL_UNDEFINED_ID;
> -                       break;
> -               }
> -
> -               /* Calculate perm */
> -               perm = 0;
> -
> -               perm |=
> -                       ((smb_ace->a_perm & SMB_ACL_READ) ?
> GLUSTER_ACL_READ : 0);
> -               perm |=
> -                       ((smb_ace->a_perm & SMB_ACL_WRITE) ?
> GLUSTER_ACL_WRITE : 0);
> -               perm |=
> -                       ((smb_ace->a_perm & SMB_ACL_EXECUTE) ?
> GLUSTER_ACL_EXECUTE : 0);
> -
> -
> -               /* TAG is the first 2 bytes of an entry */
> -               SSVAL(buf, offset, tag);
> -               offset += 2;
> -
> -               /* PERM is the next 2 bytes of an entry */
> -               SSVAL(buf, offset, perm);
> -               offset += 2;
> -
> -               /* ID is the last 4 bytes of an entry */
> -               SIVAL(buf, offset, id);
> -               offset += 4;
> -
> -               smb_ace++;
> -       }
> -
> -       /* Skip the header, sort @count number of 8-byte entries */
> -       qsort(buf+GLUSTER_ACL_HEADER_SIZE, count, GLUSTER_ACL_ENTRY_SIZE,
> -             gluster_ace_cmp);
> -
> -       return size;
> -}
> -
> -
> -static SMB_ACL_T vfs_gluster_sys_acl_get_file(struct vfs_handle_struct
> *handle,
> -                                             const char *path_p,
> -                                             SMB_ACL_TYPE_T type,
> -                                             TALLOC_CTX *mem_ctx)
> -{
> -       struct smb_acl_t *result;
> -       struct stat st;
> -       char *buf;
> -       const char *key;
> -       ssize_t ret, size = GLUSTER_ACL_SIZE(20);
> -
> -       switch (type) {
> -       case SMB_ACL_TYPE_ACCESS:
> -               key = "system.posix_acl_access";
> -               break;
> -       case SMB_ACL_TYPE_DEFAULT:
> -               key = "system.posix_acl_default";
> -               break;
> -       default:
> -               errno = EINVAL;
> -               return NULL;
> -       }
> -
> -       buf = alloca(size);
> -       if (!buf) {
> -               return NULL;
> -       }
> -
> -       ret = glfs_getxattr(handle->data, path_p, key, buf, size);
> -       if (ret == -1 && errno == ERANGE) {
> -               ret = glfs_getxattr(handle->data, path_p, key, 0, 0);
> -               if (ret > 0) {
> -                       buf = alloca(ret);
> -                       if (!buf) {
> -                               return NULL;
> -                       }
> -                       ret = glfs_getxattr(handle->data, path_p, key,
> buf, ret);
> -               }
> -       }
> -
> -       /* retrieving the ACL from the xattr has finally failed, do a
> -        * mode-to-acl mapping */
> -
> -       if (ret == -1 && errno == ENODATA) {
> -               ret = glfs_stat(handle->data, path_p, &st);
> -               if (ret == 0) {
> -                       result = mode_to_smb_acls(&st, mem_ctx);
> -                       return result;
> -               }
> -       }
> -
> -       if (ret <= 0) {
> -               return NULL;
> -       }
> -
> -       result = gluster_to_smb_acl(buf, ret, mem_ctx);
> -
> -       return result;
> -}
> -
> -static SMB_ACL_T vfs_gluster_sys_acl_get_fd(struct vfs_handle_struct
> *handle,
> -                                           struct files_struct *fsp,
> -                                           TALLOC_CTX *mem_ctx)
> -{
> -       struct smb_acl_t *result;
> -       struct stat st;
> -       ssize_t ret, size = GLUSTER_ACL_SIZE(20);
> -       char *buf;
> -       glfs_fd_t *glfd;
> -
> -       glfd = *(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
> -
> -       buf = alloca(size);
> -       if (!buf) {
> -               return NULL;
> -       }
> -
> -       ret = glfs_fgetxattr(glfd, "system.posix_acl_access", buf, size);
> -       if (ret == -1 && errno == ERANGE) {
> -               ret = glfs_fgetxattr(glfd, "system.posix_acl_access", 0,
> 0);
> -               if (ret > 0) {
> -                       buf = alloca(ret);
> -                       if (!buf) {
> -                               return NULL;
> -                       }
> -                       ret = glfs_fgetxattr(glfd,
> "system.posix_acl_access",
> -                                            buf, ret);
> -               }
> -       }
> -
> -       /* retrieving the ACL from the xattr has finally failed, do a
> -        * mode-to-acl mapping */
> -
> -       if (ret == -1 && errno == ENODATA) {
> -               ret = glfs_fstat(glfd, &st);
> -               if (ret == 0) {
> -                       result = mode_to_smb_acls(&st, mem_ctx);
> -                       return result;
> -               }
> -       }
> -
> -       if (ret <= 0) {
> -               return NULL;
> -       }
> -
> -       result = gluster_to_smb_acl(buf, ret, mem_ctx);
> -
> -       return result;
> -}
> -
> -static int vfs_gluster_sys_acl_set_file(struct vfs_handle_struct *handle,
> -                                       const char *name,
> -                                       SMB_ACL_TYPE_T acltype,
> -                                       SMB_ACL_T theacl)
> -{
> -       int ret;
> -       const char *key;
> -       char *buf;
> -       ssize_t size;
> -
> -       switch (acltype) {
> -       case SMB_ACL_TYPE_ACCESS:
> -               key = "system.posix_acl_access";
> -               break;
> -       case SMB_ACL_TYPE_DEFAULT:
> -               key = "system.posix_acl_default";
> -               break;
> -       default:
> -               errno = EINVAL;
> -               return -1;
> -       }
> -
> -       size = smb_to_gluster_acl(theacl, 0, 0);
> -       buf = alloca(size);
> -
> -       size = smb_to_gluster_acl(theacl, buf, size);
> -       if (size == -1) {
> -               return -1;
> -       }
> -
> -       ret = glfs_setxattr(handle->data, name, key, buf, size, 0);
> -
> -       return ret;
> -}
> -
> -static int vfs_gluster_sys_acl_set_fd(struct vfs_handle_struct *handle,
> -                                     struct files_struct *fsp,
> -                                     SMB_ACL_T theacl)
> -{
> -       int ret;
> -       char *buf;
> -       ssize_t size;
> -
> -       size = smb_to_gluster_acl(theacl, 0, 0);
> -       buf = alloca(size);
> -
> -       size = smb_to_gluster_acl(theacl, buf, size);
> -       if (size == -1) {
> -               return -1;
> -       }
> -
> -       ret = glfs_fsetxattr(*(glfs_fd_t
> **)VFS_FETCH_FSP_EXTENSION(handle, fsp),
> -                            "system.posix_acl_access", buf, size, 0);
> -       return ret;
> -}
> -
> -static int vfs_gluster_sys_acl_delete_def_file(struct vfs_handle_struct
> *handle,
> -                                              const char *path)
> -{
> -       return glfs_removexattr(handle->data, path,
> "system.posix_acl_default");
> -}
> -
>  static struct vfs_fn_pointers glusterfs_fns = {
>
>         /* Disk Operations */
> @@ -1871,13 +1361,13 @@ static struct vfs_fn_pointers glusterfs_fns = {
>         /* Posix ACL Operations */
>         .chmod_acl_fn = NULL,   /* passthrough to default */
>         .fchmod_acl_fn = NULL,  /* passthrough to default */
> -       .sys_acl_get_file_fn = vfs_gluster_sys_acl_get_file,
> -       .sys_acl_get_fd_fn = vfs_gluster_sys_acl_get_fd,
> +       .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
> +       .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
>         .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
>         .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
> -       .sys_acl_set_file_fn = vfs_gluster_sys_acl_set_file,
> -       .sys_acl_set_fd_fn = vfs_gluster_sys_acl_set_fd,
> -       .sys_acl_delete_def_file_fn = vfs_gluster_sys_acl_delete_def_file,
> +       .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
> +       .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
> +       .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
>
>         /* EA Operations */
>         .getxattr_fn = vfs_gluster_getxattr,
> diff --git a/source3/modules/vfs_posixacl_xattr.c
> b/source3/modules/vfs_posixacl_xattr.c
> new file mode 100644
> index 0000000..dbe0f35
> --- /dev/null
> +++ b/source3/modules/vfs_posixacl_xattr.c
> @@ -0,0 +1,487 @@
> +/*
> +   Unix SMB/Netbios implementation.
> +   VFS module to get and set posix acls through xattr
> +   Copyright (c) 2013 Anand Avati <avati at redhat.com>
> +   Copyright (c) 2016 Yan, Zheng <zyan at redhat.com>
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program 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 General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +*/
> +
> +#include "includes.h"
> +#include "system/filesys.h"
> +#include "smbd/smbd.h"
> +#include "modules/vfs_posixacl_xattr.h"
> +
> +/* private functions */
> +
> +#define ACL_EA_ACCESS          "system.posix_acl_access"
> +#define ACL_EA_DEFAULT         "system.posix_acl_default"
> +#define ACL_EA_VERSION         0x0002
> +#define ACL_EA_HEADER_SIZE     4
> +#define ACL_EA_ENTRY_SIZE      8
> +
> +#define ACL_EA_SIZE(n)  (ACL_EA_HEADER_SIZE + ((n) * ACL_EA_ENTRY_SIZE))
> +
> +static SMB_ACL_T mode_to_smb_acl(mode_t mode, TALLOC_CTX *mem_ctx)
> +{
> +       struct smb_acl_t *result;
> +       int count;
> +
> +       count = 3;
> +       result = sys_acl_init(mem_ctx);
> +       if (!result) {
> +               return NULL;
> +       }
> +
> +       result->acl = talloc_array(result, struct smb_acl_entry, count);
> +       if (!result->acl) {
> +               errno = ENOMEM;
> +               talloc_free(result);
> +               return NULL;
> +       }
> +
> +       result->count = count;
> +
> +       result->acl[0].a_type = SMB_ACL_USER_OBJ;
> +       result->acl[0].a_perm = (mode & S_IRWXU) >> 6;
> +
> +       result->acl[1].a_type = SMB_ACL_GROUP_OBJ;
> +       result->acl[1].a_perm = (mode & S_IRWXG) >> 3;
> +
> +       result->acl[2].a_type = SMB_ACL_OTHER;
> +       result->acl[2].a_perm = mode & S_IRWXO;
> +
> +       return result;
> +}
> +
> +static SMB_ACL_T posixacl_xattr_to_smb_acl(const char *buf, size_t
> xattr_size,
> +                                          TALLOC_CTX *mem_ctx)
> +{
> +       int count;
> +       int size;
> +       struct smb_acl_entry *smb_ace;
> +       struct smb_acl_t *result;
> +       int i;
> +       int offset;
> +       uint16_t tag;
> +       uint16_t perm;
> +       uint32_t id;
> +
> +       size = xattr_size;
> +
> +       if (size < ACL_EA_HEADER_SIZE) {
> +               /* ACL should be at least as big as the header (4 bytes) */
> +               errno = EINVAL;
> +               return NULL;
> +       }
> +
> +       /* Version is the first 4 bytes of the ACL */
> +       if (IVAL(buf, 0) != ACL_EA_VERSION) {
> +               DEBUG(0, ("Unknown ACL EA version: %d\n",
> +                         IVAL(buf, 0)));
> +               errno = EINVAL;
> +               return NULL;
> +       }
> +       offset = ACL_EA_HEADER_SIZE;
> +
> +       size -= ACL_EA_HEADER_SIZE;
> +       if (size % ACL_EA_ENTRY_SIZE) {
> +               /* Size of entries must strictly be a multiple of
> +                  size of an ACE (8 bytes)
> +               */
> +               DEBUG(0, ("Invalid ACL EA size: %d\n", size));
> +               errno = EINVAL;
> +               return NULL;
> +       }
> +
> +       count = size / ACL_EA_ENTRY_SIZE;
> +
> +       result = sys_acl_init(mem_ctx);
> +       if (!result) {
> +               return NULL;
> +       }
> +
> +       result->acl = talloc_array(result, struct smb_acl_entry, count);
> +       if (!result->acl) {
> +               errno = ENOMEM;
> +               talloc_free(result);
> +               return NULL;
> +       }
> +
> +       result->count = count;
> +
> +       smb_ace = result->acl;
> +
> +       for (i = 0; i < count; i++) {
> +               /* TAG is the first 2 bytes of an entry */
> +               tag = SVAL(buf, offset);
> +               offset += 2;
> +
> +               /* PERM is the next 2 bytes of an entry */
> +               perm = SVAL(buf, offset);
> +               offset += 2;
> +
> +               /* ID is the last 4 bytes of an entry */
> +               id = IVAL(buf, offset);
> +               offset += 4;
> +
> +               switch(tag) {
> +               case ACL_USER:
> +                       smb_ace->a_type = SMB_ACL_USER;
> +                       break;
> +               case ACL_USER_OBJ:
> +                       smb_ace->a_type = SMB_ACL_USER_OBJ;
> +                       break;
> +               case ACL_GROUP:
> +                       smb_ace->a_type = SMB_ACL_GROUP;
> +                       break;
> +               case ACL_GROUP_OBJ:
> +                       smb_ace->a_type = SMB_ACL_GROUP_OBJ;
> +                       break;
> +               case ACL_OTHER:
> +                       smb_ace->a_type = SMB_ACL_OTHER;
> +                       break;
> +               case ACL_MASK:
> +                       smb_ace->a_type = SMB_ACL_MASK;
> +                       break;
> +               default:
> +                       DEBUG(0, ("unknown tag type %d\n", (unsigned int)
> tag));
> +                       errno = EINVAL;
> +                       return NULL;
> +               }
> +
> +
> +               switch(smb_ace->a_type) {
> +               case SMB_ACL_USER:
> +                       smb_ace->info.user.uid = id;
> +                       break;
> +               case SMB_ACL_GROUP:
> +                       smb_ace->info.group.gid = id;
> +                       break;
> +               default:
> +                       break;
> +               }
> +
> +               smb_ace->a_perm = 0;
> +               smb_ace->a_perm |= ((perm & ACL_READ) ? SMB_ACL_READ : 0);
> +               smb_ace->a_perm |= ((perm & ACL_WRITE) ? SMB_ACL_WRITE :
> 0);
> +               smb_ace->a_perm |= ((perm & ACL_EXECUTE) ? SMB_ACL_EXECUTE
> : 0);
> +
> +               smb_ace++;
> +       }
> +
> +       return result;
> +}
> +
> +
> +static int posixacl_xattr_entry_compare(const void *left, const void
> *right)
> +{
> +       int ret = 0;
> +       uint16_t tag_left, tag_right;
> +       uint32_t id_left, id_right;
> +
> +       /*
> +         Sorting precedence:
> +          - Smaller TAG values must be earlier.
> +          - Within same TAG, smaller identifiers must be earlier, E.g:
> +            UID 0 entry must be earlier than UID 200
> +            GID 17 entry must be earlier than GID 19
> +       */
> +
> +       /* TAG is the first element in the entry */
> +       tag_left = SVAL(left, 0);
> +       tag_right = SVAL(right, 0);
> +
> +       ret = (tag_left - tag_right);
> +       if (!ret) {
> +               /* ID is the third element in the entry, after two short
> +                  integers (tag and perm), i.e at offset 4.
> +               */
> +               id_left = IVAL(left, 4);
> +               id_right = IVAL(right, 4);
> +               ret = id_left - id_right;
> +       }
> +
> +       return ret;
> +}
> +
> +
> +static int smb_acl_to_posixacl_xattr(SMB_ACL_T theacl, char *buf, size_t
> len)
> +{
> +       ssize_t size;
> +       struct smb_acl_entry *smb_ace;
> +       int i;
> +       int count;
> +       uint16_t tag;
> +       uint16_t perm;
> +       uint32_t id;
> +       int offset;
> +
> +       count = theacl->count;
> +
> +       size = ACL_EA_SIZE(count);
> +       if (!buf) {
> +               return size;
> +       }
> +       if (len < size) {
> +               return -ERANGE;
> +       }
> +       smb_ace = theacl->acl;
> +
> +       /* Version is the first 4 bytes of the ACL */
> +       SIVAL(buf, 0, ACL_EA_VERSION);
> +       offset = ACL_EA_HEADER_SIZE;
> +
> +       for (i = 0; i < count; i++) {
> +               /* Calculate tag */
> +               switch(smb_ace->a_type) {
> +               case SMB_ACL_USER:
> +                       tag = ACL_USER;
> +                       break;
> +               case SMB_ACL_USER_OBJ:
> +                       tag = ACL_USER_OBJ;
> +                       break;
> +               case SMB_ACL_GROUP:
> +                       tag = ACL_GROUP;
> +                       break;
> +               case SMB_ACL_GROUP_OBJ:
> +                       tag = ACL_GROUP_OBJ;
> +                       break;
> +               case SMB_ACL_OTHER:
> +                       tag = ACL_OTHER;
> +                       break;
> +               case SMB_ACL_MASK:
> +                       tag = ACL_MASK;
> +                       break;
> +               default:
> +                       DEBUG(0, ("Unknown tag value %d\n",
> +                                 smb_ace->a_type));
> +                       return -EINVAL;
> +               }
> +
> +
> +               /* Calculate id */
> +               switch(smb_ace->a_type) {
> +               case SMB_ACL_USER:
> +                       id = smb_ace->info.user.uid;
> +                       break;
> +               case SMB_ACL_GROUP:
> +                       id = smb_ace->info.group.gid;
> +                       break;
> +               default:
> +                       id = ACL_UNDEFINED_ID;
> +                       break;
> +               }
> +
> +               /* Calculate perm */
> +               perm = 0;
> +               perm |= (smb_ace->a_perm & SMB_ACL_READ) ? ACL_READ : 0;
> +               perm |= (smb_ace->a_perm & SMB_ACL_WRITE) ? ACL_WRITE : 0;
> +               perm |= (smb_ace->a_perm & SMB_ACL_EXECUTE) ? ACL_EXECUTE
> : 0;
> +
> +               /* TAG is the first 2 bytes of an entry */
> +               SSVAL(buf, offset, tag);
> +               offset += 2;
> +
> +               /* PERM is the next 2 bytes of an entry */
> +               SSVAL(buf, offset, perm);
> +               offset += 2;
> +
> +               /* ID is the last 4 bytes of an entry */
> +               SIVAL(buf, offset, id);
> +               offset += 4;
> +
> +               smb_ace++;
> +       }
> +
> +       /* Skip the header, sort @count number of 8-byte entries */
> +       qsort(buf+ACL_EA_HEADER_SIZE, count, ACL_EA_ENTRY_SIZE,
> +             posixacl_xattr_entry_compare);
> +
> +       return size;
> +}
> +
> +SMB_ACL_T posixacl_xattr_acl_get_file(vfs_handle_struct *handle,
> +                                     const char *path_p,
> +                                     SMB_ACL_TYPE_T type,
> +                                     TALLOC_CTX *mem_ctx)
> +{
> +       int ret;
> +       int size;
> +       char *buf;
> +       const char *name;
> +
> +       if (type == SMB_ACL_TYPE_ACCESS) {
> +               name = ACL_EA_ACCESS;
> +       } else if (type == SMB_ACL_TYPE_DEFAULT) {
> +               name = ACL_EA_DEFAULT;
> +       } else {
> +               errno = EINVAL;
> +               return NULL;
> +       }
> +
> +       size = ACL_EA_SIZE(20);
> +       buf = alloca(size);
> +       if (!buf) {
> +               return NULL;
> +       }
> +
> +       ret = SMB_VFS_GETXATTR(handle->conn, path_p, name, buf, size);
> +       if (ret < 0 && errno == ERANGE) {
> +               size = SMB_VFS_GETXATTR(handle->conn, path_p, name,
> +                                       NULL, 0);
> +               if (size > 0) {
> +                       buf = alloca(size);
> +                       if (!buf) {
> +                               return NULL;
> +                       }
> +                       ret = SMB_VFS_GETXATTR(handle->conn, path_p, name,
> +                                               buf, size);
> +               }
> +       }
> +
> +       if (ret > 0) {
> +               return posixacl_xattr_to_smb_acl(buf, ret, mem_ctx);
> +       }
> +       if (ret == 0 || errno == ENOATTR || errno == ENODATA) {
> +               mode_t mode;
> +               TALLOC_CTX *frame = talloc_stackframe();
> +               struct smb_filename *smb_fname =
> +                       synthetic_smb_fname(frame, path_p, NULL, NULL);
> +               if (smb_fname == NULL) {
> +                       errno = ENOMEM;
> +                       ret = -1;
> +               } else {
> +                       ret = SMB_VFS_STAT(handle->conn, smb_fname);
> +                       if (ret == 0) {
> +                               mode = smb_fname->st.st_ex_mode;
> +                       }
> +               }
> +               TALLOC_FREE(frame);
> +               if (ret == 0) {
> +                       if (type == SMB_ACL_TYPE_ACCESS) {
> +                               return mode_to_smb_acl(mode, mem_ctx);
> +                       }
> +                       if (S_ISDIR(mode)) {
> +                               return sys_acl_init(mem_ctx);
> +                       }
> +                       errno = EACCES;
> +               }
> +       }
> +       return NULL;
> +}
> +
> +SMB_ACL_T posixacl_xattr_acl_get_fd(vfs_handle_struct *handle,
> +                                   files_struct *fsp,
> +                                   TALLOC_CTX *mem_ctx)
> +{
> +       int ret;
> +       int size = ACL_EA_SIZE(20);
> +       char *buf = alloca(size);
> +
> +       if (!buf) {
> +               return NULL;
> +       }
> +
> +       ret = SMB_VFS_FGETXATTR(fsp, ACL_EA_ACCESS, buf, size);
> +       if (ret < 0 && errno == ERANGE) {
> +               size = SMB_VFS_FGETXATTR(fsp, ACL_EA_ACCESS, NULL, 0);
> +               if (size > 0) {
> +                       buf = alloca(size);
> +                       if (!buf) {
> +                               return NULL;
> +                       }
> +                       ret = SMB_VFS_FGETXATTR(fsp, ACL_EA_ACCESS, buf,
> size);
> +               }
> +       }
> +
> +       if (ret > 0) {
> +               return posixacl_xattr_to_smb_acl(buf, ret, mem_ctx);
> +       }
> +       if (ret == 0 || errno == ENOATTR || errno == ENODATA) {
> +               SMB_STRUCT_STAT sbuf;
> +               ret = SMB_VFS_FSTAT(fsp, &sbuf);
> +               if (ret == 0)
> +                       return mode_to_smb_acl(sbuf.st_ex_mode, mem_ctx);
> +       }
> +       return NULL;
> +}
> +
> +int posixacl_xattr_acl_set_file(vfs_handle_struct *handle,
> +                               const char *path_p,
> +                               SMB_ACL_TYPE_T type,
> +                               SMB_ACL_T theacl)
> +{
> +       const char *name;
> +       char *buf;
> +       ssize_t size;
> +       int ret;
> +
> +       size = smb_acl_to_posixacl_xattr(theacl, NULL, 0);
> +       buf = alloca(size);
> +       if (!buf) {
> +               return -1;
> +       }
> +
> +       ret = smb_acl_to_posixacl_xattr(theacl, buf, size);
> +       if (ret < 0) {
> +               errno = -ret;
> +               return -1;
> +       }
> +
> +       if (type == SMB_ACL_TYPE_ACCESS) {
> +               name = ACL_EA_ACCESS;
> +       } else if (type == SMB_ACL_TYPE_DEFAULT) {
> +               name = ACL_EA_DEFAULT;
> +       } else {
> +               errno = EINVAL;
> +               return -1;
> +       }
> +
> +       return SMB_VFS_SETXATTR(handle->conn, path_p, name, buf, size, 0);
> +}
> +
> +int posixacl_xattr_acl_set_fd(vfs_handle_struct *handle,
> +                             files_struct *fsp, SMB_ACL_T theacl)
> +{
> +       char *buf;
> +       ssize_t size;
> +       int ret;
> +
> +       size = smb_acl_to_posixacl_xattr(theacl, NULL, 0);
> +       buf = alloca(size);
> +       if (!buf) {
> +               return -1;
> +       }
> +
> +       ret = smb_acl_to_posixacl_xattr(theacl, buf, size);
> +       if (ret < 0) {
> +               errno = -ret;
> +               return -1;
> +       }
> +
> +       return SMB_VFS_FSETXATTR(fsp, ACL_EA_ACCESS, buf, size, 0);
> +}
> +
> +int posixacl_xattr_acl_delete_def_file(vfs_handle_struct *handle,
> +                                      const char *path_p)
> +{
> +       return SMB_VFS_REMOVEXATTR(handle->conn, path_p, ACL_EA_DEFAULT);
> +}
> +
> +NTSTATUS vfs_posixacl_xattr_init(void);
> +NTSTATUS vfs_posixacl_xattr_init(void)
> +{
> +       return NT_STATUS_OK;
> +}
> diff --git a/source3/modules/vfs_posixacl_xattr.h
> b/source3/modules/vfs_posixacl_xattr.h
> new file mode 100644
> index 0000000..7e1b827
> --- /dev/null
> +++ b/source3/modules/vfs_posixacl_xattr.h
> @@ -0,0 +1,46 @@
> +/*
> +   Unix SMB/Netbios implementation.
> +   VFS module to get and set posix acl through xattr
> +   Copyright (c) 2013 Anand Avati <avati at redhat.com>
> +   Copyright (c) 2016 Yan, Zheng <zyan at redhat.com>
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program 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 General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +*/
> +
> +#ifndef __VFS_POSIXACL_XATTR_H__
> +#define __VFS_POSIXACL_XATTR_H__
> +
> +SMB_ACL_T posixacl_xattr_acl_get_file(vfs_handle_struct *handle,
> +                                     const char *path_p,
> +                                     SMB_ACL_TYPE_T type,
> +                                     TALLOC_CTX *mem_ctx);
> +
> +SMB_ACL_T posixacl_xattr_acl_get_fd(vfs_handle_struct *handle,
> +                                   files_struct *fsp,
> +                                   TALLOC_CTX *mem_ctx);
> +
> +int posixacl_xattr_acl_set_file(vfs_handle_struct *handle,
> +                               const char *name,
> +                               SMB_ACL_TYPE_T type,
> +                               SMB_ACL_T theacl);
> +
> +int posixacl_xattr_acl_set_fd(vfs_handle_struct *handle,
> +                             files_struct *fsp,
> +                             SMB_ACL_T theacl);
> +
> +int posixacl_xattr_acl_delete_def_file(vfs_handle_struct *handle,
> +                                      const char *path);
> +
> +NTSTATUS vfs_posixacl_xattr_init(void);
> +#endif
> diff --git a/source3/modules/wscript_build b/source3/modules/wscript_build
> index 77b28f6..1aee8fa 100644
> --- a/source3/modules/wscript_build
> +++ b/source3/modules/wscript_build
> @@ -170,6 +170,14 @@ bld.SAMBA3_MODULE('vfs_posixacl',
>
> internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_posixacl'),
>                   enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_posixacl'))
>
> +bld.SAMBA3_MODULE('vfs_posixacl_xattr',
> +                 subsystem='vfs',
> +                 source='vfs_posixacl_xattr.c',
> +                 deps='acl attr',
> +                 init_function='',
> +
>  internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_posixacl_xattr'),
> +
>  enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_posixacl_xattr'))
> +
>  bld.SAMBA3_MODULE('vfs_aixacl',
>                   subsystem='vfs',
>                   source='vfs_aixacl.c',
> diff --git a/source3/wscript b/source3/wscript
> index 9b73bfc..c1e6930 100644
> --- a/source3/wscript
> +++ b/source3/wscript
> @@ -490,6 +490,7 @@ return acl_get_perm_np(permset_d, perm);
>                          msg="Checking whether acl_get_perm_np() is
> available")
>                  # source3/lib/sysacls.c calls posixacl_sys_acl_get_file()
>                  required_static_modules.extend(TO_LIST('vfs_posixacl'))
> +
> required_static_modules.extend(TO_LIST('vfs_posixacl_xattr'))
>                  conf.CHECK_VARIABLE('ACL_EVERYONE', headers='sys/acl.h')
>              elif conf.CHECK_FUNCS_IN(['facl'], 'sec'):
>                  Logs.info('Using solaris or UnixWare ACLs')
> --
> 2.5.0
>
>
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: redone_patches
Type: application/octet-stream
Size: 31114 bytes
Desc: not available
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20160323/eff9bf4b/redone_patches.obj>


More information about the samba-technical mailing list