add fastpath to be compatible with rdp 8.0
This commit is contained in:
@@ -40,7 +40,8 @@ class RDPClientQtFactory(rdp.ClientFactory):
|
|||||||
"""
|
"""
|
||||||
init client with correct definition
|
init client with correct definition
|
||||||
"""
|
"""
|
||||||
rdp.ClientFactory.__init__(self, width, height)
|
self._width = width
|
||||||
|
self._height = height
|
||||||
self._w = None
|
self._w = None
|
||||||
|
|
||||||
def buildObserver(self, controller):
|
def buildObserver(self, controller):
|
||||||
@@ -56,8 +57,10 @@ class RDPClientQtFactory(rdp.ClientFactory):
|
|||||||
self._w.setWindowTitle('rdpy-rdpclient')
|
self._w.setWindowTitle('rdpy-rdpclient')
|
||||||
self._w.show()
|
self._w.show()
|
||||||
|
|
||||||
#enable perf
|
#resize session
|
||||||
controller.enablePerformanceSession()
|
controller.setScreen(self._width, self._height)
|
||||||
|
controller.setPerformanceSession()
|
||||||
|
|
||||||
return client
|
return client
|
||||||
|
|
||||||
def startedConnecting(self, connector):
|
def startedConnecting(self, connector):
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ class LayerAutomata(Layer, StreamListener):
|
|||||||
|
|
||||||
self.recv = callback
|
self.recv = callback
|
||||||
|
|
||||||
#twitsed layer concept
|
#twisted layer concept
|
||||||
from twisted.internet import protocol
|
from twisted.internet import protocol
|
||||||
#first that handle stream
|
#first that handle stream
|
||||||
from type import Stream
|
from type import Stream
|
||||||
|
|||||||
@@ -372,66 +372,68 @@ class SimpleType(Type, CallableValue):
|
|||||||
return self.__class__(self.value.__rshift__(other.value))
|
return self.__class__(self.value.__rshift__(other.value))
|
||||||
|
|
||||||
def __hash__(self):
|
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 of inner value
|
||||||
'''
|
"""
|
||||||
return hash(self.value)
|
return hash(self.value)
|
||||||
|
|
||||||
def __nonzero__(self):
|
def __nonzero__(self):
|
||||||
'''
|
"""
|
||||||
boolean conversion
|
Boolean conversion
|
||||||
@return: bool of inner value
|
@return: bool of inner value
|
||||||
'''
|
"""
|
||||||
return bool(self.value)
|
return bool(self.value)
|
||||||
|
|
||||||
|
|
||||||
class CompositeType(Type):
|
class CompositeType(Type):
|
||||||
'''
|
"""
|
||||||
keep ordering declaration of simple type
|
Type node of other sub 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
|
|
||||||
'''
|
|
||||||
def __init__(self, conditional = lambda:True, optional = False, constant = False, readLen = None):
|
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)
|
Type.__init__(self, conditional = conditional, optional = optional, constant = constant)
|
||||||
#list of ordoned type
|
#list of ordoned type
|
||||||
self._typeName = []
|
self._typeName = []
|
||||||
self._readLen = readLen
|
self._readLen = readLen
|
||||||
|
|
||||||
def __setattr__(self, name, value):
|
def __setattr__(self, name, value):
|
||||||
'''
|
"""
|
||||||
magic function to update type list
|
Magic function to update type list
|
||||||
@param name: name of new attribute
|
@param name: name of new attribute
|
||||||
@param value: value 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:
|
if name[0] != '_' and (isinstance(value, Type) or isinstance(value, tuple)) and not name in self._typeName:
|
||||||
self._typeName.append(name)
|
self._typeName.append(name)
|
||||||
self.__dict__[name] = value
|
self.__dict__[name] = value
|
||||||
|
|
||||||
def __read__(self, s):
|
def __read__(self, s):
|
||||||
'''
|
"""
|
||||||
call read on each ordered subtype
|
Call read on each ordered sub-type
|
||||||
@param s: Stream
|
@param s: Stream
|
||||||
'''
|
"""
|
||||||
readLen = 0
|
readLen = 0
|
||||||
for name in self._typeName:
|
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))
|
|
||||||
try:
|
try:
|
||||||
s.readType(self.__dict__[name])
|
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:
|
except Exception as e:
|
||||||
print "Error during read %s::%s"%(self.__class__, name)
|
print "Error during read %s::%s"%(self.__class__, name)
|
||||||
#rollback already readed
|
#roll back already read
|
||||||
for tmpName in self._typeName:
|
for tmpName in self._typeName:
|
||||||
if tmpName == name:
|
if tmpName == name:
|
||||||
break
|
break
|
||||||
@@ -863,17 +865,16 @@ class ArrayType(Type):
|
|||||||
return sizeof(self._array)
|
return sizeof(self._array)
|
||||||
|
|
||||||
class FactoryType(Type):
|
class FactoryType(Type):
|
||||||
'''
|
"""
|
||||||
Call factory function on read or write
|
Call factory function on read or write
|
||||||
'''
|
"""
|
||||||
def __init__(self, factory, conditional = lambda:True, optional = False, constant = False):
|
def __init__(self, factory, conditional = lambda:True, optional = False, constant = False):
|
||||||
'''
|
"""
|
||||||
ctor of factory type
|
|
||||||
@param factory: factory
|
@param factory: factory
|
||||||
@param conditional : function call before read or write type
|
@param conditional : function call before read or write type
|
||||||
@param optional: boolean check before read if there is still data in stream
|
@param optional: boolean check before read if there is still data in stream
|
||||||
@param constant: if true check any changes of object during reading
|
@param constant: if true check any changes of object during reading
|
||||||
'''
|
"""
|
||||||
Type.__init__(self, conditional, optional, constant)
|
Type.__init__(self, conditional, optional, constant)
|
||||||
self._factory = factory
|
self._factory = factory
|
||||||
if not callable(factory):
|
if not callable(factory):
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ Each channel have a particular role.
|
|||||||
The main channel is the graphical channel.
|
The main channel is the graphical channel.
|
||||||
It exist channel for file system order, audio channel, clipboard etc...
|
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.type import sizeof, Stream, UInt8, UInt16Be
|
||||||
from rdpy.network.error import InvalidExpectedDataException, InvalidValue, InvalidSize
|
from rdpy.network.error import InvalidExpectedDataException, InvalidValue, InvalidSize
|
||||||
from rdpy.protocol.rdp.ber import writeLength
|
from rdpy.protocol.rdp.ber import writeLength
|
||||||
@@ -64,7 +64,7 @@ class MCS(LayerAutomata):
|
|||||||
the main layer of RDP protocol
|
the main layer of RDP protocol
|
||||||
is why he can do everything and more!
|
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
|
Proxy use to set as transport layer for upper channel
|
||||||
use to abstract channel id for presentation layer
|
use to abstract channel id for presentation layer
|
||||||
@@ -78,34 +78,40 @@ class MCS(LayerAutomata):
|
|||||||
self._channelId = channelId
|
self._channelId = channelId
|
||||||
|
|
||||||
def send(self, data):
|
def send(self, data):
|
||||||
'''
|
"""
|
||||||
a send proxy function, use channel id and specific
|
A send proxy function, use channel id and specific
|
||||||
send function of mcs layer
|
send function of MCS layer
|
||||||
'''
|
"""
|
||||||
self._mcs.send(self._channelId, data)
|
self._mcs.send(self._channelId, data)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
"""
|
||||||
|
Close wrapped layer
|
||||||
|
"""
|
||||||
|
self._mcs.close()
|
||||||
|
|
||||||
def getUserId(self):
|
def getUserId(self):
|
||||||
'''
|
"""
|
||||||
@return: mcs user id
|
@return: mcs user id
|
||||||
'''
|
"""
|
||||||
return self._mcs._userId
|
return self._mcs._userId
|
||||||
|
|
||||||
def getChannelId(self):
|
def getChannelId(self):
|
||||||
'''
|
"""
|
||||||
@return: return channel id of proxy
|
@return: return channel id of proxy
|
||||||
'''
|
"""
|
||||||
return self._channelId
|
return self._channelId
|
||||||
|
|
||||||
def getGCCClientSettings(self):
|
def getGCCClientSettings(self):
|
||||||
'''
|
"""
|
||||||
@return: mcs layer gcc client settings
|
@return: mcs layer gcc client settings
|
||||||
'''
|
"""
|
||||||
return self._mcs._clientSettings
|
return self._mcs._clientSettings
|
||||||
|
|
||||||
def getGCCServerSettings(self):
|
def getGCCServerSettings(self):
|
||||||
'''
|
"""
|
||||||
@return: mcs layer gcc server settings
|
@return: mcs layer gcc server settings
|
||||||
'''
|
"""
|
||||||
return self._mcs._serverSettings
|
return self._mcs._serverSettings
|
||||||
|
|
||||||
|
|
||||||
@@ -354,17 +360,3 @@ class MCS(LayerAutomata):
|
|||||||
ber.readInteger(s)
|
ber.readInteger(s)
|
||||||
return (max_channels, max_users, max_tokens, max_pdu_size)
|
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())
|
|
||||||
|
|
||||||
@@ -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.type import CompositeType, UniString, String, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType
|
||||||
from rdpy.network.error import InvalidExpectedDataException, ErrorReportedFromPeer, CallPureVirtualFuntion, InvalidType
|
from rdpy.network.error import InvalidExpectedDataException, ErrorReportedFromPeer, CallPureVirtualFuntion, InvalidType
|
||||||
|
|
||||||
import gcc, lic, caps
|
import gcc, lic, caps, tpkt
|
||||||
|
|
||||||
class SecurityFlag(object):
|
class SecurityFlag(object):
|
||||||
"""
|
"""
|
||||||
@@ -223,6 +223,30 @@ class KeyboardFlag(object):
|
|||||||
KBDFLAGS_DOWN = 0x4000
|
KBDFLAGS_DOWN = 0x4000
|
||||||
KBDFLAGS_RELEASE = 0x8000
|
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):
|
class ErrorInfo(object):
|
||||||
"""
|
"""
|
||||||
Error code use in Error info PDU
|
Error code use in Error info PDU
|
||||||
@@ -586,18 +610,26 @@ class DataPDU(CompositeType):
|
|||||||
self.shareDataHeader = ShareDataHeader(lambda:sizeof(self), pduType, userId, shareId)
|
self.shareDataHeader = ShareDataHeader(lambda:sizeof(self), pduType, userId, shareId)
|
||||||
|
|
||||||
def PDUDataFactory():
|
def PDUDataFactory():
|
||||||
|
"""
|
||||||
|
Create object in accordance self.shareDataHeader.pduType2 value
|
||||||
|
"""
|
||||||
if self.shareDataHeader.pduType2.value == PDUType2.PDUTYPE2_UPDATE:
|
if self.shareDataHeader.pduType2.value == PDUType2.PDUTYPE2_UPDATE:
|
||||||
return UpdateDataPDU()
|
return UpdateDataPDU(readLen = self.shareDataHeader.uncompressedLength)
|
||||||
|
|
||||||
elif self.shareDataHeader.pduType2.value == PDUType2.PDUTYPE2_SYNCHRONIZE:
|
elif self.shareDataHeader.pduType2.value == PDUType2.PDUTYPE2_SYNCHRONIZE:
|
||||||
return SynchronizeDataPDU()
|
return SynchronizeDataPDU(readLen = self.shareDataHeader.uncompressedLength)
|
||||||
|
|
||||||
elif self.shareDataHeader.pduType2.value == PDUType2.PDUTYPE2_CONTROL:
|
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:
|
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:
|
elif self.shareDataHeader.pduType2.value == PDUType2.PDUTYPE2_FONTLIST:
|
||||||
return FontListDataPDU()
|
return FontListDataPDU(readLen = self.shareDataHeader.uncompressedLength)
|
||||||
|
|
||||||
elif self.shareDataHeader.pduType2.value == PDUType2.PDUTYPE2_FONTMAP:
|
elif self.shareDataHeader.pduType2.value == PDUType2.PDUTYPE2_FONTMAP:
|
||||||
return FontMapDataPDU()
|
return FontMapDataPDU(readLen = self.shareDataHeader.uncompressedLength)
|
||||||
else:
|
else:
|
||||||
#read all value
|
#read all value
|
||||||
return String()
|
return String()
|
||||||
@@ -611,17 +643,24 @@ class SynchronizeDataPDU(CompositeType):
|
|||||||
"""
|
"""
|
||||||
@see http://msdn.microsoft.com/en-us/library/cc240490.aspx
|
@see http://msdn.microsoft.com/en-us/library/cc240490.aspx
|
||||||
"""
|
"""
|
||||||
def __init__(self, targetUser = UInt16Le()):
|
def __init__(self, targetUser = 0, readLen = None):
|
||||||
CompositeType.__init__(self)
|
"""
|
||||||
|
@param targetUser: MCS Channel ID
|
||||||
|
"""
|
||||||
|
CompositeType.__init__(self, readLen = readLen)
|
||||||
self.messageType = UInt16Le(1, constant = True)
|
self.messageType = UInt16Le(1, constant = True)
|
||||||
self.targetUser = targetUser
|
self.targetUser = UInt16Le(targetUser)
|
||||||
|
|
||||||
class ControlDataPDU(CompositeType):
|
class ControlDataPDU(CompositeType):
|
||||||
"""
|
"""
|
||||||
@see http://msdn.microsoft.com/en-us/library/cc240492.aspx
|
@see http://msdn.microsoft.com/en-us/library/cc240492.aspx
|
||||||
"""
|
"""
|
||||||
def __init__(self, action = None):
|
def __init__(self, action = None, readLen = None):
|
||||||
CompositeType.__init__(self)
|
"""
|
||||||
|
@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.action = UInt16Le(action, constant = True) if not action is None else UInt16Le()
|
||||||
self.grantId = UInt16Le()
|
self.grantId = UInt16Le()
|
||||||
self.controlId = UInt32Le()
|
self.controlId = UInt32Le()
|
||||||
@@ -631,10 +670,14 @@ class ErrorInfoDataPDU(CompositeType):
|
|||||||
Use to inform error in PDU layer
|
Use to inform error in PDU layer
|
||||||
@see: http://msdn.microsoft.com/en-us/library/cc240544.aspx
|
@see: http://msdn.microsoft.com/en-us/library/cc240544.aspx
|
||||||
"""
|
"""
|
||||||
def __init__(self, errorInfo = UInt32Le()):
|
def __init__(self, errorInfo = 0, readLen = None):
|
||||||
CompositeType.__init__(self)
|
"""
|
||||||
#use to collect error info pdu
|
@param errorInfo: ErrorInfo macro
|
||||||
self.errorInfo = errorInfo
|
@param readLen: Max length to read
|
||||||
|
"""
|
||||||
|
CompositeType.__init__(self, readLen = readLen)
|
||||||
|
#use to collect error info PDU
|
||||||
|
self.errorInfo = UInt32Le(errorInfo)
|
||||||
|
|
||||||
class FontListDataPDU(CompositeType):
|
class FontListDataPDU(CompositeType):
|
||||||
"""
|
"""
|
||||||
@@ -642,8 +685,11 @@ class FontListDataPDU(CompositeType):
|
|||||||
client -> server
|
client -> server
|
||||||
@see: http://msdn.microsoft.com/en-us/library/cc240498.aspx
|
@see: http://msdn.microsoft.com/en-us/library/cc240498.aspx
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self, readLen = None):
|
||||||
CompositeType.__init__(self)
|
"""
|
||||||
|
@param readLen: Max read length
|
||||||
|
"""
|
||||||
|
CompositeType.__init__(self, readLen = readLen)
|
||||||
self.numberFonts = UInt16Le()
|
self.numberFonts = UInt16Le()
|
||||||
self.totalNumFonts = UInt16Le()
|
self.totalNumFonts = UInt16Le()
|
||||||
self.listFlags = UInt16Le(0x0003)
|
self.listFlags = UInt16Le(0x0003)
|
||||||
@@ -655,8 +701,11 @@ class FontMapDataPDU(CompositeType):
|
|||||||
server -> client
|
server -> client
|
||||||
@see: http://msdn.microsoft.com/en-us/library/cc240498.aspx
|
@see: http://msdn.microsoft.com/en-us/library/cc240498.aspx
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self, readLen = None):
|
||||||
CompositeType.__init__(self)
|
"""
|
||||||
|
@param readLen: Max read length
|
||||||
|
"""
|
||||||
|
CompositeType.__init__(self, readLen = readLen)
|
||||||
self.numberEntries = UInt16Le()
|
self.numberEntries = UInt16Le()
|
||||||
self.totalNumEntries = UInt16Le()
|
self.totalNumEntries = UInt16Le()
|
||||||
self.mapFlags = UInt16Le(0x0003)
|
self.mapFlags = UInt16Le(0x0003)
|
||||||
@@ -664,32 +713,84 @@ class FontMapDataPDU(CompositeType):
|
|||||||
|
|
||||||
class UpdateDataPDU(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
|
for example
|
||||||
@see: http://msdn.microsoft.com/en-us/library/cc240608.aspx
|
@see: http://msdn.microsoft.com/en-us/library/cc240608.aspx
|
||||||
"""
|
"""
|
||||||
def __init__(self, updateType = 0, updateData = None):
|
def __init__(self, updateType = 0, updateData = None, readLen = None):
|
||||||
CompositeType.__init__(self)
|
"""
|
||||||
|
@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)
|
self.updateType = UInt16Le(updateType)
|
||||||
|
|
||||||
def UpdateDataFactory():
|
def UpdateDataFactory():
|
||||||
if self.updateType.value == UpdateType.UPDATETYPE_BITMAP:
|
if self.updateType.value == UpdateType.UPDATETYPE_BITMAP:
|
||||||
return BitmapUpdateDataPDU()
|
return BitmapUpdateDataPDU()
|
||||||
|
|
||||||
|
elif self.updateType.value == UpdateType.UPDATETYPE_SYNCHRONIZE:
|
||||||
|
return SynchronizeUpdatePDU()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
String()
|
return String()
|
||||||
|
|
||||||
if updateData is None:
|
if updateData is None:
|
||||||
updateData = UpdateDataFactory
|
updateData = UpdateDataFactory
|
||||||
|
|
||||||
self.updateData = FactoryType(updateData, conditional = lambda:(self.updateType.value != UpdateType.UPDATETYPE_SYNCHRONIZE))
|
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):
|
class BitmapUpdateDataPDU(CompositeType):
|
||||||
"""
|
"""
|
||||||
PDU use to send raw bitmap compressed or not
|
PDU use to send raw bitmap compressed or not
|
||||||
@see: http://msdn.microsoft.com/en-us/library/dd306368.aspx
|
@see: http://msdn.microsoft.com/en-us/library/dd306368.aspx
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self, readLen = None):
|
||||||
CompositeType.__init__(self)
|
"""
|
||||||
|
@param readLen: Max size of packet
|
||||||
|
"""
|
||||||
|
CompositeType.__init__(self, readLen = readLen)
|
||||||
self.numberRectangles = UInt16Le(lambda:len(self.rectangles._array))
|
self.numberRectangles = UInt16Le(lambda:len(self.rectangles._array))
|
||||||
self.rectangles = ArrayType(BitmapData, readLen = self.numberRectangles)
|
self.rectangles = ArrayType(BitmapData, readLen = self.numberRectangles)
|
||||||
|
|
||||||
@@ -775,10 +876,13 @@ class SlowPathInputEvent(CompositeType):
|
|||||||
"""
|
"""
|
||||||
if isinstance(event, PointerEvent):
|
if isinstance(event, PointerEvent):
|
||||||
return InputMessageType.INPUT_EVENT_MOUSE
|
return InputMessageType.INPUT_EVENT_MOUSE
|
||||||
|
|
||||||
elif isinstance(event, ScancodeKeyEvent):
|
elif isinstance(event, ScancodeKeyEvent):
|
||||||
return InputMessageType.INPUT_EVENT_SCANCODE
|
return InputMessageType.INPUT_EVENT_SCANCODE
|
||||||
|
|
||||||
elif isinstance(event, UnicodeKeyEvent):
|
elif isinstance(event, UnicodeKeyEvent):
|
||||||
return InputMessageType.INPUT_EVENT_UNICODE
|
return InputMessageType.INPUT_EVENT_UNICODE
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -851,7 +955,7 @@ class PDUServerListener(object):
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class PDU(LayerAutomata):
|
class PDU(LayerAutomata, tpkt.FastPathListener):
|
||||||
"""
|
"""
|
||||||
Global channel for MCS that handle session
|
Global channel for MCS that handle session
|
||||||
identification user, licensing management, and capabilities exchange
|
identification user, licensing management, and capabilities exchange
|
||||||
@@ -860,6 +964,18 @@ class PDU(LayerAutomata):
|
|||||||
"""
|
"""
|
||||||
@param listener: listener use to inform orders
|
@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
|
#logon info send from client to server
|
||||||
self._info = RDPInfo(extendedInfoConditional = lambda:(self._transport.getGCCServerSettings().core.rdpVersion.value == gcc.Version.RDP_VERSION_5_PLUS))
|
self._info = RDPInfo(extendedInfoConditional = lambda:(self._transport.getGCCServerSettings().core.rdpVersion.value == gcc.Version.RDP_VERSION_5_PLUS))
|
||||||
#server capabilities
|
#server capabilities
|
||||||
@@ -899,28 +1015,6 @@ class PDU(LayerAutomata):
|
|||||||
#determine if layer is connected
|
#determine if layer is connected
|
||||||
self._isConnected = False
|
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):
|
def connect(self):
|
||||||
"""
|
"""
|
||||||
Connect event in client mode send logon info
|
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
|
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.send(ShareDataHeader(PDUType2.PDUTYPE2_SHUTDOWN_REQUEST, self._transport.getUserId(), self._shareId))
|
||||||
|
self._transport.close()
|
||||||
|
|
||||||
def sendInfoPkt(self):
|
def sendInfoPkt(self):
|
||||||
"""
|
"""
|
||||||
@@ -968,7 +1063,7 @@ class PDU(LayerAutomata):
|
|||||||
|
|
||||||
def readDataPDU(self, data):
|
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
|
@param data: Stream from transport layer
|
||||||
@return:
|
@return:
|
||||||
"""
|
"""
|
||||||
@@ -1055,6 +1150,17 @@ class PDU(LayerAutomata):
|
|||||||
if dataPDU.shareDataHeader.pduType2.value == PDUType2.PDUTYPE2_UPDATE and dataPDU.pduData._value.updateType.value == UpdateType.UPDATETYPE_BITMAP:
|
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)
|
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):
|
def sendConfirmActivePDU(self):
|
||||||
"""
|
"""
|
||||||
Send all client capabilities
|
Send all client capabilities
|
||||||
@@ -1063,7 +1169,7 @@ class PDU(LayerAutomata):
|
|||||||
generalCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability._value
|
generalCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability._value
|
||||||
generalCapability.osMajorType.value = caps.MajorType.OSMAJORTYPE_WINDOWS
|
generalCapability.osMajorType.value = caps.MajorType.OSMAJORTYPE_WINDOWS
|
||||||
generalCapability.osMinorType.value = caps.MinorType.OSMINORTYPE_WINDOWS_NT
|
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
|
#init bitmap capability
|
||||||
bitmapCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_BITMAP].capability._value
|
bitmapCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_BITMAP].capability._value
|
||||||
@@ -1096,7 +1202,7 @@ class PDU(LayerAutomata):
|
|||||||
"""
|
"""
|
||||||
send a synchronize PDU from client to server
|
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)
|
self._transport.send(synchronizePDU)
|
||||||
|
|
||||||
#ask for cooperation
|
#ask for cooperation
|
||||||
@@ -1126,5 +1232,3 @@ class PDU(LayerAutomata):
|
|||||||
pdu = ClientInputEventPDU(self._transport.getUserId(), self._shareId)
|
pdu = ClientInputEventPDU(self._transport.getUserId(), self._shareId)
|
||||||
pdu.slowPathInputEvents._array = [SlowPathInputEvent(x) for x in pointerEvents]
|
pdu.slowPathInputEvents._array = [SlowPathInputEvent(x) for x in pointerEvents]
|
||||||
self._transport.send(pdu)
|
self._transport.send(pdu)
|
||||||
|
|
||||||
|
|
||||||
@@ -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 twisted.internet import protocol
|
||||||
from rdpy.network.error import CallPureVirtualFuntion, InvalidValue
|
from rdpy.network.error import CallPureVirtualFuntion, InvalidValue
|
||||||
|
from rdpy.network.layer import LayerMode
|
||||||
import tpkt, tpdu, mcs, pdu
|
import tpkt, tpdu, mcs, pdu
|
||||||
|
|
||||||
class RDPClientController(pdu.PDUClientListener):
|
class RDPClientController(pdu.PDUClientListener):
|
||||||
"""
|
"""
|
||||||
use to decode and dispatch to observer PDU messages and orders
|
Manage RDP stack as client
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""
|
"""
|
||||||
@@ -17,19 +38,58 @@ class RDPClientController(pdu.PDUClientListener):
|
|||||||
self._clientObserver = []
|
self._clientObserver = []
|
||||||
#transport layer
|
#transport layer
|
||||||
self._pduLayer = pdu.PDU(self)
|
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
|
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):
|
def addClientObserver(self, observer):
|
||||||
"""
|
"""
|
||||||
add observer to RDP protocol
|
add observer to RDP protocol
|
||||||
@@ -132,28 +192,15 @@ class ClientFactory(protocol.Factory):
|
|||||||
"""
|
"""
|
||||||
Factory of Client RDP protocol
|
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):
|
def buildProtocol(self, addr):
|
||||||
'''
|
"""
|
||||||
Function call from twisted and build rdp protocol stack
|
Function call from twisted and build rdp protocol stack
|
||||||
@param addr: destination address
|
@param addr: destination address
|
||||||
'''
|
"""
|
||||||
controller = RDPClientController()
|
controller = RDPClientController()
|
||||||
self.buildObserver(controller)
|
self.buildObserver(controller)
|
||||||
mcsLayer = mcs.createClient(controller)
|
|
||||||
|
|
||||||
#set screen definition in MCS layer
|
return controller.getProtocol();
|
||||||
mcsLayer._clientSettings.core.desktopHeight.value = self._height
|
|
||||||
mcsLayer._clientSettings.core.desktopWidth.value = self._width
|
|
||||||
|
|
||||||
return tpkt.TPKT(tpdu.createClient(mcsLayer));
|
|
||||||
|
|
||||||
def buildObserver(self, controller):
|
def buildObserver(self, controller):
|
||||||
'''
|
'''
|
||||||
@@ -162,9 +209,9 @@ class ClientFactory(protocol.Factory):
|
|||||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "buildObserver", "ClientFactory"))
|
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "buildObserver", "ClientFactory"))
|
||||||
|
|
||||||
class ServerFactory(protocol.Factory):
|
class ServerFactory(protocol.Factory):
|
||||||
'''
|
"""
|
||||||
Factory of Serrve RDP protocol
|
Factory of Server RDP protocol
|
||||||
'''
|
"""
|
||||||
def __init__(self, privateKeyFileName, certificateFileName):
|
def __init__(self, privateKeyFileName, certificateFileName):
|
||||||
"""
|
"""
|
||||||
@param privateKeyFileName: file contain server private key
|
@param privateKeyFileName: file contain server private key
|
||||||
@@ -178,30 +225,30 @@ class ServerFactory(protocol.Factory):
|
|||||||
Function call from twisted and build rdp protocol stack
|
Function call from twisted and build rdp protocol stack
|
||||||
@param addr: destination address
|
@param addr: destination address
|
||||||
"""
|
"""
|
||||||
pduLayer = pdu.PDU(pdu.PDUServerListener())
|
#pduLayer = pdu.PDU(pdu.PDUServerListener())
|
||||||
return tpkt.TPKT(tpdu.createServer(mcs.createServer(pduLayer), self._privateKeyFileName, self._certificateFileName));
|
#return tpkt.TPKT(tpdu.createServer(mcs.createServer(pduLayer), self._privateKeyFileName, self._certificateFileName));
|
||||||
|
|
||||||
def buildObserver(self):
|
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"))
|
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "buildObserver", "ServerFactory"))
|
||||||
|
|
||||||
class RDPClientObserver(object):
|
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):
|
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 = controller
|
||||||
self._controller.addClientObserver(self)
|
self._controller.addClientObserver(self)
|
||||||
|
|
||||||
|
|
||||||
def onBitmapUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
|
def onBitmapUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
|
||||||
'''
|
"""
|
||||||
notify bitmap update
|
Notify bitmap update
|
||||||
@param destLeft: xmin position
|
@param destLeft: xmin position
|
||||||
@param destTop: ymin position
|
@param destTop: ymin position
|
||||||
@param destRight: xmax position because RDP can send bitmap with padding
|
@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 bitsPerPixel: number of bit per pixel
|
||||||
@param isCompress: use RLE compression
|
@param isCompress: use RLE compression
|
||||||
@param data: bitmap data
|
@param data: bitmap data
|
||||||
'''
|
"""
|
||||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onBitmapUpdate", "RDPClientObserver"))
|
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onBitmapUpdate", "RDPClientObserver"))
|
||||||
@@ -251,23 +251,6 @@ class TPDU(LayerAutomata, StreamSender):
|
|||||||
"""
|
"""
|
||||||
self._transport.send((TPDUDataHeader(), 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
|
#open ssl needed
|
||||||
from twisted.internet import ssl
|
from twisted.internet import ssl
|
||||||
from OpenSSL import SSL
|
from OpenSSL import SSL
|
||||||
|
|||||||
@@ -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.layer import RawLayer, LayerMode
|
||||||
from rdpy.network.type import UInt8, UInt16Be, sizeof
|
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):
|
class TPKT(RawLayer):
|
||||||
"""
|
"""
|
||||||
TPKT layer in RDP protocol stack
|
TPKT layer in RDP protocol stack
|
||||||
this layer only handle size of packet
|
This layer only handle size of packet and determine if is a fast path packet
|
||||||
and determine if is a fast path packet
|
|
||||||
"""
|
"""
|
||||||
#first byte of classic tpkt header
|
#first byte of classic tpkt header
|
||||||
TPKT_PACKET = 3
|
TPKT_PACKET = 3
|
||||||
|
|
||||||
def __init__(self, presentation):
|
def __init__(self, presentation, fastPathListener):
|
||||||
"""
|
"""
|
||||||
Constructor
|
|
||||||
@param presentation: presentation layer, in RDP case is TPDU layer
|
@param presentation: presentation layer, in RDP case is TPDU layer
|
||||||
"""
|
"""
|
||||||
RawLayer.__init__(self, LayerMode.NONE, presentation)
|
RawLayer.__init__(self, LayerMode.NONE, presentation)
|
||||||
@@ -44,10 +55,12 @@ class TPKT(RawLayer):
|
|||||||
self._lastPacketVersion = UInt8()
|
self._lastPacketVersion = UInt8()
|
||||||
#length may be coded on more than 1 bytes
|
#length may be coded on more than 1 bytes
|
||||||
self._lastShortLength = UInt8()
|
self._lastShortLength = UInt8()
|
||||||
|
#fast path listener
|
||||||
|
self._fastPathListener = fastPathListener
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
"""
|
"""
|
||||||
call when transport layer connection
|
Call when transport layer connection
|
||||||
is made (inherit from RawLayer)
|
is made (inherit from RawLayer)
|
||||||
"""
|
"""
|
||||||
#header is on two bytes
|
#header is on two bytes
|
||||||
@@ -58,7 +71,7 @@ class TPKT(RawLayer):
|
|||||||
|
|
||||||
def readHeader(self, data):
|
def readHeader(self, data):
|
||||||
"""
|
"""
|
||||||
read header of TPKT packet
|
Read header of TPKT packet
|
||||||
@param data: Stream received from twisted layer
|
@param data: Stream received from twisted layer
|
||||||
"""
|
"""
|
||||||
#first read packet version
|
#first read packet version
|
||||||
@@ -81,7 +94,7 @@ class TPKT(RawLayer):
|
|||||||
|
|
||||||
def readExtendedHeader(self, data):
|
def readExtendedHeader(self, data):
|
||||||
"""
|
"""
|
||||||
header may be on 4 bytes
|
Header may be on 4 bytes
|
||||||
@param data: Stream from twisted layer
|
@param data: Stream from twisted layer
|
||||||
"""
|
"""
|
||||||
#next state is read data
|
#next state is read data
|
||||||
@@ -91,26 +104,27 @@ class TPKT(RawLayer):
|
|||||||
|
|
||||||
def readExtendedFastPathHeader(self, data):
|
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
|
@param data: Stream from twisted layer
|
||||||
"""
|
"""
|
||||||
leftPart = UInt8()
|
leftPart = UInt8()
|
||||||
data.readType(leftPart)
|
data.readType(leftPart)
|
||||||
self._lastShortLength.value &= ~0x80
|
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
|
#next state is fast patn data
|
||||||
self.expect(self._lastShortLength.value - 3, self.readFastPath)
|
self.expect(packetSize - 3, self.readFastPath)
|
||||||
|
|
||||||
def readFastPath(self, data):
|
def readFastPath(self, data):
|
||||||
"""
|
"""
|
||||||
fast path data
|
Fast path data
|
||||||
@param data: Stream from twisted layer
|
@param data: Stream from twisted layer
|
||||||
"""
|
"""
|
||||||
pass
|
self._fastPathListener.recvFastPath(data)
|
||||||
|
self.expect(2, self.readHeader)
|
||||||
|
|
||||||
def readData(self, data):
|
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
|
@param data: Stream with correct size
|
||||||
"""
|
"""
|
||||||
#next state is pass to
|
#next state is pass to
|
||||||
@@ -119,7 +133,7 @@ class TPKT(RawLayer):
|
|||||||
|
|
||||||
def send(self, message):
|
def send(self, message):
|
||||||
"""
|
"""
|
||||||
send encompassed data
|
Send encompassed data
|
||||||
@param message: network.Type message to send
|
@param message: network.Type message to send
|
||||||
"""
|
"""
|
||||||
RawLayer.send(self, (UInt8(TPKT.TPKT_PACKET), UInt8(0), UInt16Be(sizeof(message) + 4), message))
|
RawLayer.send(self, (UInt8(TPKT.TPKT_PACKET), UInt8(0), UInt16Be(sizeof(message) + 4), message))
|
||||||
@@ -176,7 +176,14 @@ class RDPClientQt(RDPClientObserver, QAdaptor):
|
|||||||
@param data: bitmap data
|
@param data: bitmap data
|
||||||
"""
|
"""
|
||||||
image = None
|
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:
|
if isCompress:
|
||||||
image = QtGui.QImage(width, height, QtGui.QImage.Format_RGB16)
|
image = QtGui.QImage(width, height, QtGui.QImage.Format_RGB16)
|
||||||
data = rle.bitmap_decompress(image.bits(), width, height, data, len(data), 2)
|
data = rle.bitmap_decompress(image.bits(), width, height, data, len(data), 2)
|
||||||
|
|||||||
Reference in New Issue
Block a user