Ejemplo n.º 1
0
class drs_Replicate(object):
    '''DRS replication calls'''
    def __init__(self, binding_string, lp, creds, samdb, invocation_id):
        self.drs = drsuapi.drsuapi(binding_string, lp, creds)
        (self.drs_handle, self.supported_extensions) = drs_DsBind(self.drs)
        self.net = Net(creds=creds, lp=lp)
        self.samdb = samdb
        if not isinstance(invocation_id, misc.GUID):
            raise RuntimeError("Must supply GUID for invocation_id")
        if invocation_id == misc.GUID("00000000-0000-0000-0000-000000000000"):
            raise RuntimeError(
                "Must not set GUID 00000000-0000-0000-0000-000000000000 as invocation_id"
            )
        self.replication_state = self.net.replicate_init(
            self.samdb, lp, self.drs, invocation_id)

    def drs_get_rodc_partial_attribute_set(self):
        '''get a list of attributes for RODC replication'''
        partial_attribute_set = drsuapi.DsPartialAttributeSet()
        partial_attribute_set.version = 1

        attids = []

        # the exact list of attids we send is quite critical. Note that
        # we do ask for the secret attributes, but set SPECIAL_SECRET_PROCESSING
        # to zero them out
        schema_dn = self.samdb.get_schema_basedn()
        res = self.samdb.search(
            base=schema_dn,
            scope=ldb.SCOPE_SUBTREE,
            expression="objectClass=attributeSchema",
            attrs=["lDAPDisplayName", "systemFlags", "searchFlags"])

        for r in res:
            ldap_display_name = r["lDAPDisplayName"][0]
            if "systemFlags" in r:
                system_flags = r["systemFlags"][0]
                if (int(system_flags) &
                    (samba.dsdb.DS_FLAG_ATTR_NOT_REPLICATED
                     | samba.dsdb.DS_FLAG_ATTR_IS_CONSTRUCTED)):
                    continue
            if "searchFlags" in r:
                search_flags = r["searchFlags"][0]
                if (int(search_flags) & samba.dsdb.SEARCH_FLAG_RODC_ATTRIBUTE):
                    continue
            attid = self.samdb.get_attid_from_lDAPDisplayName(
                ldap_display_name)
            attids.append(int(attid))

        # the attids do need to be sorted, or windows doesn't return
        # all the attributes we need
        attids.sort()
        partial_attribute_set.attids = attids
        partial_attribute_set.num_attids = len(attids)
        return partial_attribute_set

    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
Ejemplo n.º 2
0
 def test_net_replicate_chunk_1(self):
     lp, creds, server = self.get_lp_et_al()
     ctr = drsuapi.DsGetNCChangesCtr6()
     net = Net(creds, lp, server=server)
     net.replicate_chunk(42, 1, ctr)
Ejemplo n.º 3
0
class drs_Replicate(object):
    '''DRS replication calls'''
    def __init__(self, binding_string, lp, creds, samdb, invocation_id):
        self.drs = drsuapi.drsuapi(binding_string, lp, creds)
        (self.drs_handle, self.supported_extensions) = drs_DsBind(self.drs)
        self.net = Net(creds=creds, lp=lp)
        self.samdb = samdb
        if not isinstance(invocation_id, misc.GUID):
            raise RuntimeError("Must supply GUID for invocation_id")
        if invocation_id == misc.GUID("00000000-0000-0000-0000-000000000000"):
            raise RuntimeError(
                "Must not set GUID 00000000-0000-0000-0000-000000000000 as invocation_id"
            )
        self.replication_state = self.net.replicate_init(
            self.samdb, lp, self.drs, invocation_id)

    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)
Ejemplo n.º 4
0
class drs_Replicate(object):
    """DRS replication calls"""

    def __init__(self, binding_string, lp, creds, samdb, invocation_id):
        self.drs = drsuapi.drsuapi(binding_string, lp, creds)
        (self.drs_handle, self.supported_extensions) = drs_DsBind(self.drs)
        self.net = Net(creds=creds, lp=lp)
        self.samdb = samdb
        if not isinstance(invocation_id, misc.GUID):
            raise RuntimeError("Must supply GUID for invocation_id")
        if invocation_id == misc.GUID("00000000-0000-0000-0000-000000000000"):
            raise RuntimeError("Must not set GUID 00000000-0000-0000-0000-000000000000 as invocation_id")
        self.replication_state = self.net.replicate_init(self.samdb, lp, self.drs, invocation_id)

    def drs_get_rodc_partial_attribute_set(self):
        """get a list of attributes for RODC replication"""
        partial_attribute_set = drsuapi.DsPartialAttributeSet()
        partial_attribute_set.version = 1

        attids = []

        # the exact list of attids we send is quite critical. Note that
        # we do ask for the secret attributes, but set SPECIAL_SECRET_PROCESSING
        # to zero them out
        schema_dn = self.samdb.get_schema_basedn()
        res = self.samdb.search(
            base=schema_dn,
            scope=ldb.SCOPE_SUBTREE,
            expression="objectClass=attributeSchema",
            attrs=["lDAPDisplayName", "systemFlags", "searchFlags"],
        )

        for r in res:
            ldap_display_name = r["lDAPDisplayName"][0]
            if "systemFlags" in r:
                system_flags = r["systemFlags"][0]
                if int(system_flags) & (
                    samba.dsdb.DS_FLAG_ATTR_NOT_REPLICATED | samba.dsdb.DS_FLAG_ATTR_IS_CONSTRUCTED
                ):
                    continue
            if "searchFlags" in r:
                search_flags = r["searchFlags"][0]
                if int(search_flags) & samba.dsdb.SEARCH_FLAG_RODC_ATTRIBUTE:
                    continue
            attid = self.samdb.get_attid_from_lDAPDisplayName(ldap_display_name)
            attids.append(int(attid))

        # the attids do need to be sorted, or windows doesn't return
        # all the attributes we need
        attids.sort()
        partial_attribute_set.attids = attids
        partial_attribute_set.num_attids = len(attids)
        return partial_attribute_set

    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
            )
            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={0:d}".format((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
Ejemplo n.º 5
0
class drs_Replicate(object):
    '''DRS replication calls'''
    def __init__(self, binding_string, lp, creds, samdb, invocation_id):
        self.drs = drsuapi.drsuapi(binding_string, lp, creds)
        (self.drs_handle, self.supported_extensions) = drs_DsBind(self.drs)
        self.net = Net(creds=creds, lp=lp)
        self.samdb = samdb
        if not isinstance(invocation_id, misc.GUID):
            raise RuntimeError("Must supply GUID for invocation_id")
        if invocation_id == misc.GUID("00000000-0000-0000-0000-000000000000"):
            raise RuntimeError(
                "Must not set GUID 00000000-0000-0000-0000-000000000000 as invocation_id"
            )
        self.replication_state = self.net.replicate_init(
            self.samdb, lp, self.drs, invocation_id)

    def replicate(self,
                  dn,
                  source_dsa_invocation_id,
                  destination_dsa_guid,
                  schema=False,
                  exop=drsuapi.DRSUAPI_EXOP_NONE,
                  rodc=False,
                  replica_flags=None,
                  highwatermark=None,
                  udv=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

        if highwatermark is not None:
            req8.highwatermark = highwatermark
        else:
            req8.highwatermark = drsuapi.DsReplicaHighWaterMark()
            req8.highwatermark.tmp_highest_usn = 0
            req8.highwatermark.reserved_usn = 0
            req8.highwatermark.highest_usn = 0

        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
        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)
Ejemplo n.º 6
0
class drs_Replicate(object):
    '''DRS replication calls'''

    def __init__(self, binding_string, lp, creds, samdb, invocation_id):
        self.drs = drsuapi.drsuapi(binding_string, lp, creds)
        (self.drs_handle, self.supported_extensions) = drs_DsBind(self.drs)
        self.net = Net(creds=creds, lp=lp)
        self.samdb = samdb
        if not isinstance(invocation_id, misc.GUID):
            raise RuntimeError("Must supply GUID for invocation_id")
        if invocation_id == misc.GUID("00000000-0000-0000-0000-000000000000"):
            raise RuntimeError("Must not set GUID 00000000-0000-0000-0000-000000000000 as invocation_id")
        self.replication_state = self.net.replicate_init(self.samdb, lp, self.drs, invocation_id)

    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):
        '''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

        udv = None
        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)

        # If we can't find an upToDateVector, or where told not to, replicate fully
        hwm = drsuapi.DsReplicaHighWaterMark()
        hwm.tmp_highest_usn = 0
        hwm.reserved_usn = 0
        hwm.highest_usn = 0

        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
        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)
Ejemplo n.º 7
0
class drs_Replicate(object):
    '''DRS replication calls'''
    def __init__(self, binding_string, lp, creds, samdb, invocation_id):
        self.drs = drsuapi.drsuapi(binding_string, lp, creds)
        (self.drs_handle, self.supported_extensions) = drs_DsBind(self.drs)
        self.net = Net(creds=creds, lp=lp)
        self.samdb = samdb
        if not isinstance(invocation_id, misc.GUID):
            raise RuntimeError("Must supply GUID for invocation_id")
        if invocation_id == misc.GUID("00000000-0000-0000-0000-000000000000"):
            raise RuntimeError(
                "Must not set GUID 00000000-0000-0000-0000-000000000000 as invocation_id"
            )
        self.replication_state = self.net.replicate_init(
            self.samdb, lp, self.drs, invocation_id)
        self.more_flags = 0

    def _should_retry_with_get_tgt(self, error_code, req):

        # If the error indicates we fail to resolve a target object for a
        # linked attribute, then we should retry the request with GET_TGT
        # (if we support it and haven't already tried that)

        # TODO fix up the below line when we next update werror_err_table.txt
        # and pull in the new error-code
        # return (error_code == werror.WERR_DS_DRA_RECYCLED_TARGET and
        return (error_code == 0x21bf
                and (req.more_flags & drsuapi.DRSUAPI_DRS_GET_TGT) == 0
                and self.supported_extensions
                & drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V10)

    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
        self.net.replicate_chunk(self.replication_state,
                                 level,
                                 ctr,
                                 schema=schema,
                                 req_level=req_level,
                                 req=req)

    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.supported_extensions & drsuapi.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.supported_extensions & drsuapi.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)
Ejemplo n.º 8
0
class drs_Replicate(object):
    '''DRS replication calls'''

    def __init__(self, binding_string, lp, creds, samdb, invocation_id):
        self.drs = drsuapi.drsuapi(binding_string, lp, creds)
        (self.drs_handle, self.supported_extensions) = drs_DsBind(self.drs)
        self.net = Net(creds=creds, lp=lp)
        self.samdb = samdb
        if not isinstance(invocation_id, misc.GUID):
            raise RuntimeError("Must supply GUID for invocation_id")
        if invocation_id == misc.GUID("00000000-0000-0000-0000-000000000000"):
            raise RuntimeError("Must not set GUID 00000000-0000-0000-0000-000000000000 as invocation_id")
        self.replication_state = self.net.replicate_init(self.samdb, lp, self.drs, invocation_id)

    def _should_retry_with_get_tgt(self, error_code, req):

        # If the error indicates we fail to resolve a target object for a
        # linked attribute, then we should retry the request with GET_TGT
        # (if we support it and haven't already tried that)

        # TODO fix up the below line when we next update werror_err_table.txt
        # and pull in the new error-code
        # return (error_code == werror.WERR_DS_DRA_RECYCLED_TARGET and
        return (error_code == 0x21bf and
                (req.more_flags & drsuapi.DRSUAPI_DRS_GET_TGT) == 0 and
                self.supported_extensions & drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V10)

    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.supported_extensions & drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V10:
            req = drsuapi.DsGetNCChangesRequest10()
            req.more_flags = 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.supported_extensions & drsuapi.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
        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.net.replicate_chunk(self.replication_state, level, ctr,
                    schema=schema, req_level=req_level, req=req)
            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[0], req):

                    print("Missing target object - retrying with DRS_GET_TGT")
                    req.more_flags |= drsuapi.DRSUAPI_DRS_GET_TGT

                    # try sending the request again
                    continue
                else:
                    raise e

            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)