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:
parent
13b979b03d
commit
10c6f3f71a
1151
source4/dsdb/samdb/ldb_modules/acl.c
Normal file
1151
source4/dsdb/samdb/ldb_modules/acl.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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)))
|
||||
|
106
source4/libcli/security/object_tree.c
Normal file
106
source4/libcli/security/object_tree.c
Normal 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);
|
||||
}
|
@ -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"
|
||||
|
@ -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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user