* Copyright (C) Tim Potter, 1999-2000
* Copyright (C) Alexander Bokovoy, 2002
* Copyright (C) Andrew Bartlett, 2002,2012
+ * Copyright (C) Ralph Boehme 2017
*
* 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
#include "includes.h"
#include "system/filesys.h"
#include "smbd/smbd.h"
+#include "libcli/security/security_token.h"
+#include "libcli/security/dom_sid.h"
#include "nfs4_acls.h"
#include "librpc/gen_ndr/ndr_nfs4acl.h"
+#include "nfs4acl_xattr.h"
+#include "nfs4acl_xattr_ndr.h"
+#include "nfs4acl_xattr_xdr.h"
+#include "nfs4acl_xattr_nfs.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_VFS
-static struct nfs4acl *nfs4acl_blob2acl(DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
+static const struct enum_list nfs4acl_encoding[] = {
+ {NFS4ACL_ENCODING_NDR, "ndr"},
+ {NFS4ACL_ENCODING_XDR, "xdr"},
+ {NFS4ACL_ENCODING_NFS, "nfs"},
+};
+
+/*
+ * Check if someone changed the POSIX mode, for files we expect 0666, for
+ * directories 0777. Discard the ACL blob if the mode is different.
+ */
+static bool nfs4acl_validate_blob(vfs_handle_struct *handle,
+ files_struct *fsp)
{
- enum ndr_err_code ndr_err;
- struct nfs4acl *acl = talloc(mem_ctx, struct nfs4acl);
- if (!acl) {
- errno = ENOMEM;
- return NULL;
- }
+ struct nfs4acl_config *config = NULL;
+ mode_t expected_mode;
+ int ret;
- ndr_err = ndr_pull_struct_blob(blob, acl, acl,
- (ndr_pull_flags_fn_t)ndr_pull_nfs4acl);
+ SMB_VFS_HANDLE_GET_DATA(handle, config,
+ struct nfs4acl_config,
+ return false);
- 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;
+ if (!config->validate_mode) {
+ return true;
}
- 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;
+ if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
+ expected_mode = 0777;
+ } else {
+ expected_mode = 0666;
+ }
+ if ((fsp->fsp_name->st.st_ex_mode & expected_mode) == expected_mode) {
+ return true;
}
- return blob;
-}
-
-static NTSTATUS nfs4_get_nfs4_acl_common(TALLOC_CTX *mem_ctx,
- DATA_BLOB *blob,
- struct SMB4ACL_T **ppacl)
-{
- int i;
- struct nfs4acl *nfs4acl = NULL;
- struct 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_t) nfs4acl->ace[i].e_type;
- aceprop.aceFlags = (uint32_t) nfs4acl->ace[i].e_flags;
- aceprop.aceMask = (uint32_t) nfs4acl->ace[i].e_mask;
- aceprop.who.id = (uint32_t) 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;
- }
+ ret = SMB_VFS_NEXT_FREMOVEXATTR(handle,
+ fsp,
+ config->xattr_name);
+ if (ret != 0 && errno != ENOATTR) {
+ DBG_ERR("Removing NFS4 xattr failed: %s\n", strerror(errno));
+ return false;
}
- *ppacl = pacl;
- TALLOC_FREE(frame);
- return NT_STATUS_OK;
+ return true;
}
-/* 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, struct SMB4ACL_T **ppacl)
+static NTSTATUS nfs4acl_get_blob(struct vfs_handle_struct *handle,
+ files_struct *fsp,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob)
{
- NTSTATUS status;
- DATA_BLOB blob = data_blob_null;
+ struct nfs4acl_config *config = NULL;
+ size_t allocsize = 256;
ssize_t length;
- TALLOC_CTX *frame = talloc_stackframe();
+ bool ok;
- 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;
-}
+ SMB_VFS_HANDLE_GET_DATA(handle, config,
+ struct nfs4acl_config,
+ return NT_STATUS_INTERNAL_ERROR);
-/* 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, struct SMB4ACL_T **ppacl)
-{
- NTSTATUS status;
- DATA_BLOB blob = data_blob_null;
- ssize_t length;
- TALLOC_CTX *frame = talloc_stackframe();
+ *blob = data_blob_null;
+
+ ok = nfs4acl_validate_blob(handle, fsp);
+ if (!ok) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
do {
- blob.length += 1000;
- blob.data = talloc_realloc(frame, blob.data, uint8_t, blob.length);
- if (!blob.data) {
- TALLOC_FREE(frame);
- errno = ENOMEM;
+
+ allocsize *= 4;
+ ok = data_blob_realloc(mem_ctx, blob, allocsize);
+ if (!ok) {
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);
+
+ length = SMB_VFS_NEXT_FGETXATTR(handle,
+ fsp,
+ config->xattr_name,
+ blob->data,
+ blob->length);
+ } while (length == -1 && errno == ERANGE && allocsize <= 65536);
+
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;
+
+ return NT_STATUS_OK;
}
-static bool nfs4acl_smb4acl2nfs4acl(TALLOC_CTX *mem_ctx,
- struct SMB4ACL_T *smbacl,
- struct nfs4acl **pnfs4acl,
- bool denymissingspecial)
+static NTSTATUS nfs4acl_xattr_default_sd(
+ struct vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname,
+ TALLOC_CTX *mem_ctx,
+ struct security_descriptor **sd)
{
- struct nfs4acl *nfs4acl;
- struct SMB4ACE_T *smbace;
- bool have_special_id = false;
- int i;
-
- /* allocate the field of NFS4 aces */
- nfs4acl = talloc_zero(mem_ctx, struct nfs4acl);
- if(nfs4acl == NULL) {
- errno = ENOMEM;
- return false;
- }
+ struct nfs4acl_config *config = NULL;
+ enum default_acl_style default_acl_style;
+ mode_t required_mode;
+ SMB_STRUCT_STAT sbuf = smb_fname->st;
+ int ret;
- nfs4acl->a_count = smb_get_naces(smbacl);
+ SMB_VFS_HANDLE_GET_DATA(handle, config,
+ struct nfs4acl_config,
+ return NT_STATUS_INTERNAL_ERROR);
- nfs4acl->ace = talloc_zero_array(nfs4acl, struct nfs4ace,
- nfs4acl->a_count);
- if(nfs4acl->ace == NULL) {
- TALLOC_FREE(nfs4acl);
- errno = ENOMEM;
- return false;
- }
+ default_acl_style = config->default_acl_style;
- /* 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 (!VALID_STAT(sbuf)) {
+ ret = vfs_stat_smb_basename(handle->conn,
+ smb_fname,
+ &sbuf);
+ if (ret != 0) {
+ return map_nt_error_from_unix(errno);
}
}
- if (!have_special_id && denymissingspecial) {
- TALLOC_FREE(nfs4acl);
- errno = EACCES;
- return false;
+ if (S_ISDIR(sbuf.st_ex_mode)) {
+ required_mode = 0777;
+ } else {
+ required_mode = 0666;
+ }
+ if ((sbuf.st_ex_mode & required_mode) != required_mode) {
+ default_acl_style = DEFAULT_ACL_POSIX;
}
- SMB_ASSERT(i == nfs4acl->a_count);
+ return make_default_filesystem_acl(mem_ctx,
+ default_acl_style,
+ smb_fname->base_name,
+ &sbuf,
+ sd);
+}
- *pnfs4acl = nfs4acl;
- return true;
+static NTSTATUS nfs4acl_blob_to_smb4(struct vfs_handle_struct *handle,
+ DATA_BLOB *blob,
+ TALLOC_CTX *mem_ctx,
+ struct SMB4ACL_T **smb4acl)
+{
+ struct nfs4acl_config *config = NULL;
+ NTSTATUS status;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, config,
+ struct nfs4acl_config,
+ return NT_STATUS_INTERNAL_ERROR);
+
+ switch (config->encoding) {
+ case NFS4ACL_ENCODING_NDR:
+ status = nfs4acl_ndr_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
+ break;
+ case NFS4ACL_ENCODING_XDR:
+ status = nfs4acl_xdr_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
+ break;
+ case NFS4ACL_ENCODING_NFS:
+ status = nfs4acl_nfs_blob_to_smb4(handle, mem_ctx, blob, smb4acl);
+ break;
+ default:
+ status = NT_STATUS_INTERNAL_ERROR;
+ break;
+ }
+
+ return status;
}
-static bool nfs4acl_xattr_set_smb4acl(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- struct SMB4ACL_T *smbacl)
+static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ uint32_t security_info,
+ TALLOC_CTX *mem_ctx,
+ struct security_descriptor **sd)
{
+ struct SMB4ACL_T *smb4acl = NULL;
TALLOC_CTX *frame = talloc_stackframe();
- struct nfs4acl *nfs4acl;
- int ret;
- bool denymissingspecial;
DATA_BLOB blob;
+ NTSTATUS status;
- 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"));
+ status = nfs4acl_get_blob(handle, fsp, frame, &blob);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
TALLOC_FREE(frame);
- return false;
+ return nfs4acl_xattr_default_sd(
+ handle, fsp->fsp_name, mem_ctx, sd);
}
-
- blob = nfs4acl_acl2blob(frame, nfs4acl);
- if (!blob.data) {
- DEBUG(0, ("Failed to convert ACL to linear blob for xattr\n"));
+ if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(frame);
- errno = EINVAL;
- return false;
+ return status;
}
- ret = SMB_VFS_NEXT_SETXATTR(handle, smb_fname, NFS4ACL_XATTR_NAME,
- blob.data, blob.length, 0);
- if (ret != 0) {
- DEBUG(0, ("can't store acl in xattr: %s\n", strerror(errno)));
+
+ status = nfs4acl_blob_to_smb4(handle, &blob, frame, &smb4acl);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return status;
}
+
+ status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
+ sd, smb4acl);
TALLOC_FREE(frame);
- return ret == 0;
+ return status;
}
-/* 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,
- struct SMB4ACL_T *smbacl)
+static bool nfs4acl_smb4acl_set_fn(vfs_handle_struct *handle,
+ files_struct *fsp,
+ struct SMB4ACL_T *smb4acl)
{
- TALLOC_CTX *frame = talloc_stackframe();
- struct nfs4acl *nfs4acl;
- int ret;
- bool denymissingspecial;
+ struct nfs4acl_config *config = NULL;
DATA_BLOB blob;
+ NTSTATUS status;
+ int saved_errno = 0;
+ int ret;
- 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);
+ SMB_VFS_HANDLE_GET_DATA(handle, config,
+ struct nfs4acl_config,
+ return false);
+
+ switch (config->encoding) {
+ case NFS4ACL_ENCODING_NDR:
+ status = nfs4acl_smb4acl_to_ndr_blob(handle, talloc_tos(),
+ smb4acl, &blob);
+ break;
+ case NFS4ACL_ENCODING_XDR:
+ status = nfs4acl_smb4acl_to_xdr_blob(handle, talloc_tos(),
+ smb4acl, &blob);
+ break;
+ case NFS4ACL_ENCODING_NFS:
+ status = nfs4acl_smb4acl_to_nfs_blob(handle, talloc_tos(),
+ smb4acl, &blob);
+ break;
+ default:
+ status = NT_STATUS_INTERNAL_ERROR;
+ break;
+ }
+ if (!NT_STATUS_IS_OK(status)) {
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;
+ ret = SMB_VFS_NEXT_FSETXATTR(handle, fsp, config->xattr_name,
+ blob.data, blob.length, 0);
+ if (ret != 0) {
+ saved_errno = errno;
}
- if (fsp->fh->fd == -1) {
- DEBUG(0, ("Error: fsp->fh->fd == -1\n"));
+ data_blob_free(&blob);
+ if (saved_errno != 0) {
+ errno = saved_errno;
}
- 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)));
+ DBG_ERR("can't store acl in xattr: %s\n", strerror(errno));
+ return false;
}
- 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_t security_info_sent,
- const struct security_descriptor *psd)
-{
- return smb_set_nt_acl_nfs4(handle, fsp, NULL, security_info_sent, psd,
- nfs4acl_xattr_fset_smb4acl);
-}
-static struct SMB4ACL_T *nfs4acls_defaultacl(TALLOC_CTX *mem_ctx)
-{
- struct SMB4ACL_T *pacl = NULL;
- struct SMB4ACE_T *pace;
- SMB_ACE4PROP_T ace = {
- .flags = SMB_ACE4_ID_SPECIAL,
- .who = {
- .id = SMB_ACE4_WHO_EVERYONE,
- },
- .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE,
- .aceFlags = 0,
- .aceMask = 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;
+ return true;
}
-/*
- * 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 struct SMB4ACL_T *nfs4acls_inheritacl(vfs_handle_struct *handle,
- const char *path,
- TALLOC_CTX *mem_ctx)
+static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
+ files_struct *fsp,
+ uint32_t security_info_sent,
+ const struct security_descriptor *psd)
{
- char *parent_dir = NULL;
- struct SMB4ACL_T *pparentacl = NULL;
- struct SMB4ACL_T *pchildacl = NULL;
- struct SMB4ACE_T *pace;
- SMB_ACE4PROP_T ace;
- bool isdir;
- struct smb_filename *smb_fname = NULL;
+ struct nfs4acl_config *config = NULL;
+ const struct security_token *token = NULL;
+ mode_t existing_mode;
+ mode_t expected_mode;
+ mode_t restored_mode;
+ bool chown_needed = false;
+ struct dom_sid_buf buf;
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, 0);
- if (smb_fname == NULL) {
- TALLOC_FREE(frame);
- errno = ENOMEM;
- return NULL;
- }
+ SMB_VFS_HANDLE_GET_DATA(handle, config,
+ struct nfs4acl_config,
+ return NT_STATUS_INTERNAL_ERROR);
- 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;
+ if (!VALID_STAT(fsp->fsp_name->st)) {
+ DBG_ERR("Invalid stat info on [%s]\n", fsp_str_dbg(fsp));
+ return NT_STATUS_INTERNAL_ERROR;
}
- 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;
+ existing_mode = fsp->fsp_name->st.st_ex_mode;
+ if (S_ISDIR(existing_mode)) {
+ expected_mode = 0777;
+ } else {
+ expected_mode = 0666;
}
-
- 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);
+ if (!config->validate_mode) {
+ existing_mode = 0;
+ expected_mode = 0;
}
- else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
- pparentacl = nfs4acls_defaultacl(frame);
+ if ((existing_mode & expected_mode) != expected_mode) {
- }
- else if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(frame);
- return NULL;
- }
+ restored_mode = existing_mode | expected_mode;
- 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)) {
- struct 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 (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;
+ ret = SMB_VFS_NEXT_FCHMOD(handle,
+ fsp,
+ restored_mode);
+ if (ret != 0) {
+ DBG_ERR("Resetting POSIX mode on [%s] from [0%o]: %s\n",
+ fsp_str_dbg(fsp), existing_mode,
+ strerror(errno));
+ return map_nt_error_from_unix(errno);
}
- 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, smb_fname, pchildacl);
-
- TALLOC_FREE(frame);
- return pchildacl;
-}
-
-static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,
- struct files_struct *fsp,
- uint32_t security_info,
- TALLOC_CTX *mem_ctx,
- struct security_descriptor **ppdesc)
-{
- struct SMB4ACL_T *pacl;
- NTSTATUS status;
- TALLOC_CTX *frame = talloc_stackframe();
-
- status = nfs4_fget_nfs4_acl(handle, frame, fsp, &pacl);
- if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
- pacl = nfs4acls_inheritacl(handle, fsp->fsp_name->base_name,
- frame);
+ status = smb_set_nt_acl_nfs4(handle,
+ fsp,
+ &config->nfs4_params,
+ security_info_sent,
+ psd,
+ nfs4acl_smb4acl_set_fn);
+ if (NT_STATUS_IS_OK(status)) {
+ return NT_STATUS_OK;
}
- else if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(frame);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
return status;
}
- status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
- ppdesc, pacl);
- TALLOC_FREE(frame);
- return status;
-}
+ /*
+ * We got access denied. If we're already root, or we didn't
+ * need to do a chown, or the fsp isn't open with WRITE_OWNER
+ * access, just return.
+ */
-static NTSTATUS nfs4acl_xattr_get_nt_acl(struct vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- uint32_t security_info,
- TALLOC_CTX *mem_ctx,
- struct security_descriptor **ppdesc)
-{
- struct SMB4ACL_T *pacl;
- NTSTATUS status;
- const char *name = smb_fname->base_name;
- TALLOC_CTX *frame = talloc_stackframe();
+ if ((security_info_sent & SECINFO_OWNER) &&
+ (psd->owner_sid != NULL))
+ {
+ chown_needed = true;
+ }
+ if ((security_info_sent & SECINFO_GROUP) &&
+ (psd->group_sid != NULL))
+ {
+ chown_needed = true;
+ }
- status = nfs4_get_nfs4_acl(handle, frame, name, &pacl);
- if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
- pacl = nfs4acls_inheritacl(handle, name, frame);
+ if (get_current_uid(handle->conn) == 0 ||
+ chown_needed == false)
+ {
+ return NT_STATUS_ACCESS_DENIED;
}
- else if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(frame);
+ status = check_any_access_fsp(fsp, SEC_STD_WRITE_OWNER);
+ if (!NT_STATUS_IS_OK(status)) {
return status;
}
- status = smb_get_nt_acl_nfs4(handle->conn, smb_fname, NULL,
- security_info, mem_ctx, ppdesc,
- pacl);
- TALLOC_FREE(frame);
+ /*
+ * Only allow take-ownership, not give-ownership. That's the way Windows
+ * implements SEC_STD_WRITE_OWNER. MS-FSA 2.1.5.16 just states: If
+ * InputBuffer.OwnerSid is not a valid owner SID for a file in the
+ * objectstore, as determined in an implementation specific manner, the
+ * object store MUST return STATUS_INVALID_OWNER.
+ */
+ token = get_current_nttok(fsp->conn);
+ if (!security_token_is_sid(token, psd->owner_sid)) {
+ return NT_STATUS_INVALID_OWNER;
+ }
+
+ DBG_DEBUG("overriding chown on file %s for sid %s\n",
+ fsp_str_dbg(fsp),
+ dom_sid_str_buf(psd->owner_sid, &buf));
+
+ status = smb_set_nt_acl_nfs4(handle,
+ fsp,
+ &config->nfs4_params,
+ security_info_sent,
+ psd,
+ nfs4acl_smb4acl_set_fn);
return status;
}
-static NTSTATUS nfs4acl_xattr_fset_nt_acl(vfs_handle_struct *handle,
- files_struct *fsp,
- uint32_t security_info_sent,
- const struct security_descriptor *psd)
+static int nfs4acl_connect(struct vfs_handle_struct *handle,
+ const char *service,
+ const char *user)
{
- return nfs4_set_nt_acl(handle, fsp, security_info_sent, psd);
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
+ struct nfs4acl_config *config = NULL;
+ const struct enum_list *default_acl_style_list = NULL;
+ const char *default_xattr_name = NULL;
+ bool default_validate_mode = true;
+ int enumval;
+ unsigned nfs_version;
+ int ret;
+
+ default_acl_style_list = get_default_acl_style_list();
+
+ config = talloc_zero(handle->conn, struct nfs4acl_config);
+ if (config == NULL) {
+ DBG_ERR("talloc_zero() failed\n");
+ return -1;
+ }
+
+ ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
+ if (ret < 0) {
+ TALLOC_FREE(config);
+ return ret;
+ }
+
+ ret = smbacl4_get_vfs_params(handle->conn, &config->nfs4_params);
+ if (ret < 0) {
+ TALLOC_FREE(config);
+ return ret;
+ }
+
+ enumval = lp_parm_enum(SNUM(handle->conn),
+ "nfs4acl_xattr",
+ "encoding",
+ nfs4acl_encoding,
+ NFS4ACL_ENCODING_NDR);
+ if (enumval == -1) {
+ DBG_ERR("Invalid \"nfs4acl_xattr:encoding\" parameter\n");
+ return -1;
+ }
+ config->encoding = (enum nfs4acl_encoding)enumval;
+
+ switch (config->encoding) {
+ case NFS4ACL_ENCODING_XDR:
+ default_xattr_name = NFS4ACL_XDR_XATTR_NAME;
+ break;
+ case NFS4ACL_ENCODING_NFS:
+ default_xattr_name = NFS4ACL_NFS_XATTR_NAME;
+ default_validate_mode = false;
+ break;
+ case NFS4ACL_ENCODING_NDR:
+ default:
+ default_xattr_name = NFS4ACL_NDR_XATTR_NAME;
+ break;
+ }
+
+ nfs_version = (unsigned)lp_parm_int(SNUM(handle->conn),
+ "nfs4acl_xattr",
+ "version",
+ 41);
+ switch (nfs_version) {
+ case 40:
+ config->nfs_version = ACL4_XATTR_VERSION_40;
+ break;
+ case 41:
+ config->nfs_version = ACL4_XATTR_VERSION_41;
+ break;
+ default:
+ config->nfs_version = ACL4_XATTR_VERSION_DEFAULT;
+ break;
+ }
+
+ config->default_acl_style = lp_parm_enum(SNUM(handle->conn),
+ "nfs4acl_xattr",
+ "default acl style",
+ default_acl_style_list,
+ DEFAULT_ACL_EVERYONE);
+
+ config->xattr_name = lp_parm_substituted_string(config, lp_sub,
+ SNUM(handle->conn),
+ "nfs4acl_xattr",
+ "xattr_name",
+ default_xattr_name);
+
+ config->nfs4_id_numeric = lp_parm_bool(SNUM(handle->conn),
+ "nfs4acl_xattr",
+ "nfs4_id_numeric",
+ false);
+
+
+ config->validate_mode = lp_parm_bool(SNUM(handle->conn),
+ "nfs4acl_xattr",
+ "validate_mode",
+ default_validate_mode);
+
+ SMB_VFS_HANDLE_SET_DATA(handle, config, NULL, struct nfs4acl_config,
+ return -1);
+
+ /*
+ * Ensure we have the parameters correct if we're using this module.
+ */
+ DBG_NOTICE("Setting 'inherit acls = true', "
+ "'dos filemode = true', "
+ "'force unknown acl user = true', "
+ "'create mask = 0666', "
+ "'directory mask = 0777' and "
+ "'store dos attributes = yes' "
+ "for service [%s]\n", service);
+
+ lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
+ lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
+ lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
+ lp_do_parameter(SNUM(handle->conn), "create mask", "0666");
+ lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
+ lp_do_parameter(SNUM(handle->conn), "store dos attributes", "yes");
+
+ return 0;
}
/*
Function declarations taken from vfs_solarisacl
*/
-static SMB_ACL_T nfs4acl_xattr_fail__sys_acl_get_file(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- 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,
+ SMB_ACL_TYPE_T type,
TALLOC_CTX *mem_ctx)
{
return (SMB_ACL_T)NULL;
}
-static int nfs4acl_xattr_fail__sys_acl_set_file(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- 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_TYPE_T type,
SMB_ACL_T theacl)
{
return -1;
}
-static int nfs4acl_xattr_fail__sys_acl_delete_def_file(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname)
-{
- return -1;
-}
-
-static int nfs4acl_xattr_fail__sys_acl_blob_get_file(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- TALLOC_CTX *mem_ctx,
- char **blob_description,
- DATA_BLOB *blob)
+static int nfs4acl_xattr_fail__sys_acl_delete_def_fd(vfs_handle_struct *handle,
+ files_struct *fsp)
{
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,
+ .connect_fn = nfs4acl_connect,
+ .fget_nt_acl_fn = nfs4acl_xattr_fget_nt_acl,
+ .fset_nt_acl_fn = nfs4acl_xattr_fset_nt_acl,
+
.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,
+ .sys_acl_delete_def_fd_fn = nfs4acl_xattr_fail__sys_acl_delete_def_fd,
};
-NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *);
+static_decl_vfs;
NTSTATUS vfs_nfs4acl_xattr_init(TALLOC_CTX *ctx)
{
return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "nfs4acl_xattr",