summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/proto.h1
-rw-r--r--source3/lib/secdesc.c20
-rw-r--r--source3/modules/vfs_acl_common.c299
3 files changed, 151 insertions, 169 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 7013709fbb..8f14ef8702 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -691,6 +691,7 @@ SEC_DESC_BUF *dup_sec_desc_buf(TALLOC_CTX *ctx, SEC_DESC_BUF *src);
NTSTATUS sec_desc_add_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, uint32 mask, size_t *sd_size);
NTSTATUS sec_desc_mod_sid(SEC_DESC *sd, DOM_SID *sid, uint32 mask);
NTSTATUS sec_desc_del_sid(TALLOC_CTX *ctx, SEC_DESC **psd, DOM_SID *sid, size_t *sd_size);
+bool sd_has_inheritable_components(const SEC_DESC *parent_ctr, bool container);
NTSTATUS se_create_child_secdesc(TALLOC_CTX *ctx,
SEC_DESC **ppsd,
size_t *psize,
diff --git a/source3/lib/secdesc.c b/source3/lib/secdesc.c
index 5e35181834..d45be00212 100644
--- a/source3/lib/secdesc.c
+++ b/source3/lib/secdesc.c
@@ -474,6 +474,26 @@ static bool is_inheritable_ace(const SEC_ACE *ace,
return false;
}
+/*
+ * Does a security descriptor have any inheritable components for
+ * the newly created type ?
+ */
+
+bool sd_has_inheritable_components(const SEC_DESC *parent_ctr, bool container)
+{
+ unsigned int i;
+ const SEC_ACL *the_acl = parent_ctr->dacl;
+
+ for (i = 0; i < the_acl->num_aces; i++) {
+ const SEC_ACE *ace = &the_acl->aces[i];
+
+ if (is_inheritable_ace(ace, container)) {
+ return true;
+ }
+ }
+ return false;
+}
+
/* Create a child security descriptor using another security descriptor as
the parent container. This child object can either be a container or
non-container object. */
diff --git a/source3/modules/vfs_acl_common.c b/source3/modules/vfs_acl_common.c
index 68bf0b0530..570d14b4b2 100644
--- a/source3/modules/vfs_acl_common.c
+++ b/source3/modules/vfs_acl_common.c
@@ -162,7 +162,8 @@ static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
/*******************************************************************
Pull a DATA_BLOB from an xattr given a pathname.
- DOES NOT FALL BACK TO THE UNDERLYING ACLs ON THE FILESYSTEM.
+ If the hash doesn't match, or doesn't exist - return the underlying
+ filesystem sd.
*******************************************************************/
static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
@@ -176,6 +177,7 @@ static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
uint16_t hash_type;
uint8_t hash[XATTR_SD_HASH_SIZE];
uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
+ struct security_descriptor *psd = NULL;
struct security_descriptor *pdesc_next = NULL;
if (fsp && name == NULL) {
@@ -184,97 +186,106 @@ static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
DEBUG(10, ("get_nt_acl_internal: name=%s\n", name));
+ /* Get the full underlying sd for the hash
+ or to return as backup. */
+ if (fsp) {
+ status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
+ fsp,
+ HASH_SECURITY_INFO,
+ &pdesc_next);
+ } else {
+ status = SMB_VFS_NEXT_GET_NT_ACL(handle,
+ name,
+ HASH_SECURITY_INFO,
+ &pdesc_next);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
+ "returned %s\n",
+ name,
+ nt_errstr(status)));
+ return status;
+ }
+
status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
nt_errstr(status)));
- return status;
+ psd = pdesc_next;
+ goto out;
}
- status = parse_acl_blob(&blob, ppdesc,
+ status = parse_acl_blob(&blob, &psd,
&hash_type, &hash[0]);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("parse_acl_blob returned %s\n",
nt_errstr(status)));
- return status;
+ psd = pdesc_next;
+ goto out;
}
/* Ensure the hash type is one we know. */
switch (hash_type) {
case XATTR_SD_HASH_TYPE_NONE:
- /* No hash, goto return blob sd. */
+ /* No hash, just return blob sd. */
goto out;
case XATTR_SD_HASH_TYPE_SHA256:
break;
default:
- return NT_STATUS_REVISION_MISMATCH;
- }
-
- /* Get the full underlying sd, then hash. */
- if (fsp) {
- status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
- fsp,
- HASH_SECURITY_INFO,
- &pdesc_next);
- } else {
- status = SMB_VFS_NEXT_GET_NT_ACL(handle,
- name,
- HASH_SECURITY_INFO,
- &pdesc_next);
+ DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
+ "mismatch (%u) for file %s\n",
+ (unsigned int)hash_type,
+ name));
+ TALLOC_FREE(psd);
+ psd = pdesc_next;
+ goto out;
}
- if (!NT_STATUS_IS_OK(status)) {
- goto out;
- }
status = hash_sd_sha256(pdesc_next, hash_tmp);
if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(psd);
+ psd = pdesc_next;
goto out;
}
if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
- TALLOC_FREE(pdesc_next);
/* Hash matches, return blob sd. */
goto out;
}
/* Hash doesn't match, return underlying sd. */
-
- if (!(security_info & OWNER_SECURITY_INFORMATION)) {
- pdesc_next->owner_sid = NULL;
- }
- if (!(security_info & GROUP_SECURITY_INFORMATION)) {
- pdesc_next->group_sid = NULL;
- }
- if (!(security_info & DACL_SECURITY_INFORMATION)) {
- pdesc_next->dacl = NULL;
- }
- if (!(security_info & SACL_SECURITY_INFORMATION)) {
- pdesc_next->sacl = NULL;
- }
-
- TALLOC_FREE(*ppdesc);
- *ppdesc = pdesc_next;
+ TALLOC_FREE(psd);
+ psd = pdesc_next;
out:
+ if (psd != pdesc_next) {
+ /* We're returning the blob, throw
+ * away the filesystem SD. */
+ TALLOC_FREE(pdesc_next);
+ }
+
if (!(security_info & OWNER_SECURITY_INFORMATION)) {
- (*ppdesc)->owner_sid = NULL;
+ psd->owner_sid = NULL;
}
if (!(security_info & GROUP_SECURITY_INFORMATION)) {
- (*ppdesc)->group_sid = NULL;
+ psd->group_sid = NULL;
}
if (!(security_info & DACL_SECURITY_INFORMATION)) {
- (*ppdesc)->dacl = NULL;
+ psd->dacl = NULL;
}
if (!(security_info & SACL_SECURITY_INFORMATION)) {
- (*ppdesc)->sacl = NULL;
+ psd->sacl = NULL;
}
TALLOC_FREE(blob.data);
- return status;
+ *ppdesc = psd;
+ return NT_STATUS_OK;
}
+#if 0
/*********************************************************************
Create a default security descriptor for a file in case no inheritance
exists. All permissions to the owner and SYSTEM.
@@ -330,124 +341,60 @@ static struct security_descriptor *default_file_sd(TALLOC_CTX *mem_ctx,
pacl,
&sd_size);
}
+#endif
/*********************************************************************
+ Create a default ACL by inheriting from the parent. If no inheritance
+ from the parent available, just use the actual permissions the new
+ file or directory already got from the filesystem.
*********************************************************************/
static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
struct smb_filename *smb_fname,
files_struct *fsp,
- bool container)
+ struct security_descriptor *parent_desc,
+ bool is_directory)
{
TALLOC_CTX *ctx = talloc_tos();
- NTSTATUS status;
- struct security_descriptor *parent_desc = NULL;
+ NTSTATUS status = NT_STATUS_OK;
struct security_descriptor *psd = NULL;
struct security_descriptor *pdesc_next = NULL;
DATA_BLOB blob;
size_t size;
- char *parent_name;
- bool force_inherit = false;
uint8_t hash[XATTR_SD_HASH_SIZE];
- if (!parent_dirname(ctx, smb_fname->base_name, &parent_name, NULL)) {
- return NT_STATUS_NO_MEMORY;
- }
+ if (parent_desc == NULL) {
+ /* We don't already have the parent sd, fetch it now. */
+ char *parent_name;
- DEBUG(10,("inherit_new_acl: check directory %s\n",
- parent_name));
+ if (!parent_dirname(ctx, smb_fname->base_name, &parent_name, NULL)) {
+ return NT_STATUS_NO_MEMORY;
+ }
- status = get_nt_acl_internal(handle,
+ DEBUG(10,("inherit_new_acl: check directory %s\n",
+ parent_name));
+
+ status = get_nt_acl_internal(handle,
NULL,
parent_name,
(OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION),
&parent_desc);
- if (NT_STATUS_IS_OK(status)) {
- /* Create an inherited descriptor from the parent. */
- if (DEBUGLEVEL >= 10) {
- DEBUG(10,("inherit_new_acl: parent acl is:\n"));
- NDR_PRINT_DEBUG(security_descriptor, parent_desc);
- }
-
- status = se_create_child_secdesc(ctx,
- &psd,
- &size,
- parent_desc,
- &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX],
- &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX],
- container);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- if (DEBUGLEVEL >= 10) {
- DEBUG(10,("inherit_new_acl: child acl is:\n"));
- NDR_PRINT_DEBUG(security_descriptor, psd);
- }
-
- } else {
- DEBUG(10,("inherit_new_acl: directory %s failed "
- "to get acl %s\n",
- parent_name,
- nt_errstr(status) ));
- }
-
- if (!psd || psd->dacl == NULL) {
-
- TALLOC_FREE(psd);
- if (fsp) {
- status = vfs_stat_fsp(fsp);
- smb_fname->st = fsp->fsp_name->st;
- } else {
- int ret;
- if (lp_posix_pathnames()) {
- ret = SMB_VFS_LSTAT(handle->conn, smb_fname);
- } else {
- ret = SMB_VFS_STAT(handle->conn, smb_fname);
- }
- if (ret == -1) {
- status = map_nt_error_from_unix(errno);
- }
- }
if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10,("inherit_new_acl: directory %s failed "
+ "to get acl BLOB %s\n",
+ parent_name,
+ nt_errstr(status) ));
return status;
}
-
- /* If we get here, we could have the following possibilities:
- * 1. No ACLs exist on the parent container.
- * 2. ACLs exist on the parent container but they were
- * not inheritable.
- *
- * Check to see if case #1 occurred.
- *
- */
- if (container &&
- (parent_desc == NULL || parent_desc->dacl == NULL)) {
-
- /* If no parent descriptor exists, then there were
- * no ACLs on the parent and then we must create
- * the ACLs on this newly created folder so that they
- * will be inherited by their children (See Bug #6802).
- */
-
- force_inherit = true;
- }
-
- psd = default_file_sd(ctx, &smb_fname->st, force_inherit);
- if (!psd) {
- return NT_STATUS_NO_MEMORY;
- }
-
- if (DEBUGLEVEL >= 10) {
- DEBUG(10,("inherit_new_acl: default acl is:\n"));
- NDR_PRINT_DEBUG(security_descriptor, psd);
- }
}
- /* Object exists. Read the current SD to get the hash. */
+ /*
+ * Object must exist. Read the current SD off the filesystem
+ * for the hash.
+ */
if (fsp) {
status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
fsp,
@@ -461,9 +408,44 @@ static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
}
if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10,("inherit_new_acl: get_next_acl \n"
+ "failed for %s (%s)\n",
+ smb_fname_str_dbg(smb_fname),
+ nt_errstr(status) ));
return status;
}
+ if (parent_desc && sd_has_inheritable_components(parent_desc, is_directory)) {
+ /* Create an inherited descriptor from the parent. */
+
+ if (DEBUGLEVEL >= 10) {
+ DEBUG(10,("inherit_new_acl: parent acl is:\n"));
+ NDR_PRINT_DEBUG(security_descriptor, parent_desc);
+ }
+
+ status = se_create_child_secdesc(ctx,
+ &psd,
+ &size,
+ parent_desc,
+ &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX],
+ &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX],
+ is_directory);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ } else {
+ DEBUG(10,("inherit_new_acl: using current permissions.\n"
+ "to set Windows acl for %s\n",
+ smb_fname_str_dbg(smb_fname) ));
+ psd = pdesc_next;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ DEBUG(10,("inherit_new_acl: child acl is:\n"));
+ NDR_PRINT_DEBUG(security_descriptor, psd);
+ }
+
status = hash_sd_sha256(pdesc_next, hash);
if (!NT_STATUS_IS_OK(status)) {
return status;
@@ -482,7 +464,8 @@ static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
const char *path,
- uint32_t access_mask)
+ uint32_t access_mask,
+ struct security_descriptor **pp_parent_desc)
{
char *parent_name = NULL;
struct security_descriptor *parent_desc = NULL;
@@ -501,18 +484,6 @@ static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
DACL_SECURITY_INFORMATION),
&parent_desc);
- if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
- /* No Windows ACL stored as a blob. Let the
- * underlying filesystem take care of checking
- * permissions. */
- DEBUG(10,("check_parent_acl_common: no Windows ACL blob "
- "stored on directory %s for "
- "path %s\n",
- parent_name,
- path ));
- return NT_STATUS_OK;
- }
-
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10,("check_parent_acl_common: get_nt_acl_internal "
"on directory %s for "
@@ -536,6 +507,9 @@ static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
nt_errstr(status) ));
return status;
}
+ if (pp_parent_desc) {
+ *pp_parent_desc = parent_desc;
+ }
return NT_STATUS_OK;
}
@@ -551,6 +525,7 @@ static int open_acl_common(vfs_handle_struct *handle,
{
uint32_t access_granted = 0;
struct security_descriptor *pdesc = NULL;
+ struct security_descriptor *parent_desc = NULL;
bool file_existed = true;
char *fname = NULL;
NTSTATUS status;
@@ -596,7 +571,7 @@ static int open_acl_common(vfs_handle_struct *handle,
*/
if (flags & O_CREAT) {
status = check_parent_acl_common(handle, fname,
- SEC_DIR_ADD_FILE);
+ SEC_DIR_ADD_FILE, &parent_desc);
if (!NT_STATUS_IS_OK(status)) {
goto err;
}
@@ -616,7 +591,7 @@ static int open_acl_common(vfs_handle_struct *handle,
if (!NT_STATUS_IS_OK(status)) {
goto err;
}
- inherit_new_acl(handle, smb_fname, fsp, false);
+ inherit_new_acl(handle, smb_fname, fsp, parent_desc, false);
}
return fsp->fh->fd;
@@ -633,12 +608,13 @@ static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t
int ret;
NTSTATUS status;
SMB_STRUCT_STAT sbuf;
+ struct security_descriptor *parent_desc = NULL;
ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
if (ret == -1 && errno == ENOENT) {
/* We're creating a new directory. */
status = check_parent_acl_common(handle, path,
- SEC_DIR_ADD_SUBDIR);
+ SEC_DIR_ADD_SUBDIR, &parent_desc);
if (!NT_STATUS_IS_OK(status)) {
errno = map_errno_from_nt_status(status);
return -1;
@@ -658,7 +634,7 @@ static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t
}
/* New directory - inherit from parent. */
- inherit_new_acl(handle, smb_fname, NULL, true);
+ inherit_new_acl(handle, smb_fname, NULL, parent_desc, true);
TALLOC_FREE(smb_fname);
return ret;
}
@@ -670,16 +646,8 @@ static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t
static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
uint32_t security_info, struct security_descriptor **ppdesc)
{
- NTSTATUS status = get_nt_acl_internal(handle, fsp,
+ return get_nt_acl_internal(handle, fsp,
NULL, security_info, ppdesc);
- if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
- /* Pull the ACL from the underlying system. */
- status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
- fsp,
- security_info,
- ppdesc);
- }
- return status;
}
/*********************************************************************
@@ -689,16 +657,8 @@ static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
{
- NTSTATUS status = get_nt_acl_internal(handle, NULL,
+ return get_nt_acl_internal(handle, NULL,
name, security_info, ppdesc);
- if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
- /* Pull the ACL from the underlying system. */
- status = SMB_VFS_NEXT_GET_NT_ACL(handle,
- name,
- security_info,
- ppdesc);
- }
- return status;
}
/*********************************************************************
@@ -798,7 +758,8 @@ static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
const char *fname, const char *mask, uint32 attr)
{
- NTSTATUS status = check_parent_acl_common(handle, fname, SEC_DIR_LIST);
+ NTSTATUS status = check_parent_acl_common(handle, fname,
+ SEC_DIR_LIST, NULL);
if (!NT_STATUS_IS_OK(status)) {
errno = map_errno_from_nt_status(status);