def test_dsdb_Dn_binary(self): url = self.tempdir + "/test_dsdb_Dn_binary.ldb" sam = samba.Ldb(url=url) dn1 = dsdb_Dn(sam, "DC=foo,DC=bar") dn2 = dsdb_Dn(sam, "B:8:0000000D:<GUID=b3f0ec29-17f4-452a-b002-963e1909d101>;DC=samba,DC=example,DC=com") self.assertEquals(dn2.binary, "0000000D") self.assertEquals(13, dn2.get_binary_integer()) os.unlink(url)
def find_revealed_link(self, dn, attrname, guid): '''return a revealed link in an object''' res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, attrs=[attrname], controls=["show_deleted:0", "extended_dn:0", "reveal_internals:0"]) syntax_oid = self.samdb_schema.get_syntax_oid_from_lDAPDisplayName(attrname) for val in res[0][attrname]: dsdb_dn = dsdb_Dn(self.samdb, val, syntax_oid) guid2 = dsdb_dn.dn.get_extended_component("GUID") if guid == guid2: return dsdb_dn return None
def find_revealed_link(self, dn, attrname, guid): '''return a revealed link in an object''' res = self.samdb.search( base=dn, scope=ldb.SCOPE_BASE, attrs=[attrname], controls=["show_deleted:0", "extended_dn:0", "reveal_internals:0"]) syntax_oid = self.samdb_schema.get_syntax_oid_from_lDAPDisplayName( attrname) for val in res[0][attrname]: dsdb_dn = dsdb_Dn(self.samdb, val, syntax_oid) guid2 = dsdb_dn.dn.get_extended_component("GUID") if guid == guid2: return dsdb_dn return None
def _assert_in_revealed_users(self, user_dn, attrlist): res = self.ldb_dc1.search(scope=ldb.SCOPE_BASE, base=self.computer_dn, attrs=["msDS-RevealedUsers"]) revealed_users = res[0]["msDS-RevealedUsers"] actual_attrids = [] packed_attrs = [] unpacked_attrs = [] for attribute in revealed_users: dsdb_dn = dsdb_Dn(self.ldb_dc1, attribute.decode('utf8')) metadata = ndr_unpack(drsblobs.replPropertyMetaData1, dsdb_dn.get_bytes()) if user_dn in attribute: unpacked_attrs.append(metadata) packed_attrs.append(dsdb_dn.get_bytes()) actual_attrids.append(metadata.attid) self.assertEquals(sorted(actual_attrids), sorted(attrlist)) return (packed_attrs, unpacked_attrs)
def _assert_in_revealed_users(self, user_dn, attrlist): res = self.ldb_dc1.search(scope=ldb.SCOPE_BASE, base=self.computer_dn, attrs=["msDS-RevealedUsers"]) revealed_users = res[0]["msDS-RevealedUsers"] actual_attrids = [] packed_attrs = [] unpacked_attrs = [] for attribute in revealed_users: dsdb_dn = dsdb_Dn(self.ldb_dc1, attribute) metadata = ndr_unpack(drsblobs.replPropertyMetaData1, dsdb_dn.get_bytes()) if user_dn in attribute: unpacked_attrs.append(metadata) packed_attrs.append(dsdb_dn.get_bytes()) actual_attrids.append(metadata.attid) self.assertEquals(sorted(actual_attrids), sorted(attrlist)) return (packed_attrs, unpacked_attrs)
def test_dsdb_Dn_sorted(self): url = self.tempdir + "/test_dsdb_Dn_sorted.ldb" sam = samba.Ldb(url=url) try: dn1 = dsdb_Dn( sam, "B:8:0000000D:<GUID=b3f0ec29-17f4-452a-b002-963e1909d101>;OU=dn1,DC=samba,DC=example,DC=com" ) dn2 = dsdb_Dn( sam, "B:8:0000000C:<GUID=b3f0ec29-17f4-452a-b002-963e1909d101>;OU=dn1,DC=samba,DC=example,DC=com" ) dn3 = dsdb_Dn( sam, "B:8:0000000F:<GUID=00000000-17f4-452a-b002-963e1909d101>;OU=dn3,DC=samba,DC=example,DC=com" ) dn4 = dsdb_Dn( sam, "B:8:00000000:<GUID=ffffffff-17f4-452a-b002-963e1909d101>;OU=dn4,DC=samba,DC=example,DC=com" ) dn5 = dsdb_Dn( sam, "<GUID=ffffffff-27f4-452a-b002-963e1909d101>;OU=dn5,DC=samba,DC=example,DC=com" ) dn6 = dsdb_Dn( sam, "<GUID=00000000-27f4-452a-b002-963e1909d101>;OU=dn6,DC=samba,DC=example,DC=com" ) unsorted_links14 = [dn1, dn2, dn3, dn4] sorted_vals14 = [str(dn) for dn in sorted(unsorted_links14)] self.assertEqual(sorted_vals14[0], str(dn3)) self.assertEqual(sorted_vals14[1], str(dn2)) self.assertEqual(sorted_vals14[2], str(dn1)) self.assertEqual(sorted_vals14[3], str(dn4)) unsorted_links56 = [dn5, dn6] sorted_vals56 = [str(dn) for dn in sorted(unsorted_links56)] self.assertEqual(sorted_vals56[0], str(dn6)) self.assertEqual(sorted_vals56[1], str(dn5)) finally: del sam os.unlink(url)
"msDS-Behavior-Version"] res = samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs + ncattrs, expression="(objectClass=nTDSDSA)") # Spin thru all the DSAs looking for NC replicas # and build a list of all possible Naming Contexts # for subsequent retrieval below for msg in res: for k in msg.keys(): if k in ncattrs: for value in msg[k]: # Some of these have binary DNs so # use dsdb_Dn to split out relevent parts dsdn = dsdb_Dn(samdb, value) dnstr = str(dsdn.dn) if dnstr not in nclist: nclist.append(dnstr) # Write DSA output write_search_result(samdb, f, res) # Query NTDS Connections for msg in sites: sstr = str(msg.dn) attrs = ["objectClass", "objectGUID", "cn", "whenChanged",
def samdb_to_ldif_file(samdb, dburl, lp, creds, ldif_file): """Routine to extract all objects and attributes that are relevent to the KCC algorithms from a DC database. The point of this function is to allow a programmer/debugger to extract an LDIF file with non-security relevent information from a DC database. The LDIF file can then be used to "import" via the import_ldif() function this file into a temporary abbreviated database. The KCC algorithm can then run against this abbreviated database for debug or test verification that the topology generated is computationally the same between different OSes and algorithms. :param dburl: LDAP database URL to extract info from :param ldif_file: output LDIF file name to create """ try: samdb = SamDB(url=dburl, session_info=system_session(), credentials=creds, lp=lp) except ldb.LdbError as e: (enum, estr) = e.args raise LdifError("Unable to open sam database (%s) : %s" % (dburl, estr)) if os.path.exists(ldif_file): raise LdifError("Specify a file (%s) that doesn't already exist." % ldif_file) try: f = open(ldif_file, "w") except IOError as ioerr: raise LdifError("Unable to open (%s) : %s" % (ldif_file, str(ioerr))) try: # Query Partitions attrs = [ "objectClass", "objectGUID", "cn", "whenChanged", "objectSid", "Enabled", "systemFlags", "dnsRoot", "nCName", "msDS-NC-Replica-Locations", "msDS-NC-RO-Replica-Locations" ] sstr = "CN=Partitions,%s" % samdb.get_config_basedn() res = samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=crossRef)") # Write partitions output write_search_result(samdb, f, res) # Query cross reference container attrs = [ "objectClass", "objectGUID", "cn", "whenChanged", "fSMORoleOwner", "systemFlags", "msDS-Behavior-Version", "msDS-EnabledFeature" ] sstr = "CN=Partitions,%s" % samdb.get_config_basedn() res = samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=crossRefContainer)") # Write cross reference container output write_search_result(samdb, f, res) # Query Sites attrs = [ "objectClass", "objectGUID", "cn", "whenChanged", "systemFlags" ] sstr = "CN=Sites,%s" % samdb.get_config_basedn() sites = samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=site)") # Write sites output write_search_result(samdb, f, sites) # Query NTDS Site Settings for msg in sites: sitestr = str(msg.dn) attrs = [ "objectClass", "objectGUID", "cn", "whenChanged", "interSiteTopologyGenerator", "interSiteTopologyFailover", "schedule", "options" ] sstr = "CN=NTDS Site Settings,%s" % sitestr res = samdb.search(base=sstr, scope=ldb.SCOPE_BASE, attrs=attrs) # Write Site Settings output write_search_result(samdb, f, res) # Naming context list nclist = [] # Query Directory Service Agents for msg in sites: sstr = str(msg.dn) ncattrs = [ "hasMasterNCs", "msDS-hasMasterNCs", "hasPartialReplicaNCs", "msDS-HasDomainNCs", "msDS-hasFullReplicaNCs", "msDS-HasInstantiatedNCs" ] attrs = [ "objectClass", "objectGUID", "cn", "whenChanged", "invocationID", "options", "msDS-isRODC", "msDS-Behavior-Version" ] res = samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs + ncattrs, expression="(objectClass=nTDSDSA)") # Spin thru all the DSAs looking for NC replicas # and build a list of all possible Naming Contexts # for subsequent retrieval below for msg in res: for k in msg.keys(): if k in ncattrs: for value in msg[k]: # Some of these have binary DNs so # use dsdb_Dn to split out relevent parts dsdn = dsdb_Dn(samdb, value) dnstr = str(dsdn.dn) if dnstr not in nclist: nclist.append(dnstr) # Write DSA output write_search_result(samdb, f, res) # Query NTDS Connections for msg in sites: sstr = str(msg.dn) attrs = [ "objectClass", "objectGUID", "cn", "whenChanged", "options", "whenCreated", "enabledConnection", "schedule", "transportType", "fromServer", "systemFlags" ] res = samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=nTDSConnection)") # Write NTDS Connection output write_search_result(samdb, f, res) # Query Intersite transports attrs = [ "objectClass", "objectGUID", "cn", "whenChanged", "options", "name", "bridgeheadServerListBL", "transportAddressAttribute" ] sstr = "CN=Inter-Site Transports,CN=Sites,%s" % \ samdb.get_config_basedn() res = samdb.search(sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=interSiteTransport)") # Write inter-site transport output write_search_result(samdb, f, res) # Query siteLink attrs = [ "objectClass", "objectGUID", "cn", "whenChanged", "systemFlags", "options", "schedule", "replInterval", "siteList", "cost" ] sstr = "CN=Sites,%s" % \ samdb.get_config_basedn() res = samdb.search(sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=siteLink)", controls=['extended_dn:0']) # Write siteLink output write_search_result(samdb, f, res) # Query siteLinkBridge attrs = [ "objectClass", "objectGUID", "cn", "whenChanged", "siteLinkList" ] sstr = "CN=Sites,%s" % samdb.get_config_basedn() res = samdb.search(sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=siteLinkBridge)") # Write siteLinkBridge output write_search_result(samdb, f, res) # Query servers containers # Needed for samdb.server_site_name() attrs = [ "objectClass", "objectGUID", "cn", "whenChanged", "systemFlags" ] sstr = "CN=Sites,%s" % samdb.get_config_basedn() res = samdb.search(sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=serversContainer)") # Write servers container output write_search_result(samdb, f, res) # Query servers # Needed because some transport interfaces refer back to # attributes found in the server object. Also needed # so extended-dn will be happy with dsServiceName in rootDSE attrs = [ "objectClass", "objectGUID", "cn", "whenChanged", "systemFlags", "dNSHostName", "mailAddress" ] sstr = "CN=Sites,%s" % samdb.get_config_basedn() res = samdb.search(sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=server)") # Write server output write_search_result(samdb, f, res) # Query Naming Context replicas attrs = [ "objectClass", "objectGUID", "cn", "whenChanged", "objectSid", "fSMORoleOwner", "msDS-Behavior-Version", "repsFrom", "repsTo" ] for sstr in nclist: res = samdb.search(sstr, scope=ldb.SCOPE_BASE, attrs=attrs) # Write naming context output write_search_result(samdb, f, res) # Query rootDSE replicas attrs = [ "objectClass", "objectGUID", "cn", "whenChanged", "rootDomainNamingContext", "configurationNamingContext", "schemaNamingContext", "defaultNamingContext", "dsServiceName" ] sstr = "" res = samdb.search(sstr, scope=ldb.SCOPE_BASE, attrs=attrs) # Record the rootDSE object as a dn as it # would appear in the base ldb file. We have # to save it this way because we are going to # be importing as an abbreviated database. res[0].dn = ldb.Dn(samdb, "@ROOTDSE") # Write rootdse output write_search_result(samdb, f, res) except ldb.LdbError as e1: (enum, estr) = e1.args raise LdifError("Error processing (%s) : %s" % (sstr, estr)) f.close()
def check_dn(self, obj, attrname, syntax_oid): '''check a DN attribute for correctness''' error_count = 0 for val in obj[attrname]: dsdb_dn = dsdb_Dn(self.samdb, val, syntax_oid) # all DNs should have a GUID component guid = dsdb_dn.dn.get_extended_component("GUID") if guid is None: error_count += 1 self.err_incorrect_dn_GUID(obj.dn, attrname, val, dsdb_dn, "missing GUID") continue guidstr = str(misc.GUID(guid)) attrs=['isDeleted'] linkID = self.samdb_schema.get_linkId_from_lDAPDisplayName(attrname) reverse_link_name = self.samdb_schema.get_backlink_from_lDAPDisplayName(attrname) if reverse_link_name is not None: attrs.append(reverse_link_name) # check its the right GUID try: res = self.samdb.search(base="<GUID=%s>" % guidstr, scope=ldb.SCOPE_BASE, attrs=attrs, controls=["extended_dn:1:1", "show_recycled:1"]) except ldb.LdbError, (enum, estr): error_count += 1 self.err_incorrect_dn_GUID(obj.dn, attrname, val, dsdb_dn, "incorrect GUID") continue # now we have two cases - the source object might or might not be deleted is_deleted = 'isDeleted' in obj and obj['isDeleted'][0].upper() == 'TRUE' target_is_deleted = 'isDeleted' in res[0] and res[0]['isDeleted'][0].upper() == 'TRUE' # the target DN is not allowed to be deleted, unless the target DN is the # special Deleted Objects container if target_is_deleted and not is_deleted and not self.is_deleted_objects_dn(dsdb_dn): error_count += 1 self.err_deleted_dn(obj.dn, attrname, val, dsdb_dn, res[0].dn) continue # check the DN matches in string form if res[0].dn.extended_str() != dsdb_dn.dn.extended_str(): error_count += 1 self.err_dn_target_mismatch(obj.dn, attrname, val, dsdb_dn, res[0].dn, "incorrect string version of DN") continue # check the reverse_link is correct if there should be one if reverse_link_name is not None: match_count = 0 if reverse_link_name in res[0]: for v in res[0][reverse_link_name]: if v == obj.dn.extended_str(): match_count += 1 if match_count != 1: error_count += 1 if linkID & 1: self.err_orphaned_backlink(obj, attrname, val, reverse_link_name, dsdb_dn.dn) else: self.err_missing_backlink(obj, attrname, val, reverse_link_name, dsdb_dn.dn) continue
def check_dn(self, obj, attrname, syntax_oid): '''check a DN attribute for correctness''' error_count = 0 for val in obj[attrname]: dsdb_dn = dsdb_Dn(self.samdb, val, syntax_oid) # all DNs should have a GUID component guid = dsdb_dn.dn.get_extended_component("GUID") if guid is None: error_count += 1 self.err_incorrect_dn_GUID(obj.dn, attrname, val, dsdb_dn, "missing GUID") continue guidstr = str(misc.GUID(guid)) attrs = ['isDeleted'] linkID = self.samdb_schema.get_linkId_from_lDAPDisplayName( attrname) reverse_link_name = self.samdb_schema.get_backlink_from_lDAPDisplayName( attrname) if reverse_link_name is not None: attrs.append(reverse_link_name) # check its the right GUID try: res = self.samdb.search( base="<GUID=%s>" % guidstr, scope=ldb.SCOPE_BASE, attrs=attrs, controls=["extended_dn:1:1", "show_recycled:1"]) except ldb.LdbError, (enum, estr): error_count += 1 self.err_incorrect_dn_GUID(obj.dn, attrname, val, dsdb_dn, "incorrect GUID") continue # now we have two cases - the source object might or might not be deleted is_deleted = 'isDeleted' in obj and obj['isDeleted'][0].upper( ) == 'TRUE' target_is_deleted = 'isDeleted' in res[0] and res[0]['isDeleted'][ 0].upper() == 'TRUE' # the target DN is not allowed to be deleted, unless the target DN is the # special Deleted Objects container if target_is_deleted and not is_deleted and not self.is_deleted_objects_dn( dsdb_dn): error_count += 1 self.err_deleted_dn(obj.dn, attrname, val, dsdb_dn, res[0].dn) continue # check the DN matches in string form if res[0].dn.extended_str() != dsdb_dn.dn.extended_str(): error_count += 1 self.err_dn_target_mismatch(obj.dn, attrname, val, dsdb_dn, res[0].dn, "incorrect string version of DN") continue if is_deleted and not target_is_deleted and reverse_link_name is not None: revealed_dn = self.find_revealed_link(obj.dn, attrname, guid) rmd_flags = revealed_dn.dn.get_extended_component("RMD_FLAGS") if rmd_flags is not None and (int(rmd_flags) & 1) == 0: # the RMD_FLAGS for this link should be 1, as the target is deleted self.err_incorrect_rmd_flags(obj, attrname, revealed_dn) continue # check the reverse_link is correct if there should be one if reverse_link_name is not None: match_count = 0 if reverse_link_name in res[0]: for v in res[0][reverse_link_name]: if v == obj.dn.extended_str(): match_count += 1 if match_count != 1: error_count += 1 if linkID & 1: self.err_orphaned_backlink(obj, attrname, val, reverse_link_name, dsdb_dn.dn) else: self.err_missing_backlink(obj, attrname, val, reverse_link_name, dsdb_dn.dn) continue
def check_dn(self, obj, attrname, syntax_oid): '''check a DN attribute for correctness''' error_count = 0 for val in obj[attrname]: dsdb_dn = dsdb_Dn(self.samdb, val, syntax_oid) # all DNs should have a GUID component guid = dsdb_dn.dn.get_extended_component("GUID") if guid is None: error_count += 1 self.err_incorrect_dn_GUID(obj.dn, attrname, val, dsdb_dn, "missing GUID") continue guidstr = str(misc.GUID(guid)) attrs = ['isDeleted'] if (str(attrname).lower() == 'msds-hasinstantiatedncs') and (obj.dn == self.ntds_dsa): fixing_msDS_HasInstantiatedNCs = True attrs.append("instanceType") else: fixing_msDS_HasInstantiatedNCs = False linkID = self.samdb_schema.get_linkId_from_lDAPDisplayName(attrname) reverse_link_name = self.samdb_schema.get_backlink_from_lDAPDisplayName(attrname) if reverse_link_name is not None: attrs.append(reverse_link_name) # check its the right GUID try: res = self.samdb.search(base="<GUID=%s>" % guidstr, scope=ldb.SCOPE_BASE, attrs=attrs, controls=["extended_dn:1:1", "show_recycled:1"]) except ldb.LdbError, (enum, estr): error_count += 1 self.err_incorrect_dn_GUID(obj.dn, attrname, val, dsdb_dn, "incorrect GUID") continue if fixing_msDS_HasInstantiatedNCs: dsdb_dn.prefix = "B:8:%08X:" % int(res[0]['instanceType'][0]) dsdb_dn.binary = "%08X" % int(res[0]['instanceType'][0]) if str(dsdb_dn) != val: error_count +=1 self.err_incorrect_binary_dn(obj.dn, attrname, val, dsdb_dn, "incorrect instanceType part of Binary DN") continue # now we have two cases - the source object might or might not be deleted is_deleted = 'isDeleted' in obj and obj['isDeleted'][0].upper() == 'TRUE' target_is_deleted = 'isDeleted' in res[0] and res[0]['isDeleted'][0].upper() == 'TRUE' # the target DN is not allowed to be deleted, unless the target DN is the # special Deleted Objects container if target_is_deleted and not is_deleted and not self.is_deleted_objects_dn(dsdb_dn): error_count += 1 self.err_deleted_dn(obj.dn, attrname, val, dsdb_dn, res[0].dn) continue # check the DN matches in string form if res[0].dn.extended_str() != dsdb_dn.dn.extended_str(): error_count += 1 self.err_dn_target_mismatch(obj.dn, attrname, val, dsdb_dn, res[0].dn, "incorrect string version of DN") continue if is_deleted and not target_is_deleted and reverse_link_name is not None: revealed_dn = self.find_revealed_link(obj.dn, attrname, guid) rmd_flags = revealed_dn.dn.get_extended_component("RMD_FLAGS") if rmd_flags is not None and (int(rmd_flags) & 1) == 0: # the RMD_FLAGS for this link should be 1, as the target is deleted self.err_incorrect_rmd_flags(obj, attrname, revealed_dn) continue # check the reverse_link is correct if there should be one if reverse_link_name is not None: match_count = 0 if reverse_link_name in res[0]: for v in res[0][reverse_link_name]: if v == obj.dn.extended_str(): match_count += 1 if match_count != 1: error_count += 1 if linkID & 1: self.err_orphaned_backlink(obj, attrname, val, reverse_link_name, dsdb_dn.dn) else: self.err_missing_backlink(obj, attrname, val, reverse_link_name, dsdb_dn.dn) continue
def samdb_to_ldif_file(samdb, dburl, lp, creds, ldif_file): """Routine to extract all objects and attributes that are relevent to the KCC algorithms from a DC database. The point of this function is to allow a programmer/debugger to extract an LDIF file with non-security relevent information from a DC database. The LDIF file can then be used to "import" via the import_ldif() function this file into a temporary abbreviated database. The KCC algorithm can then run against this abbreviated database for debug or test verification that the topology generated is computationally the same between different OSes and algorithms. :param dburl: LDAP database URL to extract info from :param ldif_file: output LDIF file name to create """ try: samdb = SamDB(url=dburl, session_info=system_session(), credentials=creds, lp=lp) except ldb.LdbError as e: (enum, estr) = e.args raise LdifError("Unable to open sam database (%s) : %s" % (dburl, estr)) if os.path.exists(ldif_file): raise LdifError("Specify a file (%s) that doesn't already exist." % ldif_file) try: f = open(ldif_file, "w") except IOError as ioerr: raise LdifError("Unable to open (%s) : %s" % (ldif_file, str(ioerr))) try: # Query Partitions attrs = ["objectClass", "objectGUID", "cn", "whenChanged", "objectSid", "Enabled", "systemFlags", "dnsRoot", "nCName", "msDS-NC-Replica-Locations", "msDS-NC-RO-Replica-Locations"] sstr = "CN=Partitions,%s" % samdb.get_config_basedn() res = samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=crossRef)") # Write partitions output write_search_result(samdb, f, res) # Query cross reference container attrs = ["objectClass", "objectGUID", "cn", "whenChanged", "fSMORoleOwner", "systemFlags", "msDS-Behavior-Version", "msDS-EnabledFeature"] sstr = "CN=Partitions,%s" % samdb.get_config_basedn() res = samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=crossRefContainer)") # Write cross reference container output write_search_result(samdb, f, res) # Query Sites attrs = ["objectClass", "objectGUID", "cn", "whenChanged", "systemFlags"] sstr = "CN=Sites,%s" % samdb.get_config_basedn() sites = samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=site)") # Write sites output write_search_result(samdb, f, sites) # Query NTDS Site Settings for msg in sites: sitestr = str(msg.dn) attrs = ["objectClass", "objectGUID", "cn", "whenChanged", "interSiteTopologyGenerator", "interSiteTopologyFailover", "schedule", "options"] sstr = "CN=NTDS Site Settings,%s" % sitestr res = samdb.search(base=sstr, scope=ldb.SCOPE_BASE, attrs=attrs) # Write Site Settings output write_search_result(samdb, f, res) # Naming context list nclist = [] # Query Directory Service Agents for msg in sites: sstr = str(msg.dn) ncattrs = ["hasMasterNCs", "msDS-hasMasterNCs", "hasPartialReplicaNCs", "msDS-HasDomainNCs", "msDS-hasFullReplicaNCs", "msDS-HasInstantiatedNCs"] attrs = ["objectClass", "objectGUID", "cn", "whenChanged", "invocationID", "options", "msDS-isRODC", "msDS-Behavior-Version"] res = samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs + ncattrs, expression="(objectClass=nTDSDSA)") # Spin thru all the DSAs looking for NC replicas # and build a list of all possible Naming Contexts # for subsequent retrieval below for msg in res: for k in msg.keys(): if k in ncattrs: for value in msg[k]: # Some of these have binary DNs so # use dsdb_Dn to split out relevent parts dsdn = dsdb_Dn(samdb, value) dnstr = str(dsdn.dn) if dnstr not in nclist: nclist.append(dnstr) # Write DSA output write_search_result(samdb, f, res) # Query NTDS Connections for msg in sites: sstr = str(msg.dn) attrs = ["objectClass", "objectGUID", "cn", "whenChanged", "options", "whenCreated", "enabledConnection", "schedule", "transportType", "fromServer", "systemFlags"] res = samdb.search(base=sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=nTDSConnection)") # Write NTDS Connection output write_search_result(samdb, f, res) # Query Intersite transports attrs = ["objectClass", "objectGUID", "cn", "whenChanged", "options", "name", "bridgeheadServerListBL", "transportAddressAttribute"] sstr = "CN=Inter-Site Transports,CN=Sites,%s" % \ samdb.get_config_basedn() res = samdb.search(sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=interSiteTransport)") # Write inter-site transport output write_search_result(samdb, f, res) # Query siteLink attrs = ["objectClass", "objectGUID", "cn", "whenChanged", "systemFlags", "options", "schedule", "replInterval", "siteList", "cost"] sstr = "CN=Sites,%s" % \ samdb.get_config_basedn() res = samdb.search(sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=siteLink)", controls=['extended_dn:0']) # Write siteLink output write_search_result(samdb, f, res) # Query siteLinkBridge attrs = ["objectClass", "objectGUID", "cn", "whenChanged", "siteLinkList"] sstr = "CN=Sites,%s" % samdb.get_config_basedn() res = samdb.search(sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=siteLinkBridge)") # Write siteLinkBridge output write_search_result(samdb, f, res) # Query servers containers # Needed for samdb.server_site_name() attrs = ["objectClass", "objectGUID", "cn", "whenChanged", "systemFlags"] sstr = "CN=Sites,%s" % samdb.get_config_basedn() res = samdb.search(sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=serversContainer)") # Write servers container output write_search_result(samdb, f, res) # Query servers # Needed because some transport interfaces refer back to # attributes found in the server object. Also needed # so extended-dn will be happy with dsServiceName in rootDSE attrs = ["objectClass", "objectGUID", "cn", "whenChanged", "systemFlags", "dNSHostName", "mailAddress"] sstr = "CN=Sites,%s" % samdb.get_config_basedn() res = samdb.search(sstr, scope=ldb.SCOPE_SUBTREE, attrs=attrs, expression="(objectClass=server)") # Write server output write_search_result(samdb, f, res) # Query Naming Context replicas attrs = ["objectClass", "objectGUID", "cn", "whenChanged", "objectSid", "fSMORoleOwner", "msDS-Behavior-Version", "repsFrom", "repsTo"] for sstr in nclist: res = samdb.search(sstr, scope=ldb.SCOPE_BASE, attrs=attrs) # Write naming context output write_search_result(samdb, f, res) # Query rootDSE replicas attrs = ["objectClass", "objectGUID", "cn", "whenChanged", "rootDomainNamingContext", "configurationNamingContext", "schemaNamingContext", "defaultNamingContext", "dsServiceName"] sstr = "" res = samdb.search(sstr, scope=ldb.SCOPE_BASE, attrs=attrs) # Record the rootDSE object as a dn as it # would appear in the base ldb file. We have # to save it this way because we are going to # be importing as an abbreviated database. res[0].dn = ldb.Dn(samdb, "@ROOTDSE") # Write rootdse output write_search_result(samdb, f, res) except ldb.LdbError as e: (enum, estr) = e.args raise LdifError("Error processing (%s) : %s" % (sstr, estr)) f.close()