From 76969abba0453b232274520182c0c2cdfab93428 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Sun, 14 Apr 2013 20:06:57 +1000 Subject: [PATCH] vfs: Add new VFS module vfs_nfs4acl_xattr to use nfs4acl.idl This uses the xattr format used by the patches at http://users.suse.com/~agruen/nfs4acl/ Andrew Bartlett Reviewed-by: Jeremy Allison --- source3/Makefile.in | 5 + source3/configure.in | 2 +- source3/modules/vfs_nfs4acl_xattr.c | 414 ++++++++++++++++++++++++++++ source3/modules/wscript_build | 9 + source3/wscript | 2 +- 5 files changed, 430 insertions(+), 2 deletions(-) create mode 100644 source3/modules/vfs_nfs4acl_xattr.c diff --git a/source3/Makefile.in b/source3/Makefile.in index f4977ca5cd4..4de5cdeb4fa 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -883,6 +883,7 @@ VFS_AIXACL_OBJ = modules/vfs_aixacl.o modules/vfs_aixacl_util.o VFS_AIXACL2_OBJ = modules/vfs_aixacl2.o modules/vfs_aixacl_util.o $(NFS4ACL_OBJ) VFS_SOLARISACL_OBJ = modules/vfs_solarisacl.o VFS_ZFSACL_OBJ = modules/vfs_zfsacl.o $(NFS4ACL_OBJ) +VFS_NFS4ACL_XATTR_OBJ = modules/vfs_nfs4acl_xattr.o VFS_HPUXACL_OBJ = modules/vfs_hpuxacl.o VFS_TRU64ACL_OBJ = modules/vfs_tru64acl.o VFS_CATIA_OBJ = modules/vfs_catia.o @@ -2838,6 +2839,10 @@ bin/zfsacl.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_ZFSACL_OBJ) @echo "Building plugin $@" @$(SHLD_MODULE) $(VFS_ZFSACL_OBJ) @ZFSACL_LIBS@ +bin/nfs4acl_xattr.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_NFS4ACL_XATTR_OBJ) + @echo "Building plugin $@" + @$(SHLD_MODULE) $(VFS_NFS4ACL_XATTR_OBJ) + bin/hpuxacl.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_HPUXACL_OBJ) @echo "Building plugin $@" @$(SHLD_MODULE) $(VFS_HPUXACL_OBJ) diff --git a/source3/configure.in b/source3/configure.in index d2aa2154013..cb8f730e859 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -474,7 +474,7 @@ if test "x$developer" = xyes; then fi if test x"$selftest" = x"yes" -o "x$developer" = xyes; then - default_shared_modules="$default_shared_modules vfs_fake_acls" + default_shared_modules="$default_shared_modules vfs_fake_acls vfs_nfs4acl_xattr" fi # diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c new file mode 100644 index 00000000000..fedb768d0e8 --- /dev/null +++ b/source3/modules/vfs_nfs4acl_xattr.c @@ -0,0 +1,414 @@ +/* + * Convert NFSv4 acls stored per http://www.suse.de/~agruen/nfs4acl/ to NT acls and vice versa. + * + * Copyright (C) Jiri Sasek, 2007 + * based on the foobar.c module which is copyrighted by Volker Lendecke + * based on pvfs_acl_nfs4.c Copyright (C) Andrew Tridgell 2006 + * + * based on vfs_fake_acls: + * 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 "system/filesys.h" +#include "smbd/smbd.h" +#include "nfs4_acls.h" +#include "librpc/gen_ndr/ndr_nfs4acl.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_VFS + +static struct nfs4acl *nfs4acl_blob2acl(DATA_BLOB *blob, TALLOC_CTX *mem_ctx) +{ + enum ndr_err_code ndr_err; + struct nfs4acl *acl = talloc(mem_ctx, struct nfs4acl); + if (!acl) { + errno = ENOMEM; + return NULL; + } + + ndr_err = ndr_pull_struct_blob(blob, acl, acl, + (ndr_pull_flags_fn_t)ndr_pull_nfs4acl); + + 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 nfs4acl_acl2blob(TALLOC_CTX *mem_ctx, struct nfs4acl *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_nfs4acl); + + 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 NTSTATUS nfs4_get_nfs4_acl_common(TALLOC_CTX *mem_ctx, + DATA_BLOB *blob, + SMB4ACL_T **ppacl) +{ + int i; + struct nfs4acl *nfs4acl = NULL; + SMB4ACL_T *pacl = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + nfs4acl = nfs4acl_blob2acl(blob, frame); + + /* create SMB4ACL data */ + if((pacl = smb_create_smb4acl(mem_ctx)) == NULL) { + TALLOC_FREE(frame); + return NT_STATUS_NO_MEMORY; + } + for(i=0; ia_count; i++) { + SMB_ACE4PROP_T aceprop; + + aceprop.aceType = (uint32) nfs4acl->ace[i].e_type; + aceprop.aceFlags = (uint32) nfs4acl->ace[i].e_flags; + aceprop.aceMask = (uint32) nfs4acl->ace[i].e_mask; + aceprop.who.id = (uint32) nfs4acl->ace[i].e_id; + if (!strcmp(nfs4acl->ace[i].e_who, + NFS4ACL_XATTR_OWNER_WHO)) { + aceprop.flags = SMB_ACE4_ID_SPECIAL; + aceprop.who.special_id = SMB_ACE4_WHO_OWNER; + } else if (!strcmp(nfs4acl->ace[i].e_who, + NFS4ACL_XATTR_GROUP_WHO)) { + aceprop.flags = SMB_ACE4_ID_SPECIAL; + aceprop.who.special_id = SMB_ACE4_WHO_GROUP; + } else if (!strcmp(nfs4acl->ace[i].e_who, + NFS4ACL_XATTR_EVERYONE_WHO)) { + aceprop.flags = SMB_ACE4_ID_SPECIAL; + aceprop.who.special_id = SMB_ACE4_WHO_EVERYONE; + } else { + aceprop.flags = 0; + } + if(smb_add_ace4(pacl, &aceprop) == NULL) { + TALLOC_FREE(frame); + return NT_STATUS_NO_MEMORY; + } + } + + *ppacl = pacl; + TALLOC_FREE(frame); + return NT_STATUS_OK; +} + +/* Fetch the NFSv4 ACL from the xattr, and convert into Samba's internal NFSv4 format */ +static NTSTATUS nfs4_fget_nfs4_acl(vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, + files_struct *fsp, SMB4ACL_T **ppacl) +{ + NTSTATUS status; + DATA_BLOB blob = data_blob_null; + ssize_t length; + TALLOC_CTX *frame = talloc_stackframe(); + + do { + blob.length += 1000; + blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length); + if (!blob.data) { + TALLOC_FREE(frame); + errno = ENOMEM; + return NT_STATUS_NO_MEMORY; + } + length = SMB_VFS_NEXT_FGETXATTR(handle, fsp, NFS4ACL_XATTR_NAME, blob.data, blob.length); + blob.length = length; + } while (length == -1 && errno == ERANGE); + if (length == -1) { + TALLOC_FREE(frame); + return map_nt_error_from_unix(errno); + } + status = nfs4_get_nfs4_acl_common(mem_ctx, &blob, ppacl); + TALLOC_FREE(frame); + return status; +} + +/* Fetch the NFSv4 ACL from the xattr, and convert into Samba's internal NFSv4 format */ +static NTSTATUS nfs4_get_nfs4_acl(vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, + const char *path, SMB4ACL_T **ppacl) +{ + NTSTATUS status; + DATA_BLOB blob = data_blob_null; + ssize_t length; + TALLOC_CTX *frame = talloc_stackframe(); + + do { + blob.length += 1000; + blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length); + if (!blob.data) { + TALLOC_FREE(frame); + errno = ENOMEM; + return NT_STATUS_NO_MEMORY; + } + length = SMB_VFS_NEXT_GETXATTR(handle, path, NFS4ACL_XATTR_NAME, blob.data, blob.length); + blob.length = length; + } while (length == -1 && errno == ERANGE); + if (length == -1) { + TALLOC_FREE(frame); + return map_nt_error_from_unix(errno); + } + status = nfs4_get_nfs4_acl_common(mem_ctx, &blob, ppacl); + TALLOC_FREE(frame); + return status; +} + +/* call-back function processing the NT acl -> NFS4 acl using NFSv4 conv. */ +static bool nfs4_process_smbacl(vfs_handle_struct *handle, files_struct *fsp, SMB4ACL_T *smbacl) +{ + TALLOC_CTX *frame = talloc_stackframe(); + int i; + struct nfs4acl *nfs4acl; + SMB4ACE_T *smbace; + bool have_special_id = false; + int ret; + DATA_BLOB blob; + + /* allocate the field of NFS4 aces */ + nfs4acl = talloc_zero(frame, struct nfs4acl); + if(nfs4acl == NULL) { + TALLOC_FREE(frame); + errno = ENOMEM; + return false; + } + + nfs4acl->a_count = smb_get_naces(smbacl); + + nfs4acl->ace = talloc_zero_array(nfs4acl, struct nfs4ace, nfs4acl->a_count); + if(nfs4acl->ace == NULL) { + TALLOC_FREE(frame); + errno = ENOMEM; + return false; + } + + /* handle all aces */ + for(smbace = smb_first_ace4(smbacl), i = 0; + smbace!=NULL; + smbace = smb_next_ace4(smbace), i++) { + SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace); + + nfs4acl->ace[i].e_type = aceprop->aceType; + nfs4acl->ace[i].e_flags = aceprop->aceFlags; + nfs4acl->ace[i].e_mask = aceprop->aceMask; + nfs4acl->ace[i].e_id = aceprop->who.id; + if(aceprop->flags & SMB_ACE4_ID_SPECIAL) { + switch(aceprop->who.special_id) { + case SMB_ACE4_WHO_EVERYONE: + nfs4acl->ace[i].e_who = + NFS4ACL_XATTR_EVERYONE_WHO; + break; + case SMB_ACE4_WHO_OWNER: + nfs4acl->ace[i].e_who = + NFS4ACL_XATTR_OWNER_WHO; + break; + case SMB_ACE4_WHO_GROUP: + nfs4acl->ace[i].e_who = + NFS4ACL_XATTR_GROUP_WHO; + break; + default: + DEBUG(8, ("unsupported special_id %d\n", \ + aceprop->who.special_id)); + continue; /* don't add it !!! */ + } + have_special_id = true; + } else { + nfs4acl->ace[i].e_who = ""; + } + } + + if (!have_special_id + && lp_parm_bool(fsp->conn->params->service, "nfs4acl_xattr", + "denymissingspecial", false)) { + TALLOC_FREE(frame); + errno = EACCES; + return false; + } + + SMB_ASSERT(i == nfs4acl->a_count); + + blob = nfs4acl_acl2blob(frame, nfs4acl); + if (!blob.data) { + DEBUG(0, ("Failed to convert ACL to linear blob for xattr storage\n")); + TALLOC_FREE(frame); + errno = EINVAL; + return false; + } + ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, NFS4ACL_XATTR_NAME, blob.data, blob.length, 0); + TALLOC_FREE(frame); + + return ret == 0; +} + +/* nfs4_set_nt_acl() + * set the local file's acls obtaining it in NT form + * using the NFSv4 format conversion + */ +static NTSTATUS nfs4_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp, + uint32 security_info_sent, + const struct security_descriptor *psd) +{ + return smb_set_nt_acl_nfs4(handle, fsp, security_info_sent, psd, + nfs4_process_smbacl); +} + +static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle, + struct files_struct *fsp, + uint32 security_info, + TALLOC_CTX *mem_ctx, + struct security_descriptor **ppdesc) +{ + SMB4ACL_T *pacl; + NTSTATUS status; + TALLOC_CTX *frame = talloc_stackframe(); + + status = nfs4_fget_nfs4_acl(handle, frame, fsp, &pacl); + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { + status = SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info, + mem_ctx, ppdesc); + } + TALLOC_FREE(frame); + return status; + } + + status = smb_fget_nt_acl_nfs4(fsp, security_info, mem_ctx, ppdesc, pacl); + TALLOC_FREE(frame); + return status; +} + +static NTSTATUS nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct *handle, + const char *name, uint32 security_info, + TALLOC_CTX *mem_ctx, + struct security_descriptor **ppdesc) +{ + SMB4ACL_T *pacl; + NTSTATUS status; + TALLOC_CTX *frame = talloc_stackframe(); + + status = nfs4_get_nfs4_acl(handle, frame, name, &pacl); + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { + status = SMB_VFS_NEXT_GET_NT_ACL(handle, name, security_info, + mem_ctx, ppdesc); + } + TALLOC_FREE(frame); + return status; + } + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); + return status; + } + + status = smb_get_nt_acl_nfs4(handle->conn, name, security_info, + mem_ctx, ppdesc, + pacl); + TALLOC_FREE(frame); + return status; +} + +static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle, + files_struct *fsp, + uint32 security_info_sent, + const struct security_descriptor *psd) +{ + return nfs4_set_nt_acl(handle, fsp, security_info_sent, psd); +} + +/* + As long as Samba does not support an exiplicit method for a module + to define conflicting vfs methods, we should override all conflicting + methods here. That way, we know we are using the NFSv4 storage + + Function declarations taken from vfs_solarisacl +*/ + +static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_file(vfs_handle_struct *handle, + const char *path_p, + SMB_ACL_TYPE_T type, + TALLOC_CTX *mem_ctx) +{ + return (SMB_ACL_T)NULL; +} + +static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_fd(vfs_handle_struct *handle, + files_struct *fsp, + TALLOC_CTX *mem_ctx) +{ + return (SMB_ACL_T)NULL; +} + +static int nfs4acl_xattr_fail__sys_acl_set_file(vfs_handle_struct *handle, + const char *name, + SMB_ACL_TYPE_T type, + SMB_ACL_T theacl) +{ + return -1; +} + +static int nfs4acl_xattr_fail__sys_acl_set_fd(vfs_handle_struct *handle, + files_struct *fsp, + SMB_ACL_T theacl) +{ + return -1; +} + +static int nfs4acl_xattr_fail__sys_acl_delete_def_file(vfs_handle_struct *handle, + const char *path) +{ + return -1; +} + +static int nfs4acl_xattr_fail__sys_acl_blob_get_file(vfs_handle_struct *handle, const char *path_p, TALLOC_CTX *mem_ctx, char **blob_description, DATA_BLOB *blob) +{ + return -1; +} + +static int nfs4acl_xattr_fail__sys_acl_blob_get_fd(vfs_handle_struct *handle, files_struct *fsp, TALLOC_CTX *mem_ctx, char **blob_description, DATA_BLOB *blob) +{ + return -1; +} + +/* VFS operations structure */ + +static struct vfs_fn_pointers nfs4acl_xattr_fns = { + .sys_acl_get_file_fn = nfs4acl_xattr_fail__sys_acl_get_file, + .sys_acl_get_fd_fn = nfs4acl_xattr_fail__sys_acl_get_fd, + .sys_acl_blob_get_file_fn = nfs4acl_xattr_fail__sys_acl_blob_get_file, + .sys_acl_blob_get_fd_fn = nfs4acl_xattr_fail__sys_acl_blob_get_fd, + .sys_acl_set_file_fn = nfs4acl_xattr_fail__sys_acl_set_file, + .sys_acl_set_fd_fn = nfs4acl_xattr_fail__sys_acl_set_fd, + .sys_acl_delete_def_file_fn = nfs4acl_xattr_fail__sys_acl_delete_def_file, + .fget_nt_acl_fn = nfs4acl_xattr_fget_nt_acl, + .get_nt_acl_fn = nfs4acl_xattr_get_nt_acl, + .fset_nt_acl_fn = nfs4acl_xattr_fset_nt_acl, +}; + +NTSTATUS vfs_nfs4acl_xattr_init(void); +NTSTATUS vfs_nfs4acl_xattr_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "nfs4acl_xattr", + &nfs4acl_xattr_fns); +} diff --git a/source3/modules/wscript_build b/source3/modules/wscript_build index df4f59a41fc..65e96b2d546 100644 --- a/source3/modules/wscript_build +++ b/source3/modules/wscript_build @@ -21,6 +21,7 @@ VFS_AIXACL_SRC = '''vfs_aixacl.c''' VFS_AIXACL2_SRC = '''vfs_aixacl2.c''' VFS_SOLARISACL_SRC = '''vfs_solarisacl.c''' VFS_ZFSACL_SRC = '''vfs_zfsacl.c''' +VFS_NFS4ACL_XATTR_SRC = 'vfs_nfs4acl_xattr.c' VFS_HPUXACL_SRC = '''vfs_hpuxacl.c''' VFS_TRU64ACL_SRC = '''vfs_tru64acl.c''' VFS_CATIA_SRC = 'vfs_catia.c' @@ -247,6 +248,14 @@ bld.SAMBA3_MODULE('vfs_zfsacl', internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_zfsacl'), enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_zfsacl')) +bld.SAMBA3_MODULE('vfs_nfs4acl_xattr', + subsystem='vfs', + source=VFS_NFS4ACL_XATTR_SRC, + deps='NFS4_ACLS sunacl', + init_function='', + internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_nfs4acl_xattr'), + enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_nfs4acl_xattr')) + bld.SAMBA3_MODULE('vfs_hpuxacl', subsystem='vfs', source=VFS_HPUXACL_SRC, diff --git a/source3/wscript b/source3/wscript index 5e45facfbc7..5a3805fc151 100644 --- a/source3/wscript +++ b/source3/wscript @@ -1756,7 +1756,7 @@ main() { default_shared_modules.extend(TO_LIST('auth_skel pdb_test')) if Options.options.enable_selftest or Options.options.developer: - default_shared_modules.extend(TO_LIST('vfs_fake_acls')) + default_shared_modules.extend(TO_LIST('vfs_fake_acls vfs_nfs4acl_xattr')) if conf.CONFIG_SET('AD_DC_BUILD_IS_ENABLED'): -- 2.34.1