From 843e19eff40d300e1b671fb0e78300e6a4cc3683 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 15 Aug 2012 20:34:41 +1000 Subject: s3-vfs: Add new VFS module to fake setting an ACL The purpose of this module is to remove the relience on the system having ACL support to test NT ACLs. Andrew Bartlett --- source3/modules/vfs_fake_acls.c | 374 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 374 insertions(+) create mode 100644 source3/modules/vfs_fake_acls.c (limited to 'source3/modules') diff --git a/source3/modules/vfs_fake_acls.c b/source3/modules/vfs_fake_acls.c new file mode 100644 index 0000000000..175d6d2dc4 --- /dev/null +++ b/source3/modules/vfs_fake_acls.c @@ -0,0 +1,374 @@ +/* + * Fake ACLs VFS module. Implements passthrough operation of all VFS + * calls to disk functions, except for file ownership and ACLs, which + * are stored in xattrs. + * + * Copyright (C) Tim Potter, 1999-2000 + * Copyright (C) Alexander Bokovoy, 2002 + * Copyright (C) Andrew Bartlett, 2002,2012 + * + * 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 . + */ + +#include "includes.h" +#include "smbd/smbd.h" +#include "system/filesys.h" +#include "auth.h" +#include "librpc/gen_ndr/ndr_smb_acl.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_VFS + +#define FAKE_UID "FAKE.uid" +#define FAKE_GID "FAKE.gid" +#define FAKE_ACL_ACCESS_XATTR "FAKE.access_acl" +#define FAKE_ACL_DEFAULT_XATTR "FAKE.default_acl" + +static int fake_acls_uid(vfs_handle_struct *handle, + const char *path, + uid_t *uid) +{ + ssize_t size; + uint8_t uid_buf[4]; + size = SMB_VFS_NEXT_GETXATTR(handle, path, FAKE_UID, uid_buf, sizeof(uid_buf)); + if (size == -1 && errno == ENOATTR) { + return 0; + } + if (size != 4) { + return -1; + } + *uid = IVAL(uid_buf, 0); + return 0; +} + +static int fake_acls_gid(vfs_handle_struct *handle, + const char *path, + uid_t *gid) +{ + ssize_t size; + uint8_t gid_buf[4]; + + size = SMB_VFS_NEXT_GETXATTR(handle, path, FAKE_GID, gid_buf, sizeof(gid_buf)); + if (size == -1 && errno == ENOATTR) { + return 0; + } + if (size != 4) { + return -1; + } + *gid = IVAL(gid_buf, 0); + return 0; +} + +static int fake_acls_fuid(vfs_handle_struct *handle, + files_struct *fsp, + uid_t *uid) +{ + ssize_t size; + uint8_t uid_buf[4]; + + size = SMB_VFS_NEXT_FGETXATTR(handle, fsp, FAKE_UID, uid_buf, sizeof(uid_buf)); + if (size == -1 && errno == ENOATTR) { + return 0; + } + if (size != 4) { + return -1; + } + *uid = IVAL(uid_buf, 0); + return 0; +} + +static int fake_acls_fgid(vfs_handle_struct *handle, + files_struct *fsp, + uid_t *gid) +{ + ssize_t size; + uint8_t gid_buf[4]; + + size = SMB_VFS_NEXT_FGETXATTR(handle, fsp, FAKE_GID, gid_buf, sizeof(gid_buf)); + if (size == -1 && errno == ENOATTR) { + return 0; + } + if (size != 4) { + return -1; + } + *gid = IVAL(gid_buf, 0); + return 0; +} + +static int fake_acls_stat(vfs_handle_struct *handle, + struct smb_filename *smb_fname) +{ + int ret = -1; + + ret = SMB_VFS_NEXT_STAT(handle, smb_fname); + if (ret == 0) { + TALLOC_CTX *frame = talloc_stackframe(); + char *path; + NTSTATUS status; + status = get_full_smb_filename(frame, smb_fname, &path); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + TALLOC_FREE(frame); + return -1; + } + + ret = fake_acls_uid(handle, path, &smb_fname->st.st_ex_uid); + if (ret != 0) { + TALLOC_FREE(frame); + return ret; + } + ret = fake_acls_gid(handle, path, &smb_fname->st.st_ex_gid); + if (ret != 0) { + TALLOC_FREE(frame); + return ret; + } + TALLOC_FREE(frame); + } + + return ret; +} + +static int fake_acls_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf) +{ + int ret = -1; + + ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf); + if (ret == 0) { + ret = fake_acls_fuid(handle, fsp, &sbuf->st_ex_uid); + if (ret != 0) { + return ret; + } + ret = fake_acls_fgid(handle, fsp, &sbuf->st_ex_gid); + if (ret != 0) { + return ret; + } + } + return ret; +} + +static SMB_ACL_T fake_acls_blob2acl(DATA_BLOB *blob) +{ + enum ndr_err_code ndr_err; + /* For now, ACLs are allocated on NULL */ + struct smb_acl_t *acl = talloc(NULL, struct smb_acl_t); + if (!acl) { + errno = ENOMEM; + return NULL; + } + + ndr_err = ndr_pull_struct_blob(blob, acl, acl, + (ndr_pull_flags_fn_t)ndr_pull_smb_acl_t); + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(0, ("ndr_pull_acl_t failed: %s\n", + ndr_errstr(ndr_err))); + TALLOC_FREE(acl); + return NULL; + } + return acl; +} + +static DATA_BLOB fake_acls_acl2blob(TALLOC_CTX *mem_ctx, SMB_ACL_T acl) +{ + enum ndr_err_code ndr_err; + DATA_BLOB blob; + ndr_err = ndr_push_struct_blob(&blob, mem_ctx, acl, + (ndr_push_flags_fn_t)ndr_push_smb_acl_t); + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(0, ("ndr_push_acl_t failed: %s\n", + ndr_errstr(ndr_err))); + return data_blob_null; + } + return blob; +} + +static SMB_ACL_T fake_acls_sys_acl_get_file(struct vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T type) +{ + DATA_BLOB blob = data_blob_null; + ssize_t length; + const char *name = NULL; + struct smb_acl_t *acl = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + switch (type) { + case SMB_ACL_TYPE_ACCESS: + name = FAKE_ACL_ACCESS_XATTR; + break; + case SMB_ACL_TYPE_DEFAULT: + name = FAKE_ACL_DEFAULT_XATTR; + break; + } + + do { + blob.length += 1000; + blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length); + if (!blob.data) { + errno = ENOMEM; + TALLOC_FREE(frame); + return NULL; + } + length = SMB_VFS_NEXT_GETXATTR(handle, path, name, blob.data, blob.length); + blob.length = length; + } while (length == -1 && errno == ERANGE); + if (length == -1 && errno == ENOATTR) { + TALLOC_FREE(frame); + return NULL; + } + if (length != -1) { + acl = fake_acls_blob2acl(&blob); + } + TALLOC_FREE(frame); + return acl; +} + +static SMB_ACL_T fake_acls_sys_acl_get_fd(struct vfs_handle_struct *handle, files_struct *fsp) +{ + DATA_BLOB blob = data_blob_null; + ssize_t length; + const char *name = FAKE_ACL_ACCESS_XATTR; + struct smb_acl_t *acl; + TALLOC_CTX *frame = talloc_stackframe(); + + do { + blob.length += 1000; + blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length); + if (!blob.data) { + errno = ENOMEM; + TALLOC_FREE(frame); + return NULL; + } + length = SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, blob.data, blob.length); + blob.length = length; + } while (length == -1 && errno == ERANGE); + if (length == -1 && errno == ENOATTR) { + TALLOC_FREE(frame); + return NULL; + } + if (length != -1) { + acl = fake_acls_blob2acl(&blob); + } + TALLOC_FREE(frame); + return acl; +} + +static int fake_acls_sys_acl_set_file(vfs_handle_struct *handle, const char *path, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) +{ + int ret; + const char *name = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + DATA_BLOB blob = fake_acls_acl2blob(frame, theacl); + if (!blob.data) { + DEBUG(0, ("Failed to convert ACL to linear blob for xattr storage\n")); + TALLOC_FREE(frame); + errno = EINVAL; + return -1; + } + switch (acltype) { + case SMB_ACL_TYPE_ACCESS: + name = FAKE_ACL_ACCESS_XATTR; + break; + case SMB_ACL_TYPE_DEFAULT: + name = FAKE_ACL_DEFAULT_XATTR; + break; + } + ret = SMB_VFS_NEXT_SETXATTR(handle, path, name, blob.data, blob.length, 0); + TALLOC_FREE(frame); + return ret; +} + +static int fake_acls_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, SMB_ACL_T theacl) +{ + int ret; + const char *name = FAKE_ACL_ACCESS_XATTR; + TALLOC_CTX *frame = talloc_stackframe(); + DATA_BLOB blob = fake_acls_acl2blob(frame, theacl); + if (!blob.data) { + DEBUG(0, ("Failed to convert ACL to linear blob for xattr storage\n")); + TALLOC_FREE(frame); + errno = EINVAL; + return -1; + } + ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, name, blob.data, blob.length, 0); + TALLOC_FREE(frame); + return ret; +} + +static int fake_acls_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path) +{ + const char *name = FAKE_ACL_DEFAULT_XATTR; + return SMB_VFS_NEXT_REMOVEXATTR(handle, path, name); +} + +static int fake_acls_chown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid) +{ + int ret; + uint8_t id_buf[4]; + if (uid != -1) { + SIVAL(id_buf, 0, uid); + ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_UID, id_buf, sizeof(id_buf), 0); + if (ret != 0) { + return ret; + } + } + if (gid != -1) { + SIVAL(id_buf, 0, gid); + ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_GID, id_buf, sizeof(id_buf), 0); + if (ret != 0) { + return ret; + } + } + return 0; +} + +static int fake_acls_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid) +{ + int ret; + uint8_t id_buf[4]; + if (uid != -1) { + SIVAL(id_buf, 0, uid); + ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, FAKE_UID, id_buf, sizeof(id_buf), 0); + if (ret != 0) { + return ret; + } + } + if (gid != -1) { + SIVAL(id_buf, 0, gid); + ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, FAKE_GID, id_buf, sizeof(id_buf), 0); + if (ret != 0) { + return ret; + } + } + return 0; +} + + +static struct vfs_fn_pointers vfs_fake_acls_fns = { + .stat_fn = fake_acls_stat, + .fstat_fn = fake_acls_fstat, + .sys_acl_get_file_fn = fake_acls_sys_acl_get_file, + .sys_acl_get_fd_fn = fake_acls_sys_acl_get_fd, + .sys_acl_set_file_fn = fake_acls_sys_acl_set_file, + .sys_acl_set_fd_fn = fake_acls_sys_acl_set_fd, + .sys_acl_delete_def_file_fn = fake_acls_sys_acl_delete_def_file, + .chown_fn = fake_acls_chown, + .fchown_fn = fake_acls_fchown, + +}; + +NTSTATUS vfs_fake_acls_init(void); +NTSTATUS vfs_fake_acls_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "fake_acls", + &vfs_fake_acls_fns); +} -- cgit