From: Garming Sam Date: Fri, 18 Aug 2017 01:59:30 +0000 (+1200) Subject: schema: Allow schemaUpdateNow to refresh schema during a transaction X-Git-Tag: talloc-2.1.11~202 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2650e9258b88228544148f5254dee7958819f6eb;p=thirdparty%2Fsamba.git schema: Allow schemaUpdateNow to refresh schema during a transaction When we upgrade a schema from 2008R2 to 2012R2, we want to apply all the changes in a single transaction - if we can't apply all the updates then we don't want to be left with a schema halfway in between the two. However, as we apply each LDIF update, we also want to refresh the schema. There are 2 reasons for this: 1. The adprep .LDIF files provided by Microsoft have some writes to schemaUpdateNow in them. 2. Microsoft uses attribute OIDs in their adprep .LDIF files, which Samba doesn't handle so well. However, we can replace the OIDs with the attribute's ldapDisplayName and they work fine. But to do this, we need to query the schema to map the OID to attribute name. And to query the schema successfully, the schema needs to be refreshed after the new attribute object has been added. Basically this patch avoids bailing out during the dsdb_schema_refresh() if we are writing schemaUpdateNow as part of a larger transaction. Pair-programmed-with: Garming Sam Signed-off-by: Tim Beale Signed-off-by: Garming Sam Reviewed-by: Andrew Bartlett --- diff --git a/source4/dsdb/samdb/ldb_modules/rootdse.c b/source4/dsdb/samdb/ldb_modules/rootdse.c index d1a4409b602..0d486218c0b 100644 --- a/source4/dsdb/samdb/ldb_modules/rootdse.c +++ b/source4/dsdb/samdb/ldb_modules/rootdse.c @@ -1306,12 +1306,28 @@ static int rootdse_schemaupdatenow(struct ldb_module *module, struct ldb_request return ldb_next_request(module, req); } + /* + * schemaUpdateNow has been requested. Allow this to refresh the schema + * even if we're currently in the middle of a transaction + */ + ret = ldb_set_opaque(ldb, "dsdb_schema_refresh_expected", (void *)1); + if (ret != LDB_SUCCESS) { + return ldb_operr(ldb); + } + ret = ldb_extended(ldb, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID, schema_dn, &ext_res); if (ret != LDB_SUCCESS) { + ldb_set_opaque(ldb, "dsdb_schema_refresh_expected", (void *)0); return ldb_operr(ldb); } talloc_free(ext_res); + + ret = ldb_set_opaque(ldb, "dsdb_schema_refresh_expected", (void *)0); + if (ret != LDB_SUCCESS) { + return ldb_operr(ldb); + } + return ldb_module_done(req, NULL, NULL, ret); } diff --git a/source4/dsdb/samdb/ldb_modules/schema_load.c b/source4/dsdb/samdb/ldb_modules/schema_load.c index 4013cdf6364..0bbd5fc60f0 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_load.c +++ b/source4/dsdb/samdb/ldb_modules/schema_load.c @@ -193,9 +193,17 @@ static struct dsdb_schema *dsdb_schema_refresh(struct ldb_module *module, struct return schema; } - /* We don't allow a schema reload during a transaction - nobody else can modify our schema behind our backs */ if (private_data->in_transaction) { - return schema; + + /* + * If the refresh is not an expected part of a larger + * transaction, then we don't allow a schema reload during a + * transaction. This stops others from modifying our schema + * behind our backs + */ + if (ldb_get_opaque(ldb, "dsdb_schema_refresh_expected") != (void *)1) { + return schema; + } } SMB_ASSERT(ev == ldb_get_event_context(ldb));