add fastpath to be compatible with rdp 8.0

This commit is contained in:
speyrefitte
2014-07-11 18:18:16 +02:00
parent d6c85c382d
commit c09e466f48
9 changed files with 348 additions and 197 deletions

View File

@@ -40,7 +40,8 @@ class RDPClientQtFactory(rdp.ClientFactory):
"""
init client with correct definition
"""
rdp.ClientFactory.__init__(self, width, height)
self._width = width
self._height = height
self._w = None
def buildObserver(self, controller):
@@ -56,8 +57,10 @@ class RDPClientQtFactory(rdp.ClientFactory):
self._w.setWindowTitle('rdpy-rdpclient')
self._w.show()
#enable perf
controller.enablePerformanceSession()
#resize session
controller.setScreen(self._width, self._height)
controller.setPerformanceSession()
return client
def startedConnecting(self, connector):

View File

@@ -116,7 +116,7 @@ class LayerAutomata(Layer, StreamListener):
self.recv = callback
#twitsed layer concept
#twisted layer concept
from twisted.internet import protocol
#first that handle stream
from type import Stream

View File

@@ -372,66 +372,68 @@ class SimpleType(Type, CallableValue):
return self.__class__(self.value.__rshift__(other.value))
def __hash__(self):
'''
hash function to treat simple type in hash collection
"""
Hash function to treat simple type in hash collection
@return: hash of inner value
'''
"""
return hash(self.value)
def __nonzero__(self):
'''
boolean conversion
"""
Boolean conversion
@return: bool of inner value
'''
"""
return bool(self.value)
class CompositeType(Type):
'''
keep ordering declaration of simple type
in list and transparent for other type
@param conditional : function call before read or write type
@param optional: boolean check before read if there is still data in stream
@param constant: if true check any changement of object during reading
@param readLen: max length to read
'''
"""
Type node of other sub type
"""
def __init__(self, conditional = lambda:True, optional = False, constant = False, readLen = None):
'''
init list of simple value
'''
"""
Keep ordering declaration of simple type
in list and transparent for other type
@param conditional : function call before read or write type
@param optional: boolean check before read if there is still data in stream
@param constant: if true check any changing of object during reading
@param readLen: max length to read
"""
Type.__init__(self, conditional = conditional, optional = optional, constant = constant)
#list of ordoned type
self._typeName = []
self._readLen = readLen
def __setattr__(self, name, value):
'''
magic function to update type list
"""
Magic function to update type list
@param name: name of new attribute
@param value: value of new attribute
'''
"""
if name[0] != '_' and (isinstance(value, Type) or isinstance(value, tuple)) and not name in self._typeName:
self._typeName.append(name)
self.__dict__[name] = value
def __read__(self, s):
'''
call read on each ordered subtype
"""
Call read on each ordered sub-type
@param s: Stream
'''
"""
readLen = 0
for name in self._typeName:
if not self._readLen is None and readLen + sizeof(self.__dict__[name]) > self._readLen.value:
#optional maybe be unread
if self.__dict__[name]._optional:
continue
else:
raise InvalidSize("Impossible to read type %s::%s : read size is too small"%(self.__class__, name))
for name in self._typeName:
try:
s.readType(self.__dict__[name])
#read is ok but read out of bound
if not self._readLen is None and readLen > self._readLen.value:
#roll back
s.pos -= sizeof(self.__dict__[name])
#and notify
raise InvalidSize("Impossible to read type %s : read length is too small"%(self.__class__))
except Exception as e:
print "Error during read %s::%s"%(self.__class__, name)
#rollback already readed
#roll back already read
for tmpName in self._typeName:
if tmpName == name:
break
@@ -863,17 +865,16 @@ class ArrayType(Type):
return sizeof(self._array)
class FactoryType(Type):
'''
"""
Call factory function on read or write
'''
"""
def __init__(self, factory, conditional = lambda:True, optional = False, constant = False):
'''
ctor of factory type
"""
@param factory: factory
@param conditional : function call before read or write type
@param optional: boolean check before read if there is still data in stream
@param constant: if true check any changes of object during reading
'''
"""
Type.__init__(self, conditional, optional, constant)
self._factory = factory
if not callable(factory):

View File

@@ -24,7 +24,7 @@ Each channel have a particular role.
The main channel is the graphical channel.
It exist channel for file system order, audio channel, clipboard etc...
"""
from rdpy.network.layer import LayerAutomata, LayerMode, StreamSender
from rdpy.network.layer import LayerAutomata, StreamSender, Layer
from rdpy.network.type import sizeof, Stream, UInt8, UInt16Be
from rdpy.network.error import InvalidExpectedDataException, InvalidValue, InvalidSize
from rdpy.protocol.rdp.ber import writeLength
@@ -64,7 +64,7 @@ class MCS(LayerAutomata):
the main layer of RDP protocol
is why he can do everything and more!
"""
class MCSProxySender(StreamSender):
class MCSProxySender(Layer, StreamSender):
"""
Proxy use to set as transport layer for upper channel
use to abstract channel id for presentation layer
@@ -78,34 +78,40 @@ class MCS(LayerAutomata):
self._channelId = channelId
def send(self, data):
'''
a send proxy function, use channel id and specific
send function of mcs layer
'''
"""
A send proxy function, use channel id and specific
send function of MCS layer
"""
self._mcs.send(self._channelId, data)
def close(self):
"""
Close wrapped layer
"""
self._mcs.close()
def getUserId(self):
'''
"""
@return: mcs user id
'''
"""
return self._mcs._userId
def getChannelId(self):
'''
"""
@return: return channel id of proxy
'''
"""
return self._channelId
def getGCCClientSettings(self):
'''
"""
@return: mcs layer gcc client settings
'''
"""
return self._mcs._clientSettings
def getGCCServerSettings(self):
'''
"""
@return: mcs layer gcc server settings
'''
"""
return self._mcs._serverSettings
@@ -353,18 +359,4 @@ class MCS(LayerAutomata):
max_pdu_size = ber.readInteger(s)
ber.readInteger(s)
return (max_channels, max_users, max_tokens, max_pdu_size)
def createClient(controller):
"""
@param controller: RDP controller which initialized all channel layer
@return: MCS layer in client mode
"""
return MCS(LayerMode.CLIENT, controller.getPDULayer())
def createServer(controller):
"""
@param controller: RDP controller which initialized all channel layer
@return: MCS layer in server mode
"""
return MCS(LayerMode.SERVER, controller.getPDULayer())

View File

@@ -27,7 +27,7 @@ from rdpy.network.layer import LayerAutomata, LayerMode
from rdpy.network.type import CompositeType, UniString, String, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType
from rdpy.network.error import InvalidExpectedDataException, ErrorReportedFromPeer, CallPureVirtualFuntion, InvalidType
import gcc, lic, caps
import gcc, lic, caps, tpkt
class SecurityFlag(object):
"""
@@ -223,6 +223,30 @@ class KeyboardFlag(object):
KBDFLAGS_DOWN = 0x4000
KBDFLAGS_RELEASE = 0x8000
class FastPathUpdateType(object):
"""
Use in Fast Path update packet
@see: http://msdn.microsoft.com/en-us/library/cc240622.aspx
"""
FASTPATH_UPDATETYPE_ORDERS = 0x0
FASTPATH_UPDATETYPE_BITMAP = 0x1
FASTPATH_UPDATETYPE_PALETTE = 0x2
FASTPATH_UPDATETYPE_SYNCHRONIZE = 0x3
FASTPATH_UPDATETYPE_SURFCMDS = 0x4
FASTPATH_UPDATETYPE_PTR_NULL = 0x5
FASTPATH_UPDATETYPE_PTR_DEFAULT = 0x6
FASTPATH_UPDATETYPE_PTR_POSITION = 0x8
FASTPATH_UPDATETYPE_COLOR = 0x9
FASTPATH_UPDATETYPE_CACHED = 0xA
FASTPATH_UPDATETYPE_POINTER = 0xB
class FastPathOutputCompression(object):
"""
Flag for compression
@see: http://msdn.microsoft.com/en-us/library/cc240622.aspx
"""
FASTPATH_OUTPUT_COMPRESSION_USED = 0x2
class ErrorInfo(object):
"""
Error code use in Error info PDU
@@ -586,18 +610,26 @@ class DataPDU(CompositeType):
self.shareDataHeader = ShareDataHeader(lambda:sizeof(self), pduType, userId, shareId)
def PDUDataFactory():
"""
Create object in accordance self.shareDataHeader.pduType2 value
"""
if self.shareDataHeader.pduType2.value == PDUType2.PDUTYPE2_UPDATE:
return UpdateDataPDU()
return UpdateDataPDU(readLen = self.shareDataHeader.uncompressedLength)
elif self.shareDataHeader.pduType2.value == PDUType2.PDUTYPE2_SYNCHRONIZE:
return SynchronizeDataPDU()
return SynchronizeDataPDU(readLen = self.shareDataHeader.uncompressedLength)
elif self.shareDataHeader.pduType2.value == PDUType2.PDUTYPE2_CONTROL:
return ControlDataPDU()
return ControlDataPDU(readLen = self.shareDataHeader.uncompressedLength)
elif self.shareDataHeader.pduType2.value == PDUType2.PDUTYPE2_SET_ERROR_INFO_PDU:
return ErrorInfoDataPDU()
return ErrorInfoDataPDU(readLen = self.shareDataHeader.uncompressedLength)
elif self.shareDataHeader.pduType2.value == PDUType2.PDUTYPE2_FONTLIST:
return FontListDataPDU()
return FontListDataPDU(readLen = self.shareDataHeader.uncompressedLength)
elif self.shareDataHeader.pduType2.value == PDUType2.PDUTYPE2_FONTMAP:
return FontMapDataPDU()
return FontMapDataPDU(readLen = self.shareDataHeader.uncompressedLength)
else:
#read all value
return String()
@@ -611,17 +643,24 @@ class SynchronizeDataPDU(CompositeType):
"""
@see http://msdn.microsoft.com/en-us/library/cc240490.aspx
"""
def __init__(self, targetUser = UInt16Le()):
CompositeType.__init__(self)
def __init__(self, targetUser = 0, readLen = None):
"""
@param targetUser: MCS Channel ID
"""
CompositeType.__init__(self, readLen = readLen)
self.messageType = UInt16Le(1, constant = True)
self.targetUser = targetUser
self.targetUser = UInt16Le(targetUser)
class ControlDataPDU(CompositeType):
"""
@see http://msdn.microsoft.com/en-us/library/cc240492.aspx
"""
def __init__(self, action = None):
CompositeType.__init__(self)
def __init__(self, action = None, readLen = None):
"""
@param action: Action macro
@param readLen: Max length to read
"""
CompositeType.__init__(self, readLen = readLen)
self.action = UInt16Le(action, constant = True) if not action is None else UInt16Le()
self.grantId = UInt16Le()
self.controlId = UInt32Le()
@@ -631,10 +670,14 @@ class ErrorInfoDataPDU(CompositeType):
Use to inform error in PDU layer
@see: http://msdn.microsoft.com/en-us/library/cc240544.aspx
"""
def __init__(self, errorInfo = UInt32Le()):
CompositeType.__init__(self)
#use to collect error info pdu
self.errorInfo = errorInfo
def __init__(self, errorInfo = 0, readLen = None):
"""
@param errorInfo: ErrorInfo macro
@param readLen: Max length to read
"""
CompositeType.__init__(self, readLen = readLen)
#use to collect error info PDU
self.errorInfo = UInt32Le(errorInfo)
class FontListDataPDU(CompositeType):
"""
@@ -642,8 +685,11 @@ class FontListDataPDU(CompositeType):
client -> server
@see: http://msdn.microsoft.com/en-us/library/cc240498.aspx
"""
def __init__(self):
CompositeType.__init__(self)
def __init__(self, readLen = None):
"""
@param readLen: Max read length
"""
CompositeType.__init__(self, readLen = readLen)
self.numberFonts = UInt16Le()
self.totalNumFonts = UInt16Le()
self.listFlags = UInt16Le(0x0003)
@@ -655,8 +701,11 @@ class FontMapDataPDU(CompositeType):
server -> client
@see: http://msdn.microsoft.com/en-us/library/cc240498.aspx
"""
def __init__(self):
CompositeType.__init__(self)
def __init__(self, readLen = None):
"""
@param readLen: Max read length
"""
CompositeType.__init__(self, readLen = readLen)
self.numberEntries = UInt16Le()
self.totalNumEntries = UInt16Le()
self.mapFlags = UInt16Le(0x0003)
@@ -664,32 +713,84 @@ class FontMapDataPDU(CompositeType):
class UpdateDataPDU(CompositeType):
"""
Update data PDU use by server to inform update img or palette
Update data PDU use by server to inform update image or palet
for example
@see: http://msdn.microsoft.com/en-us/library/cc240608.aspx
"""
def __init__(self, updateType = 0, updateData = None):
CompositeType.__init__(self)
def __init__(self, updateType = 0, updateData = None, readLen = None):
"""
@param updateType: UpdateType macro
@param updateData: Update data PDU in accordance with updateType (BitmapUpdateDataPDU)
@param readLen: Max length to read
"""
CompositeType.__init__(self, readLen = readLen)
self.updateType = UInt16Le(updateType)
def UpdateDataFactory():
if self.updateType.value == UpdateType.UPDATETYPE_BITMAP:
return BitmapUpdateDataPDU()
elif self.updateType.value == UpdateType.UPDATETYPE_SYNCHRONIZE:
return SynchronizeUpdatePDU()
else:
String()
return String()
if updateData is None:
updateData = UpdateDataFactory
self.updateData = FactoryType(updateData, conditional = lambda:(self.updateType.value != UpdateType.UPDATETYPE_SYNCHRONIZE))
class FastPathUpdatePDU(CompositeType):
"""
Fast path update PDU packet
@see: http://msdn.microsoft.com/en-us/library/cc240622.aspx
"""
def __init__(self, updateType = 0, updateData = None):
CompositeType.__init__(self)
self.updateHeader = UInt8(updateType)
self.compressionFlags = UInt8(conditional = lambda:(self.updateHeader.value & FastPathOutputCompression.FASTPATH_OUTPUT_COMPRESSION_USED))
self.size = UInt16Le()
def UpdateDataFactory():
"""
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))
elif (self.updateHeader.value & 0xf) == FastPathUpdateType.FASTPATH_UPDATETYPE_SYNCHRONIZE:
return SynchronizeUpdatePDU(readLen = self.size)
else:
return String()
if updateData is None:
updateData = UpdateDataFactory
self.updateData = FactoryType(updateData)
class SynchronizeUpdatePDU(CompositeType):
"""
PDU is ignored, artefact of T.125
"""
def __init__(self, readLen = None):
"""
@param readLen: Max size of packet
"""
CompositeType.__init__(self, readLen = readLen)
self.pad2Octets = UInt16Le()
class BitmapUpdateDataPDU(CompositeType):
"""
PDU use to send raw bitmap compressed or not
@see: http://msdn.microsoft.com/en-us/library/dd306368.aspx
"""
def __init__(self):
CompositeType.__init__(self)
def __init__(self, readLen = None):
"""
@param readLen: Max size of packet
"""
CompositeType.__init__(self, readLen = readLen)
self.numberRectangles = UInt16Le(lambda:len(self.rectangles._array))
self.rectangles = ArrayType(BitmapData, readLen = self.numberRectangles)
@@ -775,10 +876,13 @@ class SlowPathInputEvent(CompositeType):
"""
if isinstance(event, PointerEvent):
return InputMessageType.INPUT_EVENT_MOUSE
elif isinstance(event, ScancodeKeyEvent):
return InputMessageType.INPUT_EVENT_SCANCODE
elif isinstance(event, UnicodeKeyEvent):
return InputMessageType.INPUT_EVENT_UNICODE
else:
return None
@@ -851,7 +955,7 @@ class PDUServerListener(object):
"""
pass
class PDU(LayerAutomata):
class PDU(LayerAutomata, tpkt.FastPathListener):
"""
Global channel for MCS that handle session
identification user, licensing management, and capabilities exchange
@@ -860,6 +964,18 @@ class PDU(LayerAutomata):
"""
@param listener: listener use to inform orders
"""
mode = None
if isinstance(listener, PDUClientListener):
mode = LayerMode.CLIENT
#set client listener
self._clientListener = listener
elif isinstance(listener, PDUServerListener):
mode = LayerMode.SERVER
else:
raise InvalidType("PDU Layer expect PDU(Client|Server)Listener as listener")
LayerAutomata.__init__(self, mode, None)
#logon info send from client to server
self._info = RDPInfo(extendedInfoConditional = lambda:(self._transport.getGCCServerSettings().core.rdpVersion.value == gcc.Version.RDP_VERSION_5_PLUS))
#server capabilities
@@ -898,29 +1014,7 @@ class PDU(LayerAutomata):
#determine if layer is connected
self._isConnected = False
mode = None
if isinstance(listener, PDUClientListener):
mode = LayerMode.CLIENT
#set client listener
self._clientListener = listener
self.initClientOrder()
elif isinstance(listener, PDUServerListener):
mode = LayerMode.SERVER
else:
raise InvalidType("PDU Layer expect PDU(Client|Server)Listener as listener")
LayerAutomata.__init__(self, mode, None)
def initClientOrder(self):
"""
Enable order in accordance of override function of _clientListener
"""
#enable rectangle order
orderCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_ORDER].capability._value
if id(PDUClientListener.recvDstBltOrder.im_func) != id(self._clientListener.recvDstBltOrder.im_func):
orderCapability.orderSupport._array[caps.Order.TS_NEG_DSTBLT_INDEX].value = 1
def connect(self):
"""
Connect event in client mode send logon info
@@ -935,6 +1029,7 @@ class PDU(LayerAutomata):
Send PDU close packet and call close method on transport method
"""
self._transport.send(ShareDataHeader(PDUType2.PDUTYPE2_SHUTDOWN_REQUEST, self._transport.getUserId(), self._shareId))
self._transport.close()
def sendInfoPkt(self):
"""
@@ -968,7 +1063,7 @@ class PDU(LayerAutomata):
def readDataPDU(self, data):
"""
Read a DataPdu struct. If is an error pdu log and close layer
Read a DataPdu struct. If is an error PDU log and close layer
@param data: Stream from transport layer
@return:
"""
@@ -1054,6 +1149,17 @@ class PDU(LayerAutomata):
dataPDU = self.readDataPDU(data)
if dataPDU.shareDataHeader.pduType2.value == PDUType2.PDUTYPE2_UPDATE and dataPDU.pduData._value.updateType.value == UpdateType.UPDATETYPE_BITMAP:
self._clientListener.recvBitmapUpdateDataPDU(dataPDU.pduData._value.updateData._value.rectangles._array)
def recvFastPath(self, fastPathData):
"""
Implement FastPathListener interface
Fast path is needed by RDP 8.0
@param fastPathData: Stream that contain fast path data
"""
fastPathPDU = FastPathUpdatePDU()
fastPathData.readType(fastPathPDU)
if fastPathPDU.updateHeader.value == FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP:
self._clientListener.recvBitmapUpdateDataPDU(fastPathPDU.updateData._value[1].rectangles._array)
def sendConfirmActivePDU(self):
"""
@@ -1063,7 +1169,7 @@ class PDU(LayerAutomata):
generalCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability._value
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
generalCapability.extraFlags.value = caps.GeneralExtraFlag.LONG_CREDENTIALS_SUPPORTED | caps.GeneralExtraFlag.NO_BITMAP_COMPRESSION_HDR | caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED
#init bitmap capability
bitmapCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_BITMAP].capability._value
@@ -1096,7 +1202,7 @@ class PDU(LayerAutomata):
"""
send a synchronize PDU from client to server
"""
synchronizePDU = DataPDU(PDUType2.PDUTYPE2_SYNCHRONIZE, SynchronizeDataPDU(UInt16Le(self._transport.getChannelId())), self._transport.getUserId(), self._shareId)
synchronizePDU = DataPDU(PDUType2.PDUTYPE2_SYNCHRONIZE, SynchronizeDataPDU(self._transport.getChannelId()), self._transport.getUserId(), self._shareId)
self._transport.send(synchronizePDU)
#ask for cooperation
@@ -1125,6 +1231,4 @@ class PDU(LayerAutomata):
"""
pdu = ClientInputEventPDU(self._transport.getUserId(), self._shareId)
pdu.slowPathInputEvents._array = [SlowPathInputEvent(x) for x in pointerEvents]
self._transport.send(pdu)
self._transport.send(pdu)

View File

@@ -1,13 +1,34 @@
'''
@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 <http://www.gnu.org/licenses/>.
#
"""
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
class RDPClientController(pdu.PDUClientListener):
"""
use to decode and dispatch to observer PDU messages and orders
Manage RDP stack as client
"""
def __init__(self):
"""
@@ -17,19 +38,58 @@ class RDPClientController(pdu.PDUClientListener):
self._clientObserver = []
#transport layer
self._pduLayer = pdu.PDU(self)
#multi channel service
self._mcsLayer = mcs.MCS(LayerMode.CLIENT, self._pduLayer)
#transport pdu layer
self._tpduLayer = tpdu.TPDU(LayerMode.CLIENT, self._mcsLayer)
#transport packet (protocol layer)
self._tpktLayer = tpkt.TPKT(self._tpduLayer, self._pduLayer)
def getPDULayer(self):
def getProtocol(self):
"""
@return: PDU layer use by controller
@return: return Protocol layer for twisted
In case of RDP TPKT is the Raw layer
"""
return self._pduLayer
return self._tpktLayer
def enablePerformanceSession(self):
def setPerformanceSession(self):
"""
Set particular flag in RDP stack to avoid wallpaper, theming, menu animation etc...
Set particular flag in RDP stack to avoid wall-paper, theme, menu animation etc...
"""
self._pduLayer._info.extendedInfo.performanceFlags.value = pdu.PerfFlag.PERF_DISABLE_WALLPAPER | pdu.PerfFlag.PERF_DISABLE_MENUANIMATIONS | pdu.PerfFlag.PERF_DISABLE_CURSOR_SHADOW | pdu.PerfFlag.PERF_DISABLE_THEMING
def setScreen(self, width, height):
"""
Set screen dim of session
@param width: width in pixel of screen
@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
def setUsername(self, username):
"""
Set the username for session
@param username: username of session
"""
#username in PDU info packet
self._pduLayer._info.userName.value = username
def setPassword(self, password):
"""
Set password for session
@param password: password of session
"""
self._pduLayer._info.password.value = password
def setDomain(self, domain):
"""
Set the windows domain of session
@param domain: domain of session
"""
self._pduLayer._info.domain.value = domain
def addClientObserver(self, observer):
"""
add observer to RDP protocol
@@ -132,28 +192,15 @@ class ClientFactory(protocol.Factory):
"""
Factory of Client RDP protocol
"""
def __init__(self, width = 1024, height = 800):
"""
@param width: width of screen
@param height: height of screen
"""
self._width = width
self._height = height
def buildProtocol(self, addr):
'''
"""
Function call from twisted and build rdp protocol stack
@param addr: destination address
'''
"""
controller = RDPClientController()
self.buildObserver(controller)
mcsLayer = mcs.createClient(controller)
#set screen definition in MCS layer
mcsLayer._clientSettings.core.desktopHeight.value = self._height
mcsLayer._clientSettings.core.desktopWidth.value = self._width
return tpkt.TPKT(tpdu.createClient(mcsLayer));
return controller.getProtocol();
def buildObserver(self, controller):
'''
@@ -162,9 +209,9 @@ class ClientFactory(protocol.Factory):
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "buildObserver", "ClientFactory"))
class ServerFactory(protocol.Factory):
'''
Factory of Serrve RDP protocol
'''
"""
Factory of Server RDP protocol
"""
def __init__(self, privateKeyFileName, certificateFileName):
"""
@param privateKeyFileName: file contain server private key
@@ -178,30 +225,30 @@ class ServerFactory(protocol.Factory):
Function call from twisted and build rdp protocol stack
@param addr: destination address
"""
pduLayer = pdu.PDU(pdu.PDUServerListener())
return tpkt.TPKT(tpdu.createServer(mcs.createServer(pduLayer), self._privateKeyFileName, self._certificateFileName));
#pduLayer = pdu.PDU(pdu.PDUServerListener())
#return tpkt.TPKT(tpdu.createServer(mcs.createServer(pduLayer), self._privateKeyFileName, self._certificateFileName));
def buildObserver(self):
'''
build observer use for connection
'''
"""
Build observer use for connection
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "buildObserver", "ServerFactory"))
class RDPClientObserver(object):
'''
class use to inform all RDP event handle by RDPY
'''
"""
Class use to inform all RDP event handle by RDPY
"""
def __init__(self, controller):
"""
@param listener: RDP listener use to interact with protocol
@param controller: RDP controller use to interact with protocol
"""
self._controller = controller
self._controller.addClientObserver(self)
def onBitmapUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
'''
notify bitmap update
"""
Notify bitmap update
@param destLeft: xmin position
@param destTop: ymin position
@param destRight: xmax position because RDP can send bitmap with padding
@@ -211,5 +258,5 @@ class RDPClientObserver(object):
@param bitsPerPixel: number of bit per pixel
@param isCompress: use RLE compression
@param data: bitmap data
'''
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onBitmapUpdate", "RDPClientObserver"))

View File

@@ -250,23 +250,6 @@ class TPDU(LayerAutomata, StreamSender):
@param message: network.Type message
"""
self._transport.send((TPDUDataHeader(), message))
def createClient(presentation):
"""
Factory of TPDU layer in Client mode
@param presentation: presentation layer, in RDP mode is MCS layer
"""
return TPDU(LayerMode.CLIENT, presentation)
def createServer(presentation, privateKeyFileName, certificateFileName):
"""
Factory of TPDU layer in Server mode
@param privateKeyFileName: file contain server private key
@param certficiateFileName: file that contain publi key
"""
tpdu = TPDU(LayerMode.SERVER, presentation)
tpdu.initTLSServerInfos(privateKeyFileName, certificateFileName)
return tpdu
#open ssl needed
from twisted.internet import ssl

View File

@@ -24,19 +24,30 @@ Use to build correct size packet and handle slow path and fast path mode
"""
from rdpy.network.layer import RawLayer, LayerMode
from rdpy.network.type import UInt8, UInt16Be, sizeof
from rdpy.network.error import CallPureVirtualFuntion
class FastPathListener(object):
"""
Fast path packet listener
Usually PDU layer
"""
def recvFastPath(self, fastPathData):
"""
Call when fast path packet is received
@param fastPathData: Stream
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "StreamListener"))
class TPKT(RawLayer):
"""
TPKT layer in RDP protocol stack
this layer only handle size of packet
and determine if is a fast path packet
This layer only handle size of packet and determine if is a fast path packet
"""
#first byte of classic tpkt header
TPKT_PACKET = 3
def __init__(self, presentation):
def __init__(self, presentation, fastPathListener):
"""
Constructor
@param presentation: presentation layer, in RDP case is TPDU layer
"""
RawLayer.__init__(self, LayerMode.NONE, presentation)
@@ -44,10 +55,12 @@ class TPKT(RawLayer):
self._lastPacketVersion = UInt8()
#length may be coded on more than 1 bytes
self._lastShortLength = UInt8()
#fast path listener
self._fastPathListener = fastPathListener
def connect(self):
"""
call when transport layer connection
Call when transport layer connection
is made (inherit from RawLayer)
"""
#header is on two bytes
@@ -58,7 +71,7 @@ class TPKT(RawLayer):
def readHeader(self, data):
"""
read header of TPKT packet
Read header of TPKT packet
@param data: Stream received from twisted layer
"""
#first read packet version
@@ -81,7 +94,7 @@ class TPKT(RawLayer):
def readExtendedHeader(self, data):
"""
header may be on 4 bytes
Header may be on 4 bytes
@param data: Stream from twisted layer
"""
#next state is read data
@@ -91,26 +104,27 @@ class TPKT(RawLayer):
def readExtendedFastPathHeader(self, data):
"""
fast path header may be on 1 byte more
Fast path header may be on 1 byte more
@param data: Stream from twisted layer
"""
leftPart = UInt8()
data.readType(leftPart)
self._lastShortLength.value &= ~0x80
self._lastShortLength.value = (self._lastShortLength.value << 8) + leftPart.value
packetSize = (self._lastShortLength.value << 8) + leftPart.value
#next state is fast patn data
self.expect(self._lastShortLength.value - 3, self.readFastPath)
self.expect(packetSize - 3, self.readFastPath)
def readFastPath(self, data):
"""
fast path data
Fast path data
@param data: Stream from twisted layer
"""
pass
self._fastPathListener.recvFastPath(data)
self.expect(2, self.readHeader)
def readData(self, data):
"""
read classic TPKT packet, last state in tpkt automata
Read classic TPKT packet, last state in tpkt automata
@param data: Stream with correct size
"""
#next state is pass to
@@ -119,7 +133,7 @@ class TPKT(RawLayer):
def send(self, message):
"""
send encompassed data
Send encompassed data
@param message: network.Type message to send
"""
RawLayer.send(self, (UInt8(TPKT.TPKT_PACKET), UInt8(0), UInt16Be(sizeof(message) + 4), message))

View File

@@ -176,13 +176,20 @@ class RDPClientQt(RDPClientObserver, QAdaptor):
@param data: bitmap data
"""
image = None
if bitsPerPixel == 16:
if bitsPerPixel == 15:
if isCompress:
image = QtGui.QImage(width, height, QtGui.QImage.Format_RGB555)
data = rle.bitmap_decompress(image.bits(), width, height, data, len(data), 2)
else:
image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB555)
elif bitsPerPixel == 16:
if isCompress:
image = QtGui.QImage(width, height, QtGui.QImage.Format_RGB16)
data = rle.bitmap_decompress(image.bits(), width, height, data, len(data), 2)
else:
image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB16)
elif bitsPerPixel == 24:
if isCompress:
image = QtGui.QImage(width, height, QtGui.QImage.Format_RGB24)