[PATCH 1/2] s3: vfs: generalize functions that set/get posix acl through xattr
Yan, Zheng
zyan at redhat.com
Wed Mar 23 07:09:58 UTC 2016
> On Mar 23, 2016, at 07:53, Jeremy Allison <jra at samba.org> wrote:
>
> 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 ?
My original plan is to benefit new vfs modules which store posixacl as xattrs. They can get posixacl support by stacking the posixacl_xattr module. Now I changed my mind, new vfs module can use these functions directly. I will remove the register module code in later patch.
Regards
Yan, Zheng
> 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