summaryrefslogtreecommitdiff
path: root/source3/modules
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2013-04-14 20:06:57 +1000
committerAndrew Bartlett <abartlet@samba.org>2013-05-09 06:18:20 +0200
commit76969abba0453b232274520182c0c2cdfab93428 (patch)
treed9efd4d404698e940e1b5501721c8f9570dc01cd /source3/modules
parent5d517f41664920faa5863cbf36b5953ad4700ebd (diff)
downloadsamba-76969abba0453b232274520182c0c2cdfab93428.tar.gz
samba-76969abba0453b232274520182c0c2cdfab93428.tar.bz2
samba-76969abba0453b232274520182c0c2cdfab93428.zip
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 <jra@samba.org>
Diffstat (limited to 'source3/modules')
-rw-r--r--source3/modules/vfs_nfs4acl_xattr.c414
-rw-r--r--source3/modules/wscript_build9
2 files changed, 423 insertions, 0 deletions
diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
new file mode 100644
index 0000000000..fedb768d0e
--- /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 <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);
+}
diff --git a/source3/modules/wscript_build b/source3/modules/wscript_build
index df4f59a41f..65e96b2d54 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,