def _get_replication(self, replica_flags, drs_error=drsuapi.DRSUAPI_EXOP_ERR_NONE, drs=None, drs_handle=None, highwatermark=None, uptodateness_vector=None, more_flags=0, max_objects=133, exop=0, dest_dsa=drsuapi.DRSUAPI_DS_BIND_GUID_W2K3, source_dsa=None, invocation_id=None, nc_dn_str=None): """ Builds a DsGetNCChanges request based on the information provided and returns the response received from the DC. """ if source_dsa is None: source_dsa = self.test_ldb_dc.get_ntds_GUID() if invocation_id is None: invocation_id = self.test_ldb_dc.get_invocation_id() if nc_dn_str is None: nc_dn_str = self.test_ldb_dc.domain_dn() if highwatermark is None: if self.default_hwm is None: (highwatermark, _) = self._get_highest_hwm_utdv(self.test_ldb_dc) else: highwatermark = self.default_hwm if drs is None: drs = self.drs if drs_handle is None: drs_handle = self.drs_handle req10 = self._getnc_req10(dest_dsa=dest_dsa, invocation_id=invocation_id, nc_dn_str=nc_dn_str, exop=exop, max_objects=max_objects, replica_flags=replica_flags, more_flags=more_flags) req10.highwatermark = highwatermark if uptodateness_vector is not None: uptodateness_vector_v1 = drsuapi.DsReplicaCursorCtrEx() cursors = [] for i in xrange(0, uptodateness_vector.count): c = uptodateness_vector.cursors[i] c1 = drsuapi.DsReplicaCursor() c1.source_dsa_invocation_id = c.source_dsa_invocation_id c1.highest_usn = c.highest_usn cursors.append(c1) uptodateness_vector_v1.count = len(cursors) uptodateness_vector_v1.cursors = cursors req10.uptodateness_vector = uptodateness_vector_v1 (level, ctr) = drs.DsGetNCChanges(drs_handle, 10, req10) self._ctr6_debug(ctr) self.assertEqual(level, 6, "expected level 6 response!") self.assertEqual(ctr.source_dsa_guid, misc.GUID(source_dsa)) self.assertEqual(ctr.source_dsa_invocation_id, misc.GUID(invocation_id)) self.assertEqual(ctr.extended_ret, drs_error) return ctr
def _get_highest_hwm_utdv(self, ldb_conn): res = ldb_conn.search("", scope=ldb.SCOPE_BASE, attrs=["highestCommittedUSN"]) hwm = drsuapi.DsReplicaHighWaterMark() hwm.tmp_highest_usn = long(res[0]["highestCommittedUSN"][0]) hwm.reserved_usn = 0 hwm.highest_usn = hwm.tmp_highest_usn utdv = drsuapi.DsReplicaCursorCtrEx() cursors = [] c1 = drsuapi.DsReplicaCursor() c1.source_dsa_invocation_id = misc.GUID(ldb_conn.get_invocation_id()) c1.highest_usn = hwm.highest_usn cursors.append(c1) utdv.count = len(cursors) utdv.cursors = cursors return (hwm, utdv)
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)
bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6 bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3 bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7 bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT (info, drs_handle) = drs_conn.DsBind(misc.GUID(drsuapi.DRSUAPI_DS_BIND_GUID), bind_info) null_guid = misc.GUID() naming_context = drsuapi.DsReplicaObjectIdentifier() naming_context.dn = dn highwatermark = store_hwm uptodateness_vector = None if store_utdv is not None: uptodateness_vector = drsuapi.DsReplicaCursorCtrEx() if store_utdv.version == 1: uptodateness_vector.cursors = store_utdv.cursors elif store_utdv.version == 2: cursors = [] for i in range(0, store_utdv.ctr.count): cursor = drsuapi.DsReplicaCursor() cursor.source_dsa_invocation_id = store_utdv.ctr.cursors[ i].source_dsa_invocation_id cursor.highest_usn = store_utdv.ctr.cursors[i].highest_usn cursors.append(cursor) uptodateness_vector.cursors = cursors req8 = drsuapi.DsGetNCChangesRequest8() req8.destination_dsa_guid = null_guid
def _check_replication(self, expected_dns, replica_flags, expected_links=[], drs_error=drsuapi.DRSUAPI_EXOP_ERR_NONE, drs=None, drs_handle=None, highwatermark=None, uptodateness_vector=None, more_flags=0, more_data=False, dn_ordered=True, links_ordered=True, max_objects=133, exop=0, dest_dsa=drsuapi.DRSUAPI_DS_BIND_GUID_W2K3, source_dsa=None, invocation_id=None, nc_dn_str=None, nc_object_count=0, nc_linked_attributes_count=0): """ Makes sure that replication returns the specific error given. """ if source_dsa is None: source_dsa = self.ldb_dc1.get_ntds_GUID() if invocation_id is None: invocation_id = self.ldb_dc1.get_invocation_id() if nc_dn_str is None: nc_dn_str = self.ldb_dc1.domain_dn() if highwatermark is None: if self.default_hwm is None: (highwatermark, _) = self._get_highest_hwm_utdv(self.ldb_dc1) else: highwatermark = self.default_hwm if drs is None: drs = self.drs if drs_handle is None: drs_handle = self.drs_handle req10 = self._getnc_req10(dest_dsa=dest_dsa, invocation_id=invocation_id, nc_dn_str=nc_dn_str, exop=exop, max_objects=max_objects, replica_flags=replica_flags) req10.highwatermark = highwatermark if uptodateness_vector is not None: uptodateness_vector_v1 = drsuapi.DsReplicaCursorCtrEx() cursors = [] for i in xrange(0, uptodateness_vector.count): c = uptodateness_vector.cursors[i] c1 = drsuapi.DsReplicaCursor() c1.source_dsa_invocation_id = c.source_dsa_invocation_id c1.highest_usn = c.highest_usn cursors.append(c1) uptodateness_vector_v1.count = len(cursors) uptodateness_vector_v1.cursors = cursors req10.uptodateness_vector = uptodateness_vector_v1 (level, ctr) = drs.DsGetNCChanges(drs_handle, 10, req10) self.assertEqual(level, 6, "expected level 6 response!") self.assertEqual(ctr.source_dsa_guid, misc.GUID(source_dsa)) self.assertEqual(ctr.source_dsa_invocation_id, misc.GUID(invocation_id)) ctr6 = ctr self.assertEqual(ctr6.extended_ret, drs_error) self._check_ctr6(ctr6, expected_dns, expected_links, nc_object_count=nc_object_count) return (ctr6.new_highwatermark, ctr6.uptodateness_vector)
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)