mirror of
https://github.com/samba-team/samba.git
synced 2025-01-21 18:04:06 +03:00
python-drs: Add client-side debug and fallback for GET_ANC
Samba 4.5 and earlier will fail to do GET_ANC correctly and will not replicate non-critical parents of objects with isCriticalSystemObject=TRUE when DRSUAPI_DRS_CRITICAL_ONLY is set. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15189 Signed-off-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
This commit is contained in:
parent
483c48f52d
commit
bff2bc9c7d
@ -204,6 +204,44 @@ class drs_Replicate(object):
|
||||
supports_ext & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V10 and
|
||||
(req.more_flags & drsuapi.DRSUAPI_DRS_GET_TGT) == 0)
|
||||
|
||||
@staticmethod
|
||||
def _should_calculate_missing_anc_locally(error_code, req):
|
||||
# If the error indicates we fail to resolve the parent object
|
||||
# for a new object, then we assume we are replicating from a
|
||||
# buggy server (Samba 4.5 and earlier) that doesn't really
|
||||
# understand how to implement GET_ANC
|
||||
|
||||
return ((error_code == werror.WERR_DS_DRA_MISSING_PARENT) and
|
||||
(req.replica_flags & drsuapi.DRSUAPI_DRS_GET_ANC) != 0)
|
||||
|
||||
|
||||
def _calculate_missing_anc_locally(self, ctr):
|
||||
self.guids_seen = set()
|
||||
|
||||
# walk objects in ctr, add to guid_seen as we see them
|
||||
# note if an object doesn't have a parent
|
||||
|
||||
object_to_check = ctr.first_object
|
||||
|
||||
while True:
|
||||
if object_to_check is None:
|
||||
break
|
||||
|
||||
self.guids_seen.add(str(object_to_check.object.identifier.guid))
|
||||
|
||||
if object_to_check.parent_object_guid is not None \
|
||||
and object_to_check.parent_object_guid \
|
||||
!= misc.GUID("00000000-0000-0000-0000-000000000000") \
|
||||
and str(object_to_check.parent_object_guid) not in self.guids_seen:
|
||||
obj_dn = ldb.Dn(self.samdb, object_to_check.object.identifier.dn)
|
||||
parent_dn = obj_dn.parent()
|
||||
print(f"Object {parent_dn} with "
|
||||
f"GUID {object_to_check.parent_object_guid} "
|
||||
"was not sent by the server in this chunk")
|
||||
|
||||
object_to_check = object_to_check.next_object
|
||||
|
||||
|
||||
def process_chunk(self, level, ctr, schema, req_level, req, first_chunk):
|
||||
'''Processes a single chunk of received replication data'''
|
||||
# pass the replication into the py_net.c python bindings for processing
|
||||
@ -326,8 +364,13 @@ class drs_Replicate(object):
|
||||
# of causing the DC to restart the replication from scratch)
|
||||
first_chunk = True
|
||||
continue
|
||||
else:
|
||||
raise e
|
||||
|
||||
if self._should_calculate_missing_anc_locally(e.args[0],
|
||||
req):
|
||||
print("Missing parent object - calculating missing objects locally")
|
||||
|
||||
self._calculate_missing_anc_locally(ctr)
|
||||
raise e
|
||||
|
||||
first_chunk = False
|
||||
num_objects += ctr.object_count
|
||||
|
@ -968,17 +968,53 @@ class DCJoinContext(object):
|
||||
destination_dsa_guid, rodc=ctx.RODC,
|
||||
replica_flags=ctx.replica_flags)
|
||||
if not ctx.subdomain:
|
||||
# Replicate first the critical object for the basedn
|
||||
if not ctx.domain_replica_flags & drsuapi.DRSUAPI_DRS_CRITICAL_ONLY:
|
||||
print("Replicating critical objects from the base DN of the domain")
|
||||
ctx.domain_replica_flags |= drsuapi.DRSUAPI_DRS_CRITICAL_ONLY
|
||||
# Replicate first the critical objects for the basedn
|
||||
|
||||
# We do this to match Windows. The default case is to
|
||||
# do a critical objects replication, then a second
|
||||
# with all objects.
|
||||
|
||||
print("Replicating critical objects from the base DN of the domain")
|
||||
try:
|
||||
repl.replicate(ctx.base_dn, source_dsa_invocation_id,
|
||||
destination_dsa_guid, rodc=ctx.RODC,
|
||||
replica_flags=ctx.domain_replica_flags)
|
||||
ctx.domain_replica_flags ^= drsuapi.DRSUAPI_DRS_CRITICAL_ONLY
|
||||
repl.replicate(ctx.base_dn, source_dsa_invocation_id,
|
||||
destination_dsa_guid, rodc=ctx.RODC,
|
||||
replica_flags=ctx.domain_replica_flags)
|
||||
replica_flags=ctx.domain_replica_flags | drsuapi.DRSUAPI_DRS_CRITICAL_ONLY)
|
||||
except WERRORError as e:
|
||||
|
||||
if e.args[0] == werror.WERR_DS_DRA_MISSING_PARENT:
|
||||
ctx.logger.warning("First pass of replication with "
|
||||
"DRSUAPI_DRS_CRITICAL_ONLY "
|
||||
"not possible due to a missing parent object. "
|
||||
"This is typical of a Samba "
|
||||
"4.5 or earlier server. "
|
||||
"We will replicate the all objects instead.")
|
||||
else:
|
||||
raise
|
||||
|
||||
# Now replicate all the objects in the domain (unless
|
||||
# we were run with --critical-only).
|
||||
#
|
||||
# Doing the replication of users as a second pass
|
||||
# matches more closely the Windows behaviour, which is
|
||||
# actually to do this on first startup.
|
||||
#
|
||||
# Use --critical-only if you want that (but you don't
|
||||
# really, it is better to see any errors here).
|
||||
if not ctx.domain_replica_flags & drsuapi.DRSUAPI_DRS_CRITICAL_ONLY:
|
||||
try:
|
||||
repl.replicate(ctx.base_dn, source_dsa_invocation_id,
|
||||
destination_dsa_guid, rodc=ctx.RODC,
|
||||
replica_flags=ctx.domain_replica_flags)
|
||||
except WERRORError as e:
|
||||
|
||||
if e.args[0] == werror.WERR_DS_DRA_MISSING_PARENT and \
|
||||
ctx.domain_replica_flags & drsuapi.DRSUAPI_DRS_CRITICAL_ONLY:
|
||||
ctx.logger.warning("Replication with DRSUAPI_DRS_CRITICAL_ONLY "
|
||||
"failed due to a missing parent object. "
|
||||
"This may be a Samba 4.5 or earlier server "
|
||||
"and is not compatible with --critical-only")
|
||||
raise
|
||||
|
||||
print("Done with always replicated NC (base, config, schema)")
|
||||
|
||||
# At this point we should already have an entry in the ForestDNS
|
||||
|
@ -2,4 +2,3 @@
|
||||
samba4.drs.getnc_exop.python\(chgdcpass\).getnc_exop.DrsReplicaSyncTestCase.test_FSMONotOwner\(chgdcpass\)
|
||||
# This fails because GET_ANC is now poorly implemented (matching Samba 4.5)
|
||||
^samba4.drs.getnc_exop.python\(chgdcpass\).getnc_exop.DrsReplicaSyncTestCase.test_link_utdv_hwm\(chgdcpass\)
|
||||
^samba4.drs.samba_tool_drs_critical.python\(chgdcpass\).samba_tool_drs_critical.SambaToolDrsTests.test_samba_tool_drs_clone_dc_critical_object_chain\(chgdcpass:local\)
|
Loading…
x
Reference in New Issue
Block a user