From e5b86d267465dba57b26a74f75ddc1e778359b23 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 22 Oct 2009 15:54:57 +1100 Subject: s4:dsdb Split schema loading and schema data management By splitting the module this way, we can load the schema at startup, after the partitions module is operational, but we leave the 'mess with details of entries in the partitions' module to operate only on the partitions module. Loading the schema later allows us to set the @ATTRIBUTES correctly on all the databases. Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/config.mk | 24 +- source4/dsdb/samdb/ldb_modules/schema_data.c | 466 +++++++++++++++++++ source4/dsdb/samdb/ldb_modules/schema_fsmo.c | 654 --------------------------- source4/dsdb/samdb/ldb_modules/schema_load.c | 258 +++++++++++ source4/scripting/python/samba/provision.py | 5 +- 5 files changed, 745 insertions(+), 662 deletions(-) create mode 100644 source4/dsdb/samdb/ldb_modules/schema_data.c delete mode 100644 source4/dsdb/samdb/ldb_modules/schema_fsmo.c create mode 100644 source4/dsdb/samdb/ldb_modules/schema_load.c diff --git a/source4/dsdb/samdb/ldb_modules/config.mk b/source4/dsdb/samdb/ldb_modules/config.mk index 40e37a47fc..c75e4a6489 100644 --- a/source4/dsdb/samdb/ldb_modules/config.mk +++ b/source4/dsdb/samdb/ldb_modules/config.mk @@ -46,16 +46,28 @@ ldb_dsdb_cache_OBJ_FILES = \ $(dsdbsrcdir)/samdb/ldb_modules/dsdb_cache.o ################################################ -# Start MODULE ldb_schema_fsmo -[MODULE::ldb_schema_fsmo] +# Start MODULE ldb_schema_load +[MODULE::ldb_schema_load] SUBSYSTEM = LIBLDB PRIVATE_DEPENDENCIES = SAMDB LIBTALLOC LIBEVENTS DSDB_MODULE_HELPERS -INIT_FUNCTION = LDB_MODULE(schema_fsmo) -# End MODULE ldb_schema_fsmo +INIT_FUNCTION = LDB_MODULE(schema_load) +# End MODULE ldb_schema_load ################################################ -ldb_schema_fsmo_OBJ_FILES = \ - $(dsdbsrcdir)/samdb/ldb_modules/schema_fsmo.o +ldb_schema_load_OBJ_FILES = \ + $(dsdbsrcdir)/samdb/ldb_modules/schema_load.o + +################################################ +# Start MODULE ldb_schema_data +[MODULE::ldb_schema_data] +SUBSYSTEM = LIBLDB +PRIVATE_DEPENDENCIES = SAMDB LIBTALLOC LIBEVENTS DSDB_MODULE_HELPERS +INIT_FUNCTION = LDB_MODULE(schema_data) +# End MODULE ldb_schema_data +################################################ + +ldb_schema_data_OBJ_FILES = \ + $(dsdbsrcdir)/samdb/ldb_modules/schema_data.o ################################################ # Start MODULE ldb_naming_fsmo diff --git a/source4/dsdb/samdb/ldb_modules/schema_data.c b/source4/dsdb/samdb/ldb_modules/schema_data.c new file mode 100644 index 0000000000..675cae3dc7 --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/schema_data.c @@ -0,0 +1,466 @@ +/* + Unix SMB/CIFS mplementation. + + The module that handles the Schema checkings and dynamic attributes + + Copyright (C) Stefan Metzmacher 2007 + Copyright (C) Andrew Bartlett 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 . + +*/ + +#include "includes.h" +#include "ldb_module.h" +#include "dsdb/samdb/samdb.h" +#include "librpc/gen_ndr/ndr_misc.h" +#include "librpc/gen_ndr/ndr_drsuapi.h" +#include "librpc/gen_ndr/ndr_drsblobs.h" +#include "param/param.h" +#include "dsdb/samdb/ldb_modules/util.h" + +static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg, + const struct dsdb_schema *schema); +static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg, + const struct dsdb_schema *schema); +static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg, + const struct dsdb_schema *schema); +static int generate_extendedAttributeInfo(struct ldb_context *ldb, struct ldb_message *msg, + const struct dsdb_schema *schema); +static int generate_extendedClassInfo(struct ldb_context *ldb, struct ldb_message *msg, + const struct dsdb_schema *schema); +static int generate_possibleInferiors(struct ldb_context *ldb, struct ldb_message *msg, + const struct dsdb_schema *schema); + +static const struct { + const char *attr; + int (*fn)(struct ldb_context *, struct ldb_message *, const struct dsdb_schema *); + bool aggregate; +} generated_attrs[] = { + { + .attr = "objectClasses", + .fn = generate_objectClasses, + .aggregate = true, + }, + { + .attr = "attributeTypes", + .fn = generate_attributeTypes, + .aggregate = true, + }, + { + .attr = "dITContentRules", + .fn = generate_dITContentRules, + .aggregate = true, + }, + { + .attr = "extendedAttributeInfo", + .fn = generate_extendedAttributeInfo, + .aggregate = true, + }, + { + .attr = "extendedClassInfo", + .fn = generate_extendedClassInfo, + .aggregate = true, + }, + { + .attr = "possibleInferiors", + .fn = generate_possibleInferiors, + .aggregate = false, + } +}; + +struct schema_data_private_data { + struct ldb_dn *aggregate_dn; + struct ldb_dn *schema_dn; +}; + +struct schema_data_search_data { + struct ldb_module *module; + struct ldb_request *req; + + const struct dsdb_schema *schema; +}; + +static int schema_data_init(struct ldb_module *module) +{ + struct ldb_context *ldb; + TALLOC_CTX *mem_ctx; + struct ldb_dn *schema_dn; + struct dsdb_schema *schema; + int ret; + struct schema_data_private_data *data; + + ret = ldb_next_init(module); + if (ret != LDB_SUCCESS) { + return ret; + } + + ldb = ldb_module_get_ctx(module); + schema_dn = samdb_schema_dn(ldb); + if (!schema_dn) { + ldb_reset_err_string(ldb); + ldb_debug(ldb, LDB_DEBUG_WARNING, + "schema_data_init: no schema dn present: (skip schema loading)\n"); + return LDB_SUCCESS; + } + + data = talloc(module, struct schema_data_private_data); + if (data == NULL) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* Check to see if this is a result on the CN=Aggregate schema */ + data->aggregate_dn = ldb_dn_copy(data, schema_dn); + if (!ldb_dn_add_child_fmt(data->aggregate_dn, "CN=Aggregate")) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + data->schema_dn = schema_dn; + + ldb_module_set_private(module, data); + return LDB_SUCCESS; +} + +static int schema_data_add(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_context *ldb; + struct dsdb_schema *schema; + const struct ldb_val *attributeID = NULL; + const struct ldb_val *governsID = NULL; + const char *oid_attr = NULL; + const char *oid = NULL; + uint32_t id32; + WERROR status; + + ldb = ldb_module_get_ctx(module); + + /* special objects should always go through */ + if (ldb_dn_is_special(req->op.add.message->dn)) { + return ldb_next_request(module, req); + } + + /* replicated update should always go through */ + if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) { + return ldb_next_request(module, req); + } + + schema = dsdb_get_schema(ldb); + if (!schema) { + return ldb_next_request(module, req); + } + + if (!schema->fsmo.we_are_master) { + ldb_debug_set(ldb, LDB_DEBUG_ERROR, + "schema_data_add: we are not master: reject request\n"); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + + attributeID = ldb_msg_find_ldb_val(req->op.add.message, "attributeID"); + governsID = ldb_msg_find_ldb_val(req->op.add.message, "governsID"); + + if (attributeID) { + oid_attr = "attributeID"; + oid = talloc_strndup(req, (const char *)attributeID->data, attributeID->length); + } else if (governsID) { + oid_attr = "governsID"; + oid = talloc_strndup(req, (const char *)governsID->data, governsID->length); + } else { + return ldb_next_request(module, req); + } + + if (!oid) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + status = dsdb_map_oid2int(schema, oid, &id32); + if (W_ERROR_IS_OK(status)) { + return ldb_next_request(module, req); + } else if (!W_ERROR_EQUAL(WERR_DS_NO_MSDS_INTID, status)) { + ldb_debug_set(ldb, LDB_DEBUG_ERROR, + "schema_data_add: failed to map %s[%s]: %s\n", + oid_attr, oid, win_errstr(status)); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + + status = dsdb_create_prefix_mapping(ldb, schema, oid); + if (!W_ERROR_IS_OK(status)) { + ldb_debug_set(ldb, LDB_DEBUG_ERROR, + "schema_data_add: failed to create prefix mapping for %s[%s]: %s\n", + oid_attr, oid, win_errstr(status)); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + + return ldb_next_request(module, req); +} + +static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg, + const struct dsdb_schema *schema) +{ + const struct dsdb_class *sclass; + int ret; + + for (sclass = schema->classes; sclass; sclass = sclass->next) { + ret = ldb_msg_add_string(msg, "objectClasses", schema_class_to_description(msg, sclass)); + if (ret != LDB_SUCCESS) { + return ret; + } + } + return LDB_SUCCESS; +} +static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg, + const struct dsdb_schema *schema) +{ + const struct dsdb_attribute *attribute; + int ret; + + for (attribute = schema->attributes; attribute; attribute = attribute->next) { + ret = ldb_msg_add_string(msg, "attributeTypes", schema_attribute_to_description(msg, attribute)); + if (ret != LDB_SUCCESS) { + return ret; + } + } + return LDB_SUCCESS; +} + +static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg, + const struct dsdb_schema *schema) +{ + const struct dsdb_class *sclass; + int ret; + + for (sclass = schema->classes; sclass; sclass = sclass->next) { + if (sclass->auxiliaryClass || sclass->systemAuxiliaryClass) { + char *ditcontentrule = schema_class_to_dITContentRule(msg, sclass, schema); + if (!ditcontentrule) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + ret = ldb_msg_add_steal_string(msg, "dITContentRules", ditcontentrule); + if (ret != LDB_SUCCESS) { + return ret; + } + } + } + return LDB_SUCCESS; +} + +static int generate_extendedAttributeInfo(struct ldb_context *ldb, + struct ldb_message *msg, + const struct dsdb_schema *schema) +{ + const struct dsdb_attribute *attribute; + int ret; + + for (attribute = schema->attributes; attribute; attribute = attribute->next) { + char *val = schema_attribute_to_extendedInfo(msg, attribute); + if (!val) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_msg_add_string(msg, "extendedAttributeInfo", val); + if (ret != LDB_SUCCESS) { + return ret; + } + } + + return LDB_SUCCESS; +} + +static int generate_extendedClassInfo(struct ldb_context *ldb, + struct ldb_message *msg, + const struct dsdb_schema *schema) +{ + const struct dsdb_class *sclass; + int ret; + + for (sclass = schema->classes; sclass; sclass = sclass->next) { + char *val = schema_class_to_extendedInfo(msg, sclass); + if (!val) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_msg_add_string(msg, "extendedClassInfo", val); + if (ret != LDB_SUCCESS) { + return ret; + } + } + + return LDB_SUCCESS; +} + + +static int generate_possibleInferiors(struct ldb_context *ldb, struct ldb_message *msg, + const struct dsdb_schema *schema) +{ + struct ldb_dn *dn = msg->dn; + int ret, i; + const char *first_component_name = ldb_dn_get_component_name(dn, 0); + const struct ldb_val *first_component_val; + const struct dsdb_class *schema_class; + const char **possibleInferiors; + + if (strcasecmp(first_component_name, "cn") != 0) { + return LDB_SUCCESS; + } + + first_component_val = ldb_dn_get_component_val(dn, 0); + + schema_class = dsdb_class_by_cn_ldb_val(schema, first_component_val); + if (schema_class == NULL) { + return LDB_SUCCESS; + } + + possibleInferiors = schema_class->possibleInferiors; + if (possibleInferiors == NULL) { + return LDB_SUCCESS; + } + + for (i=0;possibleInferiors[i];i++) { + ret = ldb_msg_add_string(msg, "possibleInferiors", possibleInferiors[i]); + if (ret != LDB_SUCCESS) { + return ret; + } + } + + return LDB_SUCCESS; +} + + +/* Add objectClasses, attributeTypes and dITContentRules from the + schema object (they are not stored in the database) + */ +static int schema_data_search_callback(struct ldb_request *req, struct ldb_reply *ares) +{ + struct ldb_context *ldb; + struct schema_data_search_data *ac; + struct schema_data_private_data *mc; + int i, ret; + + ac = talloc_get_type(req->context, struct schema_data_search_data); + mc = talloc_get_type(ldb_module_get_private(ac->module), struct schema_data_private_data); + 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) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); + } + /* Only entries are interesting, and we handle the case of the parent seperatly */ + + switch (ares->type) { + case LDB_REPLY_ENTRY: + + if (ldb_dn_compare(ares->message->dn, mc->aggregate_dn) == 0) { + for (i=0; i < ARRAY_SIZE(generated_attrs); i++) { + if (generated_attrs[i].aggregate && + ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) { + ret = generated_attrs[i].fn(ldb, ares->message, ac->schema); + if (ret != LDB_SUCCESS) { + return ret; + } + } + } + } else if ((ldb_dn_compare_base(mc->schema_dn, ares->message->dn) == 0) + && (ldb_dn_compare(mc->schema_dn, ares->message->dn) != 0)) { + for (i=0; i < ARRAY_SIZE(generated_attrs); i++) { + if (!generated_attrs[i].aggregate && + ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) { + ret = generated_attrs[i].fn(ldb, ares->message, ac->schema); + if (ret != LDB_SUCCESS) { + return ret; + } + } + } + } + + + return ldb_module_send_entry(ac->req, ares->message, ares->controls); + + case LDB_REPLY_REFERRAL: + + return ldb_module_send_referral(ac->req, ares->referral); + + case LDB_REPLY_DONE: + + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); + } + + return LDB_SUCCESS; +} + +/* search */ +static int schema_data_search(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_context *ldb = ldb_module_get_ctx(module); + int i, ret; + struct schema_data_search_data *search_context; + struct ldb_request *down_req; + struct dsdb_schema *schema = dsdb_get_schema(ldb); + + if (!schema || !ldb_module_get_private(module)) { + /* If there is no schema, there is little we can do */ + return ldb_next_request(module, req); + } + for (i=0; i < ARRAY_SIZE(generated_attrs); i++) { + if (ldb_attr_in_list(req->op.search.attrs, generated_attrs[i].attr)) { + break; + } + } + if (i == ARRAY_SIZE(generated_attrs)) { + /* No request for a generated attr found, nothing to + * see here, move along... */ + return ldb_next_request(module, req); + } + + search_context = talloc(req, struct schema_data_search_data); + if (!search_context) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + search_context->module = module; + search_context->req = req; + search_context->schema = schema; + + ret = ldb_build_search_req_ex(&down_req, ldb, search_context, + req->op.search.base, + req->op.search.scope, + req->op.search.tree, + req->op.search.attrs, + req->controls, + search_context, schema_data_search_callback, + req); + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; + } + + return ldb_next_request(module, down_req); +} + + +_PUBLIC_ const struct ldb_module_ops ldb_schema_data_module_ops = { + .name = "schema_data", + .init_context = schema_data_init, + .add = schema_data_add, + .search = schema_data_search +}; diff --git a/source4/dsdb/samdb/ldb_modules/schema_fsmo.c b/source4/dsdb/samdb/ldb_modules/schema_fsmo.c deleted file mode 100644 index 2b6606c147..0000000000 --- a/source4/dsdb/samdb/ldb_modules/schema_fsmo.c +++ /dev/null @@ -1,654 +0,0 @@ -/* - Unix SMB/CIFS mplementation. - - The module that handles the Schema FSMO Role Owner - checkings, it also loads the dsdb_schema. - - Copyright (C) Stefan Metzmacher 2007 - Copyright (C) Andrew Bartlett 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 . - -*/ - -#include "includes.h" -#include "ldb_module.h" -#include "dsdb/samdb/samdb.h" -#include "librpc/gen_ndr/ndr_misc.h" -#include "librpc/gen_ndr/ndr_drsuapi.h" -#include "librpc/gen_ndr/ndr_drsblobs.h" -#include "param/param.h" -#include "dsdb/samdb/ldb_modules/util.h" - -static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg, - const struct dsdb_schema *schema); -static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg, - const struct dsdb_schema *schema); -static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg, - const struct dsdb_schema *schema); -static int generate_extendedAttributeInfo(struct ldb_context *ldb, struct ldb_message *msg, - const struct dsdb_schema *schema); -static int generate_extendedClassInfo(struct ldb_context *ldb, struct ldb_message *msg, - const struct dsdb_schema *schema); -static int generate_possibleInferiors(struct ldb_context *ldb, struct ldb_message *msg, - const struct dsdb_schema *schema); - -static const struct { - const char *attr; - int (*fn)(struct ldb_context *, struct ldb_message *, const struct dsdb_schema *); - bool aggregate; -} generated_attrs[] = { - { - .attr = "objectClasses", - .fn = generate_objectClasses, - .aggregate = true, - }, - { - .attr = "attributeTypes", - .fn = generate_attributeTypes, - .aggregate = true, - }, - { - .attr = "dITContentRules", - .fn = generate_dITContentRules, - .aggregate = true, - }, - { - .attr = "extendedAttributeInfo", - .fn = generate_extendedAttributeInfo, - .aggregate = true, - }, - { - .attr = "extendedClassInfo", - .fn = generate_extendedClassInfo, - .aggregate = true, - }, - { - .attr = "possibleInferiors", - .fn = generate_possibleInferiors, - .aggregate = false, - } -}; - -struct schema_fsmo_private_data { - struct ldb_dn *aggregate_dn; -}; - -struct schema_fsmo_search_data { - struct ldb_module *module; - struct ldb_request *req; - - const struct dsdb_schema *schema; -}; - -/* - Given an LDB module (pointing at the schema DB), and the DN, set the populated schema -*/ - -static int dsdb_schema_from_schema_dn(TALLOC_CTX *mem_ctx, struct ldb_module *module, - struct smb_iconv_convenience *iconv_convenience, - struct ldb_dn *schema_dn, - struct dsdb_schema **schema) -{ - TALLOC_CTX *tmp_ctx; - char *error_string; - int ret; - struct ldb_context *ldb = ldb_module_get_ctx(module); - struct ldb_result *schema_res; - struct ldb_result *a_res; - struct ldb_result *c_res; - static const char *schema_attrs[] = { - "prefixMap", - "schemaInfo", - "fSMORoleOwner", - NULL - }; - unsigned flags; - - tmp_ctx = talloc_new(mem_ctx); - if (!tmp_ctx) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - - /* we don't want to trace the schema load */ - flags = ldb_get_flags(ldb); - ldb_set_flags(ldb, flags & ~LDB_FLG_ENABLE_TRACING); - - /* - * setup the prefix mappings and schema info - */ - ret = dsdb_module_search_dn(module, tmp_ctx, &schema_res, - schema_dn, schema_attrs); - if (ret == LDB_ERR_NO_SUCH_OBJECT) { - goto failed; - } else if (ret != LDB_SUCCESS) { - ldb_asprintf_errstring(ldb, - "dsdb_schema: failed to search the schema head: %s", - ldb_errstring(ldb)); - goto failed; - } - - /* - * load the attribute definitions - */ - ret = dsdb_module_search(module, tmp_ctx, &a_res, - schema_dn, LDB_SCOPE_ONELEVEL, NULL, - "(objectClass=attributeSchema)"); - if (ret != LDB_SUCCESS) { - ldb_asprintf_errstring(ldb, - "dsdb_schema: failed to search attributeSchema objects: %s", - ldb_errstring(ldb)); - goto failed; - } - - /* - * load the objectClass definitions - */ - ret = dsdb_module_search(module, tmp_ctx, &c_res, - schema_dn, LDB_SCOPE_ONELEVEL, NULL, - "(objectClass=classSchema)"); - if (ret != LDB_SUCCESS) { - ldb_asprintf_errstring(ldb, - "dsdb_schema: failed to search attributeSchema objects: %s", - ldb_errstring(ldb)); - goto failed; - } - - ret = dsdb_schema_from_ldb_results(tmp_ctx, ldb, - lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), - schema_res, a_res, c_res, schema, &error_string); - if (ret != LDB_SUCCESS) { - ldb_asprintf_errstring(ldb, - "dsdb_schema load failed: %s", - error_string); - goto failed; - } - talloc_steal(mem_ctx, *schema); - -failed: - if (flags & LDB_FLG_ENABLE_TRACING) { - flags = ldb_get_flags(ldb); - ldb_set_flags(ldb, flags | LDB_FLG_ENABLE_TRACING); - } - talloc_free(tmp_ctx); - return ret; -} - - -static int schema_fsmo_init(struct ldb_module *module) -{ - struct ldb_context *ldb; - TALLOC_CTX *mem_ctx; - struct ldb_dn *schema_dn; - struct dsdb_schema *schema; - int ret; - struct schema_fsmo_private_data *data; - - ldb = ldb_module_get_ctx(module); - schema_dn = samdb_schema_dn(ldb); - if (!schema_dn) { - ldb_reset_err_string(ldb); - ldb_debug(ldb, LDB_DEBUG_WARNING, - "schema_fsmo_init: no schema dn present: (skip schema loading)\n"); - return ldb_next_init(module); - } - - data = talloc(module, struct schema_fsmo_private_data); - if (data == NULL) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - - /* Check to see if this is a result on the CN=Aggregate schema */ - data->aggregate_dn = ldb_dn_copy(data, schema_dn); - if (!ldb_dn_add_child_fmt(data->aggregate_dn, "CN=Aggregate")) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - - ldb_module_set_private(module, data); - - if (dsdb_get_schema(ldb)) { - return ldb_next_init(module); - } - - mem_ctx = talloc_new(module); - if (!mem_ctx) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = dsdb_schema_from_schema_dn(mem_ctx, module, - lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), - schema_dn, &schema); - - if (ret == LDB_ERR_NO_SUCH_OBJECT) { - ldb_reset_err_string(ldb); - ldb_debug(ldb, LDB_DEBUG_WARNING, - "schema_fsmo_init: no schema head present: (skip schema loading)\n"); - talloc_free(mem_ctx); - return ldb_next_init(module); - } - - if (ret != LDB_SUCCESS) { - talloc_free(mem_ctx); - return ret; - } - - /* dsdb_set_schema() steal schema into the ldb_context */ - ret = dsdb_set_schema(ldb, schema); - if (ret != LDB_SUCCESS) { - ldb_debug_set(ldb, LDB_DEBUG_FATAL, - "schema_fsmo_init: dsdb_set_schema() failed: %d:%s", - ret, ldb_strerror(ret)); - talloc_free(mem_ctx); - return ret; - } - - talloc_free(mem_ctx); - return ldb_next_init(module); -} - -static int schema_fsmo_add(struct ldb_module *module, struct ldb_request *req) -{ - struct ldb_context *ldb; - struct dsdb_schema *schema; - const struct ldb_val *attributeID = NULL; - const struct ldb_val *governsID = NULL; - const char *oid_attr = NULL; - const char *oid = NULL; - uint32_t id32; - WERROR status; - - ldb = ldb_module_get_ctx(module); - - /* special objects should always go through */ - if (ldb_dn_is_special(req->op.add.message->dn)) { - return ldb_next_request(module, req); - } - - /* replicated update should always go through */ - if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) { - return ldb_next_request(module, req); - } - - schema = dsdb_get_schema(ldb); - if (!schema) { - return ldb_next_request(module, req); - } - - if (!schema->fsmo.we_are_master) { - ldb_debug_set(ldb, LDB_DEBUG_ERROR, - "schema_fsmo_add: we are not master: reject request\n"); - return LDB_ERR_UNWILLING_TO_PERFORM; - } - - attributeID = ldb_msg_find_ldb_val(req->op.add.message, "attributeID"); - governsID = ldb_msg_find_ldb_val(req->op.add.message, "governsID"); - - if (attributeID) { - oid_attr = "attributeID"; - oid = talloc_strndup(req, (const char *)attributeID->data, attributeID->length); - } else if (governsID) { - oid_attr = "governsID"; - oid = talloc_strndup(req, (const char *)governsID->data, governsID->length); - } else { - return ldb_next_request(module, req); - } - - if (!oid) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - - status = dsdb_map_oid2int(schema, oid, &id32); - if (W_ERROR_IS_OK(status)) { - return ldb_next_request(module, req); - } else if (!W_ERROR_EQUAL(WERR_DS_NO_MSDS_INTID, status)) { - ldb_debug_set(ldb, LDB_DEBUG_ERROR, - "schema_fsmo_add: failed to map %s[%s]: %s\n", - oid_attr, oid, win_errstr(status)); - return LDB_ERR_UNWILLING_TO_PERFORM; - } - - status = dsdb_create_prefix_mapping(ldb, schema, oid); - if (!W_ERROR_IS_OK(status)) { - ldb_debug_set(ldb, LDB_DEBUG_ERROR, - "schema_fsmo_add: failed to create prefix mapping for %s[%s]: %s\n", - oid_attr, oid, win_errstr(status)); - return LDB_ERR_UNWILLING_TO_PERFORM; - } - - return ldb_next_request(module, req); -} - -static int schema_fsmo_extended(struct ldb_module *module, struct ldb_request *req) -{ - struct ldb_context *ldb; - struct ldb_dn *schema_dn; - struct dsdb_schema *schema; - int ret; - TALLOC_CTX *mem_ctx; - - ldb = ldb_module_get_ctx(module); - - if (strcmp(req->op.extended.oid, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID) != 0) { - return ldb_next_request(module, req); - } - - schema_dn = samdb_schema_dn(ldb); - if (!schema_dn) { - ldb_reset_err_string(ldb); - ldb_debug(ldb, LDB_DEBUG_WARNING, - "schema_fsmo_extended: no schema dn present: (skip schema loading)\n"); - return ldb_next_request(module, req); - } - - mem_ctx = talloc_new(module); - if (!mem_ctx) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = dsdb_schema_from_schema_dn(mem_ctx, module, - lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), - schema_dn, &schema); - - if (ret == LDB_ERR_NO_SUCH_OBJECT) { - ldb_reset_err_string(ldb); - ldb_debug(ldb, LDB_DEBUG_WARNING, - "schema_fsmo_extended: no schema head present: (skip schema loading)\n"); - talloc_free(mem_ctx); - return ldb_next_request(module, req); - } - - if (ret != LDB_SUCCESS) { - talloc_free(mem_ctx); - return ldb_next_request(module, req); - } - - /* Replace the old schema*/ - ret = dsdb_set_schema(ldb, schema); - if (ret != LDB_SUCCESS) { - ldb_debug_set(ldb, LDB_DEBUG_FATAL, - "schema_fsmo_extended: dsdb_set_schema() failed: %d:%s", - ret, ldb_strerror(ret)); - talloc_free(mem_ctx); - return ret; - } - - dsdb_make_schema_global(ldb); - - talloc_free(mem_ctx); - return LDB_SUCCESS; -} - -static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg, - const struct dsdb_schema *schema) -{ - const struct dsdb_class *sclass; - int ret; - - for (sclass = schema->classes; sclass; sclass = sclass->next) { - ret = ldb_msg_add_string(msg, "objectClasses", schema_class_to_description(msg, sclass)); - if (ret != LDB_SUCCESS) { - return ret; - } - } - return LDB_SUCCESS; -} -static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg, - const struct dsdb_schema *schema) -{ - const struct dsdb_attribute *attribute; - int ret; - - for (attribute = schema->attributes; attribute; attribute = attribute->next) { - ret = ldb_msg_add_string(msg, "attributeTypes", schema_attribute_to_description(msg, attribute)); - if (ret != LDB_SUCCESS) { - return ret; - } - } - return LDB_SUCCESS; -} - -static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg, - const struct dsdb_schema *schema) -{ - const struct dsdb_class *sclass; - int ret; - - for (sclass = schema->classes; sclass; sclass = sclass->next) { - if (sclass->auxiliaryClass || sclass->systemAuxiliaryClass) { - char *ditcontentrule = schema_class_to_dITContentRule(msg, sclass, schema); - if (!ditcontentrule) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - ret = ldb_msg_add_steal_string(msg, "dITContentRules", ditcontentrule); - if (ret != LDB_SUCCESS) { - return ret; - } - } - } - return LDB_SUCCESS; -} - -static int generate_extendedAttributeInfo(struct ldb_context *ldb, - struct ldb_message *msg, - const struct dsdb_schema *schema) -{ - const struct dsdb_attribute *attribute; - int ret; - - for (attribute = schema->attributes; attribute; attribute = attribute->next) { - char *val = schema_attribute_to_extendedInfo(msg, attribute); - if (!val) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = ldb_msg_add_string(msg, "extendedAttributeInfo", val); - if (ret != LDB_SUCCESS) { - return ret; - } - } - - return LDB_SUCCESS; -} - -static int generate_extendedClassInfo(struct ldb_context *ldb, - struct ldb_message *msg, - const struct dsdb_schema *schema) -{ - const struct dsdb_class *sclass; - int ret; - - for (sclass = schema->classes; sclass; sclass = sclass->next) { - char *val = schema_class_to_extendedInfo(msg, sclass); - if (!val) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = ldb_msg_add_string(msg, "extendedClassInfo", val); - if (ret != LDB_SUCCESS) { - return ret; - } - } - - return LDB_SUCCESS; -} - - -static int generate_possibleInferiors(struct ldb_context *ldb, struct ldb_message *msg, - const struct dsdb_schema *schema) -{ - struct ldb_dn *dn = msg->dn; - int ret, i; - const char *first_component_name = ldb_dn_get_component_name(dn, 0); - const struct ldb_val *first_component_val; - const struct dsdb_class *schema_class; - const char **possibleInferiors; - - if (strcasecmp(first_component_name, "cn") != 0) { - return LDB_SUCCESS; - } - - first_component_val = ldb_dn_get_component_val(dn, 0); - - schema_class = dsdb_class_by_cn_ldb_val(schema, first_component_val); - if (schema_class == NULL) { - return LDB_SUCCESS; - } - - possibleInferiors = schema_class->possibleInferiors; - if (possibleInferiors == NULL) { - return LDB_SUCCESS; - } - - for (i=0;possibleInferiors[i];i++) { - ret = ldb_msg_add_string(msg, "possibleInferiors", possibleInferiors[i]); - if (ret != LDB_SUCCESS) { - return ret; - } - } - - return LDB_SUCCESS; -} - - -/* Add objectClasses, attributeTypes and dITContentRules from the - schema object (they are not stored in the database) - */ -static int schema_fsmo_search_callback(struct ldb_request *req, struct ldb_reply *ares) -{ - struct ldb_context *ldb; - struct schema_fsmo_search_data *ac; - struct schema_fsmo_private_data *mc; - int i, ret; - - ac = talloc_get_type(req->context, struct schema_fsmo_search_data); - mc = talloc_get_type(ldb_module_get_private(ac->module), struct schema_fsmo_private_data); - 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) { - return ldb_module_done(ac->req, ares->controls, - ares->response, ares->error); - } - /* Only entries are interesting, and we handle the case of the parent seperatly */ - - switch (ares->type) { - case LDB_REPLY_ENTRY: - - if (ldb_dn_compare(ares->message->dn, mc->aggregate_dn) == 0) { - for (i=0; i < ARRAY_SIZE(generated_attrs); i++) { - if (generated_attrs[i].aggregate && - ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) { - ret = generated_attrs[i].fn(ldb, ares->message, ac->schema); - if (ret != LDB_SUCCESS) { - return ret; - } - } - } - } else { - for (i=0; i < ARRAY_SIZE(generated_attrs); i++) { - if (!generated_attrs[i].aggregate && - ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) { - ret = generated_attrs[i].fn(ldb, ares->message, ac->schema); - if (ret != LDB_SUCCESS) { - return ret; - } - } - } - } - - - return ldb_module_send_entry(ac->req, ares->message, ares->controls); - - case LDB_REPLY_REFERRAL: - - return ldb_module_send_referral(ac->req, ares->referral); - - case LDB_REPLY_DONE: - - return ldb_module_done(ac->req, ares->controls, - ares->response, ares->error); - } - - return LDB_SUCCESS; -} - -/* search */ -static int schema_fsmo_search(struct ldb_module *module, struct ldb_request *req) -{ - struct ldb_context *ldb = ldb_module_get_ctx(module); - int i, ret; - struct schema_fsmo_search_data *search_context; - struct ldb_request *down_req; - struct dsdb_schema *schema = dsdb_get_schema(ldb); - - if (!schema || !ldb_module_get_private(module)) { - /* If there is no schema, there is little we can do */ - return ldb_next_request(module, req); - } - for (i=0; i < ARRAY_SIZE(generated_attrs); i++) { - if (ldb_attr_in_list(req->op.search.attrs, generated_attrs[i].attr)) { - break; - } - } - if (i == ARRAY_SIZE(generated_attrs)) { - /* No request for a generated attr found, nothing to - * see here, move along... */ - return ldb_next_request(module, req); - } - - search_context = talloc(req, struct schema_fsmo_search_data); - if (!search_context) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - - search_context->module = module; - search_context->req = req; - search_context->schema = schema; - - ret = ldb_build_search_req_ex(&down_req, ldb, search_context, - req->op.search.base, - req->op.search.scope, - req->op.search.tree, - req->op.search.attrs, - req->controls, - search_context, schema_fsmo_search_callback, - req); - if (ret != LDB_SUCCESS) { - return LDB_ERR_OPERATIONS_ERROR; - } - - return ldb_next_request(module, down_req); -} - - -_PUBLIC_ const struct ldb_module_ops ldb_schema_fsmo_module_ops = { - .name = "schema_fsmo", - .init_context = schema_fsmo_init, - .add = schema_fsmo_add, - .extended = schema_fsmo_extended, - .search = schema_fsmo_search -}; diff --git a/source4/dsdb/samdb/ldb_modules/schema_load.c b/source4/dsdb/samdb/ldb_modules/schema_load.c new file mode 100644 index 0000000000..62c941d5eb --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/schema_load.c @@ -0,0 +1,258 @@ +/* + Unix SMB/CIFS mplementation. + + The module that handles the Schema FSMO Role Owner + checkings, it also loads the dsdb_schema. + + Copyright (C) Stefan Metzmacher 2007 + Copyright (C) Andrew Bartlett 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 . + +*/ + +#include "includes.h" +#include "ldb_module.h" +#include "dsdb/samdb/samdb.h" +#include "librpc/gen_ndr/ndr_misc.h" +#include "librpc/gen_ndr/ndr_drsuapi.h" +#include "librpc/gen_ndr/ndr_drsblobs.h" +#include "param/param.h" +#include "dsdb/samdb/ldb_modules/util.h" + +/* + Given an LDB module (pointing at the schema DB), and the DN, set the populated schema +*/ + +static int dsdb_schema_from_schema_dn(TALLOC_CTX *mem_ctx, struct ldb_module *module, + struct smb_iconv_convenience *iconv_convenience, + struct ldb_dn *schema_dn, + struct dsdb_schema **schema) +{ + TALLOC_CTX *tmp_ctx; + char *error_string; + int ret; + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct ldb_result *schema_res; + struct ldb_result *a_res; + struct ldb_result *c_res; + static const char *schema_attrs[] = { + "prefixMap", + "schemaInfo", + "fSMORoleOwner", + NULL + }; + unsigned flags; + + tmp_ctx = talloc_new(mem_ctx); + if (!tmp_ctx) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* we don't want to trace the schema load */ + flags = ldb_get_flags(ldb); + ldb_set_flags(ldb, flags & ~LDB_FLG_ENABLE_TRACING); + + /* + * setup the prefix mappings and schema info + */ + ret = dsdb_module_search_dn(module, tmp_ctx, &schema_res, + schema_dn, schema_attrs); + if (ret == LDB_ERR_NO_SUCH_OBJECT) { + goto failed; + } else if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, + "dsdb_schema: failed to search the schema head: %s", + ldb_errstring(ldb)); + goto failed; + } + + /* + * load the attribute definitions + */ + ret = dsdb_module_search(module, tmp_ctx, &a_res, + schema_dn, LDB_SCOPE_ONELEVEL, NULL, + "(objectClass=attributeSchema)"); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, + "dsdb_schema: failed to search attributeSchema objects: %s", + ldb_errstring(ldb)); + goto failed; + } + + /* + * load the objectClass definitions + */ + ret = dsdb_module_search(module, tmp_ctx, &c_res, + schema_dn, LDB_SCOPE_ONELEVEL, NULL, + "(objectClass=classSchema)"); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, + "dsdb_schema: failed to search attributeSchema objects: %s", + ldb_errstring(ldb)); + goto failed; + } + + ret = dsdb_schema_from_ldb_results(tmp_ctx, ldb, + lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), + schema_res, a_res, c_res, schema, &error_string); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, + "dsdb_schema load failed: %s", + error_string); + goto failed; + } + talloc_steal(mem_ctx, *schema); + +failed: + if (flags & LDB_FLG_ENABLE_TRACING) { + flags = ldb_get_flags(ldb); + ldb_set_flags(ldb, flags | LDB_FLG_ENABLE_TRACING); + } + talloc_free(tmp_ctx); + return ret; +} + + +static int schema_load_init(struct ldb_module *module) +{ + struct ldb_context *ldb; + TALLOC_CTX *mem_ctx; + struct ldb_dn *schema_dn; + struct dsdb_schema *schema; + int ret; + + ret = ldb_next_init(module); + if (ret != LDB_SUCCESS) { + return ret; + } + + ldb = ldb_module_get_ctx(module); + schema_dn = samdb_schema_dn(ldb); + if (!schema_dn) { + ldb_reset_err_string(ldb); + ldb_debug(ldb, LDB_DEBUG_WARNING, + "schema_load_init: no schema dn present: (skip schema loading)\n"); + return LDB_SUCCESS; + } + + if (dsdb_get_schema(ldb)) { + return LDB_SUCCESS; + } + + mem_ctx = talloc_new(module); + if (!mem_ctx) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = dsdb_schema_from_schema_dn(mem_ctx, module, + lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), + schema_dn, &schema); + + if (ret == LDB_ERR_NO_SUCH_OBJECT) { + ldb_reset_err_string(ldb); + ldb_debug(ldb, LDB_DEBUG_WARNING, + "schema_load_init: no schema head present: (skip schema loading)\n"); + talloc_free(mem_ctx); + return LDB_SUCCESS; + } + + if (ret != LDB_SUCCESS) { + talloc_free(mem_ctx); + return ret; + } + + /* dsdb_set_schema() steal schema into the ldb_context */ + ret = dsdb_set_schema(ldb, schema); + if (ret != LDB_SUCCESS) { + ldb_debug_set(ldb, LDB_DEBUG_FATAL, + "schema_load_init: dsdb_set_schema() failed: %d:%s", + ret, ldb_strerror(ret)); + talloc_free(mem_ctx); + return ret; + } + + talloc_free(mem_ctx); + return LDB_SUCCESS; +} + +static int schema_load_extended(struct ldb_module *module, struct ldb_request *req) +{ + struct ldb_context *ldb; + struct ldb_dn *schema_dn; + struct dsdb_schema *schema; + int ret; + TALLOC_CTX *mem_ctx; + + ldb = ldb_module_get_ctx(module); + + if (strcmp(req->op.extended.oid, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID) != 0) { + return ldb_next_request(module, req); + } + + schema_dn = samdb_schema_dn(ldb); + if (!schema_dn) { + ldb_reset_err_string(ldb); + ldb_debug(ldb, LDB_DEBUG_WARNING, + "schema_load_extended: no schema dn present: (skip schema loading)\n"); + return ldb_next_request(module, req); + } + + mem_ctx = talloc_new(module); + if (!mem_ctx) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = dsdb_schema_from_schema_dn(mem_ctx, module, + lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), + schema_dn, &schema); + + if (ret == LDB_ERR_NO_SUCH_OBJECT) { + ldb_reset_err_string(ldb); + ldb_debug(ldb, LDB_DEBUG_WARNING, + "schema_load_extended: no schema head present: (skip schema loading)\n"); + talloc_free(mem_ctx); + return ldb_next_request(module, req); + } + + if (ret != LDB_SUCCESS) { + talloc_free(mem_ctx); + return ldb_next_request(module, req); + } + + /* Replace the old schema*/ + ret = dsdb_set_schema(ldb, schema); + if (ret != LDB_SUCCESS) { + ldb_debug_set(ldb, LDB_DEBUG_FATAL, + "schema_load_extended: dsdb_set_schema() failed: %d:%s", + ret, ldb_strerror(ret)); + talloc_free(mem_ctx); + return ret; + } + + dsdb_make_schema_global(ldb); + + talloc_free(mem_ctx); + return LDB_SUCCESS; +} + + +_PUBLIC_ const struct ldb_module_ops ldb_schema_load_module_ops = { + .name = "schema_load", + .init_context = schema_load_init, + .extended = schema_load_extended, +}; diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index f3011521d4..4df1188156 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -678,8 +678,9 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, "linked_attributes", "extended_dn_out_ldb"] modules_list2 = ["show_deleted", + "schema_load", "new_partition", - "partition"] + "partition"] ldap_backend_line = "# No LDAP backend" if ldap_backend is not None: ldap_backend_line = "ldapBackend: %s" % ldap_backend.ldapi_uri @@ -712,7 +713,7 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, "SCHEMADN_MOD2": ",objectguid", "CONFIGDN": ldb.Dn(schema.ldb, names.configdn).get_casefold(), "DOMAINDN": ldb.Dn(schema.ldb, names.domaindn).get_casefold(), - "SCHEMADN_MOD": "schema_fsmo", + "SCHEMADN_MOD": "schema_data", "CONFIGDN_MOD": "naming_fsmo", "DOMAINDN_MOD": "pdc_fsmo", "MODULES_LIST": ",".join(modules_list), -- cgit