From d461d6c9aa40165725d94437dac12ad1f8b53442 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Sun, 7 Oct 2012 21:46:38 -0700 Subject: [PATCH] libnet-vampire: add attributes and classes from the replicated schema to the bootstrap schema Replicated schema might have attributes and auxilary classes on some critical classes (ie. top, user, computer ) that are not in the bootstrap schema. Without those new attributes and classes, bootstrap schema is unable to translate those critical classes in the schema constructed from the replicated data. Without thoses classes new schema is useless and can't be indexed properly. In order to overcome this problem, we put all new attributes and classes definitions into the bootstrap schema so that foundations classes can be translated. --- source4/libnet/libnet_vampire.c | 130 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 126 insertions(+), 4 deletions(-) diff --git a/source4/libnet/libnet_vampire.c b/source4/libnet/libnet_vampire.c index 599119f..6d6c79c 100644 --- a/source4/libnet/libnet_vampire.c +++ b/source4/libnet/libnet_vampire.c @@ -216,6 +216,104 @@ NTSTATUS libnet_vampire_cb_check_options(void *private_data, return NT_STATUS_OK; } +/** + * @brief Add new classes found through the replication to the working schema + * + * New classes might be needed in order to translate critical classes in + * the schema created from the replication data. Without them, those classes + * (ie. top, users, computers) can't be translated and so the new schema can't + * be used because it lacks critical classes. + * + * @param[in] ldb A pointer to an ldb context + * + * @param[in] schema The current schema where the new classes + * will be added. + * + * @param[in] cls A linked list of replicated classes, not + * all classes needs to be added to the + * working schema. + * + * @return NT_STATUS_OK on success, a NT_STATUS_ERROR + * otherwise. + */ +static NTSTATUS libnet_vampire_add_new_repl_classes(struct ldb_context *ldb, + struct dsdb_schema *schema, + struct dsdb_class *cls) +{ + struct dsdb_class *cur; + int ret; + + for (cur = cls; cur; cur = cur->next) { + const struct dsdb_class *tmp = dsdb_class_by_governsID_id(schema, cur->governsID_id); + if (!tmp) { + /* + * Do a shallow copy so that original next and prev are + * not modified, we don't need to do a deep copy + * as the rest won't be modified and this is for + * a short lived object. + */ + struct dsdb_class* c = talloc_memdup(schema->classes, cur, sizeof(struct dsdb_class)); + DLIST_ADD(schema->classes, c); + } + } + ret = dsdb_setup_sorted_accessors(ldb, schema); + if (LDB_SUCCESS != ret) { + DEBUG(0,("Failed to add new attribute to reference schema!\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + return NT_STATUS_OK; +} + +/** + * @brief Add new attributes found through the replication to the working schema + * + * New attributes might be needed in order to translate critical classes in + * the schema created from the replication data. Without them those classes + * (ie. top, users, computers) can't be translated and so the new schema can't + * be used because it lacks critical classes. + * + * @param[in] ldb A pointer to an ldb context + * + * @param[in] schema The current schema where the new attributes + * will be added. + * + * @param[in] attrs A linked list of replicated attributes, not + * all attributes needs to be added to the + * working schema. + * + * @return NT_STATUS_OK on success, a NT_STATUS_ERROR + * otherwise. + */ +static NTSTATUS libnet_vampire_add_new_repl_attrs(struct ldb_context *ldb, + struct dsdb_schema *schema, + struct dsdb_attribute *attrs) +{ + struct dsdb_attribute *cur; + int ret; + + for (cur = attrs; cur; cur = cur->next) { + const struct dsdb_attribute *tmp = dsdb_attribute_by_attributeID_id(schema, cur->attributeID_id); + if (!tmp) { + /* + * Do a shallow copy so that original next and prev are + * not modified, we don't need to do a deep copy + * as the rest won't be modified and this is for + * a short lived object. + */ + struct dsdb_attribute* att = talloc_memdup(schema->attributes, cur, sizeof(struct dsdb_attribute)); + DLIST_ADD(schema->attributes, att); + } + } + ret = dsdb_setup_sorted_accessors(ldb, schema); + if (LDB_SUCCESS != ret) { + DEBUG(0,("Failed to add new attribute to reference schema!\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + return NT_STATUS_OK; +} + static NTSTATUS libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s, const struct libnet_BecomeDC_StoreChunk *c) { @@ -355,6 +453,23 @@ static NTSTATUS libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s TALLOC_CTX *tmp_ctx = talloc_new(s); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); + if (s->self_made_schema && s->self_made_schema != working_schema) { + struct dsdb_attribute *attrs = s->self_made_schema->attributes; + struct dsdb_class *cls = s->self_made_schema->classes; + NTSTATUS sts = libnet_vampire_add_new_repl_attrs(s->ldb, + working_schema, + attrs); + if (!NT_STATUS_IS_OK(sts)) { + return sts; + } + sts = libnet_vampire_add_new_repl_classes(s->ldb, + working_schema, + cls); + if (!NT_STATUS_IS_OK(sts)) { + return sts; + } + } + for (schema_list_item = schema_list; schema_list_item; schema_list_item=schema_list_next_item) { struct dsdb_extended_replicated_object object; @@ -395,6 +510,8 @@ static NTSTATUS libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s win_errstr(status))); failed_obj_count++; } else { + DEBUG(8,("Converted object %s into a schema element\n", + ldb_dn_get_linearized(object.msg->dn))); DLIST_REMOVE(schema_list, schema_list_item); converted_obj_count++; } @@ -402,9 +519,8 @@ static NTSTATUS libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s } talloc_free(tmp_ctx); - DEBUG(4,("Schema load pass %d: %d/%d of %d objects left to be converted.\n", - pass_no, failed_obj_count, converted_obj_count, object_count)); - pass_no++; + DEBUG(4,("Schema load pass %d: converted %d, %d of %d objects left to be converted.\n", + pass_no, converted_obj_count, failed_obj_count, object_count)); /* check if we converted any objects in this pass */ if (converted_obj_count == 0) { @@ -412,7 +528,12 @@ static NTSTATUS libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s return NT_STATUS_INTERNAL_ERROR; } - if (schema_list) { + /* + * Don't try to load the schema if there is missing object + * _and_ we are on the first pass as some critical objects + * might be missing. + */ + if (schema_list && (failed_obj_count == 0 || pass_no > 1)) { /* prepare for another cycle */ working_schema = s->self_made_schema; @@ -422,6 +543,7 @@ static NTSTATUS libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s return NT_STATUS_INTERNAL_ERROR; } } + pass_no++; }; /* free temp objects for 1st conversion phase */ -- 1.7.9.5