diff options
Diffstat (limited to 'libcli/security/access_check.c')
-rw-r--r-- | libcli/security/access_check.c | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/libcli/security/access_check.c b/libcli/security/access_check.c index 081efe8711a..e7c48cae085 100644 --- a/libcli/security/access_check.c +++ b/libcli/security/access_check.c @@ -250,3 +250,147 @@ done: return NT_STATUS_OK; } + + +static const struct GUID *get_ace_object_type(struct security_ace *ace) +{ + struct GUID *type; + + if (ace->object.object.flags & SEC_ACE_OBJECT_TYPE_PRESENT) + type = &ace->object.object.type.type; + else if (ace->object.object.flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT) + type = &ace->object.object.inherited_type.inherited_type; /* This doesn't look right. Is something wrong with the IDL? */ + else + type = NULL; + + return type; + +} + +/* modified access check for the purposes of DS security + * Lots of code duplication, it will ve united in just one + * function eventually */ + +NTSTATUS sec_access_check_ds(const struct security_descriptor *sd, + const struct security_token *token, + uint32_t access_desired, + uint32_t *access_granted, + struct object_tree *tree, + struct dom_sid *replace_sid) +{ + uint32_t i; + uint32_t bits_remaining; + struct object_tree *node; + const struct GUID *type; + struct dom_sid *ps_sid = dom_sid_parse_talloc(NULL, SID_NT_SELF); + + *access_granted = access_desired; + bits_remaining = access_desired; + + /* handle the maximum allowed flag */ + if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) { + access_desired |= access_check_max_allowed(sd, token); + access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED; + *access_granted = access_desired; + bits_remaining = access_desired & ~SEC_STD_DELETE; + } + + if (access_desired & SEC_FLAG_SYSTEM_SECURITY) { + if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) { + bits_remaining &= ~SEC_FLAG_SYSTEM_SECURITY; + } else { + return NT_STATUS_PRIVILEGE_NOT_HELD; + } + } + + /* a NULL dacl allows access */ + if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl == NULL) { + *access_granted = access_desired; + return NT_STATUS_OK; + } + + /* the owner always gets SEC_STD_WRITE_DAC, SEC_STD_READ_CONTROL and SEC_STD_DELETE */ + if ((bits_remaining & (SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL|SEC_STD_DELETE)) && + security_token_has_sid(token, sd->owner_sid)) { + bits_remaining &= ~(SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL|SEC_STD_DELETE); + } + if ((bits_remaining & SEC_STD_DELETE) && + security_token_has_privilege(token, SEC_PRIV_RESTORE)) { + bits_remaining &= ~SEC_STD_DELETE; + } + + if (sd->dacl == NULL) { + goto done; + } + + /* check each ace in turn. */ + for (i=0; bits_remaining && i < sd->dacl->num_aces; i++) { + struct dom_sid *trustee; + struct security_ace *ace = &sd->dacl->aces[i]; + + if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) { + continue; + } + if (dom_sid_equal(&ace->trustee, ps_sid) && replace_sid) { + trustee = replace_sid; + } + else + { + trustee = &ace->trustee; + } + if (!security_token_has_sid(token, trustee)) { + continue; + } + + switch (ace->type) { + case SEC_ACE_TYPE_ACCESS_ALLOWED: + if (tree) + object_tree_modify_access(tree, ace->access_mask); + + bits_remaining &= ~ace->access_mask; + break; + case SEC_ACE_TYPE_ACCESS_DENIED: + if (bits_remaining & ace->access_mask) { + return NT_STATUS_ACCESS_DENIED; + } + break; + case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT: + case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT: + /* check only in case we have provided a tree, + * the ACE has an object type and that type + * is in the tree */ + type = get_ace_object_type(ace); + + if (!tree) + continue; + + if (!type) + node = tree; + else + if (!(node = get_object_tree_by_GUID(tree, type))) + continue; + + if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT) { + object_tree_modify_access(node, ace->access_mask); + if (node->remaining_access == 0) { + return NT_STATUS_OK; + } + } + else { + if (node->remaining_access & ace->access_mask){ + return NT_STATUS_ACCESS_DENIED; + } + } + break; + default: /* Other ACE types not handled/supported */ + break; + } + } + +done: + if (bits_remaining != 0) { + return NT_STATUS_ACCESS_DENIED; + } + + return NT_STATUS_OK; +} |