summaryrefslogtreecommitdiff
path: root/source4/ntvfs/posix/pvfs_acl.c
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2009-10-17 21:17:29 +1100
committerAndrew Tridgell <tridge@samba.org>2009-10-18 07:13:47 +1100
commit0463d698835053af680db4f388c732d2557f7c8a (patch)
tree49b155b104c4c8c41f42560e8032e666ca37a036 /source4/ntvfs/posix/pvfs_acl.c
parentd1efaf39f51102835eda9aca12433e926354da77 (diff)
downloadsamba-0463d698835053af680db4f388c732d2557f7c8a.tar.gz
samba-0463d698835053af680db4f388c732d2557f7c8a.tar.bz2
samba-0463d698835053af680db4f388c732d2557f7c8a.zip
s4-pvfs: change the handling of access checking on create
Previously when a file was created, we produces the resulting access mask based on an ACL check against the parent. This change means we now calculate the inherited ACL much earlier, and produce the resulting access mask from that ACL, or the user supplied ACL.
Diffstat (limited to 'source4/ntvfs/posix/pvfs_acl.c')
-rw-r--r--source4/ntvfs/posix/pvfs_acl.c149
1 files changed, 103 insertions, 46 deletions
diff --git a/source4/ntvfs/posix/pvfs_acl.c b/source4/ntvfs/posix/pvfs_acl.c
index 26515cfe1a..842aced6f2 100644
--- a/source4/ntvfs/posix/pvfs_acl.c
+++ b/source4/ntvfs/posix/pvfs_acl.c
@@ -485,6 +485,8 @@ static bool pvfs_group_member(struct pvfs_state *pvfs, gid_t gid)
doing this saves on building a full security descriptor
for the common case of access check on files with no
specific NT ACL
+
+ If name is NULL then treat as a new file creation
*/
NTSTATUS pvfs_access_check_unix(struct pvfs_state *pvfs,
struct ntvfs_request *req,
@@ -499,13 +501,14 @@ NTSTATUS pvfs_access_check_unix(struct pvfs_state *pvfs,
return NT_STATUS_ACCESS_DENIED;
}
- if (uid == name->st.st_uid) {
+ if (name == NULL || uid == name->st.st_uid) {
max_bits |= SEC_STD_ALL;
} else if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
max_bits |= SEC_STD_DELETE;
}
- if ((name->st.st_mode & S_IWOTH) ||
+ if (name == NULL ||
+ (name->st.st_mode & S_IWOTH) ||
((name->st.st_mode & S_IWGRP) &&
pvfs_group_member(pvfs, name->st.st_gid))) {
max_bits |= SEC_STD_ALL;
@@ -540,7 +543,7 @@ NTSTATUS pvfs_access_check_unix(struct pvfs_state *pvfs,
if (*access_mask & ~max_bits) {
DEBUG(0,(__location__ " denied access to '%s' - wanted 0x%08x but got 0x%08x (missing 0x%08x)\n",
- name->full_name, *access_mask, max_bits, *access_mask & ~max_bits));
+ name?name->full_name:"(new file)", *access_mask, max_bits, *access_mask & ~max_bits));
return NT_STATUS_ACCESS_DENIED;
}
@@ -643,26 +646,47 @@ NTSTATUS pvfs_access_check_simple(struct pvfs_state *pvfs,
NTSTATUS pvfs_access_check_create(struct pvfs_state *pvfs,
struct ntvfs_request *req,
struct pvfs_filename *name,
- uint32_t *access_mask)
+ uint32_t *access_mask,
+ bool container,
+ struct security_descriptor **sd)
{
struct pvfs_filename *parent;
NTSTATUS status;
+ struct security_token *token = req->session_info->security_token;
+
+ if (pvfs_read_only(pvfs, *access_mask)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
status = pvfs_resolve_parent(pvfs, req, name, &parent);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- status = pvfs_access_check(pvfs, req, parent, access_mask);
+ status = pvfs_access_check_simple(pvfs, req, parent, SEC_DIR_ADD_FILE);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- if (! ((*access_mask) & SEC_DIR_ADD_FILE)) {
- return pvfs_access_check_simple(pvfs, req, parent, SEC_DIR_ADD_FILE);
+ if (*sd == NULL) {
+ status = pvfs_acl_inherited_sd(pvfs, req, req, parent, container, sd);
}
- return status;
+ talloc_free(parent);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* expand the generic access bits to file specific bits */
+ *access_mask = pvfs_translate_mask(*access_mask);
+ if (pvfs->ntvfs->ctx->protocol != PROTOCOL_SMB2) {
+ *access_mask &= ~SEC_FILE_READ_ATTRIBUTE;
+ }
+
+ if (*sd == NULL) {
+ return pvfs_access_check_unix(pvfs, req, NULL, access_mask);
+ }
+ return sec_access_check(*sd, token, *access_mask, access_mask);
}
/*
@@ -790,47 +814,42 @@ static NTSTATUS pvfs_acl_inherit_aces(struct pvfs_state *pvfs,
/*
- setup an ACL on a new file/directory based on the inherited ACL from
- the parent. If there is no inherited ACL then we don't set anything,
- as the default ACL applies anyway
+ calculate the ACL on a new file/directory based on the inherited ACL
+ from the parent. If there is no inherited ACL then return a NULL
+ ACL, which means the default ACL should be used
*/
-NTSTATUS pvfs_acl_inherit(struct pvfs_state *pvfs,
- struct ntvfs_request *req,
- struct pvfs_filename *name,
- int fd)
+NTSTATUS pvfs_acl_inherited_sd(struct pvfs_state *pvfs,
+ TALLOC_CTX *mem_ctx,
+ struct ntvfs_request *req,
+ struct pvfs_filename *parent,
+ bool container,
+ struct security_descriptor **ret_sd)
{
struct xattr_NTACL *acl;
NTSTATUS status;
- struct pvfs_filename *parent;
struct security_descriptor *parent_sd, *sd;
- bool container;
struct id_mapping *ids;
struct composite_context *ctx;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
- /* form the parents path */
- status = pvfs_resolve_parent(pvfs, req, name, &parent);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
+ *ret_sd = NULL;
acl = talloc(req, struct xattr_NTACL);
- if (acl == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
+ NT_STATUS_HAVE_NO_MEMORY_AND_FREE(acl, tmp_ctx);
status = pvfs_acl_load(pvfs, parent, -1, acl);
if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+ talloc_free(tmp_ctx);
return NT_STATUS_OK;
}
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
+ NT_STATUS_NOT_OK_RETURN_AND_FREE(status, tmp_ctx);
switch (acl->version) {
case 1:
parent_sd = acl->info.sd;
break;
default:
+ talloc_free(tmp_ctx);
return NT_STATUS_INVALID_ACL;
}
@@ -838,61 +857,99 @@ NTSTATUS pvfs_acl_inherit(struct pvfs_state *pvfs,
parent_sd->dacl == NULL ||
parent_sd->dacl->num_aces == 0) {
/* go with the default ACL */
+ talloc_free(tmp_ctx);
return NT_STATUS_OK;
}
/* create the new sd */
sd = security_descriptor_initialise(req);
- if (sd == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
+ NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sd, tmp_ctx);
ids = talloc_array(sd, struct id_mapping, 2);
- NT_STATUS_HAVE_NO_MEMORY(ids);
+ NT_STATUS_HAVE_NO_MEMORY_AND_FREE(ids, tmp_ctx);
ids[0].unixid = talloc(ids, struct unixid);
- NT_STATUS_HAVE_NO_MEMORY(ids[0].unixid);
- ids[0].unixid->id = name->st.st_uid;
+ NT_STATUS_HAVE_NO_MEMORY_AND_FREE(ids[0].unixid, tmp_ctx);
+ ids[0].unixid->id = geteuid();
ids[0].unixid->type = ID_TYPE_UID;
ids[0].sid = NULL;
ids[0].status = NT_STATUS_NONE_MAPPED;
ids[1].unixid = talloc(ids, struct unixid);
- NT_STATUS_HAVE_NO_MEMORY(ids[1].unixid);
- ids[1].unixid->id = name->st.st_gid;
+ NT_STATUS_HAVE_NO_MEMORY_AND_FREE(ids[1].unixid, tmp_ctx);
+ ids[1].unixid->id = getegid();
ids[1].unixid->type = ID_TYPE_GID;
ids[1].sid = NULL;
ids[1].status = NT_STATUS_NONE_MAPPED;
ctx = wbc_xids_to_sids_send(pvfs->wbc_ctx, ids, 2, ids);
- NT_STATUS_HAVE_NO_MEMORY(ctx);
+ NT_STATUS_HAVE_NO_MEMORY_AND_FREE(ctx, tmp_ctx);
status = wbc_xids_to_sids_recv(ctx, &ids);
- NT_STATUS_NOT_OK_RETURN(status);
+ NT_STATUS_NOT_OK_RETURN_AND_FREE(status, tmp_ctx);
sd->owner_sid = talloc_steal(sd, ids[0].sid);
sd->group_sid = talloc_steal(sd, ids[1].sid);
sd->type |= SEC_DESC_DACL_PRESENT;
- container = (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) ? true:false;
-
/* fill in the aces from the parent */
status = pvfs_acl_inherit_aces(pvfs, parent_sd, sd, container);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
+ NT_STATUS_NOT_OK_RETURN_AND_FREE(status, tmp_ctx);
/* if there is nothing to inherit then we fallback to the
default acl */
if (sd->dacl == NULL || sd->dacl->num_aces == 0) {
+ talloc_free(tmp_ctx);
return NT_STATUS_OK;
}
- acl->info.sd = sd;
+ *ret_sd = talloc_steal(mem_ctx, sd);
+
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
+
+/*
+ setup an ACL on a new file/directory based on the inherited ACL from
+ the parent. If there is no inherited ACL then we don't set anything,
+ as the default ACL applies anyway
+*/
+NTSTATUS pvfs_acl_inherit(struct pvfs_state *pvfs,
+ struct ntvfs_request *req,
+ struct pvfs_filename *name,
+ int fd)
+{
+ struct xattr_NTACL acl;
+ NTSTATUS status;
+ struct security_descriptor *sd;
+ struct pvfs_filename *parent;
+ bool container;
+
+ /* form the parents path */
+ status = pvfs_resolve_parent(pvfs, req, name, &parent);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ container = (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) ? true:false;
+
+ status = pvfs_acl_inherited_sd(pvfs, req, req, parent, container, &sd);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(parent);
+ return status;
+ }
+
+ if (sd == NULL) {
+ return NT_STATUS_OK;
+ }
+
+ acl.version = 1;
+ acl.info.sd = sd;
+
+ status = pvfs_acl_save(pvfs, name, fd, &acl);
+ talloc_free(sd);
+ talloc_free(parent);
- status = pvfs_acl_save(pvfs, name, fd, acl);
-
return status;
}