kcc: prevent non-determinism when running translation
authorGarming Sam <garming@catalyst.net.nz>
Fri, 10 Apr 2015 04:15:28 +0000 (16:15 +1200)
committerAndrew Bartlett <abartlet@samba.org>
Sat, 30 May 2015 19:05:24 +0000 (21:05 +0200)
RODC connections could appear first some runs while not always. This would
mean that repsFrom could accidentally be deleted.

Signed-off-by: Garming Sam <garming@catalyst.net.nz>
Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
python/samba/kcc_utils.py
source4/scripting/bin/samba_kcc

index f45a972d334f6600bdf99199c0402a4bf7f6cf44..2e0be7f287c025b945bd0030d908a7b3fe2d3ab2 100644 (file)
@@ -750,11 +750,12 @@ class DirectoryServiceAgent(object):
 
         :param from_dnstr: search for this from server entry
         """
-        #XXX is this connection always unique?
+        answer = []
         for connect in self.connect_table.values():
             if connect.get_from_dnstr() == from_dnstr:
-                return connect
-        return None
+                answer.append(connect)
+
+        return answer
 
     def dumpstr_current_replica_table(self):
         '''Debug dump string output of current replica table'''
@@ -1725,7 +1726,7 @@ class GraphNode(object):
            is a corresponding nTDSConnection object in the dsa.
         """
         for edge_dnstr in self.edge_from:
-            connect = dsa.get_connection_by_from_dnstr(edge_dnstr)
+            connections = dsa.get_connection_by_from_dnstr(edge_dnstr)
 
             # For each edge directed to the NC replica that
             # "should be present" on the local DC, the KCC determines
@@ -1739,8 +1740,16 @@ class GraphNode(object):
             #    the DC on which ri "is present".
             #
             #    c.options does not contain NTDSCONN_OPT_RODC_TOPOLOGY
-            if connect and not connect.is_rodc_topology():
+
+            found_valid = False
+            for connect in connections:
+                if connect.is_rodc_topology():
+                    continue
+                found_valid = True
+
+            if found_valid:
                 continue
+
             # if no such object exists then the KCC adds an object
             # c with the following attributes
 
index 8ba4decd7a4b3b2143e16f4ef11223af13651c69..c60b9f996a922c054c97869ca70e4aad5aa2bcce 100755 (executable)
@@ -881,20 +881,25 @@ class KCC(object):
         else:
             return False, None
 
-    def translate_ntdsconn(self):
+    def translate_ntdsconn(self, current_dsa=None):
         """This function adjusts values of repsFrom abstract attributes of NC
         replicas on the local DC to match those implied by
         nTDSConnection objects.
         [MS-ADTS] 6.2.2.5
         """
-        if self.my_dsa.is_translate_ntdsconn_disabled():
+        count = 0
+
+        if current_dsa is None:
+            current_dsa = self.my_dsa
+
+        if current_dsa.is_translate_ntdsconn_disabled():
             logger.debug("skipping translate_ntdsconn() "
                          "because disabling flag is set")
             return
 
         logger.debug("translate_ntdsconn(): enter")
 
-        current_rep_table, needed_rep_table = self.my_dsa.get_rep_tables()
+        current_rep_table, needed_rep_table = current_dsa.get_rep_tables()
 
         # Filled in with replicas we currently have that need deleting
         delete_reps = set()
@@ -959,7 +964,15 @@ class KCC(object):
                 # Retrieve my DSAs connection object (if it exists)
                 # that specifies the fromServer equivalent to
                 # the DSA that is specified in the repsFrom source
-                cn_conn = self.my_dsa.get_connection_by_from_dnstr(s_dnstr)
+                connections = current_dsa.get_connection_by_from_dnstr(s_dnstr)
+
+                count = 0
+                cn_conn = None
+
+                for con in connections:
+                    if con.is_rodc_topology():
+                        continue
+                    cn_conn = con
 
                 # Let (cn) be the nTDSConnection object such that (cn)
                 # is a child of the local DC's nTDSDSA object and
@@ -972,7 +985,7 @@ class KCC(object):
                 #     [...]
 
                 #XXX varying possible interpretations of rodc_topology
-                if cn_conn is None or cn_conn.is_rodc_topology():
+                if cn_conn is None:
                     t_repsFrom.to_be_deleted = True
                     continue
 
@@ -998,7 +1011,7 @@ class KCC(object):
             # Loop thru connections and add implied repsFrom tuples
             # for each NTDSConnection under our local DSA if the
             # repsFrom is not already present
-            for cn_conn in self.my_dsa.connect_table.values():
+            for cn_conn in current_dsa.connect_table.values():
 
                 implied, s_dsa = self.is_repsFrom_implied(n_rep, cn_conn)
                 if not implied:
@@ -1010,7 +1023,7 @@ class KCC(object):
                 # to have the correct attributes above
                 for t_repsFrom in n_rep.rep_repsFrom:
                     guidstr = str(t_repsFrom.source_dsa_obj_guid)
-                    #XXXX what?
+                    #XXX what?
                     if s_dsa is self.get_dsa_by_guidstr(guidstr):
                         s_dsa = None
                         break