def replicate(self, dn, source_dsa_invocation_id, destination_dsa_guid, schema=False, exop=drsuapi.DRSUAPI_EXOP_NONE, rodc=False, replica_flags=None, full_sync=True, sync_forced=False): '''replicate a single DN''' # setup for a GetNCChanges call req8 = drsuapi.DsGetNCChangesRequest8() req8.destination_dsa_guid = destination_dsa_guid req8.source_dsa_invocation_id = source_dsa_invocation_id req8.naming_context = drsuapi.DsReplicaObjectIdentifier() req8.naming_context.dn = dn # Default to a full replication if we don't find an upToDatenessVector udv = None hwm = drsuapi.DsReplicaHighWaterMark() hwm.tmp_highest_usn = 0 hwm.reserved_usn = 0 hwm.highest_usn = 0 if not full_sync: res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, attrs=["repsFrom"]) if "repsFrom" in res[0]: for reps_from_packed in res[0]["repsFrom"]: reps_from_obj = ndr_unpack(drsblobs.repsFromToBlob, reps_from_packed) if reps_from_obj.ctr.source_dsa_invocation_id == source_dsa_invocation_id: hwm = reps_from_obj.ctr.highwatermark udv = drsuapi.DsReplicaCursorCtrEx() udv.version = 1 udv.reserved1 = 0 udv.reserved2 = 0 cursors_v1 = [] cursors_v2 = dsdb._dsdb_load_udv_v2( self.samdb, self.samdb.get_default_basedn()) for cursor_v2 in cursors_v2: cursor_v1 = drsuapi.DsReplicaCursor() cursor_v1.source_dsa_invocation_id = cursor_v2.source_dsa_invocation_id cursor_v1.highest_usn = cursor_v2.highest_usn cursors_v1.append(cursor_v1) udv.cursors = cursors_v1 udv.count = len(cursors_v1) req8.highwatermark = hwm req8.uptodateness_vector = udv if replica_flags is not None: req8.replica_flags = replica_flags elif exop == drsuapi.DRSUAPI_EXOP_REPL_SECRET: req8.replica_flags = 0 else: req8.replica_flags = (drsuapi.DRSUAPI_DRS_INIT_SYNC | drsuapi.DRSUAPI_DRS_PER_SYNC | drsuapi.DRSUAPI_DRS_GET_ANC | drsuapi.DRSUAPI_DRS_NEVER_SYNCED | drsuapi.DRSUAPI_DRS_GET_ALL_GROUP_MEMBERSHIP) if rodc: req8.replica_flags |= ( drsuapi.DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING) else: req8.replica_flags |= drsuapi.DRSUAPI_DRS_WRIT_REP if sync_forced: req8.replica_flags |= drsuapi.DRSUAPI_DRS_SYNC_FORCED req8.max_object_count = 402 req8.max_ndr_size = 402116 req8.extended_op = exop req8.fsmo_info = 0 req8.partial_attribute_set = None req8.partial_attribute_set_ex = None req8.mapping_ctr.num_mappings = 0 req8.mapping_ctr.mappings = None if not schema and rodc: req8.partial_attribute_set = drs_get_rodc_partial_attribute_set( self.samdb) if self.supported_extensions & drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8: req_level = 8 req = req8 else: req_level = 5 req5 = drsuapi.DsGetNCChangesRequest5() for a in dir(req5): if a[0] != '_': setattr(req5, a, getattr(req8, a)) req = req5 num_objects = 0 num_links = 0 while True: (level, ctr) = self.drs.DsGetNCChanges(self.drs_handle, req_level, req) if ctr.first_object is None and ctr.object_count != 0: raise RuntimeError( "DsGetNCChanges: NULL first_object with object_count=%u" % (ctr.object_count)) self.net.replicate_chunk(self.replication_state, level, ctr, schema=schema, req_level=req_level, req=req) num_objects += ctr.object_count # Cope with servers that do not return level 6, so do not return any links try: num_links += ctr.linked_attributes_count except AttributeError: pass if ctr.more_data == 0: break req.highwatermark = ctr.new_highwatermark return (num_objects, num_links)
def replicate(self, dn, source_dsa_invocation_id, destination_dsa_guid, schema=False, exop=drsuapi.DRSUAPI_EXOP_NONE, rodc=False, replica_flags=None): '''replicate a single DN''' # setup for a GetNCChanges call req8 = drsuapi.DsGetNCChangesRequest8() req8.destination_dsa_guid = destination_dsa_guid req8.source_dsa_invocation_id = source_dsa_invocation_id req8.naming_context = drsuapi.DsReplicaObjectIdentifier() req8.naming_context.dn = dn req8.highwatermark = drsuapi.DsReplicaHighWaterMark() req8.highwatermark.tmp_highest_usn = 0 req8.highwatermark.reserved_usn = 0 req8.highwatermark.highest_usn = 0 req8.uptodateness_vector = None if replica_flags is not None: req8.replica_flags = replica_flags elif exop == drsuapi.DRSUAPI_EXOP_REPL_SECRET: req8.replica_flags = 0 else: req8.replica_flags = (drsuapi.DRSUAPI_DRS_INIT_SYNC | drsuapi.DRSUAPI_DRS_PER_SYNC | drsuapi.DRSUAPI_DRS_GET_ANC | drsuapi.DRSUAPI_DRS_NEVER_SYNCED | drsuapi.DRSUAPI_DRS_GET_ALL_GROUP_MEMBERSHIP) if rodc: req8.replica_flags |= ( drsuapi.DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING) else: req8.replica_flags |= drsuapi.DRSUAPI_DRS_WRIT_REP req8.max_object_count = 402 req8.max_ndr_size = 402116 req8.extended_op = exop req8.fsmo_info = 0 req8.partial_attribute_set = None req8.partial_attribute_set_ex = None req8.mapping_ctr.num_mappings = 0 req8.mapping_ctr.mappings = None if not schema and rodc: req8.partial_attribute_set = self.drs_get_rodc_partial_attribute_set( ) if self.supported_extensions & drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8: req_level = 8 req = req8 else: req_level = 5 req5 = drsuapi.DsGetNCChangesRequest5() for a in dir(req5): if a[0] != '_': setattr(req5, a, getattr(req8, a)) req = req5 while True: (level, ctr) = self.drs.DsGetNCChanges(self.drs_handle, req_level, req) if ctr.first_object is None and ctr.object_count != 0: raise RuntimeError( "DsGetNCChanges: NULL first_object with object_count=%u" % (ctr.object_count)) self.net.replicate_chunk(self.replication_state, level, ctr, schema=schema, req_level=req_level, req=req) if ctr.more_data == 0: break req.highwatermark = ctr.new_highwatermark
def replicate(self, dn, source_dsa_invocation_id, destination_dsa_guid, schema=False, exop=drsuapi.DRSUAPI_EXOP_NONE, rodc=False, replica_flags=None, full_sync=True, sync_forced=False, more_flags=0): '''replicate a single DN''' # setup for a GetNCChanges call if self.supports_ext & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V10: req = drsuapi.DsGetNCChangesRequest10() req.more_flags = (more_flags | self.more_flags) req_level = 10 else: req_level = 8 req = drsuapi.DsGetNCChangesRequest8() req.destination_dsa_guid = destination_dsa_guid req.source_dsa_invocation_id = source_dsa_invocation_id req.naming_context = drsuapi.DsReplicaObjectIdentifier() req.naming_context.dn = dn # Default to a full replication if we don't find an upToDatenessVector udv = None hwm = drsuapi.DsReplicaHighWaterMark() hwm.tmp_highest_usn = 0 hwm.reserved_usn = 0 hwm.highest_usn = 0 if not full_sync: res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, attrs=["repsFrom"]) if "repsFrom" in res[0]: for reps_from_packed in res[0]["repsFrom"]: reps_from_obj = ndr_unpack(drsblobs.repsFromToBlob, reps_from_packed) if reps_from_obj.ctr.source_dsa_invocation_id == source_dsa_invocation_id: hwm = reps_from_obj.ctr.highwatermark udv = drsuapi.DsReplicaCursorCtrEx() udv.version = 1 udv.reserved1 = 0 udv.reserved2 = 0 cursors_v1 = [] cursors_v2 = dsdb._dsdb_load_udv_v2( self.samdb, self.samdb.get_default_basedn()) for cursor_v2 in cursors_v2: cursor_v1 = drsuapi.DsReplicaCursor() cursor_v1.source_dsa_invocation_id = cursor_v2.source_dsa_invocation_id cursor_v1.highest_usn = cursor_v2.highest_usn cursors_v1.append(cursor_v1) udv.cursors = cursors_v1 udv.count = len(cursors_v1) req.highwatermark = hwm req.uptodateness_vector = udv if replica_flags is not None: req.replica_flags = replica_flags elif exop == drsuapi.DRSUAPI_EXOP_REPL_SECRET: req.replica_flags = 0 else: req.replica_flags = (drsuapi.DRSUAPI_DRS_INIT_SYNC | drsuapi.DRSUAPI_DRS_PER_SYNC | drsuapi.DRSUAPI_DRS_GET_ANC | drsuapi.DRSUAPI_DRS_NEVER_SYNCED | drsuapi.DRSUAPI_DRS_GET_ALL_GROUP_MEMBERSHIP) if rodc: req.replica_flags |= ( drsuapi.DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING) else: req.replica_flags |= drsuapi.DRSUAPI_DRS_WRIT_REP if sync_forced: req.replica_flags |= drsuapi.DRSUAPI_DRS_SYNC_FORCED req.max_object_count = 402 req.max_ndr_size = 402116 req.extended_op = exop req.fsmo_info = 0 req.partial_attribute_set = None req.partial_attribute_set_ex = None req.mapping_ctr.num_mappings = 0 req.mapping_ctr.mappings = None if not schema and rodc: req.partial_attribute_set = drs_get_rodc_partial_attribute_set( self.samdb) if not self.supports_ext & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8: req_level = 5 req5 = drsuapi.DsGetNCChangesRequest5() for a in dir(req5): if a[0] != '_': setattr(req5, a, getattr(req, a)) req = req5 num_objects = 0 num_links = 0 first_chunk = True while True: (level, ctr) = self.drs.DsGetNCChanges(self.drs_handle, req_level, req) if ctr.first_object is None and ctr.object_count != 0: raise RuntimeError( "DsGetNCChanges: NULL first_object with object_count=%u" % (ctr.object_count)) try: self.process_chunk(level, ctr, schema, req_level, req, first_chunk) except WERRORError as e: # Check if retrying with the GET_TGT flag set might resolve this error if self._should_retry_with_get_tgt(e.args[0], req): print("Missing target object - retrying with DRS_GET_TGT") req.more_flags |= drsuapi.DRSUAPI_DRS_GET_TGT # try sending the request again (this has the side-effect # of causing the DC to restart the replication from scratch) first_chunk = True continue else: raise e first_chunk = False num_objects += ctr.object_count # Cope with servers that do not return level 6, so do not return any links try: num_links += ctr.linked_attributes_count except AttributeError: pass if ctr.more_data == 0: break # update the request's HWM so we get the next chunk drs_copy_highwater_mark(req.highwatermark, ctr.new_highwatermark) return (num_objects, num_links)