summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/libnet/libnet_vampire.c126
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 */