bug fix on proxy + add comments

This commit is contained in:
speyrefitte
2014-08-01 17:47:49 +02:00
parent 9af647ab09
commit 17b57ddd4f
11 changed files with 677 additions and 517 deletions

View File

@@ -33,11 +33,15 @@ from rdpy.protocol.rdp import rdp
class RDPClientQtFactory(rdp.ClientFactory):
"""
Factory create a RDP GUI client
@summary: Factory create a RDP GUI client
"""
def __init__(self, width, height, username, password, domain):
"""
init client with correct definition
@param width: width of client
@param heigth: heigth of client
@param username: username present to the server
@param password: password present to the server
@param domain: microsoft domain
"""
self._width = width
self._height = height
@@ -46,10 +50,13 @@ class RDPClientQtFactory(rdp.ClientFactory):
self._domain = domain
self._w = None
def buildObserver(self, controller):
def buildObserver(self, controller, addr):
"""
Build RFB observer
@summary: Build RFB observer
We use a RDPClientQt as RDP observer
@param controller: build factory and needed by observer
@param addr: destination address
@return: RDPClientQt
"""
#create client observer
client = RDPClientQt(controller, self._width, self._height)
@@ -70,7 +77,7 @@ class RDPClientQtFactory(rdp.ClientFactory):
def clientConnectionLost(self, connector, reason):
"""
Connection lost event
@summary: Connection lost event
@param connector: twisted connector use for rdp connection (use reconnect to restart connection)
@param reason: str use to advertise reason of lost connection
"""
@@ -80,7 +87,7 @@ class RDPClientQtFactory(rdp.ClientFactory):
def clientConnectionFailed(self, connector, reason):
"""
Connection failed event
@summary: Connection failed event
@param connector: twisted connector use for rdp connection (use reconnect to restart connection)
@param reason: str use to advertise reason of lost connection
"""

View File

@@ -19,8 +19,14 @@
#
"""
RDP proxy recorder and spy function
Proxy RDP protocol
RDP proxy with spy capabilities
---------------------------
Client RDP -> | ProxyServer | ProxyClient | -> Server RDP
---------------------------
| ProxyAdmin |
------------
^
Admin ----------------------|
"""
import sys, os, getopt, json
@@ -35,7 +41,7 @@ from PyQt4 import QtCore, QtGui
class ProxyServer(rdp.RDPServerObserver):
"""
Server side of proxy
@summary: Server side of proxy
"""
def __init__(self, controller, credentialProvider):
"""
@@ -48,42 +54,65 @@ class ProxyServer(rdp.RDPServerObserver):
self._window = None
def showSelectView(self, machines):
self._machines = dict([("%s:%s"%(ip, port), (ip, port)) for ip, port in machines])
"""
@summary: Show select sever view to the client
@param machines: [(ip, port)]
"""
self._machines = machines
width, height = self._controller.getScreen()
self._window = view.Window(width, height, QtGui.QColor(24, 93, 123))
self._window.addView(view.Anchor(width / 2 - 250, 100, view.Label("Please select following server", 500, 50, QtGui.QFont('arial', 18, QtGui.QFont.Bold), backgroundColor = QtGui.QColor(24, 93, 123))))
self._window.addView(view.Anchor(width / 2 - 250, 150, view.List(self._machines.keys(), 500, 500, self.onSelectMachine, QtGui.QColor(24, 93, 123))), True)
self._window.update(view.RDPRenderer(self._controller, self._controller.getColorDepth()), True)
self._window = view.Window(width, height, QtGui.QColor(8, 24, 66))
def onSelectMachine(self, machine):
ip, port = self._machines[machine]
self._window.addView(view.Anchor(width / 2 - 250, 100, view.Label("Please select following server",
500, 50, QtGui.QFont('arial', 18, QtGui.QFont.Bold),
backgroundColor = QtGui.QColor(8, 24, 66))))
self._window.addView(view.Anchor(width / 2 - 250, 150, view.List(["%s:%s"%(ip, port) for ip, port in machines],
500, 500, self.onSelectMachine,
QtGui.QColor(8, 24, 66))), True)
self._window.update(view.RDPRenderer(self._controller), True)
def onSelectMachine(self, index):
"""
@summary: Callback of view.List in Select server view
@param: machine str name of machine selected
@param: index in list
"""
ip, port = self._machines[index]
width, height = self._controller.getScreen()
domain, username, password = self._controller.getCredentials()
reactor.connectTCP(ip, port, ProxyClientFactory(self, width, height, domain, username, password, "%s\\%s on %s:%s"%(domain, username, ip, port)))
reactor.connectTCP(ip, port, ProxyClientFactory(self, width, height, domain, username, password))
def clientConnected(self, client):
"""
Event throw by client when it's ready
@summary: Event throw by client when it's ready
@param client: ProxyClient
"""
self._client = client
#need to reevaluate color depth
self._controller.setColorDepth(self._client._controller.getColorDepth())
def showErrorMessage(self, message):
def showMessage(self, message):
"""
Print a message to the client
@summary: Print a message to the client
@param message: string
"""
width, height = self._controller.getScreen()
popup = view.Window(width, height, QtGui.QColor(24, 93, 123))
popup.addView(view.Anchor(width / 2 - 250, height / 2 - 25, view.Label(message, 500, 50, QtGui.QFont('arial', 18, QtGui.QFont.Bold), backgroundColor = QtGui.QColor(24, 93, 123))))
popup.update(view.RDPRenderer(self._controller, self._controller.getColorDepth()), True)
popup = view.Window(width, height, QtGui.QColor(8, 24, 66))
popup.addView(view.Anchor(width / 2 - 250, height / 2 - 25,
view.Label(message, 500, 50,
QtGui.QFont('arial', 18, QtGui.QFont.Bold),
backgroundColor = QtGui.QColor(8, 24, 66))))
popup.update(view.RDPRenderer(self._controller), True)
def onReady(self):
"""
Event use to inform state of server stack
Use to connect client
On ready is not launch only after connection sequence but after a reactivation sequence too
@summary: Event use to inform state of server stack
First time this event is called is when human client is connected
Second time is after color depth nego, because color depth nego
restart a connection sequence
Use to connect proxy client or show available server
@see: rdp.RDPServerObserver.onReady
"""
if self._client is None:
#try a connection
@@ -91,11 +120,13 @@ class ProxyServer(rdp.RDPServerObserver):
machines = self._credentialProvider.getProxyPass(domain, username)
if len(machines) == 0:
self.showErrorMessage("No servers attach to account %s\\%s"%(domain, username))
self.showMessage("No servers attach to account %s\\%s"%(domain, username))
elif len(machines) == 1:
ip, port = machines[0]
width, height = self._controller.getScreen()
reactor.connectTCP(ip, port, ProxyClientFactory(self, width, height, domain, username, password, "%s\\%s on %s:%s"%(domain, username, ip, port)))
reactor.connectTCP(ip, port, ProxyClientFactory(self, width, height,
domain, username, password,
"%s\\%s on %s:%s"%(domain, username, ip, port)))
else:
self.showSelectView(machines)
else:
@@ -105,31 +136,35 @@ class ProxyServer(rdp.RDPServerObserver):
def onClose(self):
"""
Call when client close connection
@summary: Call when human client close connection
@see: rdp.RDPServerObserver.onClose
"""
if self._client is None:
return
#close proxy client
self._client._controller.close()
def onKeyEventScancode(self, code, isPressed):
"""
Event call when a keyboard event is catch in scan code format
@summary: 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
@see: rdp.RDPServerObserver.onKeyEventScancode
"""
#no client connected
if not self._client is None:
self._client._controller.sendKeyEventScancode(code, isPressed)
elif not self._window is None and isPressed:
self._window.keyEvent(code)
self._window.update(view.RDPRenderer(self._controller, self._controller.getColorDepth()))
self._window.update(view.RDPRenderer(self._controller))
def onKeyEventUnicode(self, code, isPressed):
"""
Event call when a keyboard event is catch in unicode format
@summary: Event call when a keyboard event is catch in unicode format
@param code: unicode of key
@param isPressed: True if key is down
@see: rdp.RDPServerObserver.onKeyEventUnicode
"""
#no client connected domain
if self._client is None:
@@ -138,11 +173,12 @@ class ProxyServer(rdp.RDPServerObserver):
def onPointerEvent(self, x, y, button, isPressed):
"""
Event call on mouse event
@summary: 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
@see: rdp.RDPServerObserver.onPointerEvent
"""
#no client connected
if self._client is None:
@@ -151,33 +187,36 @@ class ProxyServer(rdp.RDPServerObserver):
class ProxyServerFactory(rdp.ServerFactory):
"""
Factory on listening events
@summary: Factory on listening events
"""
def __init__(self, credentialProvider, privateKeyFilePath, certificateFilePath):
"""
@param config: rdp-proxy configuration
@param credentialProvider: CredentialProvider
@param privateKeyFilePath: file contain server private key
@param certificateFilePath: file contain server certificate
"""
rdp.ServerFactory.__init__(self, privateKeyFilePath, certificateFilePath, 16)
self._credentialProvider = credentialProvider
def buildObserver(self, controller):
def buildObserver(self, controller, addr):
"""
Implement rdp.ServerFactory
@param controller: rdp.RDPServerController
@param addr: destination address
@see: rdp.ServerFactory.buildObserver
"""
return ProxyServer(controller, self._credentialProvider)
class ProxyClient(rdp.RDPClientObserver):
"""
Client side of proxy
@summary: Client side of proxy
"""
_CONNECTED_ = {}
def __init__(self, controller, server, name):
_CONNECTED_ = []
def __init__(self, controller, server, name = None):
"""
@param controller: RDPClientObserver
@param controller: rdp.RDPClientController
@param server: ProxyServer
@param name: name of session
@param name: name of session None if you don't
want to spy this session
"""
rdp.RDPClientObserver.__init__(self, controller)
self._server = server
@@ -185,25 +224,24 @@ class ProxyClient(rdp.RDPClientObserver):
def onReady(self):
"""
Event use to signal that RDP stack is ready
Inform proxy server that i'm connected
implement RDPClientObserver
@summary: Event use to signal that RDP stack is ready
Inform ProxyServer that i'm connected
@see: rdp.RDPClientObserver.onReady
"""
ProxyClient._CONNECTED_[self._name] = self
if not self._name is None:
ProxyClient._CONNECTED_.append(self)
self._server.clientConnected(self)
def onClose(self):
"""
Stack is closes
@summary: Event inform that stack is close
@see: rdp.RDPClientObserver.onClose
"""
if ProxyClient._CONNECTED_.has_key(self._name):
del ProxyClient._CONNECTED_[self._name]
self._server._controller.close()
ProxyClient._CONNECTED_.remove(self)
def onUpdate(self, destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data):
"""
Event use to inform bitmap update
implement RDPClientObserver
@summary: Event use to inform bitmap update
@param destLeft: xmin position
@param destTop: ymin position
@param destRight: xmax position because RDP can send bitmap with padding
@@ -213,14 +251,15 @@ class ProxyClient(rdp.RDPClientObserver):
@param bitsPerPixel: number of bit per pixel
@param isCompress: use RLE compression
@param data: bitmap data
@see: rdp.RDPClientObserver.onUpdate
"""
self._server._controller.sendUpdate(destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data)
class ProxyClientFactory(rdp.ClientFactory):
"""
Factory for proxy client
@summary: Factory for proxy client
"""
def __init__(self, server, width, height, domain, username, password, name):
def __init__(self, server, width, height, domain, username, password):
"""
@param server: ProxyServer
@param width: screen width
@@ -228,7 +267,6 @@ class ProxyClientFactory(rdp.ClientFactory):
@param domain: domain session
@param username: username session
@param password: password session
@param name: name of session
"""
self._controller = server
self._width = width
@@ -236,13 +274,14 @@ class ProxyClientFactory(rdp.ClientFactory):
self._domain = domain
self._username = username
self._password = password
self._name = name
def buildObserver(self, controller):
def buildObserver(self, controller, addr):
"""
Implement rdp.ClientFactory
Build observer (ProxyClient)
@summary: Build observer
@param controller: rdp.RDPClientController
@param addr: destination address
@see: rdp.ClientFactory.buildObserver
@return: ProxyClient
"""
#set screen resolution
controller.setScreen(self._width, self._height)
@@ -250,7 +289,7 @@ class ProxyClientFactory(rdp.ClientFactory):
controller.setDomain(self._domain)
controller.setUsername(self._username)
controller.setPassword(self._password)
proxy = ProxyClient(controller, self._controller, self._name)
proxy = ProxyClient(controller, self._controller, "%s\\%s on %s"%(self._domain, self._username, addr))
return proxy
def startedConnecting(self, connector):
@@ -265,18 +304,14 @@ class ProxyClientFactory(rdp.ClientFactory):
class ProxyAdmin(rdp.RDPServerObserver):
"""
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 spy session
@summary: Use to manage admin session
Add GUI to select which session to see
Just escape key is authorized during spy session
To switch from spy state to admin state
"""
class State(object):
"""
GUI state -> list of active session
SPY state -> watch active session
"""
GUI = 0
SPY = 1
GUI = 0 #->list of active session
SPY = 1 #->watch active session
def __init__(self, controller):
"""
@@ -289,21 +324,32 @@ class ProxyAdmin(rdp.RDPServerObserver):
def initView(self):
"""
Init GUI view
@summary: Initialize Admin GUI view
"""
self._sessions = list(ProxyClient._CONNECTED_) #copy at t time
width, height = self._controller.getScreen()
self._window = view.Window(width, height, QtGui.QColor(24, 93, 123))
self._window.addView(view.Anchor(width / 2 - 250, 100, view.Label("Please select following session", 500, 50, QtGui.QFont('arial', 18, QtGui.QFont.Bold), backgroundColor = QtGui.QColor(24, 93, 123))))
self._window.addView(view.Anchor(width / 2 - 250, 150, view.List(ProxyClient._CONNECTED_.keys(), 500, 500, self.onSelect, QtGui.QColor(24, 93, 123))), True)
self._window = view.Window(width, height, QtGui.QColor(8, 24, 66))
self._window.addView(view.Anchor(width / 2 - 250, 100, view.Label("Please select following session",
500, 50, QtGui.QFont('arial', 18, QtGui.QFont.Bold),
backgroundColor = QtGui.QColor(8, 24, 66))))
self._window.addView(view.Anchor(width / 2 - 250, 150, view.List([p._name for p in self._sessions],
500, 500, self.onSelect,
QtGui.QColor(8, 24, 66))), True)
def clientConnected(self, client):
pass
def onReady(self):
"""
Stack is ready and connected
May be called after an setColorDepth too
@summary: Stack is ready and connected
May be called after an setColorDepth too
@see: rdp.RDPServerObserver.onReady
"""
if self._state == ProxyAdmin.State.GUI:
self.initView()
self._window.update(view.RDPRenderer(self._controller, self._controller.getColorDepth()), True)
self._window.update(view.RDPRenderer(self._controller), True)
elif self._state == ProxyAdmin.State.SPY:
#refresh client
width, height = self._controller.getScreen()
@@ -311,21 +357,24 @@ class ProxyAdmin(rdp.RDPServerObserver):
def onClose(self):
"""
Stack is closes
@summary: Stack is close
@see: rdp.RDPServerObserver.onClose
"""
pass
def onKeyEventScancode(self, code, isPressed):
"""
Event call when a keyboard event is catch in scan code format
@summary: 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
@see: rdp.RDPServerObserver.onKeyEventScancode
"""
if self._state == ProxyAdmin.State.GUI:
if not isPressed:
return
self._window.keyEvent(code)
self._window.update(view.RDPRenderer(self._controller, self._controller.getColorDepth()))
self._window.update(view.RDPRenderer(self._controller))
elif code == 1:
#escape button refresh GUI
self._state = ProxyAdmin.State.GUI
@@ -334,38 +383,39 @@ class ProxyAdmin(rdp.RDPServerObserver):
def onKeyEventUnicode(self, code, isPressed):
"""
Event call when a keyboard event is catch in unicode format
In admin mode is forbidden
@summary: Event call when a keyboard event is catch in unicode format
Admin GUI add filter for this event
@param code: unicode of key
@param isPressed: True if key is down
@see: rdp.RDPServerObserver.onKeyEventUnicode
"""
pass
def onPointerEvent(self, x, y, button, isPressed):
"""
Event call on mouse event
In admin mode is forbidden
@summary: Event call on mouse event
Admin GUI add filter for this event
@param x: x position
@param y: y position
@param button: 1, 2 or 3 button
@param isPressed: True if mouse button is pressed
@see: rdp.RDPServerObserver.onPointerEvent
"""
pass
def onSelect(self, name):
def onSelect(self, index):
"""
Call back of list view
@param name: name selected by user
@summary: Callback of list view of active session
Connect to select session
@param index: index in sessions array
"""
if not ProxyClient._CONNECTED_.has_key(name):
return
self._state = ProxyAdmin.State.SPY
self._spy = ProxyClient(ProxyClient._CONNECTED_[name]._controller, self, "Admin")
self._spy = ProxyClient(self._sessions[index]._controller, self)
self._controller.setColorDepth(self._spy._controller.getColorDepth())
class ProxyAdminFactory(rdp.ServerFactory):
"""
Factory for admin
@summary: Factory for admin session
"""
def __init__(self, privateKeyFilePath, certificateFilePath):
"""
@@ -374,16 +424,19 @@ class ProxyAdminFactory(rdp.ServerFactory):
"""
rdp.ServerFactory.__init__(self, privateKeyFilePath, certificateFilePath, 16)
def buildObserver(self, controller):
def buildObserver(self, controller, addr):
"""
Implement rdp.ServerFactory
@summary: Build ProxyAdmin
@param controller: rdp.RDPServerController
@param addr: destination address
@return: ProxyAdmin
@see: rdp.ServerFactory.buildObserver
"""
return ProxyAdmin(controller)
class CredentialProvider(object):
"""
Credential provider for proxy
@summary: Credential provider for proxy
"""
def __init__(self, config):
"""
@@ -392,12 +445,19 @@ class CredentialProvider(object):
self._config = config
def getAccount(self, domain, username):
"""
@summary: Find account that match domain::username in config file
@param domain: Windows domain
@param username: username for session
@return: [(unicode(ip), port] or None if not found
"""
if not self._config.has_key(domain) or not self._config[domain].has_key(username):
return None
return self._config[domain][username]
def getProxyPass(self, domain, username):
"""
@summary: Find list of server available for thi account
@param domain: domain to check
@param username: username in domain
@return: [(ip, port)]
@@ -409,13 +469,13 @@ class CredentialProvider(object):
def help():
"""
Print help in console
@summary: Print help in console
"""
print "Usage: rdpy-rdpproxy -f credential_file_path -k private_key_file_path -c certificate_file_path listen_port"
def loadConfig(configFilePath):
"""
Load and check config file
@summary: Load and check config file
@param configFilePath: config file path
"""
if not os.path.isfile(configFilePath):

View File

@@ -24,42 +24,45 @@ Const it's use to create fake object enum in python
from copy import deepcopy
class Constant(object):
'''
Constant descriptor that deep copy value on get
'''
"""
@summary: Constant descriptor that deep copy value on get
"""
def __init__(self, value):
'''
Constructor keep value
'''
"""
@param value: value to protect
"""
self._value = value
def __get__(self, obj, objType):
'''
on get constant return deep copy of wrapped value
'''
"""
@summary: on get constant return deep copy of wrapped value
@param obj: unknown
@param objType: unknown
"""
return deepcopy(self._value)
def __set__(self, obj, value):
'''
set is forbidden
in python 2.7 this function work only
on instanciate object
'''
"""
@summary: Try to set a protect value is forbidden
in python 2.7 this function work only
on instanciate object
@param obj:
"""
raise Exception("can't assign constant")
def __delete__(self, obj):
'''
delete is forbidden on constant
'''
"""
@summary: delete is forbidden on constant
"""
raise Exception("can't delete constant")
def TypeAttributes(typeClass):
'''
call typeClass ctor on each attributes
to uniform atributes type on class
"""
@summary: Call typeClass ctor on each attributes
to uniform atributes type on class
@param typeClass: class use to construct each class attributes
@return: class decorator
'''
"""
def wrapper(cls):
for c_name, c_value in cls.__dict__.iteritems():
if c_name[0] != '_' and not callable(c_value):
@@ -68,11 +71,11 @@ def TypeAttributes(typeClass):
return wrapper
def ConstAttributes(cls):
'''
copy on read attributes
transform all attributes of class
in constant attribute
only attributes which are not begining with '_' char
and are not callable
'''
"""
@summary: Copy on read attributes
transform all attributes of class
in constant attribute
only attributes which are not begining with '_' char
and are not callable
"""
return TypeAttributes(Constant)(cls)

View File

@@ -23,7 +23,7 @@ All exceptions error use in RDPY
class CallPureVirtualFuntion(Exception):
"""
Raise when a virtual function is called and not implemented
@summary: Raise when a virtual function is called and not implemented
"""
def __init__(self, message = ""):
"""
@@ -33,7 +33,7 @@ class CallPureVirtualFuntion(Exception):
class InvalidValue(Exception):
"""
Raise when invalid value type occurred
@summary: Raise when invalid value type occurred
"""
def __init__(self, message = ""):
"""
@@ -43,7 +43,7 @@ class InvalidValue(Exception):
class InvalidExpectedDataException(Exception):
"""
Raise when expected data on network is invalid
@summary: Raise when expected data on network is invalid
"""
def __init__(self, message = ""):
"""
@@ -53,7 +53,7 @@ class InvalidExpectedDataException(Exception):
class NegotiationFailure(Exception):
"""
Raise when negotiation failure in different protocols
@summary: Raise when negotiation failure in different protocols
"""
def __init__(self, message = ""):
"""
@@ -63,7 +63,7 @@ class NegotiationFailure(Exception):
class InvalidType(Exception):
"""
Raise when invalid value type occured
@summary: Raise when invalid value type occured
"""
def __init__(self, message = ""):
"""
@@ -73,7 +73,7 @@ class InvalidType(Exception):
class InvalidSize(Exception):
"""
Raise when invalid size is present in packet type occured
@summary: Raise when invalid size is present in packet type occured
"""
def __init__(self, message = ""):
"""
@@ -83,7 +83,7 @@ class InvalidSize(Exception):
class ErrorReportedFromPeer(Exception):
"""
Raise when peer send an error
@summary: Raise when peer send an error
"""
def __init__(self, message = ""):
"""

View File

@@ -24,7 +24,7 @@ Actually very basic log engine
class Level(object):
"""
Level log
@summary: Level log
"""
DEBUG = 0
INFO = 1
@@ -34,24 +34,44 @@ class Level(object):
_LOG_LEVEL = Level.DEBUG
def log(message):
"""
@summary: Main log function
@param message: string to print
"""
print message
def error(message):
"""
@summary: Log error message
@param message: string to print as error log
"""
if _LOG_LEVEL > Level.ERROR:
return
log("ERROR : %s"%message)
def warning(message):
"""
@summary: Log warning message
@param message: string to print as warning log
"""
if _LOG_LEVEL > Level.WARNING:
return
log("WARNING : %s"%message)
def info(message):
"""
@summary: Log info message
@param message: string to print as info log
"""
if _LOG_LEVEL > Level.INFO:
return
log("INFO : %s"%message)
def debug(message):
"""
@summary: Log debug message
@param message: string to print as debug log
"""
if _LOG_LEVEL > Level.DEBUG:
return
log("DEBUG : %s"%message)

View File

@@ -27,32 +27,30 @@ from rdpy.base.error import CallPureVirtualFuntion
class IStreamListener(object):
"""
Interface use to inform that we can handle receive stream
@summary: Interface use to inform stream receiver capability
"""
def recv(self, s):
"""
Signal that data is available for this layer
call by transport layer
default is to pass data to presentation layer
@param s: raw Stream receive from transport layer
@summary: Signal that data is available
@param s: Stream
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener"))
class IStreamSender(object):
"""
Interface use to show stream sender capability
@summary: Interface use to inform stream sender capability
"""
def send(self, data):
'''
Send Stream on layer
"""
@summary: Send Stream on layer
@param data: Type or tuple element handle by transport layer
'''
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "send", "IStreamSender"))
class Layer(object):
"""
A simple double linked list with presentation and transport layer
and a subset of event (connect and close)
@summary: A simple double linked list with presentation and transport layer
and a subset of event (connect and close)
"""
def __init__(self, presentation = None):
"""
@@ -68,24 +66,25 @@ class Layer(object):
def connect(self):
"""
Call when transport layer is connected
default is send connect event to presentation layer
@summary: Call when transport layer is connected
default is send connect event to presentation layer
"""
if not self._presentation is None:
self._presentation.connect()
def close(self):
"""
Close layer event
default is sent to transport layer
@summary: Close layer event
default is sent to transport layer
"""
if not self._transport is None:
self._transport.close()
class LayerAutomata(Layer, IStreamListener):
"""
Layer with automata state
we can set next recv function used for Stream packet
@summary: Layer with automata callback
we can set next recv function used for Stream packet
Usefull for event driven engine as twisted
"""
def __init__(self, presentation = None):
"""
@@ -96,10 +95,8 @@ class LayerAutomata(Layer, IStreamListener):
def setNextState(self, callback = None):
"""
Set receive function to next callback or
current self.recv function if it's None
@param callback: a callable object that can
receive Layer, Stream parameters
@summary: Set the next callback in automata
@param callback: a callable object
"""
if callback is None:
callback = self.__class__.recv
@@ -114,11 +111,11 @@ from type import Stream
class RawLayerClientFactory(protocol.ClientFactory):
"""
Abstract class for Raw layer client factory
@summary: Abstract class for Raw layer client factory
"""
def buildProtocol(self, addr):
"""
Function call from twisted and build rdp protocol stack
@summary: Function call from twisted
@param addr: destination address
"""
rawLayer = self.buildRawLayer(addr)
@@ -127,24 +124,25 @@ class RawLayerClientFactory(protocol.ClientFactory):
def buildRawLayer(self, addr):
"""
Override this function to build raw layer
@summary: 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
@summary: Override this method to handle connection lost
@param rawlayer: rawLayer that cause connectionLost event
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener"))
class RawLayerServerFactory(protocol.ClientFactory):
"""
Abstract class for Raw layer server factory
@summary: Abstract class for Raw layer server factory
"""
def buildProtocol(self, addr):
"""
Function call from twisted and build rdp protocol stack
@summary: Function call from twisted
@param addr: destination address
"""
rawLayer = self.buildRawLayer(addr)
@@ -153,23 +151,24 @@ class RawLayerServerFactory(protocol.ClientFactory):
def buildRawLayer(self, addr):
"""
Override this function to build raw layer
@summary: 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
@summary: Override this method to handle connection lost
@param rawlayer: rawLayer that cause connectionLost event
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener"))
class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender):
"""
Inherit from protocol twisted class
allow this protocol to wait until expected size of packet
and use Layer automata to call next automata state
@summary: Wait event from twisted engine
And format correct size packet
And send correct packet to next automata callback
"""
def __init__(self, presentation = None):
"""
@@ -185,15 +184,15 @@ class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender):
def setFactory(self, factory):
"""
Call by RawLayer Factory
@summary: Call by RawLayer Factory
@param param: RawLayerClientFactory or RawLayerFactory
"""
self._factory = factory
def dataReceived(self, data):
"""
Inherit from protocol class
main event of received data
@summary: Inherit from twisted.protocol class
main event of received data
@param data: string data receive from twisted
"""
#add in buffer
@@ -209,24 +208,31 @@ class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender):
def connectionMade(self):
"""
inherit from twisted protocol
@summary: inherit from twisted protocol
"""
#join two scheme
self.connect()
def connectionLost(self, reason):
"""
@summary: Call from twisted engine when protocol is closed
@param reason: str represent reason of close connection
"""
self._factory.connectionLost(self)
def close(self):
"""
Close raw layer
@summary: Close raw layer
Use File descriptor directly to not use TLS close
Because is bugged
"""
FileDescriptor.loseConnection(self.transport)
def expect(self, expectedLen, callback = None):
"""
Configure layer to change next state with callback only
when expectLen bytes is received from transport layer
@summary: Set next automata callback,
But this callback will be only called when
data have expectedLen
@param expectedLen: in bytes length use to call next state
@param callback: callback call when expected length bytes is received
"""
@@ -236,8 +242,9 @@ class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender):
def send(self, message):
"""
Send Stream on TCP layer
format message into raw stream understood by transport layer
@summary: Send Stream on TCP layer
write rdpy Stream message to str
And send it to transport layer
@param message: (tuple | Type)
"""
s = Stream()

File diff suppressed because it is too large Load Diff

View File

@@ -27,7 +27,7 @@ import pdu.layer
import pdu.data
import pdu.caps
import rdpy.base.log as log
import tpkt, tpdu, mcs, gcc
import tpkt, x224, mcs, gcc
class RDPClientController(pdu.layer.PDUClientListener):
"""
@@ -41,9 +41,9 @@ class RDPClientController(pdu.layer.PDUClientListener):
#multi channel service
self._mcsLayer = mcs.Client(self._pduLayer)
#transport pdu layer
self._tpduLayer = tpdu.Client(self._mcsLayer)
self._x224Layer = x224.Client(self._mcsLayer)
#transport packet (protocol layer)
self._tpktLayer = tpkt.TPKT(self._tpduLayer, self._pduLayer)
self._tpktLayer = tpkt.TPKT(self._x224Layer, self._pduLayer)
#is pdu layer is ready to send
self._isReady = False
@@ -268,9 +268,9 @@ class RDPServerController(pdu.layer.PDUServerListener):
#multi channel service
self._mcsLayer = mcs.Server(self._pduLayer)
#transport pdu layer
self._tpduLayer = tpdu.Server(self._mcsLayer, privateKeyFileName, certificateFileName)
self._x224Layer = x224.Server(self._mcsLayer, privateKeyFileName, certificateFileName)
#transport packet (protocol layer)
self._tpktLayer = tpkt.TPKT(self._tpduLayer, self._pduLayer)
self._tpktLayer = tpkt.TPKT(self._x224Layer, self._pduLayer)
#set color depth of session
self.setColorDepth(colorDepth)
@@ -422,8 +422,8 @@ class ClientFactory(layer.RawLayerClientFactory):
"""
def connectionLost(self, tpktLayer):
#retrieve controller
tpduLayer = tpktLayer._presentation
mcsLayer = tpduLayer._presentation
x224Layer = tpktLayer._presentation
mcsLayer = x224Layer._presentation
pduLayer = mcsLayer._channels[mcs.Channel.MCS_GLOBAL_CHANNEL]
controller = pduLayer._listener
controller.onClose()
@@ -434,14 +434,14 @@ class ClientFactory(layer.RawLayerClientFactory):
@param addr: destination address
"""
controller = RDPClientController()
self.buildObserver(controller)
controller.getProtocol()._factory = self
self.buildObserver(controller, addr)
return controller.getProtocol()
def buildObserver(self, controller):
def buildObserver(self, controller, addr):
"""
Build observer use for connection
@param controller: RDPClientController
@param addr: destination address
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "buildObserver", "ClientFactory"))
@@ -461,8 +461,8 @@ class ServerFactory(layer.RawLayerServerFactory):
def connectionLost(self, tpktLayer):
#retrieve controller
tpduLayer = tpktLayer._presentation
mcsLayer = tpduLayer._presentation
x224Layer = tpktLayer._presentation
mcsLayer = x224Layer._presentation
pduLayer = mcsLayer._channels[mcs.Channel.MCS_GLOBAL_CHANNEL]
controller = pduLayer._listener
controller.onClose()
@@ -473,14 +473,14 @@ class ServerFactory(layer.RawLayerServerFactory):
@param addr: destination address
"""
controller = RDPServerController(self._privateKeyFileName, self._certificateFileName, self._colorDepth)
self.buildObserver(controller)
controller.getProtocol()._factory = self
self.buildObserver(controller, addr)
return controller.getProtocol()
def buildObserver(self, controller):
def buildObserver(self, controller, addr):
"""
Build observer use for connection
@param controller: RDP stack controller
@param addr: destination address
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "buildObserver", "ServerFactory"))

View File

@@ -36,40 +36,43 @@ class Action(object):
class IFastPathListener(object):
"""
Fast path packet listener
Usually PDU layer
@summary: Fast path packet listener
Usually X224 layer
"""
def recvFastPath(self, fastPathS):
"""
Call when fast path packet is received
@summary: Call when fast path packet is received
@param fastPathS: Stream
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recvFastPath", "recvFastPath"))
def setFastPathSender(self, fastPathSender):
"""
@summary: Call to set a fast path sender to listener
@param fastPathSender: IFastPathSender
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "setFastPathSender", "recvFastPath"))
class IFastPathSender(object):
"""
Fast path send capability
@summary: Fast path send capability
"""
def sendFastPath(self, fastPathS):
"""
@summary: Send fastPathS Type as fast path packet
@param fastPathS: type transform to stream and send as fastpath
"""
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendFastPath", "IFastPathSender"))
class TPKT(RawLayer, IFastPathSender):
"""
TPKT layer in RDP protocol stack
This layer only handle size of packet and determine if is a fast path packet
@summary: TPKT layer in RDP protocol stack
represent the Raw Layer in stack (first layer)
This layer only handle size of packet and determine if is a fast path packet
"""
def __init__(self, presentation, fastPathListener):
"""
@param presentation: presentation layer, in RDP case is TPDU layer
@param presentation: presentation layer, in RDP case is x224 layer
@param fastPathListener: IFastPathListener
"""
RawLayer.__init__(self, presentation)
@@ -84,8 +87,8 @@ class TPKT(RawLayer, IFastPathSender):
def connect(self):
"""
Call when transport layer connection
is made (inherit from RawLayer)
@summary: Call when transport layer connection
is made (inherit from RawLayer)
"""
#header is on two bytes
self.expect(2, self.readHeader)

View File

@@ -48,7 +48,7 @@ class NegociationType(object):
class Protocols(object):
"""
Protocols available for TPDU layer
Protocols available for x224 layer
"""
PROTOCOL_RDP = 0x00000000
PROTOCOL_SSL = 0x00000001
@@ -94,9 +94,9 @@ class ServerConnectionConfirm(CompositeType):
#read if there is enough data
self.protocolNeg = Negotiation(optional = True)
class TPDUDataHeader(CompositeType):
class X224DataHeader(CompositeType):
"""
Header send when TPDU exchange application data
Header send when x224 exchange application data
"""
def __init__(self):
CompositeType.__init__(self)
@@ -116,13 +116,13 @@ class Negotiation(CompositeType):
self.code = UInt8()
self.flag = UInt8(0)
#always 8
self.len = UInt16Le(0x0008, constant = True)#not constant because freerdp send me random value...
self.len = UInt16Le(0x0008, constant = True)
self.selectedProtocol = UInt32Le(conditional = lambda: (self.code.value != NegociationType.TYPE_RDP_NEG_FAILURE))
self.failureCode = UInt32Le(conditional = lambda: (self.code.value == NegociationType.TYPE_RDP_NEG_FAILURE))
class TPDULayer(LayerAutomata, IStreamSender):
class X224Layer(LayerAutomata, IStreamSender):
"""
TPDU layer management
x224 layer management
there is an connection automata
"""
def __init__(self, presentation):
@@ -143,7 +143,7 @@ class TPDULayer(LayerAutomata, IStreamSender):
And pass to presentation layer
@param data: Stream
"""
header = TPDUDataHeader()
header = X224DataHeader()
data.readType(header)
self._presentation.recv(data)
@@ -153,9 +153,9 @@ class TPDULayer(LayerAutomata, IStreamSender):
Add TPDU header
@param message: network.Type message
"""
self._transport.send((TPDUDataHeader(), message))
self._transport.send((X224DataHeader(), message))
class Client(TPDULayer):
class Client(X224Layer):
"""
Client automata of TPDU layer
"""
@@ -163,7 +163,7 @@ class Client(TPDULayer):
"""
@param presentation: upper layer, MCS layer in RDP case
"""
TPDULayer.__init__(self, presentation)
X224Layer.__init__(self, presentation)
def connect(self):
"""
@@ -216,9 +216,9 @@ class Client(TPDULayer):
#connection is done send to presentation
self._presentation.connect()
class Server(TPDULayer):
class Server(X224Layer):
"""
Server automata of TPDU layer
Server automata of X224 layer
"""
def __init__(self, presentation, privateKeyFileName, certificateFileName):
"""
@@ -226,7 +226,7 @@ class Server(TPDULayer):
@param privateKeyFileName: file contain server private key
@param certficiateFileName: file that contain public key
"""
TPDULayer.__init__(self, presentation)
X224Layer.__init__(self, presentation)
#Server mode informations for TLS connection
self._serverPrivateKeyFileName = privateKeyFileName
self._serverCertificateFileName = certificateFileName

View File

@@ -123,7 +123,7 @@ class List(IView):
if len(self._labels) == 0:
return
if code == KeyCode.ENTER:
self._callback(self._labels[self._current])
self._callback(self._current)
elif code == KeyCode.DOWN:
self._current = min(len(self._labels) - 1, self._current + 1)
self._needUpdate = True
@@ -221,14 +221,13 @@ class Label(IView):
qp.drawText(drawArea.rect(), QtCore.Qt.AlignCenter, self._label)
render.drawImage(drawArea)
class RDPRenderer(object):
def __init__(self, controller, colorDepth):
class RDPRenderer(IRender):
def __init__(self, controller):
"""
@param server: RDPServerController
@param colorDepth: color depth
"""
self._controller = controller
self._colorDepth = colorDepth
self._colorDepth = controller.getColorDepth()
self._dx = 0
self._dy = 0