From c40d2cd600980bc9c4e14fe6b7c9d9ce86fd2966 Mon Sep 17 00:00:00 2001 From: citronneur Date: Thu, 17 Jul 2014 23:00:39 +0200 Subject: [PATCH] refactor gcc function for server side --- rdpy/network/type.py | 8 +- rdpy/protocol/rdp/gcc.py | 181 +++++++++++++++++++++++++-------------- rdpy/protocol/rdp/mcs.py | 4 +- rdpy/protocol/rdp/pdu.py | 16 ++-- rdpy/protocol/rdp/rdp.py | 6 +- 5 files changed, 137 insertions(+), 78 deletions(-) diff --git a/rdpy/network/type.py b/rdpy/network/type.py index cd191db..7546179 100644 --- a/rdpy/network/type.py +++ b/rdpy/network/type.py @@ -821,7 +821,7 @@ class ArrayType(Type): But in read mode it can be dynamic readLen may be dynamic """ - def __init__(self, typeFactory, init = None, readLen = UInt8(), conditional = lambda:True, optional = False, constant = False): + def __init__(self, typeFactory, init = None, readLen = None, conditional = lambda:True, optional = False, constant = False): """ @param typeFactory: class use to init new element on read @param init: init array @@ -843,10 +843,14 @@ class ArrayType(Type): @param s: Stream """ self._array = [] - for _ in range(0, self._readLen.value): + i = 0 + #self._readLen is None means that array will be read until end of stream + while self._readLen is None or i < self._readLen.value: element = self._typeFactory() + element._optional = self._readLen is None s.readType(element) self._array.append(element) + i += 1 def __write__(self, s): """ diff --git a/rdpy/protocol/rdp/gcc.py b/rdpy/protocol/rdp/gcc.py index 71e2982..703550a 100644 --- a/rdpy/protocol/rdp/gcc.py +++ b/rdpy/protocol/rdp/gcc.py @@ -22,7 +22,8 @@ Implement GCC structure use in RDP protocol http://msdn.microsoft.com/en-us/library/cc240508.aspx """ -from rdpy.network.type import UInt8, UInt16Le, UInt32Le, CompositeType, String, UniString, Stream, sizeof +from rdpy.network.type import UInt8, UInt16Le, UInt32Le, CompositeType, String, UniString, Stream, sizeof, FactoryType,\ + ArrayType import per from rdpy.network.error import InvalidExpectedDataException @@ -31,27 +32,23 @@ t124_02_98_oid = ( 0, 0, 20, 124, 0, 1 ) h221_cs_key = "Duca"; h221_sc_key = "McDn"; -class ServerToClientMessage(object): +class MessageType(object): """ Server to Client block GCC conference messages @see: http://msdn.microsoft.com/en-us/library/cc240509.aspx """ + #server -> client SC_CORE = 0x0C01 SC_SECURITY = 0x0C02 SC_NET = 0x0C03 - -class ClientToServerMessage(object): - """ - Client to Server block - GCC conference messages - @see: http://msdn.microsoft.com/en-us/library/cc240509.aspx - """ + #client -> server CS_CORE = 0xC001 CS_SECURITY = 0xC002 CS_NET = 0xC003 CS_CLUSTER = 0xC004 CS_MONITOR = 0xC005 + class ColorDepth(object): """ @@ -192,12 +189,40 @@ class KeyboardLayout(object): DUTCH = 0x00000413 NORWEGIAN = 0x00000414 +class DataBlock(CompositeType): + """ + Block settings + """ + def __init__(self, dataBlock = None): + CompositeType.__init__(self) + self.type = UInt16Le(lambda:self.dataBlock.__class__._TYPE_) + self.length = UInt16Le(lambda:sizeof(self)) + + def DataBlockFactory(): + """ + build settings in accordance of type self.type.value + """ + for c in [ClientCoreData, ClientSecurityData, ClientNetworkData, ServerCoreData, ServerNetworkData, ServerSecurityData]: + if self.type.value == c._TYPE_: + return c() + print "WARNING : unknown GCC block type : %s"%self.type.value + #read entire packet + return String(readLen = self.length) + + if dataBlock is None: + dataBlock = FactoryType(DataBlockFactory) + elif not "_TYPE_" in dataBlock.__class__.__dict__: + raise InvalidExpectedDataException("Try to send an invalid GCC blocks") + + self.dataBlock = dataBlock -class ClientCoreSettings(CompositeType): +class ClientCoreData(CompositeType): """ Class that represent core setting of client @see: http://msdn.microsoft.com/en-us/library/cc240510.aspx """ + _TYPE_ = MessageType.CS_CORE + def __init__(self): CompositeType.__init__(self) self.rdpVersion = UInt32Le(Version.RDP_VERSION_5_PLUS) @@ -223,28 +248,32 @@ class ClientCoreSettings(CompositeType): self.pad1octet = UInt8() self.serverSelectedProtocol = UInt32Le() -class ServerCoreSettings(CompositeType): +class ServerCoreData(CompositeType): """ Server side core settings structure @see: http://msdn.microsoft.com/en-us/library/cc240517.aspx """ + _TYPE_ = MessageType.SC_CORE + def __init__(self): CompositeType.__init__(self) self.rdpVersion = UInt32Le(Version.RDP_VERSION_5_PLUS) self.clientRequestedProtocol = UInt32Le() -class ClientSecuritySettings(CompositeType): +class ClientSecurityData(CompositeType): """ Client security setting @deprecated: because we use ssl @see: http://msdn.microsoft.com/en-us/library/cc240511.aspx """ + _TYPE_ = MessageType.CS_SECURITY + def __init__(self): CompositeType.__init__(self) self.encryptionMethods = UInt32Le() self.extEncryptionMethods = UInt32Le() -class ServerSecuritySettings(CompositeType): +class ServerSecurityData(CompositeType): """ Server security settings May be ignored because rdpy don't use @@ -252,34 +281,71 @@ class ServerSecuritySettings(CompositeType): @deprecated: because we use SSL @see: http://msdn.microsoft.com/en-us/library/cc240518.aspx """ + _TYPE_ = MessageType.SC_SECURITY + def __init__(self): CompositeType.__init__(self) self.encryptionMethod = UInt32Le() self.encryptionLevel = UInt32Le() -class ClientRequestedChannel(CompositeType): +class ChannelDef(CompositeType): """ Channels structure share between client and server - @see: http://msdn.microsoft.com/en-us/library/cc240512.aspx @see: http://msdn.microsoft.com/en-us/library/cc240513.aspx """ - def __init__(self, name = "", options = UInt32Le()): + def __init__(self, name = "", options = 0): CompositeType.__init__(self) #name of channel self.name = String(name[0:8] + "\x00" * (8 - len(name)), readLen = UInt8(8)) #unknown - self.options = options + self.options = UInt32Le() -class ClientSettings(object): +class ClientNetworkData(CompositeType): """ - Class which group all client settings supported by RDPY + GCC client network block + All channels asked by client are listed here + @see: http://msdn.microsoft.com/en-us/library/cc240512.aspx """ + _TYPE_ = MessageType.CS_NET + def __init__(self): - self.core = ClientCoreSettings() - #list of ClientRequestedChannel read network gcc packet - self.networkChannels = [] - self.security = ClientSecuritySettings() + CompositeType.__init__(self) + self.channelCount = UInt32Le() + self.channelDefArray = ArrayType(ChannelDef, readLen = self.channelCount) + +class ServerNetworkData(CompositeType): + """ + GCC server network block + All channels asked by client are listed here + @see: All channels asked by client are listed here + """ + _TYPE_ = MessageType.SC_NET + + def __init__(self): + CompositeType.__init__(self) + self.MCSChannelId = UInt16Le() + self.channelCount = UInt16Le(lambda:len(self.channelIdArray._array)) + self.channelIdArray = ArrayType(UInt16Le, readLen = self.channelCount) + self.pad = UInt16Le(conditional = lambda:(self.channelCount.value % 2 == 1)) + +class Settings(CompositeType): + """ + Class which group all clients settings supported by RDPY + """ + def __init__(self, init = []): + CompositeType.__init__(self) + self.settings = ArrayType(DataBlock, [DataBlock(i) for i in init]) + + def getBlock(self, messageType): + """ + @param messageType: type of block + @return: specific block of type messageType + """ + for i in self.settings._array: + if i.type.value == messageType: + return i.dataBlock + return None class ServerSettings(object): """ @@ -287,12 +353,26 @@ class ServerSettings(object): """ def __init__(self): #core settings of server - self.core = ServerCoreSettings() + self.core = ServerCoreData() #unuse security informations - self.security = ServerSecuritySettings() + self.security = ServerSecurityData() #channel id accepted by server self.channelsId = [] +def clientSettings(): + """ + Build settings for client + @return: Settings + """ + return Settings([ClientCoreData(), ClientNetworkData(), ClientSecurityData()]) + +def serverSettings(): + """ + Build settings for server + @return Settings + """ + return Settings([ServerCoreData(), ServerSecurityData(), ServerSecurityData()]) + def readConferenceCreateRequest(s): """ Read a response from client @@ -333,6 +413,9 @@ def readConferenceCreateResponse(s): per.readChoice(s) if not per.readOctetStream(s, h221_sc_key, 4): raise InvalidExpectedDataException("cannot read h221_sc_key") + #serverSettings = Settings() + #s.readType(serverSettings) + #return serverSettings return readServerDataBlocks(s) def readServerDataBlocks(s): @@ -350,14 +433,14 @@ def readServerDataBlocks(s): blockLength = UInt16Le() s.readType((blockType, blockLength)) #read core block - if blockType.value == ServerToClientMessage.SC_CORE: + if blockType.value == MessageType.SC_CORE: s.readType(settings.core) #read network block - elif blockType.value == ServerToClientMessage.SC_NET: + elif blockType.value == MessageType.SC_NET: settings.channelsId = readServerSecurityData(s) #read security block #unused in rdpy because use SSL layer - elif blockType.value == ServerToClientMessage.SC_SECURITY: + elif blockType.value == MessageType.SC_SECURITY: s.readType(settings.security) else: print "Unknown server block %s"%hex(type) @@ -384,13 +467,12 @@ def readServerSecurityData(s): channelsId.append(channelId) return channelsId -def writeConferenceCreateRequest(settings): +def writeConferenceCreateRequest(userData): """ Write conference create request structure - @param settings: ClientSettings - @return: gcc packet + @param userData: Settings for client + @return: GCC packet """ - userData = writeClientDataBlocks(settings) userDataStream = Stream() userDataStream.writeType(userData) @@ -403,7 +485,7 @@ def writeConferenceCreateRequest(settings): def writeConferenceCreateResponse(settings): """ Write a conference create response packet - @param settings: ServerSettings + @param settings: ServerSettingsDataBlock @return: gcc packet """ pass @@ -414,33 +496,6 @@ def writeClientDataBlocks(settings): and return GCC valid structure @param settings: ClientSettings """ - return (writeClientCoreData(settings.core), - writeClientSecurityData(settings.security), - writeClientNetworkData(settings.networkChannels)) - -def writeClientCoreData(core): - """ - Write client settings in GCC language - @param settings: ClientSettings structure - @return: structure that represent client data blocks - """ - return (UInt16Le(ClientToServerMessage.CS_CORE), UInt16Le(sizeof(core) + 4), core) - -def writeClientSecurityData(security): - """ - Write security header block and security structure - @param security: ClientSecuritySettings - @return: GCC client security data - """ - return (UInt16Le(ClientToServerMessage.CS_SECURITY), UInt16Le(sizeof(security) + 4), security) - -def writeClientNetworkData(channels): - """ - Write network packet with channels infos - @param channels: list of ClientRequestedChannel - @return: GCC network packet - """ - if len(channels) == 0: - return () - return (UInt16Le(ClientToServerMessage.CS_NET), UInt16Le(len(channels) * sizeof(ClientRequestedChannel()) + 8), UInt32Le(len(channels)), tuple(channels)) - \ No newline at end of file + return (DataBlock(settings.core), + DataBlock(settings.security), + DataBlock(settings.network)) \ No newline at end of file diff --git a/rdpy/protocol/rdp/mcs.py b/rdpy/protocol/rdp/mcs.py index f7aed36..4f4ae47 100644 --- a/rdpy/protocol/rdp/mcs.py +++ b/rdpy/protocol/rdp/mcs.py @@ -121,7 +121,7 @@ class MCS(LayerAutomata): @param presentation: presentation layer """ LayerAutomata.__init__(self, mode, presentation) - self._clientSettings = gcc.ClientSettings() + self._clientSettings = gcc.clientSettings() self._serverSettings = gcc.ServerSettings() #default user Id self._userId = 1 @@ -136,7 +136,7 @@ class MCS(LayerAutomata): a write connect initial packet """ if self._mode == LayerMode.CLIENT: - self._clientSettings.core.serverSelectedProtocol.value = self._transport._selectedProtocol + self._clientSettings.getBlock(gcc.MessageType.CS_CORE).serverSelectedProtocol.value = self._transport._selectedProtocol self.sendConnectInitial() else: self.setNextState(self.recvConnectInitial) diff --git a/rdpy/protocol/rdp/pdu.py b/rdpy/protocol/rdp/pdu.py index f0a9872..af10fa0 100644 --- a/rdpy/protocol/rdp/pdu.py +++ b/rdpy/protocol/rdp/pdu.py @@ -1259,9 +1259,9 @@ class PDULayer(LayerAutomata, tpkt.FastPathListener): #init bitmap capability bitmapCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_BITMAP].capability - bitmapCapability.preferredBitsPerPixel = self._transport.getGCCClientSettings().core.highColorDepth - bitmapCapability.desktopWidth = self._transport.getGCCClientSettings().core.desktopWidth - bitmapCapability.desktopHeight = self._transport.getGCCClientSettings().core.desktopHeight + bitmapCapability.preferredBitsPerPixel = self._transport.getGCCClientSettings().getBlock(gcc.MessageType.CS_CORE).highColorDepth + bitmapCapability.desktopWidth = self._transport.getGCCClientSettings().getBlock(gcc.MessageType.CS_CORE).desktopWidth + bitmapCapability.desktopHeight = self._transport.getGCCClientSettings().getBlock(gcc.MessageType.CS_CORE).desktopHeight #init order capability orderCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_ORDER].capability @@ -1270,11 +1270,11 @@ class PDULayer(LayerAutomata, tpkt.FastPathListener): #init input capability inputCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_INPUT].capability inputCapability.inputFlags.value = caps.InputFlags.INPUT_FLAG_SCANCODES | caps.InputFlags.INPUT_FLAG_MOUSEX | caps.InputFlags.INPUT_FLAG_UNICODE - inputCapability.keyboardLayout = self._transport.getGCCClientSettings().core.kbdLayout - inputCapability.keyboardType = self._transport.getGCCClientSettings().core.keyboardType - inputCapability.keyboardSubType = self._transport.getGCCClientSettings().core.keyboardSubType - inputCapability.keyboardrFunctionKey = self._transport.getGCCClientSettings().core.keyboardFnKeys - inputCapability.imeFileName = self._transport.getGCCClientSettings().core.imeFileName + inputCapability.keyboardLayout = self._transport.getGCCClientSettings().getBlock(gcc.MessageType.CS_CORE).kbdLayout + inputCapability.keyboardType = self._transport.getGCCClientSettings().getBlock(gcc.MessageType.CS_CORE).keyboardType + inputCapability.keyboardSubType = self._transport.getGCCClientSettings().getBlock(gcc.MessageType.CS_CORE).keyboardSubType + inputCapability.keyboardrFunctionKey = self._transport.getGCCClientSettings().getBlock(gcc.MessageType.CS_CORE).keyboardFnKeys + inputCapability.imeFileName = self._transport.getGCCClientSettings().getBlock(gcc.MessageType.CS_CORE).imeFileName #make active PDU packet confirmActivePDU = ConfirmActivePDU() diff --git a/rdpy/protocol/rdp/rdp.py b/rdpy/protocol/rdp/rdp.py index 0beb9cf..3699c37 100644 --- a/rdpy/protocol/rdp/rdp.py +++ b/rdpy/protocol/rdp/rdp.py @@ -24,7 +24,7 @@ Use to manage RDP stack in twisted from twisted.internet import protocol from rdpy.network.error import CallPureVirtualFuntion, InvalidValue from rdpy.network.layer import LayerMode -import tpkt, tpdu, mcs, pdu +import tpkt, tpdu, mcs, pdu, gcc class RDPClientController(pdu.PDUClientListener): """ @@ -68,8 +68,8 @@ class RDPClientController(pdu.PDUClientListener): @param height: height in pixel of screen """ #set screen definition in MCS layer - self._mcsLayer._clientSettings.core.desktopHeight.value = height - self._mcsLayer._clientSettings.core.desktopWidth.value = width + self._mcsLayer._clientSettings.getBlock(gcc.MessageType.CS_CORE).desktopHeight.value = height + self._mcsLayer._clientSettings.getBlock(gcc.MessageType.CS_CORE).desktopWidth.value = width def setUsername(self, username): """