diff --git a/bin/rdpy-rdpproxy b/bin/rdpy-rdpproxy index c324b8c..33d957a 100755 --- a/bin/rdpy-rdpproxy +++ b/bin/rdpy-rdpproxy @@ -1,7 +1,29 @@ #!/usr/bin/python -''' -@author: sylvain -''' +# +# Copyright (c) 2014 Sylvain Peyrefitte +# +# This file is part of rdpy. +# +# rdpy is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +""" +RDP proxy recorder and spyer +Proxy RDP protocol +With admin account you can watch all currently session +For special session you can record +""" import sys, os # Change path so we find rdpy @@ -11,23 +33,71 @@ from rdpy.protocol.rdp import rdp from twisted.internet import reactor class ProxyServer(rdp.RDPServerObserver): + """ + Server side of proxy + """ + def __init__(self, controller): + """ + @param controller: RDPServerController + """ + rdp.RDPServerObserver.__init__(self, controller) + self._client = None + def onReady(self): - reactor.connectTCP("wav-glw-013", 3389, ProxyClientFactory(self)) + """ + Event use to inform state of server stack + Use to connect client + """ + width, height = self._controller.getScreen() + reactor.connectTCP("wav-glw-013", 3389, ProxyClientFactory(self, width, height)) + def clientConnected(self, client): - print "ok" + """ + Event throw by client when it's ready + @param client: ProxyClient + """ + self._client = client + self._controller.setColorDepth(self._client._controller.getColorDepth()) class ProxyClient(rdp.RDPClientObserver): + """ + Client side of proxy + """ def __init__(self, controller, server): + """ + @param controller: RDPClientObserver + @param server: ProxyServer + """ rdp.RDPClientObserver.__init__(self, controller) self._server = server + def onReady(self): + """ + Event use to signal that RDP stack is ready + Inform proxy server that i'm connected + implement RDPClientObserver + """ self._server.clientConnected(self) + def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data): - pass + """ + Event use to inform bitmap update + implement RDPClientObserver + @param destLeft: xmin position + @param destTop: ymin position + @param destRight: xmax position because RDP can send bitmap with padding + @param destBottom: ymax position because RDP can send bitmap with padding + @param width: width of bitmap + @param height: height of bitmap + @param bitsPerPixel: number of bit per pixel + @param isCompress: use RLE compression + @param data: bitmap data + """ + self._server._controller.sendUpdate(destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data) class ProxyServerFactory(rdp.ServerFactory): def __init__(self): - rdp.ServerFactory.__init__(self, "/home/speyrefitte/dev/certificate/rdpy.key", "/home/speyrefitte/dev/certificate/rdpy.crt") + rdp.ServerFactory.__init__(self, "/home/speyrefitte/dev/certificate/rdpy.key", "/home/speyrefitte/dev/certificate/rdpy.crt", 16) def buildObserver(self, controller): return ProxyServer(controller) @@ -42,10 +112,13 @@ class ProxyServerFactory(rdp.ServerFactory): pass class ProxyClientFactory(rdp.ClientFactory): - def __init__(self, server): + def __init__(self, server, width, height): self._server = server + self._width = width + self._height = height def buildObserver(self, controller): + controller.setScreen(self._width, self._height) return ProxyClient(controller, self._server) def startedConnecting(self, connector): diff --git a/rdpy/protocol/rdp/gcc.py b/rdpy/protocol/rdp/gcc.py index c782959..58d25e7 100644 --- a/rdpy/protocol/rdp/gcc.py +++ b/rdpy/protocol/rdp/gcc.py @@ -240,8 +240,8 @@ class ClientCoreData(CompositeType): self.postBeta2ColorDepth = UInt16Le(ColorDepth.RNS_UD_COLOR_8BPP) self.clientProductId = UInt16Le(1) self.serialNumber = UInt32Le(0) - self.highColorDepth = UInt16Le(HighColor.HIGH_COLOR_24BPP) - self.supportedColorDepths = UInt16Le(Support.RNS_UD_32BPP_SUPPORT | Support.RNS_UD_24BPP_SUPPORT | Support.RNS_UD_16BPP_SUPPORT) + self.highColorDepth = UInt16Le(HighColor.HIGH_COLOR_15BPP) + self.supportedColorDepths = UInt16Le(Support.RNS_UD_15BPP_SUPPORT) self.earlyCapabilityFlags = UInt16Le(CapabilityFlags.RNS_UD_CS_SUPPORT_ERRINFO_PDU) self.clientDigProductId = String("\x00"*64, readLen = UInt8(64)) self.connectionType = UInt8() diff --git a/rdpy/protocol/rdp/mcs.py b/rdpy/protocol/rdp/mcs.py index 94cc3fa..b70a83c 100644 --- a/rdpy/protocol/rdp/mcs.py +++ b/rdpy/protocol/rdp/mcs.py @@ -372,7 +372,7 @@ class Client(MCSLayer): if (confirm != 0) and (channelId == Channel.MCS_GLOBAL_CHANNEL or channelId == self._userId): raise InvalidExpectedDataException("Server must confirm static channel") - if confirm ==0: + if confirm == 0: serverNet = self._serverSettings.getBlock(gcc.MessageType.SC_NET) for i in range(0, serverNet.channelCount.value): if channelId == serverNet.channelIdArray._array[i].value: @@ -524,7 +524,8 @@ class Server(MCSLayer): channelId = per.readInteger16(data) #actually algo support virtual channel but RDPY have no virtual channel - self.sendChannelJoinConfirm(channelId, channelId in self._channels.keys() or channelId == self._userId) + confirm = 0 if channelId in self._channels.keys() or channelId == self._userId else 1 + self.sendChannelJoinConfirm(channelId, confirm) self._nbChannelConfirmed += 1 if self._nbChannelConfirmed == self._serverSettings.getBlock(gcc.MessageType.SC_NET).channelCount.value + 2: self.allChannelConnected() diff --git a/rdpy/protocol/rdp/pdu/data.py b/rdpy/protocol/rdp/pdu/data.py index cdbf50b..2e35aea 100644 --- a/rdpy/protocol/rdp/pdu/data.py +++ b/rdpy/protocol/rdp/pdu/data.py @@ -621,7 +621,7 @@ class DeactiveAllPDU(CompositeType): CompositeType.__init__(self) self.shareId = UInt32Le() self.lengthSourceDescriptor = UInt16Le(lambda:sizeof(self.sourceDescriptor)) - self.sourceDescriptor = String(readLen = self.lengthSourceDescriptor) + self.sourceDescriptor = String("rdpy", readLen = self.lengthSourceDescriptor) class DataPDU(CompositeType): """ @@ -849,8 +849,9 @@ class FastPathUpdatePDU(CompositeType): Create correct object in accordance to self.updateHeader field """ if (self.updateHeader.value & 0xf) == FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP: - return (UInt16Le(FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP, constant = True), BitmapUpdateDataPDU(readLen = self.size)) + return (UInt16Le(FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP, constant = True), BitmapUpdateDataPDU(readLen = self.size - 2)) else: + log.debug("unknown Fast Path PDU update data type : %s"%hex(self.updateHeader.value & 0xf)) return String() if updateData is None: @@ -904,7 +905,12 @@ class BitmapCompressedDataHeader(CompositeType): Compressed header of bitmap @see: http://msdn.microsoft.com/en-us/library/cc240644.aspx """ - def __init__(self, conditional = lambda:True): + def __init__(self, bodySize = 0, scanWidth = 0, uncompressedSize = 0, conditional = lambda:True): + """ + @param bodySize: size of image body + @param scanWidth: width of image + @param uncompressedSize: size of uncompressed image + """ CompositeType.__init__(self, conditional = conditional) self.cbCompFirstRowSize = UInt16Le(0x0000, constant = True) #compressed data size @@ -917,19 +923,29 @@ class BitmapData(CompositeType): """ Bitmap data here the screen capture """ - def __init__(self): + def __init__(self, destLeft = 0, destTop = 0, destRight = 0, destBottom = 0, width = 0, height = 0, bitsPerPixel = 0, bitmapDataStream = ""): + """ + @param destLeft: destination left coordinate + @param destTop: destination top coordinate + @param destRight: destination right coordinate + @param destBottom: destination bottom coordinate + @param width: width of image + @param height: height of image + @param bitsPerPixel: color depth + @param bitmapDataStream: data + """ CompositeType.__init__(self) - self.destLeft = UInt16Le() - self.destTop = UInt16Le() - self.destRight = UInt16Le() - self.destBottom = UInt16Le() - self.width = UInt16Le() - self.height = UInt16Le() - self.bitsPerPixel = UInt16Le() + self.destLeft = UInt16Le(destLeft) + self.destTop = UInt16Le(destTop) + self.destRight = UInt16Le(destRight) + self.destBottom = UInt16Le(destBottom) + self.width = UInt16Le(width) + self.height = UInt16Le(height) + self.bitsPerPixel = UInt16Le(bitsPerPixel) self.flags = UInt16Le() - self.bitmapLength = UInt16Le() - self.bitmapComprHdr = BitmapCompressedDataHeader(conditional = lambda:(not (self.flags.value | BitmapFlag.NO_BITMAP_COMPRESSION_HDR))) - self.bitmapDataStream = String(readLen = UInt16Le(lambda:(self.bitmapLength.value if (self.flags.value | BitmapFlag.NO_BITMAP_COMPRESSION_HDR) else self.bitmapComprHdr.cbCompMainBodySize.value))) + self.bitmapLength = UInt16Le(lambda:(sizeof(self.bitmapComprHdr) + sizeof(self.bitmapDataStream))) + self.bitmapComprHdr = BitmapCompressedDataHeader(bodySize = lambda:sizeof(self.bitmapDataStream), scanWidth = lambda:self.width.value, uncompressedSize = lambda:(self.width.value * self.height.value * self.bitsPerPixel.value), conditional = lambda:((self.flags.value | BitmapFlag.BITMAP_COMPRESSION) and not (self.flags.value | BitmapFlag.NO_BITMAP_COMPRESSION_HDR))) + self.bitmapDataStream = String(bitmapDataStream, readLen = UInt16Le(lambda:(self.bitmapLength.value if (self.flags.value | BitmapFlag.NO_BITMAP_COMPRESSION_HDR) else self.bitmapComprHdr.cbCompMainBodySize.value))) class SlowPathInputEvent(CompositeType): """ diff --git a/rdpy/protocol/rdp/pdu/layer.py b/rdpy/protocol/rdp/pdu/layer.py index b3177f7..0067d36 100644 --- a/rdpy/protocol/rdp/pdu/layer.py +++ b/rdpy/protocol/rdp/pdu/layer.py @@ -107,12 +107,14 @@ class PDULayer(LayerAutomata): def sendPDU(self, pduMessage): """ Send a PDU data to transport layer + @param pduMessage: PDU message """ self._transport.send(data.PDU(self._transport.getUserId(), pduMessage)) def sendDataPDU(self, pduData): """ Send an PDUData to transport layer + @param pduData: PDU data message """ self.sendPDU(data.DataPDU(pduData, self._shareId)) @@ -183,7 +185,10 @@ class Client(PDULayer, tpkt.FastPathListener): s.readType(pdu) if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DEMANDACTIVEPDU: - raise InvalidExpectedDataException("Expected Demand Active PDU from server") + #not a blocking error because in deactive reactive sequence + #input can be send too but ignored + log.debug("Ignore message type %s during connection sequence"%hex(pdu.shareControlHeader.pduType.value)) + return self._shareId = pdu.pduMessage.shareId.value @@ -204,7 +209,11 @@ class Client(PDULayer, tpkt.FastPathListener): pdu = data.PDU() s.readType(pdu) if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_SYNCHRONIZE: - raise InvalidExpectedDataException("Error in PDU layer automata : expected synchronizePDU") + #not a blocking error because in deactive reactive sequence + #input can be send too but ignored + log.debug("Ignore message type %s during connection sequence"%hex(pdu.shareControlHeader.pduType.value)) + return + self.setNextState(self.recvServerControlCooperatePDU) def recvServerControlCooperatePDU(self, s): @@ -216,7 +225,11 @@ class Client(PDULayer, tpkt.FastPathListener): pdu = data.PDU() s.readType(pdu) if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_CONTROL or pdu.pduMessage.pduData.action.value != data.Action.CTRLACTION_COOPERATE: - raise InvalidExpectedDataException("Error in PDU layer automata : expected controlCooperatePDU") + #not a blocking error because in deactive reactive sequence + #input can be send too but ignored + log.debug("Ignore message type %s during connection sequence"%hex(pdu.shareControlHeader.pduType.value)) + return + self.setNextState(self.recvServerControlGrantedPDU) def recvServerControlGrantedPDU(self, s): @@ -228,7 +241,11 @@ class Client(PDULayer, tpkt.FastPathListener): pdu = data.PDU() s.readType(pdu) if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_CONTROL or pdu.pduMessage.pduData.action.value != data.Action.CTRLACTION_GRANTED_CONTROL: - raise InvalidExpectedDataException("Error in PDU layer automata : expected controlGrantedPDU") + #not a blocking error because in deactive reactive sequence + #input can be send too but ignored + log.debug("Ignore message type %s during connection sequence"%hex(pdu.shareControlHeader.pduType.value)) + return + self.setNextState(self.recvServerFontMapPDU) def recvServerFontMapPDU(self, s): @@ -240,7 +257,10 @@ class Client(PDULayer, tpkt.FastPathListener): pdu = data.PDU() s.readType(pdu) if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_FONTMAP: - raise InvalidExpectedDataException("Error in PDU layer automata : expected fontMapPDU") + #not a blocking error because in deactive reactive sequence + #input can be send too but ignored + log.debug("Ignore message type %s during connection sequence"%hex(pdu.shareControlHeader.pduType.value)) + return self.setNextState(self.recvPDU) #here i'm connected @@ -421,7 +441,10 @@ class Server(PDULayer): s.readType(pdu) if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_CONFIRMACTIVEPDU: - raise InvalidExpectedDataException("Expected Confirm Active PDU from client") + #not a blocking error because in deactive reactive sequence + #input can be send too but ignored + log.debug("Ignore message type %s during connection sequence"%hex(pdu.shareControlHeader.pduType.value)) + return for cap in pdu.pduMessage.capabilitySets._array: self._clientCapabilities[cap.capabilitySetType] = cap @@ -437,7 +460,10 @@ class Server(PDULayer): pdu = data.PDU() s.readType(pdu) if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_SYNCHRONIZE: - raise InvalidExpectedDataException("Error in PDU layer automata : expected synchronizePDU") + #not a blocking error because in deactive reactive sequence + #input can be send too but ignored + log.debug("Ignore message type %s during connection sequence"%hex(pdu.shareControlHeader.pduType.value)) + return self.setNextState(self.recvClientControlCooperatePDU) def recvClientControlCooperatePDU(self, s): @@ -449,7 +475,10 @@ class Server(PDULayer): pdu = data.PDU() s.readType(pdu) if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_CONTROL or pdu.pduMessage.pduData.action.value != data.Action.CTRLACTION_COOPERATE: - raise InvalidExpectedDataException("Error in PDU layer automata : expected controlCooperatePDU") + #not a blocking error because in deactive reactive sequence + #input can be send too but ignored + log.debug("Ignore message type %s during connection sequence"%hex(pdu.shareControlHeader.pduType.value)) + return self.setNextState(self.recvClientControlRequestPDU) def recvClientControlRequestPDU(self, s): @@ -461,7 +490,10 @@ class Server(PDULayer): pdu = data.PDU() s.readType(pdu) if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_CONTROL or pdu.pduMessage.pduData.action.value != data.Action.CTRLACTION_REQUEST_CONTROL: - raise InvalidExpectedDataException("Error in PDU layer automata : expected controlGrantedPDU") + #not a blocking error because in deactive reactive sequence + #input can be send too but ignored + log.debug("Ignore message type %s during connection sequence"%hex(pdu.shareControlHeader.pduType.value)) + return self.setNextState(self.recvClientFontListPDU) def recvClientFontListPDU(self, s): @@ -474,7 +506,10 @@ class Server(PDULayer): pdu = data.PDU() s.readType(pdu) if pdu.shareControlHeader.pduType.value != data.PDUType.PDUTYPE_DATAPDU or pdu.pduMessage.shareDataHeader.pduType2.value != data.PDUType2.PDUTYPE2_FONTLIST: - raise InvalidExpectedDataException("Error in PDU layer automata : expected fontMapPDU") + #not a blocking error because in deactive reactive sequence + #input can be send but ignored + log.debug("Ignore message type %s during connection sequence"%hex(pdu.shareControlHeader.pduType.value)) + return #finalize server self.sendServerFinalizeSynchronizePDU() @@ -519,13 +554,10 @@ class Server(PDULayer): generalCapability = self._serverCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability generalCapability.osMajorType.value = caps.MajorType.OSMAJORTYPE_WINDOWS generalCapability.osMinorType.value = caps.MinorType.OSMINORTYPE_WINDOWS_NT - generalCapability.extraFlags.value = caps.GeneralExtraFlag.LONG_CREDENTIALS_SUPPORTED | caps.GeneralExtraFlag.NO_BITMAP_COMPRESSION_HDR | caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED + generalCapability.extraFlags.value = caps.GeneralExtraFlag.LONG_CREDENTIALS_SUPPORTED | caps.GeneralExtraFlag.NO_BITMAP_COMPRESSION_HDR - #init bitmap capability - bitmapCapability = self._serverCapabilities[caps.CapsType.CAPSTYPE_BITMAP].capability - bitmapCapability.preferredBitsPerPixel.value = 16 - bitmapCapability.desktopWidth.value = 800 - bitmapCapability.desktopHeight.value = 600 + inputCapability = self._serverCapabilities[caps.CapsType.CAPSTYPE_INPUT].capability + inputCapability.inputFlags.value = caps.InputFlags.INPUT_FLAG_SCANCODES | caps.InputFlags.INPUT_FLAG_MOUSEX demandActivePDU = data.DemandActivePDU() demandActivePDU.shareId.value = self._shareId @@ -551,4 +583,28 @@ class Server(PDULayer): #deprecated font list pdu fontMapPDU = data.FontMapDataPDU() - self.sendDataPDU(fontMapPDU) \ No newline at end of file + self.sendDataPDU(fontMapPDU) + + def sendPDU(self, pduMessage): + """ + Send a PDU data to transport layer + @param pduMessage: PDU message + """ + PDULayer.sendPDU(self, pduMessage) + #restart capabilities exchange in case of deactive reactive sequence + if isinstance(pduMessage, data.DeactiveAllPDU): + self.sendDemandActivePDU() + self.setNextState(self.recvConfirmActivePDU) + + def sendBitmapUpdatePDU(self, bitmapDatas): + """ + Send bitmap update data + @param bitmapDatas: List of data.BitmapData + """ + #check bitmap header for client that want it (very old client) + if self._clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability.extraFlags.value & caps.GeneralExtraFlag.NO_BITMAP_COMPRESSION_HDR: + for bitmapData in bitmapDatas: + bitmapData.flags.value |= data.BitmapFlag.NO_BITMAP_COMPRESSION_HDR + updateDataPDU = data.BitmapUpdateDataPDU() + updateDataPDU.rectangles._array = bitmapDatas + self.sendDataPDU(data.UpdateDataPDU(updateDataPDU)) \ No newline at end of file diff --git a/rdpy/protocol/rdp/rdp.py b/rdpy/protocol/rdp/rdp.py index af05e7c..987a712 100644 --- a/rdpy/protocol/rdp/rdp.py +++ b/rdpy/protocol/rdp/rdp.py @@ -25,6 +25,7 @@ from twisted.internet import protocol from rdpy.base.error import CallPureVirtualFuntion, InvalidValue import pdu.layer import pdu.data +import pdu.caps import rdpy.base.log as log import tpkt, tpdu, mcs, gcc @@ -45,6 +46,7 @@ class RDPClientController(pdu.layer.PDUClientListener): self._tpktLayer = tpkt.TPKT(self._tpduLayer, self._pduLayer) #is pdu layer is ready to send self._isReady = False + self._sendReady = False def getProtocol(self): """ @@ -52,6 +54,12 @@ class RDPClientController(pdu.layer.PDUClientListener): In case of RDP TPKT is the Raw layer """ return self._tpktLayer + + def getColorDepth(self): + """ + @return: color depth set by the server (15, 16, 24) + """ + return self._pduLayer._serverCapabilities[pdu.caps.CapsType.CAPSTYPE_BITMAP].capability.preferredBitsPerPixel.value def setPerformanceSession(self): """ @@ -113,6 +121,9 @@ class RDPClientController(pdu.layer.PDUClientListener): Call when PDU layer is connected """ self._isReady = True + if self._sendReady: + return + self._sendReady = False #signal all listener for observer in self._clientObserver: observer.onReady() @@ -206,11 +217,14 @@ class RDPServerController(pdu.layer.PDUServerListener): """ Controller use in server side mode """ - def __init__(self, privateKeyFileName, certificateFileName): + def __init__(self, privateKeyFileName, certificateFileName, colorDepth): """ @param privateKeyFileName: file contain server private key @param certficiateFileName: file that contain public key + @param colorDepth: 15, 16, 24 """ + self._isReady = False + self._sendReady = False #list of observer self._serverObserver = [] #build RDP protocol stack @@ -221,8 +235,8 @@ class RDPServerController(pdu.layer.PDUServerListener): self._tpduLayer = tpdu.Server(self._mcsLayer, privateKeyFileName, certificateFileName) #transport packet (protocol layer) self._tpktLayer = tpkt.TPKT(self._tpduLayer, self._pduLayer) - - self._isReady = False + #set color depth of session + self.setColorDepth(colorDepth) def getProtocol(self): """ @@ -259,18 +273,40 @@ class RDPServerController(pdu.layer.PDUServerListener): """ return (self.getDomain(), self.getUsername(), self.getPassword()) + def getScreen(self): + """ + @return: tuple(width, height) of client asked screen + """ + bitmapCap = self._pduLayer._clientCapabilities[pdu.caps.CapsType.CAPSTYPE_BITMAP].capability + return (bitmapCap.desktopWidth.value, bitmapCap.desktopHeight.value) + def addServerObserver(self, observer): """ Add observer to RDP protocol @param observer: new observer to add """ self._serverObserver.append(observer) + + def setColorDepth(self, colorDepth): + """ + Set color depth of session + if PDU stack is already connected send a deactive-reactive sequence + @param colorDepth: depth of session (15, 16, 24) + """ + self._pduLayer._serverCapabilities[pdu.caps.CapsType.CAPSTYPE_BITMAP].capability.preferredBitsPerPixel.value = colorDepth + if self._isReady: + #restart connection sequence + self._isReady = False + self._pduLayer.sendPDU(pdu.data.DeactiveAllPDU()) def onReady(self): """ RDP stack is now ready """ self._isReady = True + if self._sendReady: + return + self._sendReady = True for observer in self._serverObserver: observer.onReady() @@ -289,6 +325,11 @@ class RDPServerController(pdu.layer.PDUServerListener): """ if not self._isReady: return + bitmapData = pdu.data.BitmapData(destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, data) + if isCompress: + bitmapData.flags.value = pdu.data.BitmapFlag.BITMAP_COMPRESSION + + self._pduLayer.sendBitmapUpdatePDU([bitmapData]) class ClientFactory(protocol.Factory): """ @@ -314,20 +355,22 @@ class ServerFactory(protocol.Factory): """ Factory of Server RDP protocol """ - def __init__(self, privateKeyFileName, certificateFileName): + def __init__(self, privateKeyFileName, certificateFileName, colorDepth): """ @param privateKeyFileName: file contain server private key - @param certficiateFileName: file that contain publi key + @param certficiateFileName: file that contain public key + @param colorDepth: color depth of session """ self._privateKeyFileName = privateKeyFileName self._certificateFileName = certificateFileName + self._colorDepth = colorDepth def buildProtocol(self, addr): """ Function call from twisted and build rdp protocol stack @param addr: destination address """ - controller = RDPServerController(self._privateKeyFileName, self._certificateFileName) + controller = RDPServerController(self._privateKeyFileName, self._certificateFileName, self._colorDepth) self.buildObserver(controller) return controller.getProtocol()