diff --git a/source4/dsdb/repl/replicated_objects.c b/source4/dsdb/repl/replicated_objects.c index fd567e9395c..372fb2d6928 100644 --- a/source4/dsdb/repl/replicated_objects.c +++ b/source4/dsdb/repl/replicated_objects.c @@ -914,8 +914,10 @@ WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb, } talloc_free(ext_res); - /* Save our updated prefixMap */ + /* Save our updated prefixMap and check the schema is good. */ if (working_schema) { + struct ldb_result *ext_res_2; + werr = dsdb_write_prefixes_from_schema_to_ldb(working_schema, ldb, working_schema); @@ -924,7 +926,9 @@ WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb, if (used_global_schema) { dsdb_set_global_schema(ldb); } else if (cur_schema ) { - dsdb_reference_schema(ldb, cur_schema, SCHEMA_MEMORY_ONLY); + dsdb_reference_schema(ldb, + cur_schema, + SCHEMA_MEMORY_ONLY); } DEBUG(0,("Failed to save updated prefixMap: %s\n", win_errstr(werr))); @@ -932,6 +936,33 @@ WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb, TALLOC_FREE(tmp_ctx); return werr; } + + /* + * Use dsdb_schema_from_db through dsdb extended to check we + * can load the schema currently sitting in the transaction. + * We need this check because someone might have written to + * the schema or prefixMap before we started the transaction, + * which may have caused corruption. + */ + ret = ldb_extended(ldb, DSDB_EXTENDED_SCHEMA_LOAD, + NULL, &ext_res_2); + + if (ret != LDB_SUCCESS) { + if (used_global_schema) { + dsdb_set_global_schema(ldb); + } else if (cur_schema) { + dsdb_reference_schema(ldb, cur_schema, SCHEMA_MEMORY_ONLY); + } + DEBUG(0,("Corrupt schema write attempt detected, " + "aborting schema modification operation.\n" + "This probably happened due to bad timing of " + "another schema edit: %s (%s)\n", + ldb_errstring(ldb), + ldb_strerror(ret))); + ldb_transaction_cancel(ldb); + TALLOC_FREE(tmp_ctx); + return WERR_FOOBAR; + } } ret = ldb_transaction_prepare_commit(ldb); diff --git a/source4/dsdb/samdb/ldb_modules/schema_load.c b/source4/dsdb/samdb/ldb_modules/schema_load.c index d9396c9c933..473a2e0a1f7 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_load.c +++ b/source4/dsdb/samdb/ldb_modules/schema_load.c @@ -552,26 +552,35 @@ static int schema_load_extended(struct ldb_module *module, struct ldb_request *r struct dsdb_schema *schema; int ret; - if (strcmp(req->op.extended.oid, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID) != 0) { + if (strcmp(req->op.extended.oid, DSDB_EXTENDED_SCHEMA_LOAD) == 0) { + + ret = dsdb_schema_from_db(module, req, 0, &schema); + if (ret == LDB_SUCCESS) { + return ldb_module_done(req, NULL, NULL, LDB_SUCCESS); + } + return ret; + + } else if (strcmp(req->op.extended.oid, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID) == 0) { + /* Force a refresh */ + schema = dsdb_get_schema(ldb, NULL); + + ret = dsdb_schema_set_indices_and_attributes(ldb, + schema, + SCHEMA_WRITE); + + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to write new " + "@INDEXLIST and @ATTRIBUTES " + "records for updated schema: %s", + ldb_errstring(ldb)); + return ret; + } + + return ldb_next_request(module, req); + } else { + /* Pass to next module, the partition one should finish the chain */ return ldb_next_request(module, req); } - /* Force a refresh */ - schema = dsdb_get_schema(ldb, NULL); - - ret = dsdb_schema_set_indices_and_attributes(ldb, - schema, - SCHEMA_WRITE); - - if (ret != LDB_SUCCESS) { - ldb_asprintf_errstring(ldb, "Failed to write new " - "@INDEXLIST and @ATTRIBUTES " - "records for updated schema: %s", - ldb_errstring(ldb)); - return ret; - } - - /* Pass to next module, the partition one should finish the chain */ - return ldb_next_request(module, req); } static int schema_read_lock(struct ldb_module *module) diff --git a/source4/dsdb/samdb/samdb.h b/source4/dsdb/samdb/samdb.h index e1b0e4aa4e3..0835ff660cd 100644 --- a/source4/dsdb/samdb/samdb.h +++ b/source4/dsdb/samdb/samdb.h @@ -272,6 +272,8 @@ struct dsdb_create_partition_exop { */ #define DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID "1.3.6.1.4.1.7165.4.4.2" +#define DSDB_EXTENDED_SCHEMA_LOAD "1.3.6.1.4.1.7165.4.4.10" + #define DSDB_EXTENDED_SCHEMA_UPGRADE_IN_PROGRESS_OID "1.3.6.1.4.1.7165.4.4.6" #define DSDB_OPENLDAP_DEREFERENCE_CONTROL "1.3.6.1.4.1.4203.666.5.16"