From d70e17171912c190b258848edb1ae627fe59cde4 Mon Sep 17 00:00:00 2001 From: Nadezhda Ivanova Date: Mon, 14 Sep 2009 19:44:41 +0300 Subject: Owner and group defaulting. Signed-off-by: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/config.mk | 12 + source4/dsdb/samdb/ldb_modules/descriptor.c | 459 +++++++++++++++++++++++++++ source4/dsdb/samdb/ldb_modules/objectclass.c | 65 +--- 3 files changed, 479 insertions(+), 57 deletions(-) create mode 100644 source4/dsdb/samdb/ldb_modules/descriptor.c (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/config.mk b/source4/dsdb/samdb/ldb_modules/config.mk index 18144dd2c5..f868f8a9db 100644 --- a/source4/dsdb/samdb/ldb_modules/config.mk +++ b/source4/dsdb/samdb/ldb_modules/config.mk @@ -334,3 +334,15 @@ INIT_FUNCTION = LDB_MODULE(operational) ################################################ ldb_operational_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/operational.o + +################################################ +# Start MODULE ldb_descriptor +[MODULE::ldb_descriptor] +INIT_FUNCTION = LDB_MODULE(descriptor) +CFLAGS = -Ilib/ldb/include +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSECURITY NDR_SECURITY SAMDB +SUBSYSTEM = LIBLDB +# End MODULE ldb_descriptor +################################################ + +ldb_descriptor_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/descriptor.o diff --git a/source4/dsdb/samdb/ldb_modules/descriptor.c b/source4/dsdb/samdb/ldb_modules/descriptor.c new file mode 100644 index 0000000000..a22cce76a1 --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/descriptor.c @@ -0,0 +1,459 @@ + /* + ldb database library + + Copyright (C) Simo Sorce 2006-2008 + Copyright (C) Andrew Bartlett 2005-2007 + 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 . +*/ + +/* + * Name: ldb + * + * Component: DS Security descriptor module + * + * Description: + * - Calculate the security descriptor of a newly created object + * - Perform sd recalculation on a move operation + * - Handle sd modification invariants + * + * Author: Nadezhda Ivanova + */ + +#include "includes.h" +#include "ldb_module.h" +#include "dlinklist.h" +#include "dsdb/samdb/samdb.h" +#include "librpc/ndr/libndr.h" +#include "librpc/gen_ndr/ndr_security.h" +#include "libcli/security/security.h" +#include "auth/auth.h" +#include "param/param.h" + +struct descriptor_context { + struct ldb_module *module; + struct ldb_request *req; + struct ldb_reply *search_res; + int (*step_fn)(struct descriptor_context *); +}; + +static struct dsdb_class * get_last_structural_class(const struct dsdb_schema *schema, struct ldb_message_element *element) +{ + struct dsdb_class *last_class = NULL; + int i; + for (i = 0; i < element->num_values; i++){ + if (!last_class) + last_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &element->values[i]); + else { + struct dsdb_class *tmp_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &element->values[i]); + if (tmp_class->subClass_order > last_class->subClass_order) + last_class = tmp_class; + } + } + return last_class; +} + +struct dom_sid *get_default_ag(TALLOC_CTX *mem_ctx, + struct ldb_dn *dn, + struct security_token *token, + struct ldb_context *ldb) +{ + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + struct ldb_dn *root_base_dn = ldb_get_root_basedn(ldb); + struct ldb_dn *schema_base_dn = ldb_get_schema_basedn(ldb); + struct ldb_dn *config_base_dn = ldb_get_config_basedn(ldb); + const struct dom_sid *domain_sid = samdb_domain_sid(ldb); + struct dom_sid *da_sid = dom_sid_add_rid(tmp_ctx, domain_sid, DOMAIN_RID_ADMINS); + struct dom_sid *ea_sid = dom_sid_add_rid(tmp_ctx, domain_sid, DOMAIN_RID_ENTERPRISE_ADMINS); + struct dom_sid *sa_sid = dom_sid_add_rid(tmp_ctx, domain_sid, DOMAIN_RID_SCHEMA_ADMINS); + struct dom_sid *dag_sid; + + if (ldb_dn_compare_base(schema_base_dn, dn) == 0){ + if (security_token_has_sid(token, sa_sid)) + dag_sid = dom_sid_dup(mem_ctx, sa_sid); + else if (security_token_has_sid(token, ea_sid)) + dag_sid = dom_sid_dup(mem_ctx, ea_sid); + else if (security_token_has_sid(token, da_sid)) + dag_sid = dom_sid_dup(mem_ctx, da_sid); + else + dag_sid = NULL; + } + else if (ldb_dn_compare_base(config_base_dn, dn) == 0){ + if (security_token_has_sid(token, ea_sid)) + dag_sid = dom_sid_dup(mem_ctx, ea_sid); + else if (security_token_has_sid(token, da_sid)) + dag_sid = dom_sid_dup(mem_ctx, da_sid); + else + dag_sid = NULL; + } + else if (ldb_dn_compare_base(root_base_dn, dn) == 0){ + if (security_token_has_sid(token, da_sid)) + dag_sid = dom_sid_dup(mem_ctx, da_sid); + else if (security_token_has_sid(token, ea_sid)) + dag_sid = dom_sid_dup(mem_ctx, ea_sid); + else + dag_sid = NULL; + } + else + dag_sid = NULL; + + talloc_free(tmp_ctx); + return dag_sid; +} + +static struct security_descriptor *get_sd_unpacked(struct ldb_module *module, TALLOC_CTX *mem_ctx, + const struct dsdb_class *objectclass) +{ + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct security_descriptor *sd; + const struct dom_sid *domain_sid = samdb_domain_sid(ldb); + + if (!objectclass->defaultSecurityDescriptor || !domain_sid) { + return NULL; + } + + sd = sddl_decode(mem_ctx, + objectclass->defaultSecurityDescriptor, + domain_sid); + return sd; +} + +static struct dom_sid *get_default_group(TALLOC_CTX *mem_ctx, + struct ldb_context *ldb, + struct dom_sid *dag) +{ + int *domainFunctionality; + + domainFunctionality = talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int); + + if (*domainFunctionality && (*domainFunctionality >= DS_BEHAVIOR_WIN2008)){ + return dag; + } + + return NULL; +} + +static DATA_BLOB *get_new_descriptor(struct ldb_module *module, + struct ldb_dn *dn, + TALLOC_CTX *mem_ctx, + const struct dsdb_class *objectclass, + struct ldb_val *parent, + struct ldb_val *object) +{ + struct security_descriptor *user_descriptor = NULL, *parent_descriptor = NULL; + struct security_descriptor *new_sd; + DATA_BLOB *linear_sd; + enum ndr_err_code ndr_err; + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct auth_session_info *session_info + = ldb_get_opaque(ldb, "sessionInfo"); + const struct dom_sid *domain_sid = samdb_domain_sid(ldb); + char *sddl_sd; + struct dom_sid *default_owner; + struct dom_sid *default_group; + + if (object){ + user_descriptor = talloc(mem_ctx, struct security_descriptor); + if(!user_descriptor) + return NULL; + ndr_err = ndr_pull_struct_blob(object, user_descriptor, NULL, + user_descriptor, + (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)){ + talloc_free(user_descriptor); + return NULL; + } + } + else + user_descriptor = get_sd_unpacked(module, mem_ctx, objectclass); + + if (parent){ + parent_descriptor = talloc(mem_ctx, struct security_descriptor); + if(!parent_descriptor) + return NULL; + ndr_err = ndr_pull_struct_blob(parent, parent_descriptor, NULL, + parent_descriptor, + (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)){ + talloc_free(parent_descriptor); + return NULL; + } + } + default_owner = get_default_ag(mem_ctx, dn, + session_info->security_token, ldb); + default_group = get_default_group(mem_ctx, ldb, default_owner); + new_sd = create_security_descriptor(mem_ctx, parent_descriptor, user_descriptor, true, + NULL, SEC_DACL_AUTO_INHERIT|SEC_SACL_AUTO_INHERIT, + session_info->security_token, + default_owner, default_group, + map_generic_rights_ds); + if (!new_sd) + return NULL; + + + sddl_sd = sddl_encode(mem_ctx, new_sd, domain_sid); + DEBUG(10, ("Object %s created with desriptor %s", ldb_dn_get_linearized(dn), sddl_sd)); + + linear_sd = talloc(mem_ctx, DATA_BLOB); + if (!linear_sd) { + return NULL; + } + + ndr_err = ndr_push_struct_blob(linear_sd, mem_ctx, + lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), + new_sd, + (ndr_push_flags_fn_t)ndr_push_security_descriptor); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return NULL; + } + + return linear_sd; +} + +static struct descriptor_context *descriptor_init_context(struct ldb_module *module, + struct ldb_request *req) +{ + struct ldb_context *ldb; + struct descriptor_context *ac; + + ldb = ldb_module_get_ctx(module); + + ac = talloc_zero(req, struct descriptor_context); + if (ac == NULL) { + ldb_set_errstring(ldb, "Out of Memory"); + return NULL; + } + + ac->module = module; + ac->req = req; + return ac; +} + +static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares) +{ + struct ldb_context *ldb; + struct descriptor_context *ac; + int ret; + + ac = talloc_get_type(req->context, struct descriptor_context); + ldb = ldb_module_get_ctx(ac->module); + + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS && + ares->error != LDB_ERR_NO_SUCH_OBJECT) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); + } + + switch (ares->type) { + case LDB_REPLY_ENTRY: + if (ac->search_res != NULL) { + ldb_set_errstring(ldb, "Too many results"); + talloc_free(ares); + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + + ac->search_res = talloc_steal(ac, ares); + break; + + case LDB_REPLY_REFERRAL: + /* ignore */ + talloc_free(ares); + break; + + case LDB_REPLY_DONE: + talloc_free(ares); + ret = ac->step_fn(ac); + if (ret != LDB_SUCCESS) { + return ldb_module_done(ac->req, NULL, NULL, ret); + } + break; + } + + return LDB_SUCCESS; +} +static int descriptor_op_callback(struct ldb_request *req, struct ldb_reply *ares) +{ + struct descriptor_context *ac; + + ac = talloc_get_type(req->context, struct descriptor_context); + + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); + } + + if (ares->type != LDB_REPLY_DONE) { + talloc_free(ares); + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); +} + +static int descriptor_do_add(struct descriptor_context *ac) +{ + struct ldb_context *ldb; + const struct dsdb_schema *schema; + struct ldb_request *add_req; + struct ldb_message_element *objectclass_element, *sd_element = NULL; + struct ldb_message *msg; + TALLOC_CTX *mem_ctx; + int ret; + struct ldb_val *sd_val = NULL, *parentsd_val = NULL; + DATA_BLOB *sd; + struct dsdb_class *objectclass; + + ldb = ldb_module_get_ctx(ac->module); + schema = dsdb_get_schema(ldb); + + mem_ctx = talloc_new(ac); + if (mem_ctx == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message); + + /* get the security descriptor values*/ + sd_element = ldb_msg_find_element(msg, "nTSecurityDescriptor"); + objectclass_element = ldb_msg_find_element(msg, "objectClass"); + objectclass = get_last_structural_class(schema, objectclass_element); + + if (!objectclass) + return LDB_ERR_OPERATIONS_ERROR; + + if (sd_element) + sd_val = &sd_element->values[0]; + /* NC's have no parent */ + if ((ldb_dn_compare(msg->dn, (ldb_get_schema_basedn(ldb))) == 0) || + (ldb_dn_compare(msg->dn, (ldb_get_config_basedn(ldb))) == 0) || + (ldb_dn_compare(msg->dn, (ldb_get_root_basedn(ldb))) == 0)) + parentsd_val = NULL; + else if (ac->search_res != NULL) + parentsd_val = ldb_msg_find_ldb_val(ac->search_res->message, "nTSecurityDescriptor"); + + + /* get the parent descriptor and the one provided. If not provided, get the default.*/ + /* convert to security descriptor and calculate */ + sd = get_new_descriptor(ac->module, msg->dn, mem_ctx, objectclass, + parentsd_val, sd_val); + if (sd) { + ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd); + } + + talloc_free(mem_ctx); + ret = ldb_msg_sanity_check(ldb, msg); + + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_build_add_req(&add_req, ldb, ac, + msg, + ac->req->controls, + ac, descriptor_op_callback, + ac->req); + if (ret != LDB_SUCCESS) { + return ret; + } + + /* perform the add */ + return ldb_next_request(ac->module, add_req); +} + +static int descriptor_add(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_context *ldb; + struct ldb_request *search_req; + struct descriptor_context *ac; + struct ldb_dn *parent_dn; + int ret; + static const char * const descr_attrs[] = { "nTSecurityDescriptor", NULL }; + + ldb = ldb_module_get_ctx(module); + + ldb_debug(ldb, LDB_DEBUG_TRACE, "descriptor_add\n"); + + if (ldb_dn_is_special(req->op.add.message->dn)) { + return ldb_next_request(module, req); + } + + ac = descriptor_init_context(module, req); + if (ac == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* If there isn't a parent, just go on to the add processing */ + if (ldb_dn_get_comp_num(ac->req->op.add.message->dn) == 1) { + return descriptor_do_add(ac); + } + + /* get copy of parent DN */ + parent_dn = ldb_dn_get_parent(ac, ac->req->op.add.message->dn); + if (parent_dn == NULL) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_build_search_req(&search_req, ldb, + ac, parent_dn, LDB_SCOPE_BASE, + "(objectClass=*)", descr_attrs, + NULL, + ac, get_search_callback, + req); + if (ret != LDB_SUCCESS) { + return ret; + } + talloc_steal(search_req, parent_dn); + + ac->step_fn = descriptor_do_add; + + return ldb_next_request(ac->module, search_req); +} +/* TODO */ +static int descriptor_modify(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_context *ldb = ldb_module_get_ctx(module); + ldb_debug(ldb, LDB_DEBUG_TRACE, "descriptor_modify\n"); + return ldb_next_request(module, req); +} +/* TODO */ +static int descriptor_rename(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_context *ldb = ldb_module_get_ctx(module); + ldb_debug(ldb, LDB_DEBUG_TRACE, "descriptor_rename\n"); + return ldb_next_request(module, req); +} + +_PUBLIC_ const struct ldb_module_ops ldb_descriptor_module_ops = { + .name = "descriptor", + .add = descriptor_add, + .modify = descriptor_modify, + .rename = descriptor_rename, +}; + + diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index 6dbafac965..0246de130c 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -231,49 +231,6 @@ static int objectclass_sort(struct ldb_module *module, return LDB_ERR_OBJECT_CLASS_VIOLATION; } -static DATA_BLOB *get_sd(struct ldb_module *module, TALLOC_CTX *mem_ctx, - const struct dsdb_class *objectclass) -{ - struct ldb_context *ldb = ldb_module_get_ctx(module); - enum ndr_err_code ndr_err; - DATA_BLOB *linear_sd; - struct auth_session_info *session_info - = ldb_get_opaque(ldb, "sessionInfo"); - struct security_descriptor *sd; - const struct dom_sid *domain_sid = samdb_domain_sid(ldb); - - if (!objectclass->defaultSecurityDescriptor || !domain_sid) { - return NULL; - } - - sd = sddl_decode(mem_ctx, - objectclass->defaultSecurityDescriptor, - domain_sid); - - if (!sd || !session_info || !session_info->security_token) { - return NULL; - } - - sd->owner_sid = session_info->security_token->user_sid; - sd->group_sid = session_info->security_token->group_sid; - - linear_sd = talloc(mem_ctx, DATA_BLOB); - if (!linear_sd) { - return NULL; - } - - ndr_err = ndr_push_struct_blob(linear_sd, mem_ctx, - lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), - sd, - (ndr_push_flags_fn_t)ndr_push_security_descriptor); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return NULL; - } - - return linear_sd; - -} - static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares) { struct ldb_context *ldb; @@ -536,7 +493,6 @@ static int objectclass_do_add(struct oc_context *ac) return LDB_ERR_UNWILLING_TO_PERFORM; } } - if (schema) { ret = fix_attributes(ldb, schema, msg); if (ret != LDB_SUCCESS) { @@ -546,7 +502,7 @@ static int objectclass_do_add(struct oc_context *ac) /* This is now the objectClass list from the database */ objectclass_element = ldb_msg_find_element(msg, "objectClass"); - + if (!objectclass_element) { /* Where did it go? bail now... */ talloc_free(mem_ctx); @@ -565,10 +521,10 @@ static int objectclass_do_add(struct oc_context *ac) talloc_free(mem_ctx); return ret; } - + /* We must completely replace the existing objectClass entry, * because we need it sorted */ - + /* Move from the linked list back into an ldb msg */ for (current = sorted; current; current = current->next) { value = talloc_strdup(msg, current->objectclass->lDAPDisplayName); @@ -579,7 +535,7 @@ static int objectclass_do_add(struct oc_context *ac) } ret = ldb_msg_add_string(msg, "objectClass", value); if (ret != LDB_SUCCESS) { - ldb_set_errstring(ldb, + ldb_set_errstring(ldb, "objectclass: could not re-add sorted " "objectclass to modify msg"); talloc_free(mem_ctx); @@ -589,6 +545,7 @@ static int objectclass_do_add(struct oc_context *ac) if (!current->next) { struct ldb_message_element *el; int32_t systemFlags = 0; + DATA_BLOB *sd; if (!ldb_msg_find_element(msg, "objectCategory")) { value = talloc_strdup(msg, current->objectclass->defaultObjectCategory); if (value == NULL) { @@ -599,15 +556,9 @@ static int objectclass_do_add(struct oc_context *ac) ldb_msg_add_string(msg, "objectCategory", value); } if (!ldb_msg_find_element(msg, "showInAdvancedViewOnly") && (current->objectclass->defaultHidingValue == true)) { - ldb_msg_add_string(msg, "showInAdvancedViewOnly", + ldb_msg_add_string(msg, "showInAdvancedViewOnly", "TRUE"); } - if (!ldb_msg_find_element(msg, "nTSecurityDescriptor")) { - DATA_BLOB *sd = get_sd(ac->module, mem_ctx, current->objectclass); - if (sd) { - ldb_msg_add_steal_value(msg, "nTSecurityDescriptor", sd); - } - } /* There are very special rules for systemFlags, see MS-ADTS 3.1.1.5.2.4 */ el = ldb_msg_find_element(msg, "systemFlags"); @@ -619,7 +570,7 @@ static int objectclass_do_add(struct oc_context *ac) /* systemFlags &= ( SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_LIMITED_MOVE); */ ldb_msg_remove_element(msg, el); } - + /* This flag is only allowed on attributeSchema objects */ if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "attributeSchema") == 0) { systemFlags &= ~SYSTEM_FLAG_ATTR_IS_RDN; @@ -632,7 +583,7 @@ static int objectclass_do_add(struct oc_context *ac) || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "ntDSDSA") == 0) { systemFlags |= (int32_t)(SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE); - } else if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "siteLink") == 0 + } else if (ldb_attr_cmp(current->objectclass->lDAPDisplayName, "siteLink") == 0 || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "siteLinkBridge") == 0 || ldb_attr_cmp(current->objectclass->lDAPDisplayName, "nTDSConnection") == 0) { systemFlags |= (int32_t)(SYSTEM_FLAG_CONFIG_ALLOW_RENAME); -- cgit