s4:dsdb/schema: don't treat an older remote schema as SCHEMA_MISMATCH
authorStefan Metzmacher <metze@samba.org>
Thu, 4 Aug 2016 09:00:34 +0000 (11:00 +0200)
committerJeremy Allison <jra@samba.org>
Wed, 10 Aug 2016 22:49:14 +0000 (00:49 +0200)
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 <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source4/dsdb/schema/schema_info_attr.c
source4/torture/drs/unit/schemainfo_tests.c

index 76cd90da13a622dad2c8f7231f4ab64ab613b817..0d5401265bc9dcd0c25e04b29b4e5dbee4519c5a 100644 (file)
@@ -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;
        }
index 3b492b80a09659c99aa49cc88c5a3c72728c757d..e5a1c87bbebead9853adcd745406fd2d3c100b0e 100644 (file)
@@ -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;
 }