int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema) { int ret; ret = dsdb_setup_sorted_accessors(ldb, schema); if (ret != LDB_SUCCESS) { return ret; } ret = schema_fill_constructed(schema); if (ret != LDB_SUCCESS) { return ret; } ret = ldb_set_opaque(ldb, "dsdb_schema", schema); if (ret != LDB_SUCCESS) { return ret; } /* Set the new attributes based on the new schema */ ret = dsdb_schema_set_attributes(ldb, schema, true); if (ret != LDB_SUCCESS) { return ret; } talloc_steal(ldb, schema); return LDB_SUCCESS; }
/** * Attach the schema to an opaque pointer on the ldb, * so ldb modules can find it */ int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema) { struct dsdb_schema *old_schema; int ret; ret = dsdb_setup_sorted_accessors(ldb, schema); if (ret != LDB_SUCCESS) { return ret; } old_schema = ldb_get_opaque(ldb, "dsdb_schema"); ret = ldb_set_opaque(ldb, "dsdb_schema", schema); if (ret != LDB_SUCCESS) { return ret; } /* Remove the reference to the schema we just overwrote - if there was * none, NULL is harmless here */ if (old_schema != schema) { talloc_unlink(ldb, old_schema); talloc_steal(ldb, schema); } ret = ldb_set_opaque(ldb, "dsdb_use_global_schema", NULL); if (ret != LDB_SUCCESS) { return ret; } /* Set the new attributes based on the new schema */ ret = dsdb_schema_set_attributes(ldb, schema, true); if (ret != LDB_SUCCESS) { return ret; } return LDB_SUCCESS; }
struct dsdb_schema *dsdb_schema_copy_shallow(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, const struct dsdb_schema *schema) { int ret; struct dsdb_class *cls; struct dsdb_attribute *attr; struct dsdb_schema *schema_copy; schema_copy = dsdb_new_schema(mem_ctx); if (!schema_copy) { return NULL; } /* schema base_dn */ schema_copy->base_dn = ldb_dn_copy(schema_copy, schema->base_dn); if (!schema_copy->base_dn) { goto failed; } /* copy prexiMap & schemaInfo */ schema_copy->prefixmap = dsdb_schema_pfm_copy_shallow(schema_copy, schema->prefixmap); if (!schema_copy->prefixmap) { goto failed; } schema_copy->schema_info = talloc_strdup(schema_copy, schema->schema_info); /* copy classes and attributes*/ for (cls = schema->classes; cls; cls = cls->next) { struct dsdb_class *class_copy = talloc_memdup(schema_copy, cls, sizeof(*cls)); if (!class_copy) { goto failed; } DLIST_ADD(schema_copy->classes, class_copy); } schema_copy->num_classes = schema->num_classes; for (attr = schema->attributes; attr; attr = attr->next) { struct dsdb_attribute *a_copy = talloc_memdup(schema_copy, attr, sizeof(*attr)); if (!a_copy) { goto failed; } DLIST_ADD(schema_copy->attributes, a_copy); } schema_copy->num_attributes = schema->num_attributes; /* rebuild indexes */ ret = dsdb_setup_sorted_accessors(ldb, schema_copy); if (ret != LDB_SUCCESS) { goto failed; } /* leave reload_seq_number = 0 so it will be refresh ASAP */ schema_copy->refresh_fn = schema->refresh_fn; schema_copy->loaded_from_module = schema->loaded_from_module; return schema_copy; failed: talloc_free(schema_copy); return NULL; }
static WERROR dsdb_repl_merge_working_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, struct dsdb_class); if (tmp2 == NULL) { return WERR_NOMEM; } *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, struct dsdb_attribute); if (tmp2 == NULL) { return WERR_NOMEM; } *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 WERR_INTERNAL_ERROR; } return WERR_OK; }
WERROR dsdb_repl_resolve_working_schema(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct dsdb_schema_prefixmap *pfm_remote, uint32_t cycle_before_switching, struct dsdb_schema *initial_schema, struct dsdb_schema *resulting_schema, uint32_t object_count, const struct drsuapi_DsReplicaObjectListItemEx *first_object) { struct schema_list { struct schema_list *next, *prev; const struct drsuapi_DsReplicaObjectListItemEx *obj; }; struct schema_list *schema_list = NULL, *schema_list_item, *schema_list_next_item; WERROR werr; struct dsdb_schema *working_schema; const struct drsuapi_DsReplicaObjectListItemEx *cur; DATA_BLOB empty_key = data_blob_null; int ret, pass_no; uint32_t ignore_attids[] = { DRSUAPI_ATTID_auxiliaryClass, DRSUAPI_ATTID_mayContain, DRSUAPI_ATTID_mustContain, DRSUAPI_ATTID_possSuperiors, DRSUAPI_ATTID_systemPossSuperiors, DRSUAPI_ATTID_INVALID }; /* create a list of objects yet to be converted */ for (cur = first_object; cur; cur = cur->next_object) { schema_list_item = talloc(mem_ctx, struct schema_list); if (schema_list_item == NULL) { return WERR_NOMEM; } schema_list_item->obj = cur; DLIST_ADD_END(schema_list, schema_list_item, struct schema_list); } /* resolve objects until all are resolved and in local schema */ pass_no = 1; working_schema = initial_schema; while (schema_list) { uint32_t converted_obj_count = 0; uint32_t failed_obj_count = 0; if (resulting_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 */ werr = dsdb_repl_merge_working_schema(ldb, working_schema, resulting_schema); if (!W_ERROR_IS_OK(werr)) { return werr; } } for (schema_list_item = schema_list; schema_list_item; schema_list_item=schema_list_next_item) { struct dsdb_extended_replicated_object object; cur = schema_list_item->obj; /* * Save the next item, now we have saved out * the current one, so we can DLIST_REMOVE it * safely */ schema_list_next_item = schema_list_item->next; /* * Convert the objects into LDB messages using the * schema we have so far. It's ok if we fail to convert * an object. We should convert more objects on next pass. */ werr = dsdb_convert_object_ex(ldb, working_schema, pfm_remote, cur, &empty_key, ignore_attids, 0, schema_list_item, &object); if (!W_ERROR_IS_OK(werr)) { DEBUG(4,("debug: Failed to convert schema " "object %s into ldb msg, " "will try during next loop\n", cur->object.identifier->dn)); failed_obj_count++; } else { /* * 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. */ werr = dsdb_schema_set_el_from_ldb_msg_dups(ldb, resulting_schema, object.msg, true); if (!W_ERROR_IS_OK(werr)) { DEBUG(4,("debug: failed to convert " "object %s into a schema element, " "will try during next loop: %s\n", ldb_dn_get_linearized(object.msg->dn), win_errstr(werr))); 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); TALLOC_FREE(schema_list_item); converted_obj_count++; } } } 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) { DEBUG(0,("Can't continue Schema load: " "didn't manage to convert any objects: " "all %d remaining of %d objects " "failed to convert\n", failed_obj_count, object_count)); return WERR_INTERNAL_ERROR; } /* * 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 (failed_obj_count == 0 || pass_no > cycle_before_switching) { /* prepare for another cycle */ working_schema = resulting_schema; ret = dsdb_setup_sorted_accessors(ldb, working_schema); if (LDB_SUCCESS != ret) { DEBUG(0,("Failed to create schema-cache indexes!\n")); return WERR_INTERNAL_ERROR; } } pass_no++; } return WERR_OK; }