# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Author: Alberto Solino (@agsolino) # # Description: # [MS-DCOM] Interface implementation # # Best way to learn how to use these calls is to grab the protocol standard # so you understand what the call does, and then read the test case located # at https://github.com/SecureAuthCorp/impacket/tree/master/tests/SMB_RPC # # Some calls have helper functions, which makes it even easier to use. # They are located at the end of this file. # Helper functions start with "h". # There are test cases for them too. # # ToDo: # [X] Use the same DCE connection for all the calls. Right now is connecting to the remote machine # for each call, making it slower. # # [X] Implement a ping mechanism, otherwise the garbage collector at the server shuts down the objects if # not used, returning RPC_E_DISCONNECTED # from __future__ import division from __future__ import print_function import socket from struct import pack from threading import Timer, currentThread from impacket.dcerpc.v5.ndr import NDRCALL, NDRSTRUCT, NDRPOINTER, NDRUniConformantArray, NDRTLSTRUCT, UNKNOWNDATA from impacket.dcerpc.v5.dtypes import LPWSTR, ULONGLONG, HRESULT, GUID, USHORT, WSTR, DWORD, LPLONG, LONG, PGUID, ULONG, \ UUID, WIDESTR, NULL from impacket import hresult_errors, LOG from impacket.uuid import string_to_bin, uuidtup_to_bin, generate from impacket.dcerpc.v5.rpcrt import TypeSerialization1, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_NONE, \ RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_WINNT, DCERPCException from impacket.dcerpc.v5 import transport CLSID_ActivationContextInfo = string_to_bin('000001a5-0000-0000-c000-000000000046') CLSID_ActivationPropertiesIn = string_to_bin('00000338-0000-0000-c000-000000000046') CLSID_ActivationPropertiesOut = string_to_bin('00000339-0000-0000-c000-000000000046') CLSID_CONTEXT_EXTENSION = string_to_bin('00000334-0000-0000-c000-000000000046') CLSID_ContextMarshaler = string_to_bin('0000033b-0000-0000-c000-000000000046') CLSID_ERROR_EXTENSION = string_to_bin('0000031c-0000-0000-c000-000000000046') CLSID_ErrorObject = string_to_bin('0000031b-0000-0000-c000-000000000046') CLSID_InstanceInfo = string_to_bin('000001ad-0000-0000-c000-000000000046') CLSID_InstantiationInfo = string_to_bin('000001ab-0000-0000-c000-000000000046') CLSID_PropsOutInfo = string_to_bin('00000339-0000-0000-c000-000000000046') CLSID_ScmReplyInfo = string_to_bin('000001b6-0000-0000-c000-000000000046') CLSID_ScmRequestInfo = string_to_bin('000001aa-0000-0000-c000-000000000046') CLSID_SecurityInfo = string_to_bin('000001a6-0000-0000-c000-000000000046') CLSID_ServerLocationInfo = string_to_bin('000001a4-0000-0000-c000-000000000046') CLSID_SpecialSystemProperties = string_to_bin('000001b9-0000-0000-c000-000000000046') IID_IActivation = uuidtup_to_bin(('4d9f4ab8-7d1c-11cf-861e-0020af6e7c57','0.0')) IID_IActivationPropertiesIn = uuidtup_to_bin(('000001A2-0000-0000-C000-000000000046','0.0')) IID_IActivationPropertiesOut = uuidtup_to_bin(('000001A3-0000-0000-C000-000000000046','0.0')) IID_IContext = uuidtup_to_bin(('000001c0-0000-0000-C000-000000000046','0.0')) IID_IObjectExporter = uuidtup_to_bin(('99fcfec4-5260-101b-bbcb-00aa0021347a','0.0')) IID_IRemoteSCMActivator = uuidtup_to_bin(('000001A0-0000-0000-C000-000000000046','0.0')) IID_IRemUnknown = uuidtup_to_bin(('00000131-0000-0000-C000-000000000046','0.0')) IID_IRemUnknown2 = uuidtup_to_bin(('00000143-0000-0000-C000-000000000046','0.0')) IID_IUnknown = uuidtup_to_bin(('00000000-0000-0000-C000-000000000046','0.0')) IID_IClassFactory = uuidtup_to_bin(('00000001-0000-0000-C000-000000000046','0.0')) class DCERPCSessionError(DCERPCException): def __init__(self, error_string=None, error_code=None, packet=None): DCERPCException.__init__(self, error_string, error_code, packet) def __str__( self ): if self.error_code in hresult_errors.ERROR_MESSAGES: error_msg_short = hresult_errors.ERROR_MESSAGES[self.error_code][0] error_msg_verbose = hresult_errors.ERROR_MESSAGES[self.error_code][1] return 'DCOM SessionError: code: 0x%x - %s - %s' % (self.error_code, error_msg_short, error_msg_verbose) else: return 'DCOM SessionError: unknown error code: 0x%x' % self.error_code ################################################################################ # CONSTANTS ################################################################################ # 2.2.1 OID OID = ULONGLONG class OID_ARRAY(NDRUniConformantArray): item = OID class POID_ARRAY(NDRPOINTER): referent = ( ('Data', OID_ARRAY), ) # 2.2.2 SETID SETID = ULONGLONG # 2.2.4 error_status_t error_status_t = ULONG # 2.2.6 CID CID = GUID # 2.2.7 CLSID CLSID = GUID # 2.2.8 IID IID = GUID PIID = PGUID # 2.2.9 IPID IPID = GUID # 2.2.10 OXID OXID = ULONGLONG # 2.2.18 OBJREF FLAGS_OBJREF_STANDARD = 0x00000001 FLAGS_OBJREF_HANDLER = 0x00000002 FLAGS_OBJREF_CUSTOM = 0x00000004 FLAGS_OBJREF_EXTENDED = 0x00000008 # 2.2.18.1 STDOBJREF SORF_NOPING = 0x00001000 # 2.2.20 Context CTXMSHLFLAGS_BYVAL = 0x00000002 # 2.2.20.1 PROPMARSHALHEADER CPFLAG_PROPAGATE = 0x00000001 CPFLAG_EXPOSE = 0x00000002 CPFLAG_ENVOY = 0x00000004 # 2.2.22.2.1 InstantiationInfoData ACTVFLAGS_DISABLE_AAA = 0x00000002 ACTVFLAGS_ACTIVATE_32_BIT_SERVER = 0x00000004 ACTVFLAGS_ACTIVATE_64_BIT_SERVER = 0x00000008 ACTVFLAGS_NO_FAILURE_LOG = 0x00000020 # 2.2.22.2.2 SpecialPropertiesData SPD_FLAG_USE_CONSOLE_SESSION = 0x00000001 # 2.2.28.1 IDL Range Constants MAX_REQUESTED_INTERFACES = 0x8000 MAX_REQUESTED_PROTSEQS = 0x8000 MIN_ACTPROP_LIMIT = 1 MAX_ACTPROP_LIMIT = 10 ################################################################################ # STRUCTURES ################################################################################ class handle_t(NDRSTRUCT): structure = ( ('context_handle_attributes',ULONG), ('context_handle_uuid',UUID), ) def __init__(self, data=None, isNDR64=False): NDRSTRUCT.__init__(self, data, isNDR64) self['context_handle_uuid'] = b'\x00'*16 def isNull(self): return self['context_handle_uuid'] == b'\x00'*16 # 2.2.11 COMVERSION class COMVERSION(NDRSTRUCT): structure = ( ('MajorVersion',USHORT), ('MinorVersion',USHORT), ) def __init__(self, data = None,isNDR64 = False): NDRSTRUCT.__init__(self, data, isNDR64) if data is None: self['MajorVersion'] = 5 self['MinorVersion'] = 7 class PCOMVERSION(NDRPOINTER): referent = ( ('Data', COMVERSION), ) # 2.2.13.1 ORPC_EXTENT # This MUST contain an array of bytes that form the extent data. # The array size MUST be a multiple of 8 for alignment reasons. class BYTE_ARRAY(NDRUniConformantArray): item = 'c' class ORPC_EXTENT(NDRSTRUCT): structure = ( ('id',GUID), ('size',ULONG), ('data',BYTE_ARRAY), ) # 2.2.13.2 ORPC_EXTENT_ARRAY # ThisMUSTbeanarrayofORPC_EXTENTs.ThearraysizeMUSTbeamultipleof2for alignment reasons. class PORPC_EXTENT(NDRPOINTER): referent = ( ('Data', ORPC_EXTENT), ) class EXTENT_ARRAY(NDRUniConformantArray): item = PORPC_EXTENT class PEXTENT_ARRAY(NDRPOINTER): referent = ( ('Data', EXTENT_ARRAY), ) class ORPC_EXTENT_ARRAY(NDRSTRUCT): structure = ( ('size',ULONG), ('reserved',ULONG), ('extent',PEXTENT_ARRAY), ) class PORPC_EXTENT_ARRAY(NDRPOINTER): referent = ( ('Data', ORPC_EXTENT_ARRAY), ) # 2.2.13.3 ORPCTHIS class ORPCTHIS(NDRSTRUCT): structure = ( ('version',COMVERSION), ('flags',ULONG), ('reserved1',ULONG), ('cid',CID), ('extensions',PORPC_EXTENT_ARRAY), ) # 2.2.13.4 ORPCTHAT class ORPCTHAT(NDRSTRUCT): structure = ( ('flags',ULONG), ('extensions',PORPC_EXTENT_ARRAY), ) # 2.2.14 MInterfacePointer class MInterfacePointer(NDRSTRUCT): structure = ( ('ulCntData',ULONG), ('abData',BYTE_ARRAY), ) # 2.2.15 PMInterfacePointerInternal class PMInterfacePointerInternal(NDRPOINTER): referent = ( ('Data', MInterfacePointer), ) # 2.2.16 PMInterfacePointer class PMInterfacePointer(NDRPOINTER): referent = ( ('Data', MInterfacePointer), ) class PPMInterfacePointer(NDRPOINTER): referent = ( ('Data', PMInterfacePointer), ) # 2.2.18 OBJREF class OBJREF(NDRSTRUCT): commonHdr = ( ('signature',ULONG), ('flags',ULONG), ('iid',GUID), ) def __init__(self, data = None,isNDR64 = False): NDRSTRUCT.__init__(self, data, isNDR64) if data is None: self['signature'] = 0x574F454D # 2.2.18.1 STDOBJREF class STDOBJREF(NDRSTRUCT): structure = ( ('flags',ULONG), ('cPublicRefs',ULONG), ('oxid',OXID), ('oid',OID), ('ipid',IPID), ) # 2.2.18.4 OBJREF_STANDARD class OBJREF_STANDARD(OBJREF): structure = ( ('std',STDOBJREF), ('saResAddr',':'), ) def __init__(self, data = None,isNDR64 = False): OBJREF.__init__(self, data, isNDR64) if data is None: self['flags'] = FLAGS_OBJREF_STANDARD # 2.2.18.5 OBJREF_HANDLER class OBJREF_HANDLER(OBJREF): structure = ( ('std',STDOBJREF), ('clsid',CLSID), ('saResAddr',':'), ) def __init__(self, data = None,isNDR64 = False): OBJREF.__init__(self, data, isNDR64) if data is None: self['flags'] = FLAGS_OBJREF_HANDLER # 2.2.18.6 OBJREF_CUSTOM class OBJREF_CUSTOM(OBJREF): structure = ( ('clsid',CLSID), ('cbExtension',ULONG), ('ObjectReferenceSize',ULONG), ('pObjectData',':'), ) def __init__(self, data = None,isNDR64 = False): OBJREF.__init__(self, data, isNDR64) if data is None: self['flags'] = FLAGS_OBJREF_CUSTOM # 2.2.18.8 DATAELEMENT class DATAELEMENT(NDRSTRUCT): structure = ( ('dataID',GUID), ('cbSize',ULONG), ('cbRounded',ULONG), ('Data',':'), ) class DUALSTRINGARRAYPACKED(NDRSTRUCT): structure = ( ('wNumEntries',USHORT), ('wSecurityOffset',USHORT), ('aStringArray',':'), ) def getDataLen(self, data, offset=0): return self['wNumEntries']*2 # 2.2.18.7 OBJREF_EXTENDED class OBJREF_EXTENDED(OBJREF): structure = ( ('std',STDOBJREF), ('Signature1',ULONG), ('saResAddr',DUALSTRINGARRAYPACKED), ('nElms',ULONG), ('Signature2',ULONG), ('ElmArray',DATAELEMENT), ) def __init__(self, data = None, isNDR64 = False): OBJREF.__init__(self, data, isNDR64) if data is None: self['flags'] = FLAGS_OBJREF_EXTENDED self['Signature1'] = 0x4E535956 self['Signature1'] = 0x4E535956 self['nElms'] = 0x4E535956 # 2.2.19 DUALSTRINGARRAY class USHORT_ARRAY(NDRUniConformantArray): item = ' 0 or len(deletedOids) > 0: if 'setid' in DCOMConnection.OID_SET[target]: setId = DCOMConnection.OID_SET[target]['setid'] else: setId = 0 resp = objExporter.ComplexPing(setId, 0, addedOids, deletedOids) DCOMConnection.OID_SET[target]['oids'] -= deletedOids DCOMConnection.OID_SET[target]['oids'] |= addedOids DCOMConnection.OID_SET[target]['setid'] = resp['pSetId'] else: objExporter.SimplePing(DCOMConnection.OID_SET[target]['setid']) except Exception as e: # There might be exceptions when sending packets # We should try to continue tho. LOG.error(str(e)) pass DCOMConnection.PINGTIMER = Timer(120,DCOMConnection.pingServer) try: DCOMConnection.PINGTIMER.start() except Exception as e: if str(e).find('threads can only be started once') < 0: raise e def initTimer(self): if self.__oxidResolver is True: if DCOMConnection.PINGTIMER is None: DCOMConnection.PINGTIMER = Timer(120, DCOMConnection.pingServer) try: DCOMConnection.PINGTIMER.start() except Exception as e: if str(e).find('threads can only be started once') < 0: raise e def initConnection(self): stringBinding = r'ncacn_ip_tcp:%s' % self.__target rpctransport = transport.DCERPCTransportFactory(stringBinding) if hasattr(rpctransport, 'set_credentials') and len(self.__userName) >=0: # This method exists only for selected protocol sequences. rpctransport.set_credentials(self.__userName, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, self.__TGT, self.__TGS) rpctransport.set_kerberos(self.__doKerberos, self.__kdcHost) self.__portmap = rpctransport.get_dce_rpc() self.__portmap.set_auth_level(self.__authLevel) if self.__doKerberos is True: self.__portmap.set_auth_type(RPC_C_AUTHN_GSS_NEGOTIATE) self.__portmap.connect() DCOMConnection.PORTMAPS[self.__target] = self.__portmap def CoCreateInstanceEx(self, clsid, iid): scm = IRemoteSCMActivator(self.__portmap) iInterface = scm.RemoteCreateInstance(clsid, iid) self.initTimer() return iInterface def get_dce_rpc(self): return DCOMConnection.PORTMAPS[self.__target] def disconnect(self): if DCOMConnection.PINGTIMER is not None: del(DCOMConnection.PORTMAPS[self.__target]) del(DCOMConnection.OID_SET[self.__target]) if len(DCOMConnection.PORTMAPS) == 0: # This means there are no more clients using this object, kill it DCOMConnection.PINGTIMER.cancel() DCOMConnection.PINGTIMER.join() DCOMConnection.PINGTIMER = None if self.__target in INTERFACE.CONNECTIONS: del(INTERFACE.CONNECTIONS[self.__target][currentThread().getName()]) self.__portmap.disconnect() #print INTERFACE.CONNECTIONS class CLASS_INSTANCE: def __init__(self, ORPCthis, stringBinding): self.__stringBindings = stringBinding self.__ORPCthis = ORPCthis self.__authType = RPC_C_AUTHN_WINNT self.__authLevel = RPC_C_AUTHN_LEVEL_PKT_PRIVACY def get_ORPCthis(self): return self.__ORPCthis def get_string_bindings(self): return self.__stringBindings def get_auth_level(self): if RPC_C_AUTHN_LEVEL_NONE < self.__authLevel < RPC_C_AUTHN_LEVEL_PKT_PRIVACY: if self.__authType == RPC_C_AUTHN_WINNT: return RPC_C_AUTHN_LEVEL_PKT_INTEGRITY else: return RPC_C_AUTHN_LEVEL_PKT_PRIVACY return self.__authLevel def set_auth_level(self, level): self.__authLevel = level def get_auth_type(self): return self.__authType def set_auth_type(self, authType): self.__authType = authType class INTERFACE: # class variable holding the transport connections, organized by target IP CONNECTIONS = {} def __init__(self, cinstance=None, objRef=None, ipidRemUnknown=None, iPid=None, oxid=None, oid=None, target=None, interfaceInstance=None): if interfaceInstance is not None: self.__target = interfaceInstance.get_target() self.__iPid = interfaceInstance.get_iPid() self.__oid = interfaceInstance.get_oid() self.__oxid = interfaceInstance.get_oxid() self.__cinstance = interfaceInstance.get_cinstance() self.__objRef = interfaceInstance.get_objRef() self.__ipidRemUnknown = interfaceInstance.get_ipidRemUnknown() else: if target is None: raise Exception('No target') self.__target = target self.__iPid = iPid self.__oid = oid self.__oxid = oxid self.__cinstance = cinstance self.__objRef = objRef self.__ipidRemUnknown = ipidRemUnknown # We gotta check if we have a container inside our connection list, if not, create if (self.__target in INTERFACE.CONNECTIONS) is not True: INTERFACE.CONNECTIONS[self.__target] = {} INTERFACE.CONNECTIONS[self.__target][currentThread().getName()] = {} if objRef is not None: self.process_interface(objRef) def process_interface(self, data): objRefType = OBJREF(data)['flags'] objRef = None if objRefType == FLAGS_OBJREF_CUSTOM: objRef = OBJREF_CUSTOM(data) elif objRefType == FLAGS_OBJREF_HANDLER: objRef = OBJREF_HANDLER(data) elif objRefType == FLAGS_OBJREF_STANDARD: objRef = OBJREF_STANDARD(data) elif objRefType == FLAGS_OBJREF_EXTENDED: objRef = OBJREF_EXTENDED(data) else: LOG.error("Unknown OBJREF Type! 0x%x" % objRefType) if objRefType != FLAGS_OBJREF_CUSTOM: if objRef['std']['flags'] & SORF_NOPING == 0: DCOMConnection.addOid(self.__target, objRef['std']['oid']) self.__iPid = objRef['std']['ipid'] self.__oid = objRef['std']['oid'] self.__oxid = objRef['std']['oxid'] if self.__oxid is None: objRef.dump() raise Exception('OXID is None') def get_oxid(self): return self.__oxid def set_oxid(self, oxid): self.__oxid = oxid def get_oid(self): return self.__oid def set_oid(self, oid): self.__oid = oid def get_target(self): return self.__target def get_iPid(self): return self.__iPid def set_iPid(self, iPid): self.__iPid = iPid def get_objRef(self): return self.__objRef def set_objRef(self, objRef): self.__objRef = objRef def get_ipidRemUnknown(self): return self.__ipidRemUnknown def get_dce_rpc(self): return INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['dce'] def get_cinstance(self): return self.__cinstance def set_cinstance(self, cinstance): self.__cinstance = cinstance def is_fdqn(self): # I will assume the following # If I can't socket.inet_aton() then it's not an IPv4 address # Same for ipv6, but since socket.inet_pton is not available in Windows, I'll look for ':'. There can't be # an FQDN with ':' # Is it isn't both, then it is a FDQN try: socket.inet_aton(self.__target) except: # Not an IPv4 try: self.__target.index(':') except: # Not an IPv6, it's a FDQN return True return False def connect(self, iid = None): if (self.__target in INTERFACE.CONNECTIONS) is True: if currentThread().getName() in INTERFACE.CONNECTIONS[self.__target] and \ (self.__oxid in INTERFACE.CONNECTIONS[self.__target][currentThread().getName()]) is True: dce = INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['dce'] currentBinding = INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['currentBinding'] if currentBinding == iid: # We don't need to alter_ctx pass else: newDce = dce.alter_ctx(iid) INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['dce'] = newDce INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['currentBinding'] = iid else: stringBindings = self.get_cinstance().get_string_bindings() # No OXID present, we should create a new connection and store it stringBinding = None isTargetFDQN = self.is_fdqn() LOG.debug('Target system is %s and isFDQN is %s' % (self.get_target(), isTargetFDQN)) for strBinding in stringBindings: # Here, depending on the get_target() value several things can happen # 1) it's an IPv4 address # 2) it's an IPv6 address # 3) it's a NetBios Name # we should handle all this cases accordingly # Does this match exactly what get_target() returns? LOG.debug('StringBinding: %s' % strBinding['aNetworkAddr']) if strBinding['wTowerId'] == 7: # If there's port information, let's strip it for now. if strBinding['aNetworkAddr'].find('[') >= 0: binding, _, bindingPort = strBinding['aNetworkAddr'].partition('[') bindingPort = '[' + bindingPort else: binding = strBinding['aNetworkAddr'] bindingPort = '' if binding.upper().find(self.get_target().upper()) >= 0: stringBinding = 'ncacn_ip_tcp:' + strBinding['aNetworkAddr'][:-1] break # If get_target() is a FQDN, does it match the hostname? elif isTargetFDQN and binding.upper().find(self.get_target().upper().partition('.')[0]) >= 0: # Here we replace the aNetworkAddr with self.get_target() # This is to help resolving the target system name. # self.get_target() has been resolved already otherwise we wouldn't be here whereas # aNetworkAddr is usually the NetBIOS name and unless you have your DNS resolver # with the right suffixes it will probably not resolve right. stringBinding = 'ncacn_ip_tcp:%s%s' % (self.get_target(), bindingPort) break LOG.debug('StringBinding chosen: %s' % stringBinding) if stringBinding is None: # Something wen't wrong, let's just report it raise Exception('Can\'t find a valid stringBinding to connect') dcomInterface = transport.DCERPCTransportFactory(stringBinding) if hasattr(dcomInterface, 'set_credentials'): # This method exists only for selected protocol sequences. dcomInterface.set_credentials(*DCOMConnection.PORTMAPS[self.__target].get_credentials()) dcomInterface.set_kerberos(DCOMConnection.PORTMAPS[self.__target].get_rpc_transport().get_kerberos(), DCOMConnection.PORTMAPS[self.__target].get_rpc_transport().get_kdcHost()) dcomInterface.set_connect_timeout(300) dce = dcomInterface.get_dce_rpc() if iid is None: raise Exception('IID is None') else: dce.set_auth_level(self.__cinstance.get_auth_level()) dce.set_auth_type(self.__cinstance.get_auth_type()) dce.connect() if iid is None: raise Exception('IID is None') else: dce.bind(iid) if self.__oxid is None: #import traceback #traceback.print_stack() raise Exception("OXID NONE, something wrong!!!") INTERFACE.CONNECTIONS[self.__target][currentThread().getName()] = {} INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid] = {} INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['dce'] = dce INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['currentBinding'] = iid else: # No connection created raise Exception('No connection created') def request(self, req, iid = None, uuid = None): req['ORPCthis'] = self.get_cinstance().get_ORPCthis() req['ORPCthis']['flags'] = 0 self.connect(iid) dce = self.get_dce_rpc() try: resp = dce.request(req, uuid) except Exception as e: if str(e).find('RPC_E_DISCONNECTED') >= 0: msg = str(e) + '\n' msg += "DCOM keep-alive pinging it might not be working as expected. You can't be idle for more than 14 minutes!\n" msg += "You should exit the app and start again\n" raise DCERPCException(msg) else: raise return resp def disconnect(self): return INTERFACE.CONNECTIONS[self.__target][currentThread().getName()][self.__oxid]['dce'].disconnect() # 3.1.1.5.6.1 IRemUnknown Methods class IRemUnknown(INTERFACE): def __init__(self, interface): self._iid = IID_IRemUnknown #INTERFACE.__init__(self, interface.get_cinstance(), interface.get_objRef(), interface.get_ipidRemUnknown(), # interface.get_iPid(), target=interface.get_target()) INTERFACE.__init__(self, interfaceInstance=interface) self.set_oxid(interface.get_oxid()) def RemQueryInterface(self, cRefs, iids): # For now, it only supports a single IID request = RemQueryInterface() request['ORPCthis'] = self.get_cinstance().get_ORPCthis() request['ORPCthis']['flags'] = 0 request['ripid'] = self.get_iPid() request['cRefs'] = cRefs request['cIids'] = len(iids) for iid in iids: _iid = IID() _iid['Data'] = iid request['iids'].append(_iid) resp = self.request(request, IID_IRemUnknown, self.get_ipidRemUnknown()) #resp.dump() return IRemUnknown2( INTERFACE(self.get_cinstance(), None, self.get_ipidRemUnknown(), resp['ppQIResults']['std']['ipid'], oxid=resp['ppQIResults']['std']['oxid'], oid=resp['ppQIResults']['std']['oxid'], target=self.get_target())) def RemAddRef(self): request = RemAddRef() request['ORPCthis'] = self.get_cinstance().get_ORPCthis() request['ORPCthis']['flags'] = 0 request['cInterfaceRefs'] = 1 element = REMINTERFACEREF() element['ipid'] = self.get_iPid() element['cPublicRefs'] = 1 request['InterfaceRefs'].append(element) resp = self.request(request, IID_IRemUnknown, self.get_ipidRemUnknown()) return resp def RemRelease(self): request = RemRelease() request['ORPCthis'] = self.get_cinstance().get_ORPCthis() request['ORPCthis']['flags'] = 0 request['cInterfaceRefs'] = 1 element = REMINTERFACEREF() element['ipid'] = self.get_iPid() element['cPublicRefs'] = 1 request['InterfaceRefs'].append(element) resp = self.request(request, IID_IRemUnknown, self.get_ipidRemUnknown()) DCOMConnection.delOid(self.get_target(), self.get_oid()) return resp # 3.1.1.5.7 IRemUnknown2 Interface class IRemUnknown2(IRemUnknown): def __init__(self, interface): IRemUnknown.__init__(self, interface) self._iid = IID_IRemUnknown2 # 3.1.2.5.1 IObjectExporter Methods class IObjectExporter: def __init__(self, dce): self.__portmap = dce # 3.1.2.5.1.1 IObjectExporter::ResolveOxid (Opnum 0) def ResolveOxid(self, pOxid, arRequestedProtseqs): self.__portmap.connect() self.__portmap.bind(IID_IObjectExporter) request = ResolveOxid() request['pOxid'] = pOxid request['cRequestedProtseqs'] = len(arRequestedProtseqs) for protSeq in arRequestedProtseqs: request['arRequestedProtseqs'].append(protSeq) resp = self.__portmap.request(request) Oxids = b''.join(pack(' 0: for oid in addToSet: oidn = OID() oidn['Data'] = oid request['AddToSet'].append(oidn) else: request['AddToSet'] = NULL if len(delFromSet) > 0: for oid in delFromSet: oidn = OID() oidn['Data'] = oid request['DelFromSet'].append(oidn) else: request['DelFromSet'] = NULL resp = self.__portmap.request(request) return resp # 3.1.2.5.1.4 IObjectExporter::ServerAlive (Opnum 3) def ServerAlive(self): self.__portmap.connect() self.__portmap.bind(IID_IObjectExporter) request = ServerAlive() resp = self.__portmap.request(request) return resp # 3.1.2.5.1.5 IObjectExporter::ResolveOxid2 (Opnum 4) def ResolveOxid2(self,pOxid, arRequestedProtseqs): self.__portmap.connect() self.__portmap.bind(IID_IObjectExporter) request = ResolveOxid2() request['pOxid'] = pOxid request['cRequestedProtseqs'] = len(arRequestedProtseqs) for protSeq in arRequestedProtseqs: request['arRequestedProtseqs'].append(protSeq) resp = self.__portmap.request(request) Oxids = b''.join(pack('