summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthieu Patou <mat@matws.net>2012-10-07 21:46:38 -0700
committerAndrew Bartlett <abartlet@samba.org>2013-05-23 20:26:17 +1000
commitc7d4b87512eabbff5172716a755a3cd61fe5476b (patch)
treea9507020863ddfb8425f012a8c2e667129693909
parentfe85bc1fb9ab2f891a9fd46bd8e00325622d39cf (diff)
downloadsamba-c7d4b87512eabbff5172716a755a3cd61fe5476b.tar.gz
samba-c7d4b87512eabbff5172716a755a3cd61fe5476b.tar.bz2
samba-c7d4b87512eabbff5172716a755a3cd61fe5476b.zip
libnet-vampire: add attributes and classes from the replicated schema to the bootstrap schema (bug #8680)
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. Pair-Programmed-With: Stefan Metzmacher <metze@samba.org> Signed-off-by: Matthieu Patou <mat@matws.net> Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
-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 */