diff options
-rw-r--r-- | source4/libnet/libnet_vampire.c | 126 |
1 files changed, 119 insertions, 7 deletions
diff --git a/source4/libnet/libnet_vampire.c b/source4/libnet/libnet_vampire.c index 599119f814..0f20b151ab 100644 --- a/source4/libnet/libnet_vampire.c +++ b/source4/libnet/libnet_vampire.c @@ -216,6 +216,77 @@ NTSTATUS libnet_vampire_cb_check_options(void *private_data, return NT_STATUS_OK; } +static NTSTATUS libnet_vampire_merge_schema(struct ldb_context *ldb, + struct dsdb_schema *dest_schema, + const struct dsdb_schema *ref_schema) +{ + const struct dsdb_class *cur_class = NULL; + const struct dsdb_attribute *cur_attr = NULL; + int ret; + + for (cur_class = ref_schema->classes; + cur_class; + cur_class = cur_class->next) + { + const struct dsdb_class *tmp1; + struct dsdb_class *tmp2; + + tmp1 = dsdb_class_by_governsID_id(dest_schema, + cur_class->governsID_id); + if (tmp1 != NULL) { + continue; + } + + /* + * 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. + */ + tmp2 = talloc(dest_schema->classes, struct dsdb_class); + if (tmp2 == NULL) { + return NT_STATUS_NO_MEMORY; + } + *tmp2 = *cur_class; + DLIST_ADD(dest_schema->classes, tmp2); + } + + for (cur_attr = ref_schema->attributes; + cur_attr; + cur_attr = cur_attr->next) + { + const struct dsdb_attribute *tmp1; + struct dsdb_attribute *tmp2; + + tmp1 = dsdb_attribute_by_attributeID_id(dest_schema, + cur_attr->attributeID_id); + if (tmp1 != NULL) { + continue; + } + + /* + * 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. + */ + tmp2 = talloc(dest_schema->attributes, struct dsdb_attribute); + if (tmp2 == NULL) { + return NT_STATUS_NO_MEMORY; + } + *tmp2 = *cur_attr; + DLIST_ADD(dest_schema->attributes, tmp2); + } + + ret = dsdb_setup_sorted_accessors(ldb, dest_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) { @@ -321,6 +392,11 @@ static NTSTATUS libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name); s_dsa->other_info->dns_name = tmp_dns_name; + if (s->self_made_schema == NULL) { + DEBUG(0,("libnet_vampire_cb_apply_schema: called with out self_made_schema\n")); + return NT_STATUS_INTERNAL_ERROR; + } + schema_ldb = provision_get_schema(s, s->lp_ctx, c->forest->schema_dn_str, &s->prefixmap_blob); @@ -352,9 +428,31 @@ static NTSTATUS libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s while (schema_list) { uint32_t converted_obj_count = 0; uint32_t failed_obj_count = 0; + int cycle_before_switching = 0; TALLOC_CTX *tmp_ctx = talloc_new(s); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); + if (s->self_made_schema != working_schema) { + /* + * If the selfmade schema is not the schema used to + * translate and validate replicated object, + * Which means that we are using the bootstrap schema + * Then we add attributes and classes that were already + * translated to the working schema, the idea is that + * we might need to add new attributes and classes + * to be able to translate critical replicated objects + * and without that we wouldn't be able to translate them + */ + NTSTATUS nt_status; + + nt_status = libnet_vampire_merge_schema(s->ldb, + working_schema, + s->self_made_schema); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + } + for (schema_list_item = schema_list; schema_list_item; schema_list_item=schema_list_next_item) { struct dsdb_extended_replicated_object object; @@ -385,16 +483,22 @@ static NTSTATUS libnet_vampire_cb_apply_schema(struct libnet_vampire_cb_state *s * Convert the schema from ldb_message format * (OIDs as OID strings) into schema, using * the remote prefixMap + * + * It's not likely, but possible to get the + * same object twice and we should keep + * the last instance. */ - status = dsdb_schema_set_el_from_ldb_msg(s->ldb, - s->self_made_schema, - object.msg); + status = dsdb_schema_set_el_from_ldb_msg_dups(s->ldb, + s->self_made_schema, + object.msg, true); if (!W_ERROR_IS_OK(status)) { DEBUG(1,("Warning: failed to convert object %s into a schema element: %s\n", ldb_dn_get_linearized(object.msg->dn), 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 +506,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 +515,15 @@ 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. + */ + cycle_before_switching = lpcfg_parm_int(s->lp_ctx, NULL, + "become dc", + "schema convert retrial", 1); + if (failed_obj_count == 0 || pass_no > cycle_before_switching) { /* prepare for another cycle */ working_schema = s->self_made_schema; @@ -422,6 +533,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 */ |