summaryrefslogtreecommitdiff
path: root/source3/modules
diff options
context:
space:
mode:
Diffstat (limited to 'source3/modules')
-rw-r--r--source3/modules/vfs_nfs4acl_xattr.c292
1 files changed, 263 insertions, 29 deletions
diff --git a/source3/modules/vfs_nfs4acl_xattr.c b/source3/modules/vfs_nfs4acl_xattr.c
index fedb768d0e..bdaca82b8c 100644
--- a/source3/modules/vfs_nfs4acl_xattr.c
+++ b/source3/modules/vfs_nfs4acl_xattr.c
@@ -176,30 +176,29 @@ static NTSTATUS nfs4_get_nfs4_acl(vfs_handle_struct *handle, TALLOC_CTX *mem_ctx
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)
+static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
+ SMB4ACL_T *smbacl,
+ struct nfs4acl **pnfs4acl,
+ bool denymissingspecial)
{
- TALLOC_CTX *frame = talloc_stackframe();
- int i;
struct nfs4acl *nfs4acl;
SMB4ACE_T *smbace;
bool have_special_id = false;
- int ret;
- DATA_BLOB blob;
+ int i;
/* allocate the field of NFS4 aces */
- nfs4acl = talloc_zero(frame, struct nfs4acl);
+ nfs4acl = talloc_zero(mem_ctx, 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);
+ nfs4acl->ace = talloc_zero_array(nfs4acl, struct nfs4ace,
+ nfs4acl->a_count);
if(nfs4acl->ace == NULL) {
- TALLOC_FREE(frame);
+ TALLOC_FREE(nfs4acl);
errno = ENOMEM;
return false;
}
@@ -239,26 +238,93 @@ static bool nfs4_process_smbacl(vfs_handle_struct *handle, files_struct *fsp, SM
}
}
- if (!have_special_id
- && lp_parm_bool(fsp->conn->params->service, "nfs4acl_xattr",
- "denymissingspecial", false)) {
- TALLOC_FREE(frame);
+ if (!have_special_id && denymissingspecial) {
+ TALLOC_FREE(nfs4acl);
errno = EACCES;
return false;
}
SMB_ASSERT(i == nfs4acl->a_count);
+ *pnfs4acl = nfs4acl;
+ return true;
+}
+
+static bool nfs4acl_xattr_set_smb4acl(vfs_handle_struct *handle,
+ const char *path,
+ SMB4ACL_T *smbacl)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct nfs4acl *nfs4acl;
+ int ret;
+ bool denymissingspecial;
+ DATA_BLOB blob;
+
+ denymissingspecial = lp_parm_bool(handle->conn->params->service,
+ "nfs4acl_xattr",
+ "denymissingspecial", false);
+
+ if (!nfs4acl_smb4acl2nfs4acl(frame, smbacl, &nfs4acl,
+ denymissingspecial)) {
+ DEBUG(0, ("Failed to convert smb ACL to nfs4 ACL.\n"));
+ TALLOC_FREE(frame);
+ return false;
+ }
+
blob = nfs4acl_acl2blob(frame, nfs4acl);
if (!blob.data) {
- DEBUG(0, ("Failed to convert ACL to linear blob for xattr storage\n"));
+ DEBUG(0, ("Failed to convert ACL to linear blob for xattr\n"));
TALLOC_FREE(frame);
errno = EINVAL;
return false;
}
- ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, NFS4ACL_XATTR_NAME, blob.data, blob.length, 0);
+ ret = SMB_VFS_NEXT_SETXATTR(handle, path, NFS4ACL_XATTR_NAME,
+ blob.data, blob.length, 0);
+ if (ret != 0) {
+ DEBUG(0, ("can't store acl in xattr: %s\n", strerror(errno)));
+ }
TALLOC_FREE(frame);
+ return ret == 0;
+}
+/* call-back function processing the NT acl -> NFS4 acl using NFSv4 conv. */
+static bool nfs4acl_xattr_fset_smb4acl(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SMB4ACL_T *smbacl)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct nfs4acl *nfs4acl;
+ int ret;
+ bool denymissingspecial;
+ DATA_BLOB blob;
+
+ denymissingspecial = lp_parm_bool(fsp->conn->params->service,
+ "nfs4acl_xattr",
+ "denymissingspecial", false);
+
+ if (!nfs4acl_smb4acl2nfs4acl(frame, smbacl, &nfs4acl,
+ denymissingspecial)) {
+ DEBUG(0, ("Failed to convert smb ACL to nfs4 ACL.\n"));
+ TALLOC_FREE(frame);
+ return false;
+ }
+
+ blob = nfs4acl_acl2blob(frame, nfs4acl);
+ if (!blob.data) {
+ DEBUG(0, ("Failed to convert ACL to linear blob for xattr\n"));
+ TALLOC_FREE(frame);
+ errno = EINVAL;
+ return false;
+ }
+ if (fsp->fh->fd == -1) {
+ DEBUG(0, ("Error: fsp->fh->fd == -1\n"));
+ }
+ ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, NFS4ACL_XATTR_NAME,
+ blob.data, blob.length, 0);
+ if (ret != 0) {
+ DEBUG(0, ("can't store acl in xattr: %s\n", strerror(errno)));
+ }
+ TALLOC_FREE(frame);
return ret == 0;
}
@@ -271,7 +337,180 @@ static NTSTATUS nfs4_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
const struct security_descriptor *psd)
{
return smb_set_nt_acl_nfs4(handle, fsp, security_info_sent, psd,
- nfs4_process_smbacl);
+ nfs4acl_xattr_fset_smb4acl);
+}
+
+static SMB4ACL_T *nfs4acls_defaultacl(TALLOC_CTX *mem_ctx)
+{
+ SMB4ACL_T *pacl = NULL;
+ SMB4ACE_T *pace;
+ SMB_ACE4PROP_T ace = { SMB_ACE4_ID_SPECIAL,
+ SMB_ACE4_WHO_EVERYONE,
+ SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE,
+ 0,
+ SMB_ACE4_ALL_MASKS };
+
+ DEBUG(10, ("Building default full access acl\n"));
+
+ pacl = smb_create_smb4acl(mem_ctx);
+ if (pacl == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ pace = smb_add_ace4(pacl, &ace);
+ if (pace == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(pacl);
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ return pacl;
+}
+
+/*
+ * Because there is no good way to guarantee that a new xattr will be
+ * created on file creation there might be no acl xattr on a file when
+ * trying to read the acl. In this case the acl xattr will get
+ * constructed at that time from the parent acl.
+ * If the parent ACL doesn't have an xattr either the call will
+ * recurse to the next parent directory until the share root is
+ * reached. If the share root doesn't contain an ACL xattr either a
+ * default ACL will be used.
+ * Also a default ACL will be set if a non inheriting ACL is encountered.
+ *
+ * Basic algorithm:
+ * read acl xattr blob
+ * if acl xattr blob doesn't exist
+ * stat current directory to know if it's a file or directory
+ * read acl xattr blob from parent dir
+ * acl xattr blob to smb nfs4 acl
+ * calculate inherited smb nfs4 acl
+ * without inheritance use default smb nfs4 acl
+ * smb nfs4 acl to acl xattr blob
+ * set acl xattr blob
+ * return smb nfs4 acl
+ * else
+ * acl xattr blob to smb nfs4 acl
+ *
+ * Todo: Really use mem_ctx after fixing interface of nfs4_acls
+ */
+static SMB4ACL_T *nfs4acls_inheritacl(vfs_handle_struct *handle,
+ const char *path,
+ TALLOC_CTX *mem_ctx)
+{
+ char *parent_dir = NULL;
+ SMB4ACL_T *pparentacl = NULL;
+ SMB4ACL_T *pchildacl = NULL;
+ SMB4ACE_T *pace;
+ SMB_ACE4PROP_T ace;
+ bool isdir;
+ struct smb_filename *smb_fname = NULL;
+ NTSTATUS status;
+ int ret;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ DEBUG(10, ("nfs4acls_inheritacl invoked for %s\n", path));
+ smb_fname = synthetic_smb_fname(frame, path, NULL, NULL);
+ if (smb_fname == NULL) {
+ TALLOC_FREE(frame);
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ ret = SMB_VFS_STAT(handle->conn, smb_fname);
+ if (ret == -1) {
+ DEBUG(0,("nfs4acls_inheritacl: failed to stat "
+ "directory %s. Error was %s\n",
+ smb_fname_str_dbg(smb_fname),
+ strerror(errno)));
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+ isdir = S_ISDIR(smb_fname->st.st_ex_mode);
+
+ if (!parent_dirname(talloc_tos(),
+ path,
+ &parent_dir,
+ NULL)) {
+ TALLOC_FREE(frame);
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ status = nfs4_get_nfs4_acl(handle, frame, parent_dir, &pparentacl);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)
+ && strncmp(parent_dir, ".", 2) != 0) {
+ pparentacl = nfs4acls_inheritacl(handle, parent_dir,
+ frame);
+ }
+ else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+ pparentacl = nfs4acls_defaultacl(frame);
+
+ }
+ else if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ pchildacl = smb_create_smb4acl(mem_ctx);
+ if (pchildacl == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(frame);
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ for (pace = smb_first_ace4(pparentacl); pace != NULL;
+ pace = smb_next_ace4(pace)) {
+ SMB4ACE_T *pchildace;
+ ace = *smb_get_ace4(pace);
+ if (isdir && !(ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
+ || !isdir && !(ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
+ DEBUG(10, ("non inheriting ace type: %d, iflags: %x, "
+ "flags: %x, mask: %x, who: %d\n",
+ ace.aceType, ace.flags, ace.aceFlags,
+ ace.aceMask, ace.who.id));
+ continue;
+ }
+ DEBUG(10, ("inheriting ace type: %d, iflags: %x, "
+ "flags: %x, mask: %x, who: %d\n",
+ ace.aceType, ace.flags, ace.aceFlags,
+ ace.aceMask, ace.who.id));
+ ace.aceFlags |= SMB_ACE4_INHERITED_ACE;
+ if ((isdir && (ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
+ || !isdir && (ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE))
+ && ace.aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) {
+ ace.aceFlags &= ~SMB_ACE4_INHERIT_ONLY_ACE;
+ }
+ if (ace.aceFlags & SMB_ACE4_NO_PROPAGATE_INHERIT_ACE) {
+ ace.aceFlags &= ~SMB_ACE4_FILE_INHERIT_ACE;
+ ace.aceFlags &= ~SMB_ACE4_DIRECTORY_INHERIT_ACE;
+ ace.aceFlags &= ~SMB_ACE4_NO_PROPAGATE_INHERIT_ACE;
+ }
+ pchildace = smb_add_ace4(pchildacl, &ace);
+ if (pchildace == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(frame);
+ errno = ENOMEM;
+ return NULL;
+ }
+ }
+
+ /* Set a default ACL if we didn't inherit anything. */
+ if (smb_first_ace4(pchildacl) == NULL) {
+ TALLOC_FREE(pchildacl);
+ pchildacl = nfs4acls_defaultacl(mem_ctx);
+ }
+
+ /* store the returned ACL to get it directly in the
+ future and avoid dynamic inheritance behavior. */
+ nfs4acl_xattr_set_smb4acl(handle, path, pchildacl);
+
+ TALLOC_FREE(frame);
+ return pchildacl;
}
static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
@@ -285,11 +524,11 @@ static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
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);
- }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+ pacl = nfs4acls_inheritacl(handle, fsp->fsp_name->base_name,
+ frame);
+ }
+ else if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(frame);
return status;
}
@@ -310,14 +549,9 @@ static NTSTATUS nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct *handle,
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;
+ pacl = nfs4acls_inheritacl(handle, name, frame);
}
- if (!NT_STATUS_IS_OK(status)) {
+ else if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(frame);
return status;
}