1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-25 17:57:42 +03:00

Initial Implementation of the DS objects access checks.

Currently disabled. The search will be greatly modified,
also the object tree stuff will be simplified.
This commit is contained in:
Nadezhda Ivanova 2009-09-21 17:27:50 -07:00
parent 13b979b03d
commit 10c6f3f71a
9 changed files with 1441 additions and 1 deletions

File diff suppressed because it is too large Load Diff

View File

@ -357,3 +357,15 @@ INIT_FUNCTION = LDB_MODULE(resolve_oids)
################################################
ldb_resolve_oids_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/resolve_oids.o
################################################
# Start MODULE ldb_acl
[MODULE::ldb_acl]
PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSECURITY SAMDB
SUBSYSTEM = LIBLDB
INIT_FUNCTION = LDB_MODULE(acl)
# End MODULE ldb_acl
################################################
ldb_acl_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/acl.o

View File

@ -35,6 +35,7 @@
#include "auth/auth.h"
#include "libcli/security/security.h"
#include "dsdb/samdb/samdb.h"
#include "param/param.h"
/* Kludge ACL rules:
*
@ -46,6 +47,7 @@
struct kludge_private_data {
const char **password_attrs;
bool acl_perform;
};
static enum security_user_level what_is_user(struct ldb_module *module)
@ -325,6 +327,9 @@ static int kludge_acl_search(struct ldb_module *module, struct ldb_request *req)
data = talloc_get_type(ldb_module_get_private(module), struct kludge_private_data);
if (data && data->acl_perform)
return ldb_next_request(module, req);
ac->module = module;
ac->req = req;
ac->user_type = what_is_user(module);
@ -397,6 +402,12 @@ static int kludge_acl_change(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_context *ldb = ldb_module_get_ctx(module);
enum security_user_level user_type = what_is_user(module);
struct kludge_private_data *data = talloc_get_type(ldb_module_get_private(module),
struct kludge_private_data);
if (data->acl_perform)
return ldb_next_request(module, req);
switch (user_type) {
case SECURITY_SYSTEM:
case SECURITY_ADMINISTRATOR:
@ -459,6 +470,8 @@ static int kludge_acl_init(struct ldb_module *module)
}
data->password_attrs = NULL;
data->acl_perform = lp_parm_bool(ldb_get_opaque(ldb, "loadparm"),
NULL, "acl", "perform", false);
ldb_module_set_private(module, data);
if (!mem_ctx) {

View File

@ -416,3 +416,15 @@ const char **dsdb_full_attribute_list(TALLOC_CTX *mem_ctx,
const char **attr_list = dsdb_full_attribute_list_internal_el(mem_ctx, schema, class_list, query);
return dedup_attr_list(attr_list);
}
/* Return the schemaIDGUID of a class */
const struct GUID * class_schemaid_guid_by_lDAPDisplayName(const struct dsdb_schema *schema,
const char *name)
{
const struct dsdb_class *object_class = dsdb_class_by_lDAPDisplayName(schema, name);
if (!object_class)
return NULL;
return &object_class->schemaIDGUID;
}

View File

@ -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;
}

View File

@ -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)))

View File

@ -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);
}

View File

@ -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"

View File

@ -614,6 +614,7 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
# - each partition has its own module list then
modules_list = ["resolve_oids",
"rootdse",
"acl",
"paged_results",
"ranged_results",
"anr",