fix bug + more license automata

This commit is contained in:
speyrefitte
2014-07-15 17:11:06 +02:00
parent 088893fa63
commit c04982f434
8 changed files with 321 additions and 109 deletions

View File

@@ -1,6 +1,9 @@
# RDPY
Remote Desktop Protocol in Twisted Python
Remote Desktop Protocol in Twisted Python.
RDPY is ful python except the bitmap decompression in RDP client for performance. RDPY has no ambition to be as faster as freerdp, rdesktop or mstsc, is made to play with microsoft protocol. There are some limitations essentially due to price of license (Packet redirection and License extesion in RDP protocol).
## Requirements
* python2.7
@@ -8,16 +11,45 @@ Remote Desktop Protocol in Twisted Python
* python-openssl
* python-qt4
* python-qt4reactor
## Requirements libs
* python-sip-dev
* scons
## Build
```
$ git clone https://github.com/citronneur/rdpy.git rdpy
$ scons -C rdpy/lib install
```
## Binaries
Binaries are uses as examples to use rdpy lib.
To create an RDP client (this example doesn't need build step of project because it doesn't call bitmap uncompress):
```
from rdpy.protocol.rdp import rdp
class RDPClientQtFactory(rdp.ClientFactory):
def buildObserver(self, controller):
class MyObserver(rdp.RDPClientObserver)
def __init__(self, controller)
rdp.RDPClientObserver.__init__(self, controller)
def onBitmapUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
#here code handle bitmap
pass
def onReady(self):
#send r key
self._controller.sendKeyEventUnicode(ord(unicode("r".toUtf8(), encoding="UTF-8")), True)
#mouse and click at pixel 200x200
self._controller.sendPointerEvent(200, 200, 1, true)
return MyObserver(controller)
def startedConnecting(self, connector):
pass
def clientConnectionLost(self, connector, reason):
pass
def clientConnectionFailed(self, connector, reason):
pass
```
RDP Client
```
$ rdpy/bin/rdpy-rdpclient XXX.XXX.XXX.XXX 3389
@@ -30,15 +62,15 @@ $ rdpy/bin/rdpy-vncclient XXX.XXX.XXX.XXX 5901
RDP Proxy
```
$ rdpy/bin/rdpy-vncclient XXX.XXX.XXX.XXX 5901
$ rdpy/bin/rdpy-rdpproxy
```
##Must be implemented before first release
##Limitations
* CreedSSP
* Packet redirection
* License
* Most common orders
* FastPath messages
* Des VNC (using pyDes)
* VNC server side
this project is still in progress.

View File

@@ -443,10 +443,10 @@ class CompositeType(Type):
readLen += sizeof(self.__dict__[name])
def __write__(self, s):
'''
call write on each ordered subtype
"""
Call write on each ordered sub type
@param s: Stream
'''
"""
for name in self._typeName:
try:
s.writeType(self.__dict__[name])
@@ -818,21 +818,20 @@ class Stream(StringIO):
value.write(self)
class ArrayType(Type):
'''
in write mode ArrayType is just list
but in read mode it can be dynamic
"""
In write mode ArrayType is just list
But in read mode it can be dynamic
readLen may be dynamic
'''
"""
def __init__(self, typeFactory, init = None, readLen = UInt8(), conditional = lambda:True, optional = False, constant = False):
'''
constructor
"""
@param typeFactory: class use to init new element on read
@param init: init array
@param readLen: number of element in sequence
@param conditional : function call before read or write type
@param optional: boolean check before read if there is still data in stream
@param constant: if true check any changes of object during reading
'''
"""
Type.__init__(self, conditional, optional, constant)
self._typeFactory = typeFactory
self._readLen = readLen
@@ -841,10 +840,10 @@ class ArrayType(Type):
self._array = init
def __read__(self, s):
'''
create new object and read it
"""
Create new object and read it
@param s: Stream
'''
"""
self._array = []
for _ in range(0, self._readLen.value):
element = self._typeFactory()
@@ -852,21 +851,21 @@ class ArrayType(Type):
self._array.append(element)
def __write__(self, s):
'''
just write array
"""
Just write array
@param s: Stream
'''
"""
s.writeType(self._array)
def __sizeof__(self):
'''
sizeof inner array
'''
"""
Size of inner array
"""
return sizeof(self._array)
class FactoryType(Type):
"""
Call factory function on read or write
Call factory function on read
"""
def __init__(self, factory, conditional = lambda:True, optional = False, constant = False):
"""
@@ -880,29 +879,43 @@ class FactoryType(Type):
if not callable(factory):
self._factory = lambda:factory
self._value = self._factory()
self._value = None
def __read__(self, s):
'''
call factory and read it
"""
Call factory and write it
@param s: Stream
'''
"""
self._value = self._factory()
s.readType(self._value)
def __write__(self, s):
'''
call factory and write elements
"""
Call factory and read it
@param s: Stream
'''
"""
self._value = self._factory()
s.writeType(self._value)
def __getattr__(self, name):
"""
Magic function to be FactoryType as transparent as possible
@return: _value parameter
"""
return self._value.__getattribute__(name)
def __getitem__(self, item):
"""
Magic function to be FactoryType as transparent as possible
@return: index of _value
"""
return self._value.__getitem__(item)
def __sizeof__(self):
'''
sizeof of object returned by factory
'''
return sizeof(self._factory())
"""
Size of of object returned by factory
"""
return sizeof(self._value)
def CheckValueOnRead(cls):
'''
@@ -923,7 +936,7 @@ def CheckValueOnRead(cls):
def hexDump(src, length=16):
'''
print hex representation of sr
print hex representation of str
@param src: string
'''
FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or '.' for x in range(256)])

View File

@@ -269,9 +269,9 @@ class Capability(CompositeType):
return String(readLen = UInt16Le(lambda:self.lengthCapability.value - 4))
if capability is None:
capability = CapabilityFactory
capability = FactoryType(CapabilityFactory)
self.capability = FactoryType(capability)
self.capability = capability
class GeneralCapability(CompositeType):
"""

View File

@@ -22,7 +22,7 @@ RDP extended license
@see: http://msdn.microsoft.com/en-us/library/cc241880.aspx
"""
from rdpy.network.type import CompositeType, UInt8, UInt16Le, UInt32Le, String, sizeof
from rdpy.network.type import CompositeType, UInt8, UInt16Le, UInt32Le, String, sizeof, FactoryType, ArrayType
class MessageType(object):
"""
@@ -41,6 +41,7 @@ class MessageType(object):
class ErrorCode(object):
"""
License error message code
@see: http://msdn.microsoft.com/en-us/library/cc240482.aspx
"""
ERR_INVALID_SERVER_CERTIFICATE = 0x00000001
ERR_NO_LICENSE = 0x00000002
@@ -55,41 +56,163 @@ class ErrorCode(object):
class StateTransition(object):
"""
Automata state transition
@see: http://msdn.microsoft.com/en-us/library/cc240482.aspx
"""
ST_TOTAL_ABORT = 0x00000001
ST_NO_TRANSITION = 0x00000002
ST_RESET_PHASE_TO_START = 0x00000003
ST_RESEND_LAST_MESSAGE = 0x00000004
class LicenceBinaryBlob(CompositeType):
class BinaryBlobType(object):
"""
Blob use by license manager to echange security data
Binary blob data type
@see: http://msdn.microsoft.com/en-us/library/cc240481.aspx
"""
def __init__(self):
BB_DATA_BLOB = 0x0001
BB_RANDOM_BLOB = 0x0002
BB_CERTIFICATE_BLOB = 0x0003
BB_ERROR_BLOB = 0x0004
BB_ENCRYPTED_DATA_BLOB = 0x0009
BB_KEY_EXCHG_ALG_BLOB = 0x000D
BB_SCOPE_BLOB = 0x000E
BB_CLIENT_USER_NAME_BLOB = 0x000F
BB_CLIENT_MACHINE_NAME_BLOB = 0x0010
class LicenseBinaryBlob(CompositeType):
"""
Blob use by license manager to exchange security data
@see: http://msdn.microsoft.com/en-us/library/cc240481.aspx
"""
def __init__(self, blobType = 0):
CompositeType.__init__(self)
self.wBlobType = UInt16Le()
self.wBlobType = UInt16Le(blobType, constant = True)
self.wBlobLen = UInt16Le(lambda:sizeof(self.blobData))
self.blobData = String(readLen = self.wBlobLen, conditional = lambda:self.wBlobLen.value > 0)
self.blobData = String(readLen = self.wBlobLen)
class LicensingErrorMessage(CompositeType):
"""
License error message
@see: http://msdn.microsoft.com/en-us/library/cc240482.aspx
"""
def __init__(self, conditional = lambda:True):
CompositeType.__init__(self, conditional = conditional)
self.dwErrorCode = UInt32Le()
self.dwStateTransition = UInt32Le()
self.blob = LicenceBinaryBlob()
self.blob = LicenseBinaryBlob(BinaryBlobType.BB_ERROR_BLOB)
class ProductInformation(CompositeType):
"""
License server product information
@see: http://msdn.microsoft.com/en-us/library/cc241915.aspx
"""
def __init__(self):
CompositeType.__init__(self)
self.dwVersion = UInt32Le()
self.cbCompanyName = UInt32Le(lambda:sizeof(self.pbCompanyName))
#may contain "Microsoft Corporation" from server microsoft
self.pbCompanyName = String(readLen = self.cbCompanyName)
self.cbProductId = UInt32Le(lambda:sizeof(self.pbProductId))
#may contain "A02" from microsoft license server
self.pbProductId = String(readLen = self.cbProductId)
class Scope(CompositeType):
"""
Use in license nego
@see: http://msdn.microsoft.com/en-us/library/cc241917.aspx
"""
def __init__(self):
CompositeType.__init__(self)
self.scope = LicenseBinaryBlob(BinaryBlobType.BB_SCOPE_BLOB)
class ScopeList(CompositeType):
"""
Use in license nego
@see: http://msdn.microsoft.com/en-us/library/cc241916.aspx
"""
def __init__(self):
CompositeType.__init__(self)
self.scopeCount = UInt32Le(lambda:sizeof(self.scopeArray))
self.scopeArray = ArrayType(Scope, readLen = self.scopeCount)
class ServerLicenseRequest(CompositeType):
"""
Send by server to signal license request
server -> client
@see: http://msdn.microsoft.com/en-us/library/cc241914.aspx
"""
def __init__(self):
CompositeType.__init__(self)
self.serverRandom = String(readLen = UInt8(32))
self.productInfo = ProductInformation()
self.keyExchangeList = LicenseBinaryBlob(BinaryBlobType.BB_KEY_EXCHG_ALG_BLOB)
self.serverCertificate = LicenseBinaryBlob(BinaryBlobType.BB_CERTIFICATE_BLOB)
self.scopeList = ScopeList()
class ClientNewLicenseRequest(CompositeType):
"""
Send by client to ask new license for client.
RDPY doesn'support license reuse, need it in futur version
@see: http://msdn.microsoft.com/en-us/library/cc241918.aspx
"""
def __init__(self):
CompositeType.__init__(self)
#RSA and must be only RSA
self.preferredKeyExchangeAlg = UInt32Le(0x00000001, constant = True)
#pure microsoft client ;-)
#http://msdn.microsoft.com/en-us/library/1040af38-c733-4fb3-acd1-8db8cc979eda#id10
self.platformId = UInt32Le(0x04000000 | 0x00020000)
self.clientRandom = String("\x00" * 32)
self.encryptedPreMasterSecret = LicenseBinaryBlob(BinaryBlobType.BB_RANDOM_BLOB)
self.ClientUserName = LicenseBinaryBlob(BinaryBlobType.BB_CLIENT_USER_NAME_BLOB)
self.ClientMachineName = LicenseBinaryBlob(BinaryBlobType.BB_CLIENT_MACHINE_NAME_BLOB)
class LicPacket(CompositeType):
"""
A license packet
"""
def __init__(self):
def __init__(self, message = None):
CompositeType.__init__(self)
def MessageTypeFactory():
"""
Determine type in accordance of instance of licensingMessage type
Use in write mode
"""
if isinstance(self.licensingMessage, LicensingErrorMessage):
return MessageType.ERROR_ALERT
elif isinstance(self.licensingMessage, ServerLicenseRequest):
return MessageType.LICENSE_REQUEST
elif isinstance(self.licensingMessage, ClientNewLicenseRequest):
return MessageType.NEW_LICENSE_REQUEST
#preambule
self.bMsgtype = UInt8()
self.bMsgtype = UInt8(lambda:(MessageTypeFactory()))
self.flag = UInt8()
self.wMsgSize = UInt16Le(lambda: sizeof(self))
self.errorMessage = LicensingErrorMessage(conditional = lambda:self.bMsgtype.value == MessageType.ERROR_ALERT)
def LicensingMessageFactory():
"""
factory for message nego
Use in read mode
"""
if self.bMsgtype.value == MessageType.ERROR_ALERT:
return LicensingErrorMessage()
elif self.bMsgtype.value == MessageType.LICENSE_REQUEST:
return ServerLicenseRequest()
elif self.bMsgtype.value == MessageType.NEW_LICENSE_REQUEST:
ClientNewLicenseRequest()
if message is None:
message = FactoryType(LicensingMessageFactory)
self.licensingMessage = message
def createNewLicenseRequest(serverLicenseRequest):
"""
Create new license request in response to server license request
@see: http://msdn.microsoft.com/en-us/library/cc241989.aspx
@see: http://msdn.microsoft.com/en-us/library/cc241918.aspx
@todo: need RDP license server
"""
return LicPacket(message = ClientNewLicenseRequest())

View File

@@ -32,9 +32,24 @@ import gcc, lic, caps, tpkt
class SecurityFlag(object):
"""
Microsoft security flags
@see: http://msdn.microsoft.com/en-us/library/cc240579.aspx
"""
SEC_EXCHANGE_PKT = 0x0001
SEC_TRANSPORT_REQ = 0x0002
RDP_SEC_TRANSPORT_RSP = 0x0004
SEC_ENCRYPT = 0x0008
SEC_RESET_SEQNO = 0x0010
SEC_IGNORE_SEQNO = 0x0020
SEC_INFO_PKT = 0x0040
SEC_LICENSE_PKT = 0x0080
SEC_LICENSE_ENCRYPT_CS = 0x0200
SEC_LICENSE_ENCRYPT_SC = 0x0200
SEC_REDIRECTION_PKT = 0x0400
SEC_SECURE_CHECKSUM = 0x0800
SEC_AUTODETECT_REQ = 0x1000
SEC_AUTODETECT_RSP = 0x2000
SEC_HEARTBEAT = 0x4000
SEC_FLAGSHI_VALID = 0x8000
class InfoFlag(object):
"""
@@ -635,9 +650,9 @@ class DataPDU(CompositeType):
return String()
if pduData is None:
pduData = PDUDataFactory
pduData = FactoryType(PDUDataFactory)
self.pduData = FactoryType(pduData)
self.pduData = pduData
class SynchronizeDataPDU(CompositeType):
"""
@@ -737,9 +752,9 @@ class UpdateDataPDU(CompositeType):
return String()
if updateData is None:
updateData = UpdateDataFactory
updateData = FactoryType(UpdateDataFactory, conditional = lambda:(self.updateType.value != UpdateType.UPDATETYPE_SYNCHRONIZE))
self.updateData = FactoryType(updateData, conditional = lambda:(self.updateType.value != UpdateType.UPDATETYPE_SYNCHRONIZE))
self.updateData = updateData
class FastPathUpdatePDU(CompositeType):
"""
@@ -766,9 +781,9 @@ class FastPathUpdatePDU(CompositeType):
return String()
if updateData is None:
updateData = UpdateDataFactory
updateData = FactoryType(UpdateDataFactory)
self.updateData = FactoryType(updateData)
self.updateData = updateData
class SynchronizeUpdatePDU(CompositeType):
"""
@@ -876,26 +891,21 @@ 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
self.messageType = UInt16Le(lambda:MessageTypeFactory(self.slowPathInputData._value))
self.messageType = UInt16Le(lambda:MessageTypeFactory(self.slowPathInputData))
def SlowPathInputDataFactory():
if self.messageType.value == InputMessageType.INPUT_EVENT_MOUSE:
return PointerEvent()
if messageData is None:
messageData = SlowPathInputDataFactory
messageData = FactoryType(SlowPathInputDataFactory)
self.slowPathInputData = FactoryType(messageData)
self.slowPathInputData = messageData
class PointerEvent(CompositeType):
"""
@@ -935,7 +945,13 @@ class PDUClientListener(object):
"""
Interface for PDU client automata listener
"""
def recvBitmapUpdateDataPDU(self, rectangles):
def onReady(self):
"""
Event call when PDU layer is ready to send events
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "PDUClientListener"))
def onUpdate(self, rectangles):
"""
call when a bitmap data is received from update PDU
@param rectangles: [pdu.BitmapData] struct
@@ -1012,9 +1028,6 @@ class PDU(LayerAutomata, tpkt.FastPathListener):
#share id between client and server
self._shareId = 0
#determine if layer is connected
self._isConnected = False
def connect(self):
"""
Connect event in client mode send logon info
@@ -1043,6 +1056,7 @@ class PDU(LayerAutomata, tpkt.FastPathListener):
Read license info packet and check if is a valid client info
@param data: Stream
"""
#license preambule
securityFlag = UInt16Le()
securityFlagHi = UInt16Le()
data.readType((securityFlag, securityFlagHi))
@@ -1053,13 +1067,14 @@ class PDU(LayerAutomata, tpkt.FastPathListener):
validClientPdu = lic.LicPacket()
data.readType(validClientPdu)
if not validClientPdu.errorMessage._is_readed:
raise InvalidExpectedDataException("Waiting valid client PDU : rdpy doesn't support licensing nego")
if not (validClientPdu.errorMessage.dwErrorCode.value == lic.ErrorCode.STATUS_VALID_CLIENT and validClientPdu.errorMessage.dwStateTransition.value == lic.StateTransition.ST_NO_TRANSITION):
raise InvalidExpectedDataException("Server refuse licensing negotiation")
self.setNextState(self.recvDemandActivePDU)
if validClientPdu.bMsgtype.value == lic.MessageType.ERROR_ALERT and validClientPdu.licensingMessage.dwErrorCode.value == lic.ErrorCode.STATUS_VALID_CLIENT and validClientPdu.licensingMessage.dwStateTransition.value == lic.StateTransition.ST_NO_TRANSITION:
self.setNextState(self.recvDemandActivePDU)
#not tested because i can't buy RDP license server
elif validClientPdu.bMsgtype.value == lic.MessageType.LICENSE_REQUEST:
newLicenseReq = lic.createNewLicenseRequest(validClientPdu.licensingMessage)
self._transport.send((UInt16Le(SecurityFlag.SEC_LICENSE_PKT), UInt16Le(), newLicenseReq))
else:
raise InvalidExpectedDataException("Not a valid license packet")
def readDataPDU(self, data):
"""
@@ -1073,9 +1088,9 @@ class PDU(LayerAutomata, tpkt.FastPathListener):
if dataPDU.shareDataHeader.pduType2.value != PDUType2.PDUTYPE2_SET_ERROR_INFO_PDU:
return dataPDU
message = "Unknown code %s"%hex(dataPDU.pduData._value.errorInfo.value)
if ErrorInfo._MESSAGES_.has_key(dataPDU.pduData._value.errorInfo):
message = ErrorInfo._MESSAGES_[dataPDU.pduData._value.errorInfo]
message = "Unknown code %s"%hex(dataPDU.pduData.errorInfo.value)
if ErrorInfo._MESSAGES_.has_key(dataPDU.pduData.errorInfo):
message = ErrorInfo._MESSAGES_[dataPDU.pduData.errorInfo]
raise ErrorReportedFromPeer("Receive PDU Error info : %s"%message)
@@ -1114,7 +1129,7 @@ class PDU(LayerAutomata, tpkt.FastPathListener):
@param data: Stream from transport layer
"""
dataPDU = self.readDataPDU(data)
if dataPDU.shareDataHeader.pduType2.value != PDUType2.PDUTYPE2_CONTROL or dataPDU.pduData._value.action.value != Action.CTRLACTION_COOPERATE:
if dataPDU.shareDataHeader.pduType2.value != PDUType2.PDUTYPE2_CONTROL or dataPDU.pduData.action.value != Action.CTRLACTION_COOPERATE:
raise InvalidExpectedDataException("Error in PDU layer automata : expected controlCooperatePDU")
self.setNextState(self.recvServerControlGrantedPDU)
@@ -1124,7 +1139,7 @@ class PDU(LayerAutomata, tpkt.FastPathListener):
@param data: Stream from transport layer
"""
dataPDU = self.readDataPDU(data)
if dataPDU.shareDataHeader.pduType2.value != PDUType2.PDUTYPE2_CONTROL or dataPDU.pduData._value.action.value != Action.CTRLACTION_GRANTED_CONTROL:
if dataPDU.shareDataHeader.pduType2.value != PDUType2.PDUTYPE2_CONTROL or dataPDU.pduData.action.value != Action.CTRLACTION_GRANTED_CONTROL:
raise InvalidExpectedDataException("Error in PDU layer automata : expected controlGrantedPDU")
self.setNextState(self.recvServerFontMapPDU)
@@ -1138,7 +1153,7 @@ class PDU(LayerAutomata, tpkt.FastPathListener):
raise InvalidExpectedDataException("Error in PDU layer automata : expected fontMapPDU")
#here i'm connected
self._isConnected = True
self._clientListener.onReady()
self.setNextState(self.recvDataPDU)
def recvDataPDU(self, data):
@@ -1147,8 +1162,8 @@ class PDU(LayerAutomata, tpkt.FastPathListener):
@param data: Stream from transport layer
"""
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)
if dataPDU.shareDataHeader.pduType2.value == PDUType2.PDUTYPE2_UPDATE and dataPDU.pduData.updateType.value == UpdateType.UPDATETYPE_BITMAP:
self._clientListener.onUpdate(dataPDU.pduData.updateData.rectangles._array)
def recvFastPath(self, fastPathData):
"""
@@ -1159,30 +1174,30 @@ class PDU(LayerAutomata, tpkt.FastPathListener):
fastPathPDU = FastPathUpdatePDU()
fastPathData.readType(fastPathPDU)
if fastPathPDU.updateHeader.value == FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP:
self._clientListener.recvBitmapUpdateDataPDU(fastPathPDU.updateData._value[1].rectangles._array)
self._clientListener.onUpdate(fastPathPDU.updateData[1].rectangles._array)
def sendConfirmActivePDU(self):
"""
Send all client capabilities
"""
#init general capability
generalCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability._value
generalCapability = self._clientCapabilities[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
#init bitmap capability
bitmapCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_BITMAP].capability._value
bitmapCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_BITMAP].capability
bitmapCapability.preferredBitsPerPixel = self._transport.getGCCClientSettings().core.highColorDepth
bitmapCapability.desktopWidth = self._transport.getGCCClientSettings().core.desktopWidth
bitmapCapability.desktopHeight = self._transport.getGCCClientSettings().core.desktopHeight
#init order capability
orderCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_ORDER].capability._value
orderCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_ORDER].capability
orderCapability.orderFlags.value |= caps.OrderFlag.ZEROBOUNDSDELTASSUPPORT
#init input capability
inputCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_INPUT].capability._value
inputCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_INPUT].capability
inputCapability.inputFlags.value = caps.InputFlags.INPUT_FLAG_SCANCODES | caps.InputFlags.INPUT_FLAG_MOUSEX | caps.InputFlags.INPUT_FLAG_UNICODE
inputCapability.keyboardLayout = self._transport.getGCCClientSettings().core.kbdLayout
inputCapability.keyboardType = self._transport.getGCCClientSettings().core.keyboardType

View File

@@ -45,6 +45,9 @@ class RDPClientController(pdu.PDUClientListener):
#transport packet (protocol layer)
self._tpktLayer = tpkt.TPKT(self._tpduLayer, self._pduLayer)
#is pdu layer is ready to send
self._isReady = False
def getProtocol(self):
"""
@return: return Protocol layer for twisted
@@ -92,21 +95,30 @@ class RDPClientController(pdu.PDUClientListener):
def addClientObserver(self, observer):
"""
add observer to RDP protocol
Add observer to RDP protocol
@param observer: new observer to add
"""
self._clientObserver.append(observer)
observer._clientListener = self
def recvBitmapUpdateDataPDU(self, rectangles):
def onUpdate(self, rectangles):
"""
call when a bitmap data is received from update PDU
Call when a bitmap data is received from update PDU
@param rectangles: [pdu.BitmapData] struct
"""
for observer in self._clientObserver:
#for each rectangle in update PDU
for rectangle in rectangles:
observer.onBitmapUpdate(rectangle.destLeft.value, rectangle.destTop.value, rectangle.destRight.value, rectangle.destBottom.value, rectangle.width.value, rectangle.height.value, rectangle.bitsPerPixel.value, rectangle.flags.value & pdu.BitmapFlag.BITMAP_COMPRESSION, rectangle.bitmapDataStream.value)
observer.onUpdate(rectangle.destLeft.value, rectangle.destTop.value, rectangle.destRight.value, rectangle.destBottom.value, rectangle.width.value, rectangle.height.value, rectangle.bitsPerPixel.value, rectangle.flags.value & pdu.BitmapFlag.BITMAP_COMPRESSION, rectangle.bitmapDataStream.value)
def onReady(self):
"""
Call when PDU layer is connected
"""
self._isReady = True
#signal all listener
for observer in self._clientObserver:
observer.onReady()
def sendPointerEvent(self, x, y, button, isPressed):
"""
@@ -116,7 +128,7 @@ class RDPClientController(pdu.PDUClientListener):
@param button: 1 or 2 or 3
@param isPressed: true if button is pressed or false if it's released
"""
if not self._pduLayer._isConnected:
if not self._isReady:
return
try:
@@ -149,7 +161,7 @@ class RDPClientController(pdu.PDUClientListener):
@param code: scan code
@param isPressed: True if key is pressed and false if it's released
"""
if not self._pduLayer._isConnected:
if not self._isReady:
return
try:
@@ -172,7 +184,7 @@ class RDPClientController(pdu.PDUClientListener):
@param code: unicode
@param isPressed: True if key is pressed and false if it's released
"""
if not self._pduLayer._isConnected:
if not self._isReady:
return
try:
@@ -271,8 +283,13 @@ class RDPClientObserver(object):
self._controller = controller
self._controller.addClientObserver(self)
def onReady(self):
"""
Stack is ready and connected
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "RDPClientObserver"))
def onBitmapUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
"""
Notify bitmap update
@param destLeft: xmin position
@@ -285,4 +302,4 @@ class RDPClientObserver(object):
@param isCompress: use RLE compression
@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__, "onUpdate", "RDPClientObserver"))

View File

@@ -140,8 +140,7 @@ class TPDU(LayerAutomata, StreamSender):
def connect(self):
"""
connection request
for client send a connection request packet
Connection request for client send a connection request packet
"""
if self._mode == LayerMode.CLIENT:
self.sendConnectionRequest()
@@ -150,9 +149,9 @@ class TPDU(LayerAutomata, StreamSender):
def recvConnectionConfirm(self, data):
"""
receive connection confirm message
next state is recvData
call connect on presentation layer if all is good
Receive connection confirm message
Next state is recvData
Call connect on presentation layer if all is good
@param data: Stream that contain connection confirm
@see: response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx
@see: failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx
@@ -170,14 +169,16 @@ class TPDU(LayerAutomata, StreamSender):
self._selectedProtocol = message.protocolNeg.selectedProtocol.value
if self._selectedProtocol != Protocols.PROTOCOL_SSL:
raise InvalidExpectedDataException("only ssl protocol is supported in RDPY version")
raise InvalidExpectedDataException("only SSL protocol is supported in RDPY version")
#_transport is TPKT and transport is TCP layer of twisted
self._transport.transport.startTLS(ClientTLSContext())
#now i'm ready to receive data
self.setNextState(self.recvData)
#connection is done send to presentation
self._presentation.connect(self)
self._presentation.connect()
def recvConnectionRequest(self, data):
"""

View File

@@ -162,7 +162,7 @@ class RDPClientQt(RDPClientObserver, QAdaptor):
"""
self._controller.sendKeyEventUnicode(ord(unicode(e.text().toUtf8(), encoding="UTF-8")), isPressed)
def onBitmapUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
"""
Notify bitmap update
@param destLeft: xmin position
@@ -207,8 +207,19 @@ class RDPClientQt(RDPClientObserver, QAdaptor):
print "Receive image in bad format"
return
#if image need to be cut
#For bit alignement server may send more than image pixel
if width != destRight - destLeft + 1 or height != destBottom - destTop + 1:
image = image.copy(0, 0, destRight - destLeft + 1, destBottom - destTop + 1)
self._widget.notifyImage(destLeft, destTop, image)
def onReady(self):
"""
Call when stack is ready
"""
#do something maybe a loader
pass
class QRemoteDesktop(QtGui.QWidget):
"""
@@ -225,7 +236,7 @@ class QRemoteDesktop(QtGui.QWidget):
#because we can update image only in paint
#event function. When protocol receive image
#we will stock into refresh list
#and in paiont event paint list of all refresh images
#and in paint event paint list of all refresh images
self._refresh = []
#bind mouse event
self.setMouseTracking(True)