From 008449d99f7f0bcc165cdf9dc479eb9dc5e1a856 Mon Sep 17 00:00:00 2001 From: Tim Beale Date: Thu, 8 Nov 2018 17:34:26 +1300 Subject: [PATCH] netcmd: Flush replUpToDateVector when restoring offline backup The replUpToDateVector could be incorrect after an offline backup was restored. This means replication propagation dampening doesn't work properly. In the worst case, a singleton DC would have no replUpToDateVector at all, and so *all* objects created on that DC get replicated every time a new DRS connection is established between 2 DCs. This becomes a real problem if you used that singleton DC to create 100K objects... This patch flushes the replUpToDateVector when an offline backup gets restored. We need to do this before we add in the new DC and remove the old DCs. Note that this is only a problem for offline backups. The online/rename backups are received over DRS, and as part of the replication they receive the latest replUpToDateVector from the DC being backed up. Signed-off-by: Tim Beale Reviewed-by: Andrew Bartlett --- python/samba/netcmd/domain_backup.py | 38 +++++++++++++++++++++++++--- selftest/knownfail.d/domain_backup | 3 --- 2 files changed, 34 insertions(+), 7 deletions(-) delete mode 100644 selftest/knownfail.d/domain_backup diff --git a/python/samba/netcmd/domain_backup.py b/python/samba/netcmd/domain_backup.py index afa70e3b34e..c7602a8be26 100644 --- a/python/samba/netcmd/domain_backup.py +++ b/python/samba/netcmd/domain_backup.py @@ -33,7 +33,7 @@ from samba.auth import system_session from samba.join import DCJoinContext, join_clone, DCCloneAndRenameContext from samba.dcerpc.security import dom_sid from samba.netcmd import Option, CommandError -from samba.dcerpc import misc, security +from samba.dcerpc import misc, security, drsblobs from samba import Ldb from . fsmo import cmd_fsmo_seize from samba.provision import make_smbconf, DEFAULTSITE @@ -51,6 +51,8 @@ from samba.mdb_util import mdb_copy import errno from subprocess import CalledProcessError from samba import sites +from samba.dsdb import _dsdb_load_udv_v2 +from samba.ndr import ndr_pack # work out a SID (based on a free RID) to use when the domain gets restored. @@ -417,6 +419,26 @@ class cmd_domain_backup_restore(cmd_fsmo_seize): return backup_type + def save_uptodate_vectors(self, samdb, partitions): + """Ensures the UTDV used by DRS is correct after an offline backup""" + for nc in partitions: + # load the replUpToDateVector we *should* have + utdv = _dsdb_load_udv_v2(samdb, nc) + + # convert it to NDR format and write it into the DB + utdv_blob = drsblobs.replUpToDateVectorBlob() + utdv_blob.version = 2 + utdv_blob.ctr.cursors = utdv + utdv_blob.ctr.count = len(utdv) + new_value = ndr_pack(utdv_blob) + + m = ldb.Message() + m.dn = ldb.Dn(samdb, nc) + m["replUpToDateVector"] = ldb.MessageElement(new_value, + ldb.FLAG_MOD_REPLACE, + "replUpToDateVector") + samdb.modify(m) + def run(self, sambaopts=None, credopts=None, backup_file=None, targetdir=None, newservername=None, host_ip=None, host_ip6=None, site=None): @@ -471,13 +493,21 @@ class cmd_domain_backup_restore(cmd_fsmo_seize): site = self.create_default_site(samdb, logger) logger.info("Adding new DC to site '{0}'".format(site)) - # Create account using the join_add_objects function in the join object - # We need namingContexts, account control flags, and the sid saved by - # the backup process. + # read the naming contexts out of the DB res = samdb.search(base="", scope=ldb.SCOPE_BASE, attrs=['namingContexts']) ncs = [str(r) for r in res[0].get('namingContexts')] + # for offline backups we need to make sure the upToDateness info + # contains the invocation-ID and highest-USN of the DC we backed up. + # Otherwise replication propagation dampening won't correctly filter + # objects created by that DC + if backup_type == "offline": + self.save_uptodate_vectors(samdb, ncs) + + # Create account using the join_add_objects function in the join object + # We need namingContexts, account control flags, and the sid saved by + # the backup process. creds = credopts.get_credentials(lp) ctx = DCJoinContext(logger, creds=creds, lp=lp, site=site, forced_local_samdb=samdb, diff --git a/selftest/knownfail.d/domain_backup b/selftest/knownfail.d/domain_backup deleted file mode 100644 index 0484a922962..00000000000 --- a/selftest/knownfail.d/domain_backup +++ /dev/null @@ -1,3 +0,0 @@ -samba.tests.domain_backup.samba.tests.domain_backup.DomainBackupOffline.test_backup_restore\(ad_dc:local\) -samba.tests.domain_backup.samba.tests.domain_backup.DomainBackupOffline.test_backup_restore_into_site\(ad_dc:local\) -samba.tests.domain_backup.samba.tests.domain_backup.DomainBackupOffline.test_backup_restore_with_conf\(ad_dc:local\)