samba_kcc: Fix compile failures and correctly implement MS-ADTS 6.2.2.3.1 ISTG selection
authorAndrew Bartlett <abartlet@samba.org>
Tue, 17 Feb 2015 23:13:38 +0000 (12:13 +1300)
committerAndrew Bartlett <abartlet@samba.org>
Thu, 28 May 2015 05:25:07 +0000 (07:25 +0200)
The previous code did not operate as c_rep.source_dsa_invocation_id was not valid, and in any case
this was not the correct check.  We need to look for the old interSiteTopologyGenerator in our
list of replication partners, and confirm it is current.

Andrew Bartlett

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
python/samba/kcc_utils.py

index e27d9091c877120cea0f77e98b0a3462940d3ec6..8da457018de4a2a583b05599bb7f1517d6ddec38 100644 (file)
@@ -377,6 +377,35 @@ class NCReplica(NamingContext):
             raise Exception("Could not set repsFrom for (%s) - (%s)" %
                             (self.nc_dnstr, estr))
 
+    def load_replUpToDateVector(self, samdb):
+        """Given an NC replica which has been discovered thru the nTDSDSA
+        database object, load the replUpToDateVector attribute for the local replica.
+        held by my dsa.  The replUpToDateVector attribute is not replicated so this
+        attribute is relative only to the local DSA that the samdb exists on
+        """
+        try:
+            res = samdb.search(base=self.nc_dnstr, scope=ldb.SCOPE_BASE,
+                               attrs=[ "replUpToDateVector" ])
+
+        except ldb.LdbError, (enum, estr):
+            raise Exception("Unable to find NC for (%s) - (%s)" %
+                            (self.nc_dnstr, estr))
+
+        msg = res[0]
+
+        # Possibly no replUpToDateVector if this is a singleton DC
+        if "replUpToDateVector" in msg:
+            value = msg["replUpToDateVector"][0]
+            replUpToDateVectorBlob = ndr_unpack(drsblobs.replUpToDateVectorBlob, value)
+            if replUpToDateVectorBlob.version != 2:
+                # Samba only generates version 2, and this runs locally
+                raise AttributeError("Unexpected replUpToDateVector version %d"
+                                     % replUpToDateVectorBlob.version)
+
+            self.rep_replUpToDateVector_cursors = replUpToDateVectorBlob.ctr.cursors
+        else:
+            self.rep_replUpToDateVector_cursors = []
+
     def dumpstr_to_be_deleted(self):
         text=""
         for repsFrom in self.rep_repsFrom:
@@ -1489,16 +1518,18 @@ class Site(object):
             if c_rep.is_config():
                 break
 
-        if c_rep is None:
+        if not c_rep.is_config():
             raise Exception("Unable to find config NC replica for (%s)" %
                             mydsa.dsa_dnstr)
 
-        # Load repsFrom if not already loaded so we can get the current
+        # Load repsFrom and replUpToDateVector if not already loaded so we can get the current
         # state of the config replica and whether we are getting updates
         # from the istg
         c_rep.load_repsFrom(samdb)
 
-        # From MS-Tech ISTG selection:
+        c_rep.load_replUpToDateVector(samdb)
+
+        # From MS-ADTS 6.2.2.3.1 ISTG selection:
         #     First, the KCC on a writable DC determines whether it acts
         #     as an ISTG for its site
         #
@@ -1540,7 +1571,7 @@ class Site(object):
         else:
             f = self.site_topo_failover * 60 * 10000000
 
-        # From MS-Tech ISTG selection:
+        # From MS-ADTS 6.2.2.3.1 ISTG selection:
         #     If o != NULL and o!interSiteTopologyGenerator is not the
         #     nTDSDSA object for the local DC and
         #     o!interSiteTopologyGenerator is an element dj of sequence D:
@@ -1551,7 +1582,7 @@ class Site(object):
             j_idx = D_sort.index(d_dsa)
 
         if d_dsa is not None and d_dsa is not mydsa:
-           # From MS-Tech ISTG selection:
+           # From MS-ADTS 6.2.2.3.1 ISTG Selection:
            #     Let c be the cursor in the replUpToDateVector variable
            #     associated with the NC replica of the config NC such
            #     that c.uuidDsa = dj!invocationId. If no such c exists
@@ -1570,16 +1601,22 @@ class Site(object):
            #
            # last_success appears to be a double word containing
            #     number of 100 nanosecond intervals since the 1600s
-           if d_dsa.dsa_ivid != c_rep.source_dsa_invocation_id:
-               i_idx = j_idx
-               t_time = 0
+           found = False
+           for cursor in c_rep.rep_replUpToDateVector_cursors:
+               if d_dsa.dsa_ivid == cursor.source_dsa_invocation_id:
+                   found = True
+                   break
+
+           if not found:
+                i_idx = j_idx
+                t_time = 0
 
-           elif ntnow < (c_rep.last_success - f):
+           elif ntnow < (cursor.last_sync_success - f):
                i_idx = 0
                t_time = 0
            else:
                i_idx = j_idx
-               t_time = c_rep.last_success
+               t_time = cursor.last_sync_success
 
         # Otherwise (Nominate local DC as ISTG):
         #     Let i be the integer such that di is the nTDSDSA