summaryrefslogtreecommitdiffstats
path: root/source4/libcli/security
diff options
context:
space:
mode:
authorNadezhda Ivanova <nadezhda.ivanova@postpath.com>2009-09-21 17:27:50 -0700
committerNadezhda Ivanova <nadezhda.ivanova@postpath.com>2009-09-21 17:27:50 -0700
commit10c6f3f71a4fe3e36e2a0476dc0077187371fafb (patch)
tree927a846bae4922c8eb6dea848479ddcd54814a21 /source4/libcli/security
parent13b979b03d86f3ae43dc5fd539fa5d3f22f579a0 (diff)
Initial Implementation of the DS objects access checks.
Currently disabled. The search will be greatly modified, also the object tree stuff will be simplified.
Diffstat (limited to 'source4/libcli/security')
-rw-r--r--source4/libcli/security/access_check.c135
-rw-r--r--source4/libcli/security/config.mk3
-rw-r--r--source4/libcli/security/object_tree.c106
-rw-r--r--source4/libcli/security/security.h9
4 files changed, 252 insertions, 1 deletions
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 <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * 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"