From 10c6f3f71a4fe3e36e2a0476dc0077187371fafb Mon Sep 17 00:00:00 2001 From: Nadezhda Ivanova Date: Mon, 21 Sep 2009 17:27:50 -0700 Subject: Initial Implementation of the DS objects access checks. Currently disabled. The search will be greatly modified, also the object tree stuff will be simplified. --- source4/libcli/security/access_check.c | 135 +++++++++++++++++++++++++++++++++ source4/libcli/security/config.mk | 3 +- source4/libcli/security/object_tree.c | 106 ++++++++++++++++++++++++++ source4/libcli/security/security.h | 9 +++ 4 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 source4/libcli/security/object_tree.c (limited to 'source4/libcli') diff --git a/source4/libcli/security/access_check.c b/source4/libcli/security/access_check.c index af6a3d6fb3..543b0f74c5 100644 --- a/source4/libcli/security/access_check.c +++ b/source4/libcli/security/access_check.c @@ -69,6 +69,21 @@ static uint32_t access_check_max_allowed(const struct security_descriptor *sd, return granted & ~denied; } +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; + +} + /* the main entry point for access checking. */ @@ -153,3 +168,123 @@ done: return NT_STATUS_OK; } + +/* 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) +{ + int i; + uint32_t bits_remaining; + struct object_tree *node; + struct GUID *type; + + *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 security_ace *ace = &sd->dacl->aces[i]; + + if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) { + continue; + } + + if (!security_token_has_sid(token, &ace->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); + } + 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; +} + + + + diff --git a/source4/libcli/security/config.mk b/source4/libcli/security/config.mk index ca545f817f..f1ca20a2e8 100644 --- a/source4/libcli/security/config.mk +++ b/source4/libcli/security/config.mk @@ -2,6 +2,7 @@ PUBLIC_DEPENDENCIES = LIBNDR LIBSECURITY_COMMON LIBSECURITY_OBJ_FILES = $(addprefix $(libclisrcdir)/security/, \ - security_token.o access_check.o privilege.o sddl.o create_descriptor.o) \ + security_token.o access_check.o privilege.o sddl.o \ + create_descriptor.o object_tree.o) $(eval $(call proto_header_template,$(libclisrcdir)/security/proto.h,$(LIBSECURITY_OBJ_FILES:.o=.c))) diff --git a/source4/libcli/security/object_tree.c b/source4/libcli/security/object_tree.c new file mode 100644 index 0000000000..8a90019a59 --- /dev/null +++ b/source4/libcli/security/object_tree.c @@ -0,0 +1,106 @@ +/* + Unix SMB/CIFS implementation. + + security access checking routines + + Copyright (C) Nadezhda Ivanova 2009 + + 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 + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/* + * Description: Contains data handler functions for + * the object tree that must be constructed to perform access checks. + * The object tree is an unbalanced tree of depth 3, indexed by + * object type guid. Perhaps a different data structure + * should be concidered later to improve performance + * + * Author: Nadezhda Ivanova + */ +#include "includes.h" +#include "libcli/security/security.h" +#include "lib/util/dlinklist.h" +#include "librpc/ndr/libndr.h" + +/* Adds a new node to the object tree. If attributeSecurityGUID is not zero and + * has already been added to the tree, the new node is added as a child of that node + * In all other cases as a child of the root + */ + +struct object_tree * insert_in_object_tree(TALLOC_CTX *mem_ctx, + const struct GUID *schemaGUIDID, + const struct GUID *attributeSecurityGUID, + uint32_t init_access, + struct object_tree *root) +{ + struct object_tree * parent = NULL; + struct object_tree * new_node; + + new_node = talloc(mem_ctx, struct object_tree); + if (!new_node) + return NULL; + memset(new_node, 0, sizeof(struct object_tree)); + new_node->remaining_access = init_access; + + if (!root){ + memcpy(&new_node->guid, schemaGUIDID, sizeof(struct GUID)); + return new_node; + } + + if (attributeSecurityGUID && !GUID_all_zero(attributeSecurityGUID)){ + parent = get_object_tree_by_GUID(root, attributeSecurityGUID); + memcpy(&new_node->guid, attributeSecurityGUID, sizeof(struct GUID)); + } + else + memcpy(&new_node->guid, schemaGUIDID, sizeof(struct GUID)); + + if (!parent) + parent = root; + + new_node->remaining_access = init_access; + DLIST_ADD(parent, new_node); + return new_node; +} + +/* search by GUID */ +struct object_tree * get_object_tree_by_GUID(struct object_tree *root, + const struct GUID *guid) +{ + struct object_tree *p; + struct object_tree *result = NULL; + + if (!root || GUID_equal(&root->guid, guid)) + result = root; + else{ + for (p = root->children; p != NULL; p = p->next) + if ((result = get_object_tree_by_GUID(p, guid))) + break; + } + + return result; +} + +/* Change the granted access per each ACE */ + +void object_tree_modify_access(struct object_tree *root, + uint32_t access) +{ + struct object_tree *p; + if (root){ + root->remaining_access &= ~access; + } + + for (p = root->children; p != NULL; p = p->next) + object_tree_modify_access(p, access); +} diff --git a/source4/libcli/security/security.h b/source4/libcli/security/security.h index 3cfa484816..18f6c820d1 100644 --- a/source4/libcli/security/security.h +++ b/source4/libcli/security/security.h @@ -29,6 +29,15 @@ enum security_user_level { struct auth_session_info; +struct object_tree { + uint32_t remaining_access; + struct GUID guid; + /* linked list of children */ + struct object_tree * children; + struct object_tree * prev; + struct object_tree * next; +}; + /* Moved the dom_sid functions to the top level dir with manual proto header */ #include "libcli/security/dom_sid.h" #include "libcli/security/secace.h" -- cgit