summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2023-03-09 20:25:06 +1300
committerJule Anger <janger@samba.org>2023-03-30 16:10:35 +0000
commite2df45934ab415732f7f0377601774119b37e7b3 (patch)
tree8b47ce1da4bd7527e0dfadec88013be4c3f06f05
parenteaff4ef61624276b16dc0dcb11868e2778d2e46f (diff)
downloadsamba-e2df45934ab415732f7f0377601774119b37e7b3.tar.gz
dsdb: Avoid ERROR(ldb): uncaught exception - Deleted target CN=NTDS Settings... in join
"samba-tool domain join" uses the replication API in a strange way, perhaps no longer required, except that we often still have folks upgrading from very old Samba versions. When deferring the writing out to the DB of link replication to the very end, there is a greater opportunity for the deletion of an object to have been sent with the other objects, and have the link applied later. This tells the repl_meta_data code to behave as if GET_TGT had been sent at the time the link was returned, allowing a link to a deleted object to be silently discarded. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15329 Signed-off-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Joseph Sutton <josephsutton@catalyst.net.nz> (cherry picked from commit bfc33b47bb428233e100f75e7a725ac52179f823) Autobuild-User(v4-17-test): Jule Anger <janger@samba.org> Autobuild-Date(v4-17-test): Thu Mar 30 16:10:35 UTC 2023 on sn-devel-184
-rw-r--r--python/samba/join.py19
-rw-r--r--selftest/knownfail.d/replicate_against_deleted1
-rw-r--r--source4/dsdb/samdb/ldb_modules/repl_meta_data.c13
3 files changed, 31 insertions, 2 deletions
diff --git a/python/samba/join.py b/python/samba/join.py
index 650bb5a08ae..30d33d43f11 100644
--- a/python/samba/join.py
+++ b/python/samba/join.py
@@ -50,6 +50,7 @@ import tempfile
from collections import OrderedDict
from samba.common import get_string
from samba.netcmd import CommandError
+from samba import dsdb
class DCJoinException(Exception):
@@ -937,6 +938,10 @@ class DCJoinContext(object):
"""Replicate the SAM."""
ctx.logger.info("Starting replication")
+
+ # A global transaction is started so that linked attributes
+ # are applied at the very end, once all partitions are
+ # replicated. This helps get all cross-partition links.
ctx.local_samdb.transaction_start()
try:
source_dsa_invocation_id = misc.GUID(ctx.samdb.get_invocation_id())
@@ -1057,7 +1062,21 @@ class DCJoinContext(object):
ctx.local_samdb.transaction_cancel()
raise
else:
+
+ # This is a special case, we have completed a full
+ # replication so if a link comes to us that points to a
+ # deleted object, and we asked for all objects already, we
+ # just have to ignore it, the chance to re-try the
+ # replication with GET_TGT has long gone. This can happen
+ # if the object is deleted and sent to us after the link
+ # was sent, as we are processing all links in the
+ # transaction_commit().
+ if not ctx.domain_replica_flags & drsuapi.DRSUAPI_DRS_CRITICAL_ONLY:
+ ctx.local_samdb.set_opaque_integer(dsdb.DSDB_FULL_JOIN_REPLICATION_COMPLETED_OPAQUE_NAME,
+ 1)
ctx.local_samdb.transaction_commit()
+ ctx.local_samdb.set_opaque_integer(dsdb.DSDB_FULL_JOIN_REPLICATION_COMPLETED_OPAQUE_NAME,
+ 0)
ctx.logger.info("Committed SAM database")
# A large replication may have caused our LDB connection to the
diff --git a/selftest/knownfail.d/replicate_against_deleted b/selftest/knownfail.d/replicate_against_deleted
deleted file mode 100644
index 9caa5346a45..00000000000
--- a/selftest/knownfail.d/replicate_against_deleted
+++ /dev/null
@@ -1 +0,0 @@
-samba4.drs.ridalloc_exop.python\(.*\).ridalloc_exop.DrsReplicaSyncTestCase.test_replicate_against_deleted_objects_transaction
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index c1ea5ad90f8..175a02d3ba7 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -7533,6 +7533,16 @@ static int replmd_allow_missing_target(struct ldb_module *module,
source_dn,
target_dn);
if (is_in_same_nc) {
+ /*
+ * We allow the join.py code to point out that all
+ * replication is completed, so failing now would just
+ * trigger errors, rather than trigger a GET_TGT
+ */
+ int *finished_full_join_ptr =
+ talloc_get_type(ldb_get_opaque(ldb,
+ DSDB_FULL_JOIN_REPLICATION_COMPLETED_OPAQUE_NAME),
+ int);
+ bool finished_full_join = finished_full_join_ptr && *finished_full_join_ptr;
/*
* if the target is already be up-to-date there's no point in
@@ -7540,7 +7550,8 @@ static int replmd_allow_missing_target(struct ldb_module *module,
* on a one-way link was deleted. We ignore the link rather
* than failing the replication cycle completely
*/
- if (dsdb_repl_flags & DSDB_REPL_FLAG_TARGETS_UPTODATE) {
+ if (finished_full_join
+ || dsdb_repl_flags & DSDB_REPL_FLAG_TARGETS_UPTODATE) {
*ignore_link = true;
DBG_WARNING("%s is %s "
"but up to date. Ignoring link from %s\n",