[PATCH 1/2 v2] s3: vfs: generalize functions that set/get posix acl through xattr
Yan, Zheng
zyan at redhat.com
Wed Mar 23 12:23:13 UTC 2016
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
More information about the samba-technical
mailing list