fix bug + more license automata
This commit is contained in:
@@ -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)])
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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())
|
||||
@@ -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
|
||||
@@ -1011,9 +1027,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):
|
||||
"""
|
||||
@@ -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
|
||||
|
||||
@@ -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 onBitmapUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
|
||||
def onReady(self):
|
||||
"""
|
||||
Stack is ready and connected
|
||||
"""
|
||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "RDPClientObserver"))
|
||||
|
||||
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"))
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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,7 +207,18 @@ 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)
|
||||
|
||||
Reference in New Issue
Block a user