From a9ba4b5cfed4398b0cb1e75486805bde34044caa Mon Sep 17 00:00:00 2001 From: speyrefitte Date: Tue, 27 May 2014 16:55:41 +0200 Subject: [PATCH] pdu error handle --- rdpy/network/error.py | 13 +- rdpy/network/type.py | 33 ++++- rdpy/protocol/rdp/pdu.py | 298 +++++++++++++++++++++++++++++++++++--- rdpy/rdpclient.py | 2 +- rdpy/test/network/type.py | 69 ++++++++- 5 files changed, 389 insertions(+), 26 deletions(-) diff --git a/rdpy/network/error.py b/rdpy/network/error.py index a6ad224..540aa6f 100644 --- a/rdpy/network/error.py +++ b/rdpy/network/error.py @@ -55,4 +55,15 @@ class InvalidSize(Exception): constructor with message @param message: message show when exception is raised ''' - Exception.__init__(self, message) + Exception.__init__(self, message) + +class ErrorReportedFromPeer(Exception): + ''' + raise when peer send an error + ''' + def __init__(self, message = ""): + ''' + constructor with message + @param message: message show when exception is raised + ''' + Exception.__init__(self, message) diff --git a/rdpy/network/type.py b/rdpy/network/type.py index 1e31c46..90b131a 100644 --- a/rdpy/network/type.py +++ b/rdpy/network/type.py @@ -6,7 +6,7 @@ import struct from copy import deepcopy from StringIO import StringIO from error import InvalidValue -from rdpy.network.error import InvalidExpectedDataException +from rdpy.network.error import InvalidExpectedDataException, InvalidSize def sizeof(element): ''' @@ -70,10 +70,19 @@ class Type(object): self._is_readed = self._conditional() if not self._is_readed: return + + #not constant mode direct reading + if not self._constant: + self.__read__(s) + return + + #constant mode old = deepcopy(self) self.__read__(s) #check constant value - if self._constant and old != self: + if old != self: + #rollback read value + s.pos -= sizeof(self) raise InvalidExpectedDataException("%s const value expected %s != %s"%(self.__class__, old.value, self.value)) def __read__(self, s): @@ -229,7 +238,9 @@ class SimpleType(Type, CallableValue): use struct package @param s: Stream ''' - self.value = struct.unpack(self._structFormat,s.read(self._typeSize))[0] + if s.dataLen() < self._typeSize: + raise InvalidSize("Stream is too small to read expected data") + self.value = struct.unpack(self._structFormat, s.read(self._typeSize))[0] def mask(self): ''' @@ -381,6 +392,11 @@ class CompositeType(Type): s.readType(self.__dict__[name]) except Exception as e: print "Error during read %s::%s"%(self.__class__, name) + #rollback already readed + for tmpName in self._typeName: + if tmpName == name: + break + s.pos -= sizeof(self.__dict__[tmpName]) raise e def __write__(self, s): @@ -720,7 +736,15 @@ class Stream(StringIO): #read each tuple if isinstance(value, tuple) or isinstance(value, list): for element in value: - self.readType(element) + try: + self.readType(element) + except Exception as e: + #rollback already readed elements + for tmpElement in value: + if tmpElement == element: + break + self.pos -= sizeof(tmpElement) + raise e return #optional value not present @@ -760,6 +784,7 @@ class ArrayType(Type): ''' constructor @param typeFactory: class use to init new element on read + @param init: init array @param readLen: number of element in sequence @param conditional : function call before read or write type @param optional: boolean check before read if there is still data in stream diff --git a/rdpy/protocol/rdp/pdu.py b/rdpy/protocol/rdp/pdu.py index c52593d..a44d2fc 100644 --- a/rdpy/protocol/rdp/pdu.py +++ b/rdpy/protocol/rdp/pdu.py @@ -5,7 +5,7 @@ from rdpy.network.layer import LayerAutomata from rdpy.network.type import CompositeType, UniString, String, UInt8, UInt16Le, UInt16Be, UInt32Le, sizeof, ArrayType from rdpy.network.const import ConstAttributes, TypeAttributes -from rdpy.network.error import InvalidExpectedDataException +from rdpy.network.error import InvalidExpectedDataException, ErrorReportedFromPeer import gcc import lic @@ -286,11 +286,150 @@ class OrderEx(object): ''' ORDERFLAGS_EX_CACHE_BITMAP_REV3_SUPPORT = 0x0002 ORDERFLAGS_EX_ALTSEC_FRAME_MARKER_SUPPORT = 0x0004 + +@ConstAttributes +@TypeAttributes(UInt16Le) +class Action(object): + ''' + Action flag use in Control PDU packet + @see: http://msdn.microsoft.com/en-us/library/cc240492.aspx + ''' + CTRLACTION_REQUEST_CONTROL = 0x0001 + CTRLACTION_GRANTED_CONTROL = 0x0002 + CTRLACTION_DETACH = 0x0003 + CTRLACTION_COOPERATE = 0x0004 + +@ConstAttributes +@TypeAttributes(UInt16Le) +class PersistentKeyListFlag(object): + ''' + use to determine the number of persistent key packet + @see: http://msdn.microsoft.com/en-us/library/cc240495.aspx + ''' + PERSIST_FIRST_PDU = 0x01 + PERSIST_LAST_PDU = 0x02 + +@ConstAttributes +@TypeAttributes(UInt32Le) +class ErrorInfo(object): + ''' + Error code use in Error info pdu + @see: http://msdn.microsoft.com/en-us/library/cc240544.aspx + ''' + ERRINFO_RPC_INITIATED_DISCONNECT = 0x00000001 + ERRINFO_RPC_INITIATED_LOGOFF = 0x00000002 + ERRINFO_IDLE_TIMEOUT = 0x00000003 + ERRINFO_LOGON_TIMEOUT = 0x00000004 + ERRINFO_DISCONNECTED_BY_OTHERCONNECTION = 0x00000005 + ERRINFO_OUT_OF_MEMORY = 0x00000006 + ERRINFO_SERVER_DENIED_CONNECTION = 0x00000007 + ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES = 0x00000009 + ERRINFO_SERVER_FRESH_CREDENTIALS_REQUIRED = 0x0000000A + ERRINFO_RPC_INITIATED_DISCONNECT_BYUSER = 0x0000000B + ERRINFO_LOGOFF_BY_USER = 0x0000000C + ERRINFO_LICENSE_INTERNAL = 0x00000100 + ERRINFO_LICENSE_NO_LICENSE_SERVER = 0x00000101 + ERRINFO_LICENSE_NO_LICENSE = 0x00000102 + ERRINFO_LICENSE_BAD_CLIENT_MSG = 0x00000103 + ERRINFO_LICENSE_HWID_DOESNT_MATCH_LICENSE = 0x00000104 + ERRINFO_LICENSE_BAD_CLIENT_LICENSE = 0x00000105 + ERRINFO_LICENSE_CANT_FINISH_PROTOCOL = 0x00000106 + ERRINFO_LICENSE_CLIENT_ENDED_PROTOCOL = 0x00000107 + ERRINFO_LICENSE_BAD_CLIENT_ENCRYPTION = 0x00000108 + ERRINFO_LICENSE_CANT_UPGRADE_LICENSE = 0x00000109 + ERRINFO_LICENSE_NO_REMOTE_CONNECTIONS = 0x0000010A + ERRINFO_CB_DESTINATION_NOT_FOUND = 0x0000400 + ERRINFO_CB_LOADING_DESTINATION = 0x0000402 + ERRINFO_CB_REDIRECTING_TO_DESTINATION = 0x0000404 + ERRINFO_CB_SESSION_ONLINE_VM_WAKE = 0x0000405 + ERRINFO_CB_SESSION_ONLINE_VM_BOOT = 0x0000406 + ERRINFO_CB_SESSION_ONLINE_VM_NO_DNS = 0x0000407 + ERRINFO_CB_DESTINATION_POOL_NOT_FREE = 0x0000408 + ERRINFO_CB_CONNECTION_CANCELLED = 0x0000409 + ERRINFO_CB_CONNECTION_ERROR_INVALID_SETTINGS = 0x0000410 + ERRINFO_CB_SESSION_ONLINE_VM_BOOT_TIMEOUT = 0x0000411 + ERRINFO_CB_SESSION_ONLINE_VM_SESSMON_FAILED = 0x0000412 + ERRINFO_UNKNOWNPDUTYPE2 = 0x000010C9 + ERRINFO_UNKNOWNPDUTYPE = 0x000010CA + ERRINFO_DATAPDUSEQUENCE = 0x000010CB + ERRINFO_CONTROLPDUSEQUENCE = 0x000010CD + ERRINFO_INVALIDCONTROLPDUACTION = 0x000010CE + ERRINFO_INVALIDINPUTPDUTYPE = 0x000010CF + ERRINFO_INVALIDINPUTPDUMOUSE = 0x000010D0 + ERRINFO_INVALIDREFRESHRECTPDU = 0x000010D1 + ERRINFO_CREATEUSERDATAFAILED = 0x000010D2 + ERRINFO_CONNECTFAILED =0x000010D3 + ERRINFO_CONFIRMACTIVEWRONGSHAREID = 0x000010D4 + ERRINFO_CONFIRMACTIVEWRONGORIGINATOR = 0x000010D5 + ERRINFO_PERSISTENTKEYPDUBADLENGTH = 0x000010DA + ERRINFO_PERSISTENTKEYPDUILLEGALFIRST = 0x000010DB + ERRINFO_PERSISTENTKEYPDUTOOMANYTOTALKEYS = 0x000010DC + ERRINFO_PERSISTENTKEYPDUTOOMANYCACHEKEYS = 0x000010DD + ERRINFO_INPUTPDUBADLENGTH = 0x000010DE + ERRINFO_BITMAPCACHEERRORPDUBADLENGTH = 0x000010DF + ERRINFO_SECURITYDATATOOSHORT = 0x000010E0 + ERRINFO_VCHANNELDATATOOSHORT = 0x000010E1 + ERRINFO_SHAREDATATOOSHORT = 0x000010E2 + ERRINFO_BADSUPRESSOUTPUTPDU = 0x000010E3 + ERRINFO_CONFIRMACTIVEPDUTOOSHORT = 0x000010E5 + ERRINFO_CAPABILITYSETTOOSMALL = 0x000010E7 + ERRINFO_CAPABILITYSETTOOLARGE = 0x000010E8 + ERRINFO_NOCURSORCACHE = 0x000010E9 + ERRINFO_BADCAPABILITIES = 0x000010EA + ERRINFO_VIRTUALCHANNELDECOMPRESSIONERR = 0x000010EC + ERRINFO_INVALIDVCCOMPRESSIONTYPE = 0x000010ED + ERRINFO_INVALIDCHANNELID = 0x000010EF + ERRINFO_VCHANNELSTOOMANY = 0x000010F0 + ERRINFO_REMOTEAPPSNOTENABLED = 0x000010F3 + ERRINFO_CACHECAPNOTSET = 0x000010F4 + ERRINFO_BITMAPCACHEERRORPDUBADLENGTH2 = 0x000010F5 + ERRINFO_OFFSCRCACHEERRORPDUBADLENGTH = 0x000010F6 + ERRINFO_DNGCACHEERRORPDUBADLENGTH = 0x000010F7 + ERRINFO_GDIPLUSPDUBADLENGTH = 0x000010F8 + ERRINFO_SECURITYDATATOOSHORT2 = 0x00001111 + ERRINFO_SECURITYDATATOOSHORT3 = 0x00001112 + ERRINFO_SECURITYDATATOOSHORT4 = 0x00001113 + ERRINFO_SECURITYDATATOOSHORT5 = 0x00001114 + ERRINFO_SECURITYDATATOOSHORT6 = 0x00001115 + ERRINFO_SECURITYDATATOOSHORT7 = 0x00001116 + ERRINFO_SECURITYDATATOOSHORT8 = 0x00001117 + ERRINFO_SECURITYDATATOOSHORT9 = 0x00001118 + ERRINFO_SECURITYDATATOOSHORT10 = 0x00001119 + ERRINFO_SECURITYDATATOOSHORT11 = 0x0000111A + ERRINFO_SECURITYDATATOOSHORT12 = 0x0000111B + ERRINFO_SECURITYDATATOOSHORT13 = 0x0000111C + ERRINFO_SECURITYDATATOOSHORT14 = 0x0000111D + ERRINFO_SECURITYDATATOOSHORT15 = 0x0000111E + ERRINFO_SECURITYDATATOOSHORT16 = 0x0000111F + ERRINFO_SECURITYDATATOOSHORT17 = 0x00001120 + ERRINFO_SECURITYDATATOOSHORT18 = 0x00001121 + ERRINFO_SECURITYDATATOOSHORT19 = 0x00001122 + ERRINFO_SECURITYDATATOOSHORT20 = 0x00001123 + ERRINFO_SECURITYDATATOOSHORT21 = 0x00001124 + ERRINFO_SECURITYDATATOOSHORT22 = 0x00001125 + ERRINFO_SECURITYDATATOOSHORT23 = 0x00001126 + ERRINFO_BADMONITORDATA = 0x00001129 + ERRINFO_VCDECOMPRESSEDREASSEMBLEFAILED = 0x0000112A + ERRINFO_VCDATATOOLONG = 0x0000112B + ERRINFO_BAD_FRAME_ACK_DATA = 0x0000112C + ERRINFO_GRAPHICSMODENOTSUPPORTED = 0x0000112D + ERRINFO_GRAPHICSSUBSYSTEMRESETFAILED = 0x0000112E + ERRINFO_GRAPHICSSUBSYSTEMFAILED = 0x0000112F + ERRINFO_TIMEZONEKEYNAMELENGTHTOOSHORT = 0x00001130 + ERRINFO_TIMEZONEKEYNAMELENGTHTOOLONG = 0x00001131 + ERRINFO_DYNAMICDSTDISABLEDFIELDMISSING = 0x00001132 + ERRINFO_VCDECODINGERROR = 0x00001133 + ERRINFO_UPDATESESSIONKEYFAILED = 0x00001191 + ERRINFO_DECRYPTFAILED = 0x00001192 + ERRINFO_ENCRYPTFAILED = 0x00001193 + ERRINFO_ENCPKGMISMATCH = 0x00001194 + ERRINFO_DECRYPTFAILED2 = 0x00001195 class RDPInfo(CompositeType): ''' client informations contains credentials (very important packet) + @see: http://msdn.microsoft.com/en-us/library/cc240475.aspx ''' def __init__(self, extendedInfoConditional): CompositeType.__init__(self) @@ -333,7 +472,7 @@ class ShareControlHeader(CompositeType): PDU share control header @see: http://msdn.microsoft.com/en-us/library/cc240576.aspx ''' - def __init__(self, totalLength, pduType): + def __init__(self, totalLength, pduType, userId): ''' constructor @param totalLength: total length of pdu packet @@ -342,16 +481,16 @@ class ShareControlHeader(CompositeType): #share control header self.totalLength = UInt16Le(totalLength) self.pduType = UInt16Le(pduType.value, constant = True) - self.PDUSource = UInt16Le() + self.PDUSource = UInt16Le(userId.value + 1001) -class SharedataHeader(CompositeType): +class ShareDataHeader(CompositeType): ''' PDU share data header @see: http://msdn.microsoft.com/en-us/library/cc240577.aspx ''' - def __init__(self, size, pduType, pduType2): + def __init__(self, size, pduType2, userId = UInt16Le()): CompositeType.__init__(self) - self.shareControlHeader = ShareControlHeader(size, pduType) + self.shareControlHeader = ShareControlHeader(size, PDUType.PDUTYPE_DATAPDU, userId) self.shareId = UInt32Le() self.pad1 = UInt8() self.streamId = UInt8() @@ -428,7 +567,7 @@ class OrderCapability(CompositeType): self.pad2octetsA = UInt16Le(0) self.maximumOrderLevel = UInt16Le(1) self.numberFonts = UInt16Le(0) - self.orderFlags = UInt16Le(OrderFlag.NEGOTIATEORDERSUPPORT) + self.orderFlags = OrderFlag.NEGOTIATEORDERSUPPORT self.orderSupport = ArrayType(UInt8, readLen = UInt8(32)) self.textFlags = UInt16Le() self.orderSupportExFlags = UInt16Le() @@ -444,9 +583,9 @@ class DemandActivePDU(CompositeType): @see: http://msdn.microsoft.com/en-us/library/cc240485.aspx main use for capabilities exchange server -> client ''' - def __init__(self): + def __init__(self, userId = UInt16Le()): CompositeType.__init__(self) - self.shareControlHeader = ShareControlHeader(lambda:sizeof(self), PDUType.PDUTYPE_DEMANDACTIVEPDU) + self.shareControlHeader = ShareControlHeader(lambda:sizeof(self), PDUType.PDUTYPE_DEMANDACTIVEPDU, userId) self.shareId = UInt32Le() self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) self.lengthCombinedCapabilities = UInt16Le(lambda:(sizeof(self.numberCapabilities) + sizeof(self.pad2Octets) + sizeof(self.capabilitySets))) @@ -461,9 +600,9 @@ class ConfirmActivePDU(CompositeType): @see: http://msdn.microsoft.com/en-us/library/cc240488.aspx main use for capabilities confirm client -> sever ''' - def __init__(self): + def __init__(self, userId = UInt16Le()): CompositeType.__init__(self) - self.shareControlHeader = ShareControlHeader(lambda:sizeof(self), PDUType.PDUTYPE_CONFIRMACTIVEPDU) + self.shareControlHeader = ShareControlHeader(lambda:sizeof(self), PDUType.PDUTYPE_CONFIRMACTIVEPDU, userId) self.shareId = UInt32Le() self.originatorId = UInt16Le(0x03EA, constant = True) self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) @@ -477,11 +616,68 @@ class SynchronizePDU(CompositeType): ''' @see http://msdn.microsoft.com/en-us/library/cc240490.aspx ''' - def __init__(self): + def __init__(self, userId = UInt16Le()): CompositeType.__init__(self) - self.shareControlHeader = SharedataHeader(lambda:sizeof(self), PDUType.PDUTYPE_DATAPDU, PDUType2.PDUTYPE2_SYNCHRONIZE) + self.shareControlHeader = ShareDataHeader(lambda:sizeof(self), PDUType2.PDUTYPE2_SYNCHRONIZE, userId) self.messageType = UInt16Le(1, constant = True) self.targetUser = UInt16Le() + +class ControlPDU(CompositeType): + ''' + @see http://msdn.microsoft.com/en-us/library/cc240492.aspx + ''' + def __init__(self, userId = UInt16Le()): + CompositeType.__init__(self) + self.shareControlHeader = ShareDataHeader(lambda:sizeof(self), PDUType2.PDUTYPE2_CONTROL, userId) + self.action = UInt16Le() + self.grantId = UInt16Le() + self.controlId = UInt32Le() + +class PersistentListEntry(CompositeType): + ''' + use to record persistent key in PersistentListPDU + @see: http://msdn.microsoft.com/en-us/library/cc240496.aspx + ''' + def __init__(self): + CompositeType.__init__(self) + self.key1 = UInt32Le() + self.key2 = UInt32Le() + + +class PersistentListPDU(CompositeType): + ''' + Use to indicate that bitmap cache was already + fill with some keys from previous session + @see: http://msdn.microsoft.com/en-us/library/cc240495.aspx + ''' + def __init__(self, userId = UInt16Le()): + CompositeType.__init__(self) + self.shareControlHeader = ShareDataHeader(lambda:sizeof(self), PDUType2.PDUTYPE2_BITMAPCACHE_PERSISTENT_LIST, userId) + self.numEntriesCache0 = UInt16Le() + self.numEntriesCache1 = UInt16Le() + self.numEntriesCache2 = UInt16Le() + self.numEntriesCache3 = UInt16Le() + self.numEntriesCache4 = UInt16Le() + self.totalEntriesCache0 = UInt16Le() + self.totalEntriesCache1 = UInt16Le() + self.totalEntriesCache2 = UInt16Le() + self.totalEntriesCache3 = UInt16Le() + self.totalEntriesCache4 = UInt16Le() + self.bitMask = UInt8() + self.pad2 = UInt8() + self.pad3 = UInt16Le() + self.entries = ArrayType(PersistentListEntry, readLen = lambda:(self.numEntriesCache0 + self.numEntriesCache1 + self.numEntriesCache2 + self.numEntriesCache3 + self.numEntriesCache4)) + +class ErrorInfoPDU(CompositeType): + ''' + Use to inform error in PDU layer + @see: http://msdn.microsoft.com/en-us/library/cc240544.aspx + ''' + def __init__(self): + CompositeType.__init__(self) + self.shareControlHeader = ShareDataHeader(lambda:sizeof(self), PDUType2.PDUTYPE2_SET_ERROR_INFO_PDU) + #use to collect error info pdu + self.errorInfo = UInt32Le() class PDU(LayerAutomata): ''' @@ -503,12 +699,17 @@ class PDU(LayerAutomata): self._clientCapabilities = {} #share id between client and server self._shareId = UInt32Le() + #mcs user id use for pdu packet + self._userId = UInt16Be() def connect(self): ''' connect event in client mode send logon info nextstate recv licence pdu ''' + #get user id from mcs layer + self._userId = self._transport._userId + self.sendInfoPkt() #next state is licence info PDU self.setNextState(self.recvLicenceInfo) @@ -543,6 +744,21 @@ class PDU(LayerAutomata): self.setNextState(self.recvDemandActivePDU) + def readPDU(self, data, pdu): + ''' + Try to read expected pdu or try to parse error info pdu + ''' + try: + data.readType(pdu) + except Exception: + #maybe an error message + errorInfoPDU = ErrorInfoPDU() + try: + data.readType(errorInfoPDU) + raise ErrorReportedFromPeer("Receive PDU Error info : %s"%hex(errorInfoPDU.errorInfo.value)) + except: + raise InvalidExpectedDataException("Invalid PDU") + def recvDemandActivePDU(self, data): ''' receive demand active PDU which contains @@ -552,13 +768,32 @@ class PDU(LayerAutomata): @param data: Stream ''' demandActivePDU = DemandActivePDU() - data.readType(demandActivePDU) + self.readPDU(data, demandActivePDU) + + self._shareId = demandActivePDU.shareId for cap in demandActivePDU.capabilitySets._array: self._serverCapabilities[cap.capabilitySetType] = cap self.sendConfirmActivePDU() + def recvServerFinalizeSynchronizePDU(self, data): + ''' + receive from server + ''' + synchronizePDU = SynchronizePDU() + self.readPDU(data, synchronizePDU) + + + if synchronizePDU.targetUser != self._channelId: + raise InvalidExpectedDataException("receive synchronize for an invalide user") + + controlCooparatePDU = ControlPDU(self._userId) + self.readPDU(data, controlCooparatePDU) + + if controlCooparatePDU.action != Action.CTRLACTION_COOPERATE: + raise InvalidExpectedDataException("receive an invalid cooparate control PDU") + def sendConfirmActivePDU(self): ''' send all client capabilities @@ -571,7 +806,7 @@ class PDU(LayerAutomata): capability.generalCapability.extraFlags = GeneralExtraFlag.LONG_CREDENTIALS_SUPPORTED self._clientCapabilities[capability.capabilitySetType] = capability - #init general capability + #init bitmap capability capability = Capability() capability.capabilitySetType = CapsType.CAPSTYPE_BITMAP capability.bitmapCapability.preferredBitsPerPixel = self._transport._clientSettings.core.colorDepth @@ -579,18 +814,43 @@ class PDU(LayerAutomata): capability.bitmapCapability.desktopHeight = self._transport._clientSettings.core.desktopHeight self._clientCapabilities[capability.capabilitySetType] = capability + #init order capability + capability = Capability() + capability.capabilitySetType = CapsType.CAPSTYPE_ORDER + capability.orderCapability.orderFlags |= OrderFlag.ZEROBOUNDSDELTASSUPPORT + capability.orderCapability.orderSupport = [UInt8(0) for i in range (0, 32)] + self._clientCapabilities[capability.capabilitySetType] = capability + #make active PDU packet - confirmActivePDU = ConfirmActivePDU() + confirmActivePDU = ConfirmActivePDU(self._userId) + confirmActivePDU.shareId = self._shareId confirmActivePDU.capabilitySets._array = self._clientCapabilities.values() self._transport.send(self._channelId, confirmActivePDU) #send synchronize - self.sendSynchronizePDU() + self.sendClientFinalizeSynchronizePDU() - def sendSynchronizePDU(self): + def sendClientFinalizeSynchronizePDU(self): ''' send a synchronize PDU from client to server ''' - synchronizePDU = SynchronizePDU() + synchronizePDU = SynchronizePDU(self._userId) synchronizePDU.targetUser = self._channelId self._transport.send(self._channelId, synchronizePDU) + + #ask for cooperation + controlCooperatePDU = ControlPDU(self._userId) + controlCooperatePDU.action = Action.CTRLACTION_COOPERATE + self._transport.send(self._channelId, controlCooperatePDU) + + #request control + controlRequestPDU = ControlPDU(self._userId) + controlRequestPDU.action = Action.CTRLACTION_REQUEST_CONTROL + self._transport.send(self._channelId, controlRequestPDU) + + #send persistent list pdu + persistentListPDU = PersistentListPDU(self._userId) + persistentListPDU.bitMask = PersistentKeyListFlag.PERSIST_FIRST_PDU | PersistentKeyListFlag.PERSIST_LAST_PDU + self._transport.send(self._channelId, persistentListPDU) + + self.setNextState(self.recvServerFinalizeSynchronizePDU) \ No newline at end of file diff --git a/rdpy/rdpclient.py b/rdpy/rdpclient.py index 3a7d230..4283094 100644 --- a/rdpy/rdpclient.py +++ b/rdpy/rdpclient.py @@ -15,5 +15,5 @@ if __name__ == '__main__': from twisted.internet import reactor #reactor.connectTCP("127.0.0.1", 5901, factory.RfbFactory(protocol)) #reactor.connectTCP("192.168.1.90", 3389, factory.RfbFactory(tpkt.TPKT(tpdu.TPDU(mcs.MCS())))) - reactor.connectTCP("192.168.135.123", 3389, rdp.Factory(LayerMode.CLIENT)) + reactor.connectTCP("192.168.135.198", 3389, rdp.Factory(LayerMode.CLIENT)) reactor.run() \ No newline at end of file diff --git a/rdpy/test/network/type.py b/rdpy/test/network/type.py index a5a109c..2fed9e7 100644 --- a/rdpy/test/network/type.py +++ b/rdpy/test/network/type.py @@ -264,4 +264,71 @@ class TypeCase(unittest.TestCase): s1 = rdpy.network.type.Stream("\x01\x00\x00\x00") s1.readType(t) self.assertEqual(t.value, 1, "invalid stream read conditional value") - \ No newline at end of file + + def test_strem_read_rollback_constant_constraint(self): + ''' + test if constant constraint fail, the reading stream is correctly rollback + ''' + class TestComposite(rdpy.network.type.CompositeType): + def __init__(self): + rdpy.network.type.CompositeType.__init__(self) + self.padding = rdpy.network.type.UInt32Le(0) + self.constraint = rdpy.network.type.UInt32Le(1, constant = True) + + s = rdpy.network.type.Stream("\x00\x00\x00\x00\x00\x00\x00\x00") + try: + s.readType(TestComposite()) + except Exception: + self.assertEqual(s.readLen(), 0, "invalid stream roll back operation") + return + self.assertTrue(False, "Constant constraint fail") + + def test_strem_read_rollback_constant_constraint_recurcive(self): + ''' + test if constant constraint fail even in recurcive composite type, + the reading stream is correctly rollback + ''' + class TestSubComposite(rdpy.network.type.CompositeType): + def __init__(self): + rdpy.network.type.CompositeType.__init__(self) + self.padding = rdpy.network.type.UInt32Le(0) + self.constraint = rdpy.network.type.UInt32Le(1, constant = True) + + class TestComposite(rdpy.network.type.CompositeType): + def __init__(self): + rdpy.network.type.CompositeType.__init__(self) + self.padding = rdpy.network.type.UInt32Le(0) + self.recurcive = TestSubComposite() + + s = rdpy.network.type.Stream("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + try: + s.readType(TestComposite()) + except Exception: + self.assertEqual(s.readLen(), 0, "invalid stream roll back operation") + return + self.assertTrue(False, "Constant constraint fail") + + def test_strem_read_rollback_not_enough_data(self): + ''' + test if constant constraint fail even in recurcive composite type, + the reading stream is correctly rollback + ''' + class TestSubComposite(rdpy.network.type.CompositeType): + def __init__(self): + rdpy.network.type.CompositeType.__init__(self) + self.padding = rdpy.network.type.UInt32Le(0) + self.constraint = rdpy.network.type.UInt32Le(1) + + class TestComposite(rdpy.network.type.CompositeType): + def __init__(self): + rdpy.network.type.CompositeType.__init__(self) + self.padding = rdpy.network.type.UInt32Le(0) + self.recurcive = TestSubComposite() + + s = rdpy.network.type.Stream("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00") + try: + s.readType(TestComposite()) + except Exception: + self.assertEqual(s.readLen(), 0, "invalid stream roll back operation") + return + self.assertTrue(False, "Constant constraint fail") \ No newline at end of file