dbcheck: Add a rule regarding replica locations
authorGarming Sam <garming@catalyst.net.nz>
Mon, 18 Jul 2016 05:06:57 +0000 (17:06 +1200)
committerGarming Sam <garming@samba.org>
Thu, 21 Jul 2016 04:37:08 +0000 (06:37 +0200)
This fixes any RW DCs with repsFrom without the corresponding link. On
any RODC, this just reports an error (and doesn't fix it).

(the knownfail entry is also now removed)

BUG: https://bugzilla.samba.org/show_bug.cgi?id=9200

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

index 16258cf6ce3ef8483caa79385d5d9748b8712459..e904b4afb39c4cddfa7971b1351eae89e9635ede 100644 (file)
@@ -90,6 +90,7 @@ class dbcheck(object):
         self.wellknown_sds = get_wellknown_sds(self.samdb)
         self.fix_all_missing_objectclass = False
         self.fix_missing_deleted_objects = False
+        self.fix_replica_locations = False
 
         self.dn_set = set()
         self.link_id_cache = {}
@@ -123,6 +124,7 @@ class dbcheck(object):
         res = self.samdb.search(base="", scope=ldb.SCOPE_BASE, attrs=['namingContexts'])
         self.deleted_objects_containers = []
         self.ncs_lacking_deleted_containers = []
+        self.dns_partitions = []
         try:
             self.ncs = res[0]["namingContexts"]
         except KeyError:
@@ -138,6 +140,23 @@ class dbcheck(object):
             except KeyError:
                 self.ncs_lacking_deleted_containers.append(ldb.Dn(self.samdb, nc))
 
+        domaindns_zone = 'DC=DomainDnsZones,%s' % self.samdb.get_default_basedn()
+        forestdns_zone = 'DC=ForestDnsZones,%s' % self.samdb.get_root_basedn()
+        domain = self.samdb.search(scope=ldb.SCOPE_ONELEVEL,
+                                   attrs=["msDS-NC-Replica-Locations", "msDS-NC-RO-Replica-Locations"],
+                                   base=self.samdb.get_partitions_dn(),
+                                   expression="(&(objectClass=crossRef)(ncName=%s))" % domaindns_zone)
+        if len(domain) == 1:
+            self.dns_partitions.append((ldb.Dn(self.samdb, forestdns_zone), domain[0]))
+
+        forest = self.samdb.search(scope=ldb.SCOPE_ONELEVEL,
+                                   attrs=["msDS-NC-Replica-Locations", "msDS-NC-RO-Replica-Locations"],
+                                   base=self.samdb.get_partitions_dn(),
+                                   expression="(&(objectClass=crossRef)(ncName=%s))" % forestdns_zone)
+        if len(forest) == 1:
+            self.dns_partitions.append((ldb.Dn(self.samdb, domaindns_zone), forest[0]))
+
+
     def check_database(self, DN=None, scope=ldb.SCOPE_SUBTREE, controls=[], attrs=['*']):
         '''perform a database check, returning the number of errors found'''
         res = self.samdb.search(base=DN, scope=scope, attrs=['dn'], controls=controls)
@@ -161,7 +180,6 @@ class dbcheck(object):
         self.report('Checked %u objects (%u errors)' % (len(res), error_count))
         return error_count
 
-
     def check_deleted_objects_containers(self):
         """This function only fixes conflicts on the Deleted Objects
         containers, not the attributes"""
@@ -1382,6 +1400,23 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
                           "Failed to fix Deleted Objects container  %s" % dn):
             self.report("Fixed Deleted Objects container '%s'\n" % (dn))
 
+    def err_replica_locations(self, obj, cross_ref, attr):
+        nmsg = ldb.Message()
+        nmsg.dn = cross_ref
+        target = self.samdb.get_dsServiceName()
+
+        if self.samdb.am_rodc():
+            self.report('Not fixing %s for the RODC' % (attr, obj.dn))
+            return
+
+        if not self.confirm_all('Add yourself to the replica locations for %s?'
+                                % (obj.dn), 'fix_replica_locations'):
+            self.report('Not fixing missing/incorrect attributes on %s\n' % (obj.dn))
+            return
+
+        nmsg[attr] = ldb.MessageElement(target, ldb.FLAG_MOD_ADD, attr)
+        if self.do_modify(nmsg, [], "Failed to add %s for %s" % (attr, obj.dn)):
+            self.report("Fixed %s for %s" % (attr, obj.dn))
 
     def is_fsmo_role(self, dn):
         if dn == self.samdb.domain_dn:
@@ -1784,6 +1819,27 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
                 self.err_deleted_deleted_objects(obj)
                 error_count += 1
 
+        for (dns_part, msg) in self.dns_partitions:
+            if dn == dns_part and 'repsFrom' in obj:
+                location = "msDS-NC-Replica-Locations"
+                if self.samdb.am_rodc():
+                    location = "msDS-NC-RO-Replica-Locations"
+
+                if location not in msg:
+                    # There are no replica locations!
+                    self.err_replica_locations(obj, msg.dn, location)
+                    error_count += 1
+                    continue
+
+                found = False
+                for loc in msg[location]:
+                    if loc == self.samdb.get_dsServiceName():
+                        found = True
+                if not found:
+                    # This DC is not in the replica locations
+                    self.err_replica_locations(obj, msg.dn, location)
+                    error_count += 1
+
         return error_count
 
     ################################################################
index ef98ecb959de9d444d7bbd4905da8c277056b4d8..1a92a5d3198fb137d00f04170905c349b300e613 100644 (file)
 
 # fl2000dc doesn't support AES
 ^samba4.krb5.kdc.*as-req-aes.*fl2000dc
-^samba4.blackbox.dbcheck.release-4-1-0rc3.check_expected_after_values