diff options
Diffstat (limited to 'source4/ntvfs/posix/pvfs_acl.c')
-rw-r--r-- | source4/ntvfs/posix/pvfs_acl.c | 149 |
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; } |