vfs: Add new VFS module vfs_nfs4acl_xattr to use nfs4acl.idl
authorAndrew Bartlett <abartlet@samba.org>
Sun, 14 Apr 2013 10:06:57 +0000 (20:06 +1000)
committerAndrew Bartlett <abartlet@samba.org>
Thu, 9 May 2013 04:18:20 +0000 (06:18 +0200)
This uses the xattr format used by the patches at http://users.suse.com/~agruen/nfs4acl/

Andrew Bartlett
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/Makefile.in
source3/configure.in
source3/modules/vfs_nfs4acl_xattr.c [new file with mode: 0644]
source3/modules/wscript_build
source3/wscript

index f4977ca5cd427c48152eeb2451eb99865cce9a92..4de5cdeb4fa567a168d29873837fe458ab699160 100644 (file)
@@ -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)
index d2aa21540138a9315ef9693d920fb6a03e1aaf6f..cb8f730e859c7d8f2661f64b022d9687791e1ae0 100644 (file)
@@ -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 (file)
index 0000000..fedb768
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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; i<nfs4acl->a_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);
+}
index df4f59a41fcf1e0c27900dffb2489d29c964a2e6..65e96b2d546dcaffa2e7999a0d18388d21839e5a 100644 (file)
@@ -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,
index 5e45facfbc756183e380cd137695a544c76e8c89..5a3805fc15170e9b9dac444699df7ca03eeee375 100644 (file)
@@ -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'):