bug fix + finish proxy
This commit is contained in:
@@ -138,5 +138,4 @@ if __name__ == '__main__':
|
|||||||
from twisted.internet import reactor
|
from twisted.internet import reactor
|
||||||
reactor.connectTCP(ip, int(port), RDPClientQtFactory(width, height, username, password, domain))
|
reactor.connectTCP(ip, int(port), RDPClientQtFactory(width, height, username, password, domain))
|
||||||
reactor.runReturn()
|
reactor.runReturn()
|
||||||
app.exec_()
|
app.exec_()
|
||||||
reactor.stop()
|
|
||||||
@@ -21,8 +21,6 @@
|
|||||||
"""
|
"""
|
||||||
RDP proxy recorder and spyer
|
RDP proxy recorder and spyer
|
||||||
Proxy RDP protocol
|
Proxy RDP protocol
|
||||||
With admin account you can watch all currently session
|
|
||||||
For special session you can record
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys, os
|
import sys, os
|
||||||
@@ -43,14 +41,6 @@ class ProxyServer(rdp.RDPServerObserver):
|
|||||||
rdp.RDPServerObserver.__init__(self, controller)
|
rdp.RDPServerObserver.__init__(self, controller)
|
||||||
self._client = None
|
self._client = None
|
||||||
|
|
||||||
def onReady(self):
|
|
||||||
"""
|
|
||||||
Event use to inform state of server stack
|
|
||||||
Use to connect client
|
|
||||||
"""
|
|
||||||
width, height = self._controller.getScreen()
|
|
||||||
reactor.connectTCP("wav-glw-013", 3389, ProxyClientFactory(self, width, height))
|
|
||||||
|
|
||||||
def clientConnected(self, client):
|
def clientConnected(self, client):
|
||||||
"""
|
"""
|
||||||
Event throw by client when it's ready
|
Event throw by client when it's ready
|
||||||
@@ -58,6 +48,52 @@ class ProxyServer(rdp.RDPServerObserver):
|
|||||||
"""
|
"""
|
||||||
self._client = client
|
self._client = client
|
||||||
self._controller.setColorDepth(self._client._controller.getColorDepth())
|
self._controller.setColorDepth(self._client._controller.getColorDepth())
|
||||||
|
|
||||||
|
def onReady(self):
|
||||||
|
"""
|
||||||
|
Event use to inform state of server stack
|
||||||
|
Use to connect client
|
||||||
|
"""
|
||||||
|
width, height = self._controller.getScreen()
|
||||||
|
reactor.connectTCP("si-hyperv-002", 3389, ProxyClientFactory(self, width, height))
|
||||||
|
|
||||||
|
def onKeyEventScancode(self, code, isPressed):
|
||||||
|
"""
|
||||||
|
Event call when a keyboard event is catch in scan code format
|
||||||
|
@param code: scan code of key
|
||||||
|
@param isPressed: True if key is down
|
||||||
|
"""
|
||||||
|
#no client connected
|
||||||
|
if self._client is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._client._controller.sendKeyEventScancode(code, isPressed)
|
||||||
|
|
||||||
|
def onKeyEventUnicode(self, code, isPressed):
|
||||||
|
"""
|
||||||
|
Event call when a keyboard event is catch in unicode format
|
||||||
|
@param code: unicode of key
|
||||||
|
@param isPressed: True if key is down
|
||||||
|
"""
|
||||||
|
#no client connected
|
||||||
|
if self._client is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._client._controller.sendKeyEventUnicode(code, isPressed)
|
||||||
|
|
||||||
|
def onPointerEvent(self, x, y, button, isPressed):
|
||||||
|
"""
|
||||||
|
Event call on mouse event
|
||||||
|
@param x: x position
|
||||||
|
@param y: y position
|
||||||
|
@param button: 1, 2 or 3 button
|
||||||
|
@param isPressed: True if mouse button is pressed
|
||||||
|
"""
|
||||||
|
#no client connected
|
||||||
|
if self._client is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._client._controller.sendPointerEvent(x, y, button, isPressed)
|
||||||
|
|
||||||
class ProxyClient(rdp.RDPClientObserver):
|
class ProxyClient(rdp.RDPClientObserver):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -151,6 +151,12 @@ class RawLayer(protocol.Protocol, LayerAutomata, StreamSender):
|
|||||||
"""
|
"""
|
||||||
#join two scheme
|
#join two scheme
|
||||||
self.connect()
|
self.connect()
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
"""
|
||||||
|
Close raw layer
|
||||||
|
"""
|
||||||
|
self.transport.loseConnection()
|
||||||
|
|
||||||
def expect(self, expectedLen, callback = None):
|
def expect(self, expectedLen, callback = None):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -240,8 +240,8 @@ class ClientCoreData(CompositeType):
|
|||||||
self.postBeta2ColorDepth = UInt16Le(ColorDepth.RNS_UD_COLOR_8BPP)
|
self.postBeta2ColorDepth = UInt16Le(ColorDepth.RNS_UD_COLOR_8BPP)
|
||||||
self.clientProductId = UInt16Le(1)
|
self.clientProductId = UInt16Le(1)
|
||||||
self.serialNumber = UInt32Le(0)
|
self.serialNumber = UInt32Le(0)
|
||||||
self.highColorDepth = UInt16Le(HighColor.HIGH_COLOR_15BPP)
|
self.highColorDepth = UInt16Le(HighColor.HIGH_COLOR_24BPP)
|
||||||
self.supportedColorDepths = UInt16Le(Support.RNS_UD_15BPP_SUPPORT)
|
self.supportedColorDepths = UInt16Le(Support.RNS_UD_15BPP_SUPPORT | Support.RNS_UD_16BPP_SUPPORT | Support.RNS_UD_24BPP_SUPPORT | Support.RNS_UD_32BPP_SUPPORT)
|
||||||
self.earlyCapabilityFlags = UInt16Le(CapabilityFlags.RNS_UD_CS_SUPPORT_ERRINFO_PDU)
|
self.earlyCapabilityFlags = UInt16Le(CapabilityFlags.RNS_UD_CS_SUPPORT_ERRINFO_PDU)
|
||||||
self.clientDigProductId = String("\x00"*64, readLen = UInt8(64))
|
self.clientDigProductId = String("\x00"*64, readLen = UInt8(64))
|
||||||
self.connectionType = UInt8()
|
self.connectionType = UInt8()
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ 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, StreamSender, Layer
|
from rdpy.network.layer import LayerAutomata, StreamSender, Layer
|
||||||
from rdpy.network.type import sizeof, Stream, UInt8, UInt16Le
|
from rdpy.network.type import sizeof, Stream, UInt8, UInt16Le, String
|
||||||
from rdpy.base.error import InvalidExpectedDataException, InvalidValue, InvalidSize
|
from rdpy.base.error import InvalidExpectedDataException, InvalidValue, InvalidSize
|
||||||
from rdpy.protocol.rdp.ber import writeLength
|
from rdpy.protocol.rdp.ber import writeLength
|
||||||
import rdpy.base.log as log
|
import rdpy.base.log as log
|
||||||
@@ -137,6 +137,14 @@ class MCSLayer(LayerAutomata):
|
|||||||
#receive opcode
|
#receive opcode
|
||||||
self._receiveOpcode = receiveOpcode
|
self._receiveOpcode = receiveOpcode
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
"""
|
||||||
|
Send disconnect provider ultimatum
|
||||||
|
"""
|
||||||
|
self._transport.send((UInt8(self.writeMCSPDUHeader(DomainMCSPDU.DISCONNECT_PROVIDER_ULTIMATUM, 1)),
|
||||||
|
per.writeEnumerates(0x80), String("\x00" * 6)))
|
||||||
|
self._transport.close()
|
||||||
|
|
||||||
def allChannelConnected(self):
|
def allChannelConnected(self):
|
||||||
"""
|
"""
|
||||||
All channels are connected to MCS layer
|
All channels are connected to MCS layer
|
||||||
|
|||||||
@@ -783,8 +783,8 @@ class ClientInputEventPDU(CompositeType):
|
|||||||
|
|
||||||
class ShutdownRequestPDU(CompositeType):
|
class ShutdownRequestPDU(CompositeType):
|
||||||
"""
|
"""
|
||||||
PDU use to signal that the session will be closzed are connected
|
PDU use to signal that the session will be closed
|
||||||
server -> client
|
client -> server
|
||||||
"""
|
"""
|
||||||
_PDUTYPE2_ = PDUType2.PDUTYPE2_SHUTDOWN_REQUEST
|
_PDUTYPE2_ = PDUType2.PDUTYPE2_SHUTDOWN_REQUEST
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -792,7 +792,7 @@ class ShutdownRequestPDU(CompositeType):
|
|||||||
|
|
||||||
class ShutdownDeniedPDU(CompositeType):
|
class ShutdownDeniedPDU(CompositeType):
|
||||||
"""
|
"""
|
||||||
PDU use to signal that the session will be closzed are connected
|
PDU use to signal which the session will be closed is connected
|
||||||
server -> client
|
server -> client
|
||||||
"""
|
"""
|
||||||
_PDUTYPE2_ = PDUType2.PDUTYPE2_SHUTDOWN_DENIED
|
_PDUTYPE2_ = PDUType2.PDUTYPE2_SHUTDOWN_DENIED
|
||||||
@@ -842,17 +842,17 @@ class FastPathUpdatePDU(CompositeType):
|
|||||||
CompositeType.__init__(self)
|
CompositeType.__init__(self)
|
||||||
self.updateHeader = UInt8(lambda:updateData.__class__._FASTPATH_UPDATE_TYPE_)
|
self.updateHeader = UInt8(lambda:updateData.__class__._FASTPATH_UPDATE_TYPE_)
|
||||||
self.compressionFlags = UInt8(conditional = lambda:((self.updateHeader.value >> 4) & FastPathOutputCompression.FASTPATH_OUTPUT_COMPRESSION_USED))
|
self.compressionFlags = UInt8(conditional = lambda:((self.updateHeader.value >> 4) & FastPathOutputCompression.FASTPATH_OUTPUT_COMPRESSION_USED))
|
||||||
self.size = UInt16Le()
|
self.size = UInt16Le(lambda:sizeof(self.updateData))
|
||||||
|
|
||||||
def UpdateDataFactory():
|
def UpdateDataFactory():
|
||||||
"""
|
"""
|
||||||
Create correct object in accordance to self.updateHeader field
|
Create correct object in accordance to self.updateHeader field
|
||||||
"""
|
"""
|
||||||
if (self.updateHeader.value & 0xf) == FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP:
|
for c in [FastPathBitmapUpdateDataPDU]:
|
||||||
return (UInt16Le(FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP, constant = True), BitmapUpdateDataPDU(readLen = self.size - 2))
|
if (self.updateHeader.value & 0xf) == c._FASTPATH_UPDATE_TYPE_:
|
||||||
else:
|
return c()
|
||||||
log.debug("unknown Fast Path PDU update data type : %s"%hex(self.updateHeader.value & 0xf))
|
log.debug("unknown Fast Path PDU update data type : %s"%hex(self.updateHeader.value & 0xf))
|
||||||
return String()
|
return String()
|
||||||
|
|
||||||
if updateData is None:
|
if updateData is None:
|
||||||
updateData = FactoryType(UpdateDataFactory)
|
updateData = FactoryType(UpdateDataFactory)
|
||||||
@@ -867,7 +867,6 @@ class BitmapUpdateDataPDU(CompositeType):
|
|||||||
@see: http://msdn.microsoft.com/en-us/library/dd306368.aspx
|
@see: http://msdn.microsoft.com/en-us/library/dd306368.aspx
|
||||||
"""
|
"""
|
||||||
_UPDATE_TYPE_ = UpdateType.UPDATETYPE_BITMAP
|
_UPDATE_TYPE_ = UpdateType.UPDATETYPE_BITMAP
|
||||||
_FASTPATH_UPDATE_TYPE_ = FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP
|
|
||||||
|
|
||||||
def __init__(self, readLen = None):
|
def __init__(self, readLen = None):
|
||||||
"""
|
"""
|
||||||
@@ -946,7 +945,20 @@ class BitmapData(CompositeType):
|
|||||||
self.bitmapLength = UInt16Le(lambda:(sizeof(self.bitmapComprHdr) + sizeof(self.bitmapDataStream)))
|
self.bitmapLength = UInt16Le(lambda:(sizeof(self.bitmapComprHdr) + sizeof(self.bitmapDataStream)))
|
||||||
self.bitmapComprHdr = BitmapCompressedDataHeader(bodySize = lambda:sizeof(self.bitmapDataStream), scanWidth = lambda:self.width.value, uncompressedSize = lambda:(self.width.value * self.height.value * self.bitsPerPixel.value), conditional = lambda:((self.flags.value | BitmapFlag.BITMAP_COMPRESSION) and not (self.flags.value | BitmapFlag.NO_BITMAP_COMPRESSION_HDR)))
|
self.bitmapComprHdr = BitmapCompressedDataHeader(bodySize = lambda:sizeof(self.bitmapDataStream), scanWidth = lambda:self.width.value, uncompressedSize = lambda:(self.width.value * self.height.value * self.bitsPerPixel.value), conditional = lambda:((self.flags.value | BitmapFlag.BITMAP_COMPRESSION) and not (self.flags.value | BitmapFlag.NO_BITMAP_COMPRESSION_HDR)))
|
||||||
self.bitmapDataStream = String(bitmapDataStream, readLen = UInt16Le(lambda:(self.bitmapLength.value if (self.flags.value | BitmapFlag.NO_BITMAP_COMPRESSION_HDR) else self.bitmapComprHdr.cbCompMainBodySize.value)))
|
self.bitmapDataStream = String(bitmapDataStream, readLen = UInt16Le(lambda:(self.bitmapLength.value if (self.flags.value | BitmapFlag.NO_BITMAP_COMPRESSION_HDR) else self.bitmapComprHdr.cbCompMainBodySize.value)))
|
||||||
|
|
||||||
|
class FastPathBitmapUpdateDataPDU(CompositeType):
|
||||||
|
"""
|
||||||
|
Fast path version of bitmap update PDU
|
||||||
|
@see: http://msdn.microsoft.com/en-us/library/dd306368.aspx
|
||||||
|
"""
|
||||||
|
_FASTPATH_UPDATE_TYPE_ = FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
CompositeType.__init__(self)
|
||||||
|
self.header = UInt16Le(FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP, constant = True)
|
||||||
|
self.numberRectangles = UInt16Le(lambda:len(self.rectangles._array))
|
||||||
|
self.rectangles = ArrayType(BitmapData, readLen = self.numberRectangles)
|
||||||
|
|
||||||
class SlowPathInputEvent(CompositeType):
|
class SlowPathInputEvent(CompositeType):
|
||||||
"""
|
"""
|
||||||
PDU use in slow-path sending client inputs
|
PDU use in slow-path sending client inputs
|
||||||
|
|||||||
@@ -64,6 +64,12 @@ class PDUServerListener(object):
|
|||||||
"""
|
"""
|
||||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "PDUServerListener"))
|
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "PDUServerListener"))
|
||||||
|
|
||||||
|
def onSlowPathInput(self, slowPathInputEvents):
|
||||||
|
"""
|
||||||
|
Event call when slow path input are available
|
||||||
|
@param slowPathInputEvents: [data.SlowPathInputEvent]
|
||||||
|
"""
|
||||||
|
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onSlowPathInput", "PDUServerListener"))
|
||||||
|
|
||||||
class PDULayer(LayerAutomata):
|
class PDULayer(LayerAutomata):
|
||||||
"""
|
"""
|
||||||
@@ -128,6 +134,8 @@ class Client(PDULayer, tpkt.FastPathListener):
|
|||||||
"""
|
"""
|
||||||
PDULayer.__init__(self)
|
PDULayer.__init__(self)
|
||||||
self._listener = listener
|
self._listener = listener
|
||||||
|
#enable or not fast path
|
||||||
|
self._fastPathSender = None
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
"""
|
"""
|
||||||
@@ -138,12 +146,22 @@ class Client(PDULayer, tpkt.FastPathListener):
|
|||||||
self.sendInfoPkt()
|
self.sendInfoPkt()
|
||||||
#next state is license info PDU
|
#next state is license info PDU
|
||||||
self.setNextState(self.recvLicenceInfo)
|
self.setNextState(self.recvLicenceInfo)
|
||||||
|
#check if client support fast path message
|
||||||
|
self._clientFastPathSupported = False
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""
|
"""
|
||||||
Send PDU close packet and call close method on transport method
|
Send PDU close packet and call close method on transport method
|
||||||
"""
|
"""
|
||||||
self.sendDataPDU(data.ShutdownRequestPDU())
|
self._transport.close()
|
||||||
|
#self.sendDataPDU(data.ShutdownRequestPDU())
|
||||||
|
|
||||||
|
def setFastPathSender(self, fastPathSender):
|
||||||
|
"""
|
||||||
|
@param fastPathSender: tpkt.FastPathSender
|
||||||
|
@note: implement tpkt.FastPathListener
|
||||||
|
"""
|
||||||
|
self._fastPathSender = fastPathSender
|
||||||
|
|
||||||
def recvLicenceInfo(self, s):
|
def recvLicenceInfo(self, s):
|
||||||
"""
|
"""
|
||||||
@@ -290,7 +308,7 @@ class Client(PDULayer, tpkt.FastPathListener):
|
|||||||
fastPathPDU = data.FastPathUpdatePDU()
|
fastPathPDU = data.FastPathUpdatePDU()
|
||||||
fastPathS.readType(fastPathPDU)
|
fastPathS.readType(fastPathPDU)
|
||||||
if fastPathPDU.updateHeader.value == data.FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP:
|
if fastPathPDU.updateHeader.value == data.FastPathUpdateType.FASTPATH_UPDATETYPE_BITMAP:
|
||||||
self._listener.onUpdate(fastPathPDU.updateData[1].rectangles._array)
|
self._listener.onUpdate(fastPathPDU.updateData.rectangles._array)
|
||||||
|
|
||||||
def readDataPDU(self, dataPDU):
|
def readDataPDU(self, dataPDU):
|
||||||
"""
|
"""
|
||||||
@@ -333,7 +351,9 @@ class Client(PDULayer, tpkt.FastPathListener):
|
|||||||
generalCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability
|
generalCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability
|
||||||
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 | caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED
|
generalCapability.extraFlags.value = caps.GeneralExtraFlag.LONG_CREDENTIALS_SUPPORTED | caps.GeneralExtraFlag.NO_BITMAP_COMPRESSION_HDR
|
||||||
|
if not self._fastPathSender is None:
|
||||||
|
generalCapability.extraFlags.value |= caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED
|
||||||
|
|
||||||
#init bitmap capability
|
#init bitmap capability
|
||||||
bitmapCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_BITMAP].capability
|
bitmapCapability = self._clientCapabilities[caps.CapsType.CAPSTYPE_BITMAP].capability
|
||||||
@@ -390,7 +410,7 @@ class Client(PDULayer, tpkt.FastPathListener):
|
|||||||
pdu.slowPathInputEvents._array = [data.SlowPathInputEvent(x) for x in pointerEvents]
|
pdu.slowPathInputEvents._array = [data.SlowPathInputEvent(x) for x in pointerEvents]
|
||||||
self.sendDataPDU(pdu)
|
self.sendDataPDU(pdu)
|
||||||
|
|
||||||
class Server(PDULayer):
|
class Server(PDULayer, tpkt.FastPathListener):
|
||||||
"""
|
"""
|
||||||
Server Automata of PDU layer
|
Server Automata of PDU layer
|
||||||
"""
|
"""
|
||||||
@@ -400,6 +420,8 @@ class Server(PDULayer):
|
|||||||
"""
|
"""
|
||||||
PDULayer.__init__(self)
|
PDULayer.__init__(self)
|
||||||
self._listener = listener
|
self._listener = listener
|
||||||
|
#fast path layer
|
||||||
|
self._fastPathSender = None
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
"""
|
"""
|
||||||
@@ -408,6 +430,13 @@ class Server(PDULayer):
|
|||||||
"""
|
"""
|
||||||
self.setNextState(self.recvInfoPkt)
|
self.setNextState(self.recvInfoPkt)
|
||||||
|
|
||||||
|
def setFastPathSender(self, fastPathSender):
|
||||||
|
"""
|
||||||
|
@param fastPathSender: tpkt.FastPathSender
|
||||||
|
@note: implement tpkt.FastPathListener
|
||||||
|
"""
|
||||||
|
self._fastPathSender = fastPathSender
|
||||||
|
|
||||||
def recvInfoPkt(self, s):
|
def recvInfoPkt(self, s):
|
||||||
"""
|
"""
|
||||||
Receive info packet from client
|
Receive info packet from client
|
||||||
@@ -449,6 +478,9 @@ class Server(PDULayer):
|
|||||||
for cap in pdu.pduMessage.capabilitySets._array:
|
for cap in pdu.pduMessage.capabilitySets._array:
|
||||||
self._clientCapabilities[cap.capabilitySetType] = cap
|
self._clientCapabilities[cap.capabilitySetType] = cap
|
||||||
|
|
||||||
|
#find use full flag
|
||||||
|
self._clientFastPathSupported = self._clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability.extraFlags.value & caps.GeneralExtraFlag.FASTPATH_OUTPUT_SUPPORTED
|
||||||
|
|
||||||
self.setNextState(self.recvClientSynchronizePDU)
|
self.setNextState(self.recvClientSynchronizePDU)
|
||||||
|
|
||||||
def recvClientSynchronizePDU(self, s):
|
def recvClientSynchronizePDU(self, s):
|
||||||
@@ -538,6 +570,18 @@ class Server(PDULayer):
|
|||||||
errorMessage = data.ErrorInfo._MESSAGES_[dataPDU.pduData.errorInfo]
|
errorMessage = data.ErrorInfo._MESSAGES_[dataPDU.pduData.errorInfo]
|
||||||
|
|
||||||
log.error("INFO PDU : %s"%errorMessage)
|
log.error("INFO PDU : %s"%errorMessage)
|
||||||
|
elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_INPUT:
|
||||||
|
self._listener.onSlowPathInput(dataPDU.pduData.slowPathInputEvents._array)
|
||||||
|
elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_SHUTDOWN_REQUEST:
|
||||||
|
self._transport.close()
|
||||||
|
|
||||||
|
def recvFastPath(self, fastPathS):
|
||||||
|
"""
|
||||||
|
Implement FastPathListener interface
|
||||||
|
Fast path is needed by RDP 8.0
|
||||||
|
@param fastPathS: Stream that contain fast path data
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
def sendLicensingErrorMessage(self):
|
def sendLicensingErrorMessage(self):
|
||||||
"""
|
"""
|
||||||
@@ -604,7 +648,16 @@ class Server(PDULayer):
|
|||||||
#check bitmap header for client that want it (very old client)
|
#check bitmap header for client that want it (very old client)
|
||||||
if self._clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability.extraFlags.value & caps.GeneralExtraFlag.NO_BITMAP_COMPRESSION_HDR:
|
if self._clientCapabilities[caps.CapsType.CAPSTYPE_GENERAL].capability.extraFlags.value & caps.GeneralExtraFlag.NO_BITMAP_COMPRESSION_HDR:
|
||||||
for bitmapData in bitmapDatas:
|
for bitmapData in bitmapDatas:
|
||||||
bitmapData.flags.value |= data.BitmapFlag.NO_BITMAP_COMPRESSION_HDR
|
if bitmapData.flags.value & data.BitmapFlag.BITMAP_COMPRESSION:
|
||||||
updateDataPDU = data.BitmapUpdateDataPDU()
|
bitmapData.flags.value |= data.BitmapFlag.NO_BITMAP_COMPRESSION_HDR
|
||||||
updateDataPDU.rectangles._array = bitmapDatas
|
|
||||||
self.sendDataPDU(data.UpdateDataPDU(updateDataPDU))
|
if self._clientFastPathSupported and not self._fastPathSender is None:
|
||||||
|
#fast path case
|
||||||
|
fastPathUpdateDataPDU = data.FastPathBitmapUpdateDataPDU()
|
||||||
|
fastPathUpdateDataPDU.rectangles._array = bitmapDatas
|
||||||
|
self._fastPathSender.sendFastPath(data.FastPathUpdatePDU(fastPathUpdateDataPDU))
|
||||||
|
else:
|
||||||
|
#slow path case
|
||||||
|
updateDataPDU = data.BitmapUpdateDataPDU()
|
||||||
|
updateDataPDU.rectangles._array = bitmapDatas
|
||||||
|
self.sendDataPDU(data.UpdateDataPDU(updateDataPDU))
|
||||||
@@ -60,6 +60,12 @@ class RDPClientController(pdu.layer.PDUClientListener):
|
|||||||
@return: color depth set by the server (15, 16, 24)
|
@return: color depth set by the server (15, 16, 24)
|
||||||
"""
|
"""
|
||||||
return self._pduLayer._serverCapabilities[pdu.caps.CapsType.CAPSTYPE_BITMAP].capability.preferredBitsPerPixel.value
|
return self._pduLayer._serverCapabilities[pdu.caps.CapsType.CAPSTYPE_BITMAP].capability.preferredBitsPerPixel.value
|
||||||
|
|
||||||
|
def getKeyEventUniCodeSupport(self):
|
||||||
|
"""
|
||||||
|
@return: True if server support unicode input
|
||||||
|
"""
|
||||||
|
return self._pduLayer._serverCapabilities[pdu.caps.CapsType.CAPSTYPE_INPUT].capability.inputFlags.value & pdu.caps.InputFlags.INPUT_FLAG_UNICODE
|
||||||
|
|
||||||
def setPerformanceSession(self):
|
def setPerformanceSession(self):
|
||||||
"""
|
"""
|
||||||
@@ -298,6 +304,12 @@ class RDPServerController(pdu.layer.PDUServerListener):
|
|||||||
#restart connection sequence
|
#restart connection sequence
|
||||||
self._isReady = False
|
self._isReady = False
|
||||||
self._pduLayer.sendPDU(pdu.data.DeactiveAllPDU())
|
self._pduLayer.sendPDU(pdu.data.DeactiveAllPDU())
|
||||||
|
|
||||||
|
def setKeyEventUnicodeSupport(self):
|
||||||
|
"""
|
||||||
|
Enable key event in unicode format
|
||||||
|
"""
|
||||||
|
self._pduLayer._serverCapabilities[pdu.caps.CapsType.CAPSTYPE_INPUT].capability.inputFlags.value |= pdu.caps.InputFlags.INPUT_FLAG_UNICODE
|
||||||
|
|
||||||
def onReady(self):
|
def onReady(self):
|
||||||
"""
|
"""
|
||||||
@@ -309,6 +321,31 @@ class RDPServerController(pdu.layer.PDUServerListener):
|
|||||||
self._sendReady = True
|
self._sendReady = True
|
||||||
for observer in self._serverObserver:
|
for observer in self._serverObserver:
|
||||||
observer.onReady()
|
observer.onReady()
|
||||||
|
|
||||||
|
def onSlowPathInput(self, slowPathInputEvents):
|
||||||
|
"""
|
||||||
|
Event call when slow path input are available
|
||||||
|
@param slowPathInputEvents: [data.SlowPathInputEvent]
|
||||||
|
"""
|
||||||
|
for observer in self._serverObserver:
|
||||||
|
for event in slowPathInputEvents:
|
||||||
|
#scan code
|
||||||
|
if event.messageType.value == pdu.data.InputMessageType.INPUT_EVENT_SCANCODE:
|
||||||
|
observer.onKeyEventScancode(event.slowPathInputData.keyCode.value, not (event.slowPathInputData.keyboardFlags.value & pdu.data.KeyboardFlag.KBDFLAGS_RELEASE))
|
||||||
|
#unicode
|
||||||
|
elif event.messageType.value == pdu.data.InputMessageType.INPUT_EVENT_UNICODE:
|
||||||
|
observer.onKeyEventUnicode(event.slowPathInputData.unicode.value, not (event.slowPathInputData.keyboardFlags.value & pdu.data.KeyboardFlag.KBDFLAGS_RELEASE))
|
||||||
|
#mouse event
|
||||||
|
elif event.messageType.value == pdu.data.InputMessageType.INPUT_EVENT_MOUSE:
|
||||||
|
isPressed = event.slowPathInputData.pointerFlags.value & pdu.data.PointerFlag.PTRFLAGS_DOWN
|
||||||
|
button = 0
|
||||||
|
if event.slowPathInputData.pointerFlags.value & pdu.data.PointerFlag.PTRFLAGS_BUTTON1:
|
||||||
|
button = 1
|
||||||
|
elif event.slowPathInputData.pointerFlags.value & pdu.data.PointerFlag.PTRFLAGS_BUTTON2:
|
||||||
|
button = 2
|
||||||
|
elif event.slowPathInputData.pointerFlags.value & pdu.data.PointerFlag.PTRFLAGS_BUTTON3:
|
||||||
|
button = 3
|
||||||
|
observer.onPointerEvent(event.slowPathInputData.xPos.value, event.slowPathInputData.yPos.value, button, isPressed)
|
||||||
|
|
||||||
def sendUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
|
def sendUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
|
||||||
"""
|
"""
|
||||||
@@ -428,4 +465,30 @@ class RDPServerObserver(object):
|
|||||||
"""
|
"""
|
||||||
Stack is ready and connected
|
Stack is ready and connected
|
||||||
"""
|
"""
|
||||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "RDPServerObserver"))
|
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "RDPServerObserver"))
|
||||||
|
|
||||||
|
def onKeyEventScancode(self, code, isPressed):
|
||||||
|
"""
|
||||||
|
Event call when a keyboard event is catch in scan code format
|
||||||
|
@param code: scan code of key
|
||||||
|
@param isPressed: True if key is down
|
||||||
|
"""
|
||||||
|
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onKeyEventScanCode", "RDPServerObserver"))
|
||||||
|
|
||||||
|
def onKeyEventUnicode(self, code, isPressed):
|
||||||
|
"""
|
||||||
|
Event call when a keyboard event is catch in unicode format
|
||||||
|
@param code: unicode of key
|
||||||
|
@param isPressed: True if key is down
|
||||||
|
"""
|
||||||
|
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onKeyEventUnicode", "RDPServerObserver"))
|
||||||
|
|
||||||
|
def onPointerEvent(self, x, y, button, isPressed):
|
||||||
|
"""
|
||||||
|
Event call on mouse event
|
||||||
|
@param x: x position
|
||||||
|
@param y: y position
|
||||||
|
@param button: 1, 2 or 3 button
|
||||||
|
@param isPressed: True if mouse button is pressed
|
||||||
|
"""
|
||||||
|
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onPointerEvent", "RDPServerObserver"))
|
||||||
@@ -26,6 +26,14 @@ from rdpy.network.layer import RawLayer
|
|||||||
from rdpy.network.type import UInt8, UInt16Be, sizeof
|
from rdpy.network.type import UInt8, UInt16Be, sizeof
|
||||||
from rdpy.base.error import CallPureVirtualFuntion
|
from rdpy.base.error import CallPureVirtualFuntion
|
||||||
|
|
||||||
|
class Action(object):
|
||||||
|
"""
|
||||||
|
@see: http://msdn.microsoft.com/en-us/library/cc240621.aspx
|
||||||
|
@see: http://msdn.microsoft.com/en-us/library/cc240589.aspx
|
||||||
|
"""
|
||||||
|
FASTPATH_ACTION_FASTPATH = 0x0
|
||||||
|
FASTPATH_ACTION_X224 = 0x3
|
||||||
|
|
||||||
class FastPathListener(object):
|
class FastPathListener(object):
|
||||||
"""
|
"""
|
||||||
Fast path packet listener
|
Fast path packet listener
|
||||||
@@ -36,19 +44,33 @@ class FastPathListener(object):
|
|||||||
Call when fast path packet is received
|
Call when fast path packet is received
|
||||||
@param fastPathS: Stream
|
@param fastPathS: Stream
|
||||||
"""
|
"""
|
||||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "StreamListener"))
|
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recvFastPath", "recvFastPath"))
|
||||||
|
|
||||||
|
def setFastPathSender(self, fastPathSender):
|
||||||
|
"""
|
||||||
|
@param fastPathSender: FastPathSender
|
||||||
|
"""
|
||||||
|
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "setFastPathSender", "recvFastPath"))
|
||||||
|
|
||||||
class TPKT(RawLayer):
|
class FastPathSender(object):
|
||||||
|
"""
|
||||||
|
Fast path send capability
|
||||||
|
"""
|
||||||
|
def sendFastPath(self, fastPathS):
|
||||||
|
"""
|
||||||
|
@param fastPathS: type transform to stream and send as fastpath
|
||||||
|
"""
|
||||||
|
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendFastPath", "FastPathSender"))
|
||||||
|
|
||||||
|
class TPKT(RawLayer, FastPathSender):
|
||||||
"""
|
"""
|
||||||
TPKT layer in RDP protocol stack
|
TPKT layer in RDP protocol stack
|
||||||
This layer only handle size of packet and determine if is a fast path packet
|
This layer only handle size of packet and determine if is a fast path packet
|
||||||
"""
|
"""
|
||||||
#first byte of classic tpkt header
|
|
||||||
TPKT_PACKET = 3
|
|
||||||
|
|
||||||
def __init__(self, presentation, fastPathListener):
|
def __init__(self, presentation, fastPathListener):
|
||||||
"""
|
"""
|
||||||
@param presentation: presentation layer, in RDP case is TPDU layer
|
@param presentation: presentation layer, in RDP case is TPDU layer
|
||||||
|
@param fastPathListener: FastPathListener
|
||||||
"""
|
"""
|
||||||
RawLayer.__init__(self, presentation)
|
RawLayer.__init__(self, presentation)
|
||||||
#last packet version read from header
|
#last packet version read from header
|
||||||
@@ -57,6 +79,8 @@ class TPKT(RawLayer):
|
|||||||
self._lastShortLength = UInt8()
|
self._lastShortLength = UInt8()
|
||||||
#fast path listener
|
#fast path listener
|
||||||
self._fastPathListener = fastPathListener
|
self._fastPathListener = fastPathListener
|
||||||
|
#set me as fast path sender
|
||||||
|
fastPathListener.setFastPathSender(self)
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
"""
|
"""
|
||||||
@@ -77,7 +101,7 @@ class TPKT(RawLayer):
|
|||||||
#first read packet version
|
#first read packet version
|
||||||
data.readType(self._lastPacketVersion)
|
data.readType(self._lastPacketVersion)
|
||||||
#classic packet
|
#classic packet
|
||||||
if self._lastPacketVersion.value == TPKT.TPKT_PACKET:
|
if self._lastPacketVersion.value == Action.FASTPATH_ACTION_X224:
|
||||||
#padding
|
#padding
|
||||||
data.readType(UInt8())
|
data.readType(UInt8())
|
||||||
#read end header
|
#read end header
|
||||||
@@ -136,4 +160,10 @@ class TPKT(RawLayer):
|
|||||||
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(Action.FASTPATH_ACTION_X224), UInt8(0), UInt16Be(sizeof(message) + 4), message))
|
||||||
|
|
||||||
|
def sendFastPath(self, fastPathS):
|
||||||
|
"""
|
||||||
|
@param fastPathS: type transform to stream and send as fastpath
|
||||||
|
"""
|
||||||
|
RawLayer.send(self, (UInt8(Action.FASTPATH_ACTION_FASTPATH), UInt16Be((sizeof(fastPathS) + 3) | 0x8000), fastPathS))
|
||||||
Reference in New Issue
Block a user