From: Stefan Metzmacher Date: Thu, 4 Aug 2016 09:00:34 +0000 (+0200) Subject: s4:dsdb/schema: don't treat an older remote schema as SCHEMA_MISMATCH X-Git-Tag: tevent-0.9.30~162 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0a1627de6d7c70f2462a4d4db717ea50c8aefc2f;p=thirdparty%2Fsamba.git s4:dsdb/schema: don't treat an older remote schema as SCHEMA_MISMATCH It's perfectly valid to replicate from a partner with an older schema version, otherwise schema changes would block any other replication until every dc in the forest has the schema changes. The avoids an endless loop trying to get schema in sync with the partner. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12115 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- diff --git a/source4/dsdb/schema/schema_info_attr.c b/source4/dsdb/schema/schema_info_attr.c index 76cd90da13a..0d5401265bc 100644 --- a/source4/dsdb/schema/schema_info_attr.c +++ b/source4/dsdb/schema/schema_info_attr.c @@ -204,8 +204,17 @@ WERROR dsdb_schema_info_cmp(const struct dsdb_schema *schema, return werr; } - if (schema->schema_info->revision != schema_info->revision) { + if (schema->schema_info->revision > schema_info->revision) { + /* + * It's ok if our schema is newer than the remote one + */ + werr = WERR_OK; + } else if (schema->schema_info->revision < schema_info->revision) { werr = WERR_DS_DRA_SCHEMA_MISMATCH; + } else if (!GUID_equal(&schema->schema_info->invocation_id, + &schema_info->invocation_id)) + { + werr = WERR_DS_DRA_SCHEMA_CONFLICT; } else { werr = WERR_OK; } diff --git a/source4/torture/drs/unit/schemainfo_tests.c b/source4/torture/drs/unit/schemainfo_tests.c index 3b492b80a09..e5a1c87bbeb 100644 --- a/source4/torture/drs/unit/schemainfo_tests.c +++ b/source4/torture/drs/unit/schemainfo_tests.c @@ -344,14 +344,14 @@ static bool test_dsdb_schema_info_cmp(struct torture_context *tctx, WERR_INVALID_PARAMETER, "dsdb_schema_info_cmp(): unexpected result"); - /* test with valid schemaInfo, but not correct one */ + /* test with valid schemaInfo, but older one should be ok */ blob = strhex_to_data_blob(ctr, "FF0000000000000000000000000000000000000000"); torture_assert(tctx, blob.data, "Not enough memory!"); ctr->mappings[0].oid.length = blob.length; ctr->mappings[0].oid.binary_oid = blob.data; torture_assert_werr_equal(tctx, dsdb_schema_info_cmp(priv->schema, ctr), - WERR_DS_DRA_SCHEMA_MISMATCH, + WERR_OK, "dsdb_schema_info_cmp(): unexpected result"); /* test with correct schemaInfo, but invalid ATTID */ @@ -373,6 +373,73 @@ static bool test_dsdb_schema_info_cmp(struct torture_context *tctx, dsdb_schema_info_cmp(priv->schema, ctr), "dsdb_schema_info_cmp(): unexpected result"); + /* test with valid schemaInfo, but older revision */ + schema_info = *priv->schema->schema_info; + schema_info.revision -= 1; + torture_assert_werr_ok(tctx, + dsdb_blob_from_schema_info(&schema_info, tctx, &blob), + "dsdb_blob_from_schema_info() failed"); + ctr->mappings[0].oid.length = blob.length; + ctr->mappings[0].oid.binary_oid = blob.data; + torture_assert_werr_equal(tctx, + dsdb_schema_info_cmp(priv->schema, ctr), + WERR_OK, + "dsdb_schema_info_cmp(): unexpected result"); + + /* test with valid schemaInfo, but newer revision */ + schema_info = *priv->schema->schema_info; + schema_info.revision += 1; + torture_assert_werr_ok(tctx, + dsdb_blob_from_schema_info(&schema_info, tctx, &blob), + "dsdb_blob_from_schema_info() failed"); + ctr->mappings[0].oid.length = blob.length; + ctr->mappings[0].oid.binary_oid = blob.data; + torture_assert_werr_equal(tctx, + dsdb_schema_info_cmp(priv->schema, ctr), + WERR_DS_DRA_SCHEMA_MISMATCH, + "dsdb_schema_info_cmp(): unexpected result"); + + /* test with valid schemaInfo, but newer revision and other invocationId */ + schema_info = *priv->schema->schema_info; + schema_info.revision += 1; + schema_info.invocation_id.time_mid += 1; + torture_assert_werr_ok(tctx, + dsdb_blob_from_schema_info(&schema_info, tctx, &blob), + "dsdb_blob_from_schema_info() failed"); + ctr->mappings[0].oid.length = blob.length; + ctr->mappings[0].oid.binary_oid = blob.data; + torture_assert_werr_equal(tctx, + dsdb_schema_info_cmp(priv->schema, ctr), + WERR_DS_DRA_SCHEMA_MISMATCH, + "dsdb_schema_info_cmp(): unexpected result"); + + /* test with valid schemaInfo, but older revision and other invocationId */ + schema_info = *priv->schema->schema_info; + schema_info.revision -= 1; + schema_info.invocation_id.time_mid += 1; + torture_assert_werr_ok(tctx, + dsdb_blob_from_schema_info(&schema_info, tctx, &blob), + "dsdb_blob_from_schema_info() failed"); + ctr->mappings[0].oid.length = blob.length; + ctr->mappings[0].oid.binary_oid = blob.data; + torture_assert_werr_equal(tctx, + dsdb_schema_info_cmp(priv->schema, ctr), + WERR_OK, + "dsdb_schema_info_cmp(): unexpected result"); + + /* test with valid schemaInfo, but same revision and other invocationId */ + schema_info = *priv->schema->schema_info; + schema_info.invocation_id.time_mid += 1; + torture_assert_werr_ok(tctx, + dsdb_blob_from_schema_info(&schema_info, tctx, &blob), + "dsdb_blob_from_schema_info() failed"); + ctr->mappings[0].oid.length = blob.length; + ctr->mappings[0].oid.binary_oid = blob.data; + torture_assert_werr_equal(tctx, + dsdb_schema_info_cmp(priv->schema, ctr), + WERR_DS_DRA_SCHEMA_CONFLICT, + "dsdb_schema_info_cmp(): unexpected result"); + talloc_free(ctr); return true; }