dsdb: Ensure replication of renames works in schema partition
authorAndrew Bartlett <abartlet@samba.org>
Wed, 14 Jun 2017 01:12:32 +0000 (13:12 +1200)
committerGarming Sam <garming@samba.org>
Wed, 14 Jun 2017 23:24:25 +0000 (01:24 +0200)
This caused failures against vampire_dc (on large-dc), likely due to
more frequent replication propagating the record before it was renamed.
The DC ran out of RIDs and RID allocation causes schema replication,
which failed.

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
BUG: https://bugzilla.samba.org/show_bug.cgi?id=12841
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
source4/dsdb/common/util.c
source4/dsdb/samdb/ldb_modules/repl_meta_data.c
source4/dsdb/samdb/ldb_modules/util.h
source4/torture/drs/python/repl_schema.py

index 8f74b45a84e9651ef9e3db3ce854dadb083ce6c8..b46a7fc4054078754db21a3e69fbfd1b731e18e2 100644 (file)
 #include "../lib/util/util_runcmd.h"
 #include "lib/util/access.h"
 
+/*
+ * This included to allow us to handle DSDB_FLAG_REPLICATED_UPDATE in
+ * dsdb_request_add_controls()
+ */
+#include "dsdb/samdb/ldb_modules/util.h"
+
 /*
   search the sam for the specified attributes in a specific domain, filter on
   objectSid being in domain_sid.
@@ -4309,6 +4315,13 @@ int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
                }
        }
 
+       if (dsdb_flags & DSDB_FLAG_REPLICATED_UPDATE) {
+               ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+       }
+
        return LDB_SUCCESS;
 }
 
index 4f077c01a26cba718b3f9181d11daea1b6a05146..ce06ee8901352fd54145416dafd6cec6efb188bd 100644 (file)
@@ -4519,7 +4519,14 @@ static int replmd_name_modify(struct replmd_replicated_request *ar,
                goto failed;
        }
 
-       ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
+       /*
+        * We have to mark this as a replicated update otherwise
+        * schema_data may reject a rename in the schema partition
+        */
+
+       ret = dsdb_module_modify(ar->module, msg,
+                                DSDB_FLAG_OWN_MODULE|DSDB_FLAG_REPLICATED_UPDATE,
+                                req);
        if (ret != LDB_SUCCESS) {
                DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
                         ldb_dn_get_linearized(dn),
index e40730557a326710c81ebe885a47d867e1746f5f..5ecf0eee0d2e312d1baf464458f40cf216914e15 100644 (file)
@@ -38,3 +38,4 @@ struct netlogon_samlogon_response;
 #define DSDB_FLAG_OWN_MODULE                 0x00400000
 #define DSDB_FLAG_TOP_MODULE                 0x00800000
 #define DSDB_FLAG_TRUSTED                    0x01000000
+#define DSDB_FLAG_REPLICATED_UPDATE           0x02000000
index 0ce70e752823f200600f1292792ed401a0de5be9..4514237cc55a4aeb23bdfcb6488de74ad80ece37 100644 (file)
@@ -417,3 +417,34 @@ class DrsReplSchemaTestCase(drs_base.DrsBaseTestCase):
                                 nc_dn=self.schema_dn, forced=True)
         self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1,
                                 nc_dn=self.domain_dn, forced=True)
+
+    def test_rename(self):
+        """Basic plan is to create a classSchema
+           and attributeSchema objects, replicate Schema NC
+           and then check all objects are replicated correctly"""
+
+        # add new classSchema object
+        (c_ldn, c_dn) = self._schema_new_class(self.ldb_dc1, "cls-B", 20)
+
+        self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1,
+                                nc_dn=self.schema_dn, forced=True)
+
+        # check objects are replicated
+        self._check_object(c_dn)
+
+        # rename the Class CN
+        c_dn_new = ldb.Dn(self.ldb_dc1, str(c_dn))
+        c_dn_new.set_component(0,
+                               "CN",
+                               c_dn.get_component_value(0) + "-NEW")
+        try:
+            self.ldb_dc1.rename(c_dn, c_dn_new)
+        except LdbError, (num, _):
+            self.fail("failed to change CN for %s: %s" % (c_dn, _))
+
+        # force replication from DC1 to DC2
+        self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1,
+                                nc_dn=self.schema_dn, forced=True)
+
+        # check objects are replicated
+        self._check_object(c_dn_new)