[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