[PATCH 1/2] s3: vfs: generalize functions that set/get posix acl through xattr
Jeremy Allison
jra at samba.org
Tue Mar 22 23:53:14 UTC 2016
OK, I went through these carefully, and the code looks good,
but I have a few questions before I +1.
You've moved the posix acl related code to a seperate module,
but you then link the functions within it directly to the
vfs_glusterfs and vfs_ceph modules, by adding them into
the struct vfs_fn_pointers vectors in both gluster and
ceph VFS modules.
But you also add a separate vfs_posixacl_xattr module.
What is the point of adding that as a separate VFS module ?
Do you have future plans for it ? Can you explain this
more ?
If so, it also needs an xml documentation patch as we
no longer ship modules without a man page.
Great work otherwise !
Cheers,
Jeremy.
On Mon, Mar 21, 2016 at 10:42:20AM +0800, Yan, Zheng 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 | 501 +++++++++++++++++++++++++++++++++
> source3/modules/vfs_posixacl_xattr.h | 46 +++
> source3/modules/wscript_build | 8 +
> source3/wscript | 1 +
> 5 files changed, 562 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..42d8f0b
> --- /dev/null
> +++ b/source3/modules/vfs_posixacl_xattr.c
> @@ -0,0 +1,501 @@
> +/*
> + 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);
> +}
> +
> +/* VFS operations structure */
> +
> +static struct vfs_fn_pointers posixacl_xattr_fns = {
> + .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 = 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,
> +};
> +
> +NTSTATUS vfs_posixacl_xattr_init(void);
> +NTSTATUS vfs_posixacl_xattr_init(void)
> +{
> + DEBUG(1, ("vfs_posixacl_xattr_init\n"));
> + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "posixacl_xattr",
> + &posixacl_xattr_fns);
> +}
> 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
>
More information about the samba-technical
mailing list