summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2021-08-23 18:14:16 +1200
committerJule Anger <janger@samba.org>2021-09-08 12:32:11 +0000
commit2f8295604ce6bf0c7829332ae56f6cfecdb18afa (patch)
tree6e95e0122ffd6d67ecc55e66e59ab591badadd4d
parent21e1a6b48d6c3670f7dad4fa595b39178e77f445 (diff)
downloadsamba-2f8295604ce6bf0c7829332ae56f6cfecdb18afa.tar.gz
samba-tool: Rework transations/locks to hold a lock during mdb backup
We now also get sidForRestore under that lock, rather than after the backup. This avoids using the database again after the backup process While not entirely clear how/why this matters with LMDB as seen in Fedora 34, likely due to the same issues seen with 0.9.26 or later fixed by commmit bb3dcd403ced922574a89011dd3814c4fe87dd76. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14676 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14817 Signed-off-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Andreas Schneider <asn@samba.org> (cherry picked from commit 958931ad379af26dcbc55cfbc49e7886ef8e0550)
-rw-r--r--python/samba/netcmd/domain_backup.py38
1 files changed, 32 insertions, 6 deletions
diff --git a/python/samba/netcmd/domain_backup.py b/python/samba/netcmd/domain_backup.py
index 4f669a940b7..3a2622c5c80 100644
--- a/python/samba/netcmd/domain_backup.py
+++ b/python/samba/netcmd/domain_backup.py
@@ -1004,7 +1004,12 @@ class cmd_domain_backup_offline(samba.netcmd.Command):
# sam.ldb must have a transaction started on it before backing up
# everything in sam.ldb.d with the appropriate backup function.
+ #
+ # Obtains the sidForRestore (SID for the new DC) and returns it
+ # from under the transaction
def backup_smb_dbs(self, private_dir, samdb, lp, logger):
+ sam_ldb_path = os.path.join(private_dir, 'sam.ldb')
+
# First, determine if DB backend is MDB. Assume not unless there is a
# 'backendStore' attribute on @PARTITION containing the text 'mdb'
store_label = "backendStore"
@@ -1012,11 +1017,24 @@ class cmd_domain_backup_offline(samba.netcmd.Command):
attrs=[store_label])
mdb_backend = store_label in res[0] and str(res[0][store_label][0]) == 'mdb'
- sam_ldb_path = os.path.join(private_dir, 'sam.ldb')
+ # This is needed to keep this variable in scope until the end
+ # of the transaction.
+ res_iterator = None
+
copy_function = None
if mdb_backend:
logger.info('MDB backend detected. Using mdb backup function.')
copy_function = self.offline_mdb_copy
+
+ # We can't backup with a write transaction open, so get a
+ # read lock with a search_iterator().
+ #
+ # We have tests in lib/ldb/tests/python/api.py that the
+ # search iterator takes a read lock effective against a
+ # transaction. This in turn will ensure there are no
+ # transactions on either the main or sub-database, even if
+ # the read locks were not enforced globally (they are).
+ res_iterator = samdb.search_iterator()
else:
logger.info('Starting transaction on ' + sam_ldb_path)
copy_function = self.offline_tdb_copy
@@ -1034,9 +1052,16 @@ class cmd_domain_backup_offline(samba.netcmd.Command):
logger.info(' copying locked/related file ' + sam_file)
shutil.copyfile(sam_file, sam_file + self.backup_ext)
- if not mdb_backend:
+ sid = get_sid_for_restore(samdb, logger)
+
+ if mdb_backend:
+ # Delete the iterator, release the read lock
+ del(res_iterator)
+ else:
samdb.transaction_cancel()
+ return sid
+
# Find where a path should go in the fixed backup archive structure.
def get_arc_path(self, path, conf_paths):
backup_dirs = {"private": conf_paths.private_dir,
@@ -1119,16 +1144,17 @@ class cmd_domain_backup_offline(samba.netcmd.Command):
samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp,
flags=ldb.FLG_DONT_CREATE_DB)
+ # Backup secrets, sam.ldb and their downstream files
self.backup_secrets(paths.private_dir, lp, logger)
- self.backup_smb_dbs(paths.private_dir, samdb, lp, logger)
+ sid = self.backup_smb_dbs(paths.private_dir, samdb, lp, logger)
# Get the domain SID so we can later place it in the backup
dom_sid_str = samdb.get_domain_sid()
dom_sid = security.dom_sid(dom_sid_str)
- sid = get_sid_for_restore(samdb, logger)
-
- # Close the original samdb
+ # Close the original samdb, to avoid any confusion, we will
+ # not use this any more as the data has all been copied under
+ # the transaction
samdb = None
# Open the new backed up samdb, flag it as backed up, and write