close cleanly connection

This commit is contained in:
speyrefitte
2014-07-29 18:01:34 +02:00
parent 3319b86d66
commit be1eb94920
7 changed files with 445 additions and 88 deletions

View File

@@ -17,6 +17,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from twisted.mail.pop3client import ERR
""" """
RDP proxy recorder and spy function RDP proxy recorder and spy function
@@ -34,16 +35,56 @@ from twisted.internet import reactor
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
class IProxyClient(object): class IProxyClient(object):
"""
Interface use by Proxy server to interact with client
"""
def close(self):
"""
Close proxy client
"""
raise error.CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "getColorDepth", "IProxyClient"))
def getColorDepth(self): def getColorDepth(self):
pass """
Color depth client, Use to re-negociate color depth with server
"""
raise error.CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "getColorDepth", "IProxyClient"))
def sendKeyEventScancode(self, code, isPressed): def sendKeyEventScancode(self, code, isPressed):
pass """
Key event as scan code
@param code: scan code of key
@param isPressed: True if key is down
"""
raise error.CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendKeyEventScancode", "IProxyClient"))
def sendKeyEventUnicode(self, code, isPressed): def sendKeyEventUnicode(self, code, isPressed):
pass """
Key event as unicode
@param code: unicode of key
@param isPressed: True if key is down
"""
raise error.CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendKeyEventUnicode", "IProxyClient"))
def sendPointerEvent(self, x, y, button, isPressed): def sendPointerEvent(self, x, y, button, isPressed):
pass """
Mouse event
@param x: x position
@param y: y position
@param isPressed: True if button is down
"""
raise error.CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendPointerEvent", "IProxyClient"))
def sendRefreshOrder(self, left, top, right, bottom): def sendRefreshOrder(self, left, top, right, bottom):
pass """
Refresh zone
@param left: left postion
@param top: top position
@param right: right position
@param bottom: bottom position
"""
raise error.CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendRefreshOrder", "IProxyClient"))
class ProxyServer(rdp.RDPServerObserver): class ProxyServer(rdp.RDPServerObserver):
""" """
@@ -92,6 +133,13 @@ class ProxyServer(rdp.RDPServerObserver):
#refresh client #refresh client
width, height = self._controller.getScreen() width, height = self._controller.getScreen()
self._client.sendRefreshOrder(0, 0, width, height) self._client.sendRefreshOrder(0, 0, width, height)
def onClose(self):
"""
Call when client close connection
"""
if not self._client is None:
self._client.close()
def onKeyEventScancode(self, code, isPressed): def onKeyEventScancode(self, code, isPressed):
""" """
@@ -111,7 +159,7 @@ class ProxyServer(rdp.RDPServerObserver):
@param code: unicode of key @param code: unicode of key
@param isPressed: True if key is down @param isPressed: True if key is down
""" """
#no client connectedomaind #no client connected domain
if self._client is None: if self._client is None:
return return
@@ -135,7 +183,8 @@ class ProxyClient(rdp.RDPClientObserver, IProxyClient):
""" """
Client side of proxy Client side of proxy
""" """
def __init__(self, controller, server): _CONNECTED_ = {}
def __init__(self, controller, server, name):
""" """
@param controller: RDPClientObserver @param controller: RDPClientObserver
@param server: ProxyServer @param server: ProxyServer
@@ -143,6 +192,7 @@ class ProxyClient(rdp.RDPClientObserver, IProxyClient):
""" """
rdp.RDPClientObserver.__init__(self, controller) rdp.RDPClientObserver.__init__(self, controller)
self._server = server self._server = server
self._name = name
def onReady(self): def onReady(self):
""" """
@@ -150,8 +200,23 @@ class ProxyClient(rdp.RDPClientObserver, IProxyClient):
Inform proxy server that i'm connected Inform proxy server that i'm connected
implement RDPClientObserver implement RDPClientObserver
""" """
ProxyClient._CONNECTED_[self._name] = self
self._server.clientConnected(self) self._server.clientConnected(self)
def onClose(self):
"""
Stack is closes
"""
if ProxyClient._CONNECTED_.has_key(self._name):
del ProxyClient._CONNECTED_[self._name]
self._server._controller.close()
def close(self):
"""
Close proxy client
"""
self._controller.close()
def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data): def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
""" """
Event use to inform bitmap update Event use to inform bitmap update
@@ -169,18 +234,44 @@ class ProxyClient(rdp.RDPClientObserver, IProxyClient):
self._server._controller.sendUpdate(destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data) self._server._controller.sendUpdate(destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data)
def getColorDepth(self): def getColorDepth(self):
"""
Color depth client, Use to re-negociate color depth with server
"""
return self._controller.getColorDepth() return self._controller.getColorDepth()
def sendKeyEventScancode(self, code, isPressed): def sendKeyEventScancode(self, code, isPressed):
"""
Key event as scan code
@param code: scan code of key
@param isPressed: True if key is down
"""
self._controller.sendKeyEventScancode(code, isPressed) self._controller.sendKeyEventScancode(code, isPressed)
def sendKeyEventUnicode(self, code, isPressed): def sendKeyEventUnicode(self, code, isPressed):
"""
Key event as uni code
@param code: uni code of key
@param isPressed: True if key is down
"""
self._controller.sendKeyEventUnicode(code, isPressed) self._controller.sendKeyEventUnicode(code, isPressed)
def sendPointerEvent(self, x, y, button, isPressed): def sendPointerEvent(self, x, y, button, isPressed):
"""
Mouse event
@param x: x position
@param y: y position
@param isPressed: True if button is down
"""
self._controller.sendPointerEvent(x, y, button, isPressed) self._controller.sendPointerEvent(x, y, button, isPressed)
def sendRefreshOrder(self, left, top, right, bottom): def sendRefreshOrder(self, left, top, right, bottom):
"""
Refresh zone
@param left: left postion
@param top: top position
@param right: right position
@param bottom: bottom position
"""
self._controller.sendRefreshOrder(left, top, right, bottom) self._controller.sendRefreshOrder(left, top, right, bottom)
class ProxyServerFactory(rdp.ServerFactory): class ProxyServerFactory(rdp.ServerFactory):
@@ -192,7 +283,7 @@ class ProxyServerFactory(rdp.ServerFactory):
@param config: rdp-proxy configuration @param config: rdp-proxy configuration
@param credentialProvider: CredentialProvider @param credentialProvider: CredentialProvider
""" """
rdp.ServerFactory.__init__(self, "/home/sylvain/dev/certificate/rdpy.key", "/home/sylvain/dev/certificate/rdpy.crt", 16) rdp.ServerFactory.__init__(self, "/home/speyrefitte/dev/certificate/rdpy.key", "/home/speyrefitte/dev/certificate/rdpy.crt", 16)
self._credentialProvider = credentialProvider self._credentialProvider = credentialProvider
def buildObserver(self, controller): def buildObserver(self, controller):
@@ -201,21 +292,11 @@ class ProxyServerFactory(rdp.ServerFactory):
@param controller: rdp.RDPServerController @param controller: rdp.RDPServerController
""" """
return ProxyServer(controller, self._credentialProvider) return ProxyServer(controller, self._credentialProvider)
def startedConnecting(self, connector):
pass
def clientConnectionLost(self, connector, reason):
pass
def clientConnectionFailed(self, connector, reason):
pass
class ProxyClientFactory(rdp.ClientFactory): class ProxyClientFactory(rdp.ClientFactory):
""" """
Factory for proxy client Factory for proxy client
""" """
_CLIENT_PROXY_ = {}
def __init__(self, server, width, height, domain, username, password, name): def __init__(self, server, width, height, domain, username, password, name):
""" """
@param server: ProxyServer @param server: ProxyServer
@@ -224,6 +305,7 @@ class ProxyClientFactory(rdp.ClientFactory):
@param domain: domain session @param domain: domain session
@param username: username session @param username: username session
@param password: password session @param password: password session
@param name: name of session
""" """
self._server = server self._server = server
self._width = width self._width = width
@@ -245,21 +327,128 @@ class ProxyClientFactory(rdp.ClientFactory):
controller.setDomain(self._domain) controller.setDomain(self._domain)
controller.setUsername(self._username) controller.setUsername(self._username)
controller.setPassword(self._password) controller.setPassword(self._password)
proxy = ProxyClient(controller, self._server) proxy = ProxyClient(controller, self._server, self._name)
ProxyClientFactory._CLIENT_PROXY_[self._name] = proxy
return proxy return proxy
def startedConnecting(self, connector): def startedConnecting(self, connector):
pass pass
def clientConnectionLost(self, connector, reason): def clientConnectionLost(self, connector, reason):
if ProxyClientFactory._CLIENT_PROXY_.has_key(self._name): pass
del ProxyClientFactory._CLIENT_PROXY_[self._name]
def clientConnectionFailed(self, connector, reason): def clientConnectionFailed(self, connector, reason):
if ProxyClientFactory._CLIENT_PROXY_.has_key(self._name): pass
del ProxyClientFactory._CLIENT_PROXY_[self._name]
class ProxyAdmin(IProxyClient):
"""
Use to manage client side of admin session
Add GUI to select which session to see
And manage see session
Just escape key is authorized during see session
"""
class State(object):
"""
GUI state -> list of active session
SPY state -> watch active session
"""
GUI = 0
SPY = 1
def __init__(self, server):
"""
@param server: rdp.RDPServerController
"""
self._server = server
self._spyProxy = None
self.initView()
self._state = ProxyAdmin.State.GUI
def initView(self):
"""
Init GUI view
"""
width, height = self._server._controller.getScreen()
self._window = view.WindowView(width, height, QtGui.QColor(24, 93, 123))
self._window.addView(view.AnchorView(width / 2 - 250, height / 2 - 250, view.ListView(ProxyClient._CONNECTED_.keys(), 500, 500, self.onSelect, QtGui.QColor(24, 93, 123))))
self._render = view.RDPRenderer(self._server._controller)
def close(self):
"""
Close proxy client
"""
pass
def getColorDepth(self):
"""
Use same Color depth as server init
@return color depth of GUI
"""
if self._state == ProxyAdmin.State.GUI:
return self._server._controller.getColorDepth()
elif self._state == ProxyAdmin.State.SPY:
return self._spyProxy.getColorDepth()
def sendKeyEventScancode(self, code, isPressed):
"""
IProxyClient implement is unauthorized during admin session
Only for GUI
@param code: scan code of key
@param isPressed: True if key is down
"""
if self._state == ProxyAdmin.State.GUI:
if not isPressed:
return
self._window.keyEvent(code)
self._window.update(self._render)
elif code == 1:
#escape button refresh GUI
self._spyProxy._controller.removeClientObserver(self._spyProxy)
self._state = ProxyAdmin.State.GUI
self._server.clientConnected(self)
def sendKeyEventUnicode(self, code, isPressed):
"""
Key event as uni code is unauthorized during admin session
@param code: uni code of key
@param isPressed: True if key is down
"""
pass
def sendPointerEvent(self, x, y, button, isPressed):
"""
Mouse event is unauthorized during admin session
@param x: x position
@param y: y position
@param isPressed: True if button is down
"""
pass
def sendRefreshOrder(self, left, top, right, bottom):
"""
Refresh zone
@param left: left postion
@param top: top position
@param right: right position
@param bottom: bottom position
"""
if self._state == ProxyAdmin.State.GUI:
self._window.update(self._render)
elif self._state == ProxyAdmin.State.SPY:
self._spyProxy.sendRefreshOrder(left, top, right, bottom)
def onSelect(self, name):
"""
Call back of list view
@param name: name selected by user
"""
if not ProxyClient._CONNECTED_.has_key(name):
return
self._spyProxy = ProxyClient(ProxyClient._CONNECTED_[name]._controller, self._server, "Admin")
self._state = ProxyAdmin.State.SPY
#reconnect me
self._server.clientConnected(self)
class CredentialProvider(object): class CredentialProvider(object):
""" """
Credential provider for proxy Credential provider for proxy
@@ -293,33 +482,7 @@ class CredentialProvider(object):
""" """
account = self.getAccount(domain, username) account = self.getAccount(domain, username)
return account.has_key("admin") and account["admin"] and account.has_key("password") and str(account["password"]) == password return account.has_key("admin") and account["admin"] and account.has_key("password") and str(account["password"]) == password
class ProxyAdmin(IProxyClient):
"""
Use to manage client side of admin session
Add GUI to select wich session to see
"""
def __init__(self, server):
self._server = server
self._list = view.ListView(ProxyClientFactory._CLIENT_PROXY_.keys(), 300, 300, self.onSelect)
self._render = view.RDPRenderer(self._server._controller)
self._list.update(self._render)
def getColorDepth(self):
return 16
def sendKeyEventScancode(self, code, isPressed):
if isPressed:
self._list.keyEvent(code)
self._list.update(self._render)
def sendKeyEventUnicode(self, code, isPressed):
pass
def sendPointerEvent(self, x, y, button, isPressed):
pass
def sendRefreshOrder(self, left, top, right, bottom):
self._list.update(self._render)
def onSelect(self, name):
if ProxyClientFactory._CLIENT_PROXY_.has_key(name):
self._server.clientConnected(ProxyClient(ProxyClientFactory._CLIENT_PROXY_[name]._controller, self._server))
def help(): def help():
""" """
Print help in console Print help in console

View File

@@ -108,9 +108,63 @@ class LayerAutomata(Layer, IStreamListener):
#twisted layer concept #twisted layer concept
from twisted.internet import protocol from twisted.internet import protocol
from twisted.internet.abstract import FileDescriptor
#first that handle stream #first that handle stream
from type import Stream from type import Stream
class RawLayerClientFactory(protocol.ClientFactory):
"""
Abstract class for Raw layer client factory
"""
def buildProtocol(self, addr):
"""
Function call from twisted and build rdp protocol stack
@param addr: destination address
"""
rawLayer = self.buildRawLayer(addr)
rawLayer.setFactory(self)
return rawLayer
def buildRawLayer(self, addr):
"""
Override this function to build raw layer
@param addr: destination address
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener"))
def connectionLost(self, rawlayer):
"""
Overirde this method to handle connection lost
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener"))
class RawLayerServerFactory(protocol.ClientFactory):
"""
Abstract class for Raw layer server factory
"""
def buildProtocol(self, addr):
"""
Function call from twisted and build rdp protocol stack
@param addr: destination address
"""
rawLayer = self.buildRawLayer(addr)
rawLayer.setFactory(self)
return rawLayer
def buildRawLayer(self, addr):
"""
Override this function to build raw layer
@param addr: destination address
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener"))
def connectionLost(self, rawlayer):
"""
Overirde this method to handle connection lost
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener"))
class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender): class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender):
""" """
Inherit from protocol twisted class Inherit from protocol twisted class
@@ -127,6 +181,14 @@ class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender):
self._buffer = "" self._buffer = ""
#len of next packet pass to next state function #len of next packet pass to next state function
self._expectedLen = 0 self._expectedLen = 0
self._factory = None
def setFactory(self, factory):
"""
Call by RawLayer Factory
@param param: RawLayerClientFactory or RawLayerFactory
"""
self._factory = factory
def dataReceived(self, data): def dataReceived(self, data):
""" """
@@ -152,11 +214,14 @@ class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender):
#join two scheme #join two scheme
self.connect() self.connect()
def connectionLost(self, reason):
self._factory.connectionLost(self)
def close(self): def close(self):
""" """
Close raw layer Close raw layer
""" """
self.transport.loseConnection() FileDescriptor.loseConnection(self.transport)
def expect(self, expectedLen, callback = None): def expect(self, expectedLen, callback = None):
""" """

View File

@@ -25,7 +25,7 @@ In this layer are managed all mains bitmap update orders end user inputs
from rdpy.network.type import CompositeType, String, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType from rdpy.network.type import CompositeType, String, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType
from rdpy.base.error import InvalidExpectedDataException from rdpy.base.error import InvalidExpectedDataException
import rdpy.base.log as log import rdpy.base.log as log
import caps import caps, order
class SecurityFlag(object): class SecurityFlag(object):
""" """
@@ -930,17 +930,7 @@ class OrderUpdateDataPDU(CompositeType):
self.pad2OctetsA = UInt16Le() self.pad2OctetsA = UInt16Le()
self.numberOrders = UInt16Le(lambda:len(self.orderData._array)) self.numberOrders = UInt16Le(lambda:len(self.orderData._array))
self.pad2OctetsB = UInt16Le() self.pad2OctetsB = UInt16Le()
self.orderData = ArrayType(DrawingOrder, readLen = self.numberOrders) self.orderData = ArrayType(order.DrawingOrder, readLen = self.numberOrders)
class DrawingOrder(CompositeType):
"""
GDI drawing orders
@see: http://msdn.microsoft.com/en-us/library/cc241574.aspx
@todo: not implemented yet but need it
"""
def __init__(self):
CompositeType.__init__(self)
self.controlFlags = UInt8()
class BitmapCompressedDataHeader(CompositeType): class BitmapCompressedDataHeader(CompositeType):
""" """

View File

@@ -573,10 +573,11 @@ class Server(PDULayer, tpkt.IFastPathListener):
elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_INPUT: elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_INPUT:
self._listener.onSlowPathInput(dataPDU.pduData.slowPathInputEvents._array) self._listener.onSlowPathInput(dataPDU.pduData.slowPathInputEvents._array)
elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_SHUTDOWN_REQUEST: elif dataPDU.shareDataHeader.pduType2.value == data.PDUType2.PDUTYPE2_SHUTDOWN_REQUEST:
log.debug("Receive Shutdown Request")
self._transport.close() self._transport.close()
def recvFastPath(self, fastPathS): def recvFastPath(self, fastPathS):
"""r """
Implement IFastPathListener interface Implement IFastPathListener interface
Fast path is needed by RDP 8.0 Fast path is needed by RDP 8.0
@param fastPathS: Stream that contain fast path data @param fastPathS: Stream that contain fast path data

View File

@@ -0,0 +1,45 @@
#
# 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/>.
#
"""
GDI order structure
"""
from rdpy.network.type import CompositeType, UInt8
class ControlFlag(object):
TS_STANDARD = 0x01
TS_SECONDARY = 0x02
class DrawingOrder(CompositeType):
"""
GDI drawing orders
@see: http://msdn.microsoft.com/en-us/library/cc241574.aspx
"""
def __init__(self):
CompositeType.__init__(self)
self.controlFlags = UInt8()
class PrimaryDrawingOrder(CompositeType):
"""
GDI Primary drawing order
@see: http://msdn.microsoft.com/en-us/library/cc241586.aspx
"""
def __init__(self):
CompositeType.__init__(self)

View File

@@ -21,7 +21,7 @@
Use to manage RDP stack in twisted Use to manage RDP stack in twisted
""" """
from twisted.internet import protocol from rdpy.network import layer
from rdpy.base.error import CallPureVirtualFuntion, InvalidValue from rdpy.base.error import CallPureVirtualFuntion, InvalidValue
import pdu.layer import pdu.layer
import pdu.data import pdu.data
@@ -46,7 +46,6 @@ class RDPClientController(pdu.layer.PDUClientListener):
self._tpktLayer = tpkt.TPKT(self._tpduLayer, self._pduLayer) self._tpktLayer = tpkt.TPKT(self._tpduLayer, self._pduLayer)
#is pdu layer is ready to send #is pdu layer is ready to send
self._isReady = False self._isReady = False
self._sendReady = False
def getProtocol(self): def getProtocol(self):
""" """
@@ -112,6 +111,16 @@ class RDPClientController(pdu.layer.PDUClientListener):
""" """
self._clientObserver.append(observer) self._clientObserver.append(observer)
def removeClientObserver(self, observer):
"""
Remove observer to RDP protocol stack
@param observer: observer to remove
"""
for i in range(0, len(self._clientObserver)):
if self._clientObserver[i] == observer:
del self._clientObserver[i]
return
def onUpdate(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
@@ -127,12 +136,17 @@ class RDPClientController(pdu.layer.PDUClientListener):
Call when PDU layer is connected Call when PDU layer is connected
""" """
self._isReady = True self._isReady = True
if self._sendReady:
return
self._sendReady = False
#signal all listener #signal all listener
for observer in self._clientObserver: for observer in self._clientObserver:
observer.onReady() observer.onReady()
def onClose(self):
"""
Event call when RDP stack is closed
"""
self._isReady = False
for observer in self._clientObserver:
observer.onClose()
def sendPointerEvent(self, x, y, button, isPressed): def sendPointerEvent(self, x, y, button, isPressed):
""" """
@@ -260,6 +274,12 @@ class RDPServerController(pdu.layer.PDUServerListener):
#set color depth of session #set color depth of session
self.setColorDepth(colorDepth) self.setColorDepth(colorDepth)
def close(self):
"""
Close protocol stack
"""
self._pduLayer.close()
def getProtocol(self): def getProtocol(self):
""" """
@return: the twisted protocol layer @return: the twisted protocol layer
@@ -342,6 +362,14 @@ class RDPServerController(pdu.layer.PDUServerListener):
for observer in self._serverObserver: for observer in self._serverObserver:
observer.onReady() observer.onReady()
def onClose(self):
"""
Event call when RDP stack is closed
"""
self._isReady = False
for observer in self._serverObserver:
observer.onClose()
def onSlowPathInput(self, slowPathInputEvents): def onSlowPathInput(self, slowPathInputEvents):
""" """
Event call when slow path input are available Event call when slow path input are available
@@ -388,27 +416,36 @@ class RDPServerController(pdu.layer.PDUServerListener):
self._pduLayer.sendBitmapUpdatePDU([bitmapData]) self._pduLayer.sendBitmapUpdatePDU([bitmapData])
class ClientFactory(protocol.Factory): class ClientFactory(layer.RawLayerClientFactory):
""" """
Factory of Client RDP protocol Factory of Client RDP protocol
""" """
def buildProtocol(self, addr): def connectionLost(self, tpktLayer):
#retrieve controller
tpduLayer = tpktLayer._presentation
mcsLayer = tpduLayer._presentation
pduLayer = mcsLayer._channels[mcs.Channel.MCS_GLOBAL_CHANNEL]
controller = pduLayer._listener
controller.onClose()
def buildRawLayer(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)
controller.getProtocol()._factory = self
return controller.getProtocol(); return controller.getProtocol()
def buildObserver(self, controller): def buildObserver(self, controller):
''' """
build observer use for connection Build observer use for connection
''' @param controller: RDPClientController
"""
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(layer.RawLayerServerFactory):
""" """
Factory of Server RDP protocol Factory of Server RDP protocol
""" """
@@ -421,14 +458,23 @@ class ServerFactory(protocol.Factory):
self._privateKeyFileName = privateKeyFileName self._privateKeyFileName = privateKeyFileName
self._certificateFileName = certificateFileName self._certificateFileName = certificateFileName
self._colorDepth = colorDepth self._colorDepth = colorDepth
def buildProtocol(self, addr): def connectionLost(self, tpktLayer):
#retrieve controller
tpduLayer = tpktLayer._presentation
mcsLayer = tpduLayer._presentation
pduLayer = mcsLayer._channels[mcs.Channel.MCS_GLOBAL_CHANNEL]
controller = pduLayer._listener
controller.onClose()
def buildRawLayer(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 = RDPServerController(self._privateKeyFileName, self._certificateFileName, self._colorDepth) controller = RDPServerController(self._privateKeyFileName, self._certificateFileName, self._colorDepth)
self.buildObserver(controller) self.buildObserver(controller)
controller.getProtocol()._factory = self
return controller.getProtocol() return controller.getProtocol()
def buildObserver(self, controller): def buildObserver(self, controller):
@@ -455,6 +501,12 @@ class RDPClientObserver(object):
""" """
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "RDPClientObserver")) raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "RDPClientObserver"))
def onClose(self):
"""
Stack is closes
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onClose", "RDPClientObserver"))
def onUpdate(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 Notify bitmap update
@@ -488,6 +540,12 @@ class RDPServerObserver(object):
""" """
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 onClose(self):
"""
Stack is closes
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onClose", "RDPClientObserver"))
def onKeyEventScancode(self, code, isPressed): def onKeyEventScancode(self, code, isPressed):
""" """
Event call when a keyboard event is catch in scan code format Event call when a keyboard event is catch in scan code format

View File

@@ -20,7 +20,7 @@
""" """
Fake widget Fake widget
""" """
from rdpy.base.error import CallPureVirtualFuntion from rdpy.base.error import CallPureVirtualFuntion, InvalidExpectedDataException
from PyQt4 import QtGui, QtCore from PyQt4 import QtGui, QtCore
@@ -34,6 +34,8 @@ class IRender(object):
pass pass
def drawImage(self, image): def drawImage(self, image):
pass pass
def getImageFormat(self):
pass
class IView(object): class IView(object):
def keyEvent(self, code): def keyEvent(self, code):
@@ -54,20 +56,19 @@ class AnchorView(IView):
self._view.pointerEvent(x - self._x, y - self._y) self._view.pointerEvent(x - self._x, y - self._y)
def update(self, render): def update(self, render):
render.translate(self._x, self._y) render.translate(self._x, self._y)
self._view.update(self._view, render) self._view.update(render)
render.translate(- self._x, - self._y) render.translate(- self._x, - self._y)
class ListView(IView): class ListView(IView):
""" """
List widget simulate by QT painter List widget simulate by QT painter
""" """
def __init__(self, labels, width, height, callback): def __init__(self, labels, width, height, callback, backgroudColor = QtCore.Qt.black):
self._labels = labels self._labels = labels
self._width = width self._width = width
self._height = height self._height = height
self._cellHeight = 25 self._cellHeight = 25
self._backGroudColor = QtGui.QColor(24, 93, 123) self._backgroudColor = backgroudColor
self._fontSize = 14 self._fontSize = 14
self._current = 0 self._current = 0
self._callback = callback self._callback = callback
@@ -91,9 +92,9 @@ class ListView(IView):
Draw GUI that list active session Draw GUI that list active session
""" """
i = 0 i = 0
drawArea = QtGui.QImage(self._width, self._height, QtGui.QImage.Format_RGB16) drawArea = QtGui.QImage(self._width, self._height, render.getImageFormat())
#fill with background Color #fill with background Color
drawArea.fill(self._backGroudColor) drawArea.fill(self._backgroudColor)
with QtGui.QPainter(drawArea) as qp: with QtGui.QPainter(drawArea) as qp:
for label in self._labels: for label in self._labels:
rect = QtCore.QRect(0, i * self._cellHeight, self._width, self._cellHeight) rect = QtCore.QRect(0, i * self._cellHeight, self._width, self._cellHeight)
@@ -105,6 +106,29 @@ class ListView(IView):
qp.drawText(rect, QtCore.Qt.AlignCenter, label) qp.drawText(rect, QtCore.Qt.AlignCenter, label)
i += 1 i += 1
render.drawImage(drawArea) render.drawImage(drawArea)
class WindowView(IView):
def __init__(self, width, height, backgroundColor = QtCore.Qt.black):
self._views = []
self._focusIndex = 0
self._width = width
self._height = height
self._backgroundColor = backgroundColor
def addView(self, view):
self._views.append(view)
def keyEvent(self, code):
if self._focusIndex < len(self._views):
self._views[self._focusIndex].keyEvent(code)
def pointerEvent(self, x, y, button):
if self._focusIndex < len(self._views):
self._views[self._focusIndex].pointerEvent(x, y, button)
def update(self, render):
drawArea = QtGui.QImage(self._width, self._height, render.getImageFormat())
#fill with background Color
drawArea.fill(self._backgroundColor)
render.drawImage(drawArea)
for view in self._views:
view.update(render)
class RDPRenderer(object): class RDPRenderer(object):
def __init__(self, server): def __init__(self, server):
@@ -112,10 +136,21 @@ class RDPRenderer(object):
@param server: RDPServerController @param server: RDPServerController
""" """
self._server = server self._server = server
self._colorDepth = self._server.getColorDepth()
self._dx = 0 self._dx = 0
self._dy = 0 self._dy = 0
self._renderSize = 64 self._renderSize = 64
def getImageFormat(self):
if self._colorDepth == 15:
return QtGui.QImage.Format_RGB15
elif self._colorDepth == 16:
return QtGui.QImage.Format_RGB16
elif self._colorDepth == 24:
return QtGui.QImage.Format_RGB24
elif self._colorDepth == 32:
return QtGui.QImage.Format_RGB32
def translate(self, dx, dy): def translate(self, dx, dy):
self._dx += dx self._dx += dx
self._dy += dy self._dy += dy
@@ -133,5 +168,5 @@ class RDPRenderer(object):
tmp = tmp.transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) tmp = tmp.transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
ptr = tmp.bits() ptr = tmp.bits()
ptr.setsize(tmp.byteCount()) ptr.setsize(tmp.byteCount())
self._server.sendUpdate(i * self._renderSize + self._dx, j * self._renderSize + self._dy, min((i + 1) * self._renderSize, image.width()) + self._dx - 1, min((j + 1) * self._renderSize, image.height()) + self._dy - 1, tmp.width(), tmp.height(), 16, False, ptr.asstring()) self._server.sendUpdate(i * self._renderSize + self._dx, j * self._renderSize + self._dy, min((i + 1) * self._renderSize, image.width()) + self._dx - 1, min((j + 1) * self._renderSize, image.height()) + self._dy - 1, tmp.width(), tmp.height(), self._colorDepth, False, ptr.asstring())