From 3f854bd18b6a1447f410fc7080d91a5186e7e5a0 Mon Sep 17 00:00:00 2001 From: speyrefitte Date: Fri, 25 Jul 2014 18:15:42 +0200 Subject: [PATCH] finish proxy --- bin/rdpy-rdpproxy | 214 +++++++++++++++++++++++++-------- rdpy/network/layer.py | 12 +- rdpy/network/proxy.py | 53 ++++++++ rdpy/protocol/rdp/mcs.py | 4 +- rdpy/protocol/rdp/pdu/data.py | 45 ++++++- rdpy/protocol/rdp/pdu/layer.py | 12 +- rdpy/protocol/rdp/rdp.py | 26 ++++ rdpy/protocol/rdp/tpdu.py | 4 +- rdpy/protocol/rdp/tpkt.py | 12 +- rdpy/ui/qt4.py | 1 + 10 files changed, 311 insertions(+), 72 deletions(-) create mode 100644 rdpy/network/proxy.py diff --git a/bin/rdpy-rdpproxy b/bin/rdpy-rdpproxy index 23aa4f0..d0b9395 100755 --- a/bin/rdpy-rdpproxy +++ b/bin/rdpy-rdpproxy @@ -19,7 +19,7 @@ # """ -RDP proxy recorder and spyer +RDP proxy recorder and spy function Proxy RDP protocol """ @@ -29,8 +29,10 @@ sys.path.insert(1, os.path.join(sys.path[0], '..')) from rdpy.base import log, error from rdpy.protocol.rdp import rdp +from rdpy.network.proxy import IProxyClient from twisted.internet import reactor -clientMacro = None +from PyQt4 import QtCore, QtGui + class ProxyServer(rdp.RDPServerObserver): """ Server side of proxy @@ -49,10 +51,8 @@ class ProxyServer(rdp.RDPServerObserver): Event throw by client when it's ready @param client: ProxyClient """ - global clientMacro self._client = client - clientMacro = client - self._controller.setColorDepth(self._client._controller.getColorDepth()) + self._controller.setColorDepth(self._client.getColorDepth()) def onReady(self): """ @@ -62,18 +62,18 @@ class ProxyServer(rdp.RDPServerObserver): domain, username, password = self._controller.getCredentials() if self._credentialProvider.isAdmin(domain, username, password): - self.clientConnected(ProxyClient(clientMacro._controller, self)) + self.clientConnected(AdminGUI(self)) return try: - ip, port, domain, username, password = self._credentialProvider.getCredentials(domain, username, password) + dstIp, dstPort, dstDomain, dstUsername, dstPassword = self._credentialProvider.getCredentials(domain, username, password) except error.InvalidExpectedDataException as e: log.info(e.message) - self._controller.close() + #self._controller.close() return width, height = self._controller.getScreen() - reactor.connectTCP(ip, port, ProxyClientFactory(self, width, height)) + reactor.connectTCP(dstIp, dstPort, ProxyClientFactory(self, width, height, dstDomain, dstUsername, dstPassword, "%s/%s -> %s %s/%s"%(domain, username, dstIp, dstDomain, dstUsername))) def onKeyEventScancode(self, code, isPressed): """ @@ -85,7 +85,7 @@ class ProxyServer(rdp.RDPServerObserver): if self._client is None: return - self._client._controller.sendKeyEventScancode(code, isPressed) + self._client.sendKeyEventScancode(code, isPressed) def onKeyEventUnicode(self, code, isPressed): """ @@ -97,7 +97,7 @@ class ProxyServer(rdp.RDPServerObserver): if self._client is None: return - self._client._controller.sendKeyEventUnicode(code, isPressed) + self._client.sendKeyEventUnicode(code, isPressed) def onPointerEvent(self, x, y, button, isPressed): """ @@ -111,9 +111,9 @@ class ProxyServer(rdp.RDPServerObserver): if self._client is None: return - self._client._controller.sendPointerEvent(x, y, button, isPressed) + self._client.sendPointerEvent(x, y, button, isPressed) -class ProxyClient(rdp.RDPClientObserver): +class ProxyClient(rdp.RDPClientObserver, IProxyClient): """ Client side of proxy """ @@ -121,10 +121,34 @@ class ProxyClient(rdp.RDPClientObserver): """ @param controller: RDPClientObserver @param server: ProxyServer + @param name: name of session """ rdp.RDPClientObserver.__init__(self, controller) self._server = server + def getColorDepth(self): + """ + @return: color depth of session (15,16,24,32) + """ + return self._controller.getColorDepth() + + def sendKeyEventScancode(self, code, isPressed): + """ + Send key event with scan code + @param code: scan code + @param isPressed: True if keyboard key is pressed + """ + self._controller.sendKeyEventScancode(code, isPressed) + + def sendPointerEvent(self, x, y, button, isPressed): + """ + Send Pointer event + @param x: x position + @param y: y position + @param button: mouse button 1|2|3 + """ + self._controller.sendPointerEvent(x, y, button, isPressed) + def onReady(self): """ Event use to signal that RDP stack is ready @@ -150,12 +174,15 @@ class ProxyClient(rdp.RDPClientObserver): self._server._controller.sendUpdate(destLeft, destTop, destRight, destBottom, width, height, bitsPerPixel, isCompress, data) class ProxyServerFactory(rdp.ServerFactory): + """ + Factory on listening events + """ def __init__(self, credentialProvider): """ @param config: rdp-proxy configuration @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 def buildObserver(self, controller): @@ -175,27 +202,144 @@ class ProxyServerFactory(rdp.ServerFactory): pass class ProxyClientFactory(rdp.ClientFactory): - def __init__(self, server, width, height): + """ + Factory for proxy client + """ + _CLIENT_PROXY_ = {} + def __init__(self, server, width, height, domain, username, password, name): + """ + @param server: ProxyServer + @param width: screen width + @param height: screen height + @param domain: domain session + @param username: username session + @param password: password session + """ self._server = server self._width = width self._height = height + self._domain = domain + self._username = username + self._password = password + self._name = name def buildObserver(self, controller): + """ + Implement rdp.ClientFactory + Build observer (ProxyClient) + @param controller: rdp.RDPClientController + """ + #set screen resolution controller.setScreen(self._width, self._height) - return ProxyClient(controller, self._server) + #set credential + controller.setDomain(self._domain) + controller.setUsername(self._username) + controller.setPassword(self._password) + proxy = ProxyClient(controller, self._server) + ProxyClientFactory._CLIENT_PROXY_[self._name] = proxy + return proxy def startedConnecting(self, connector): pass def clientConnectionLost(self, connector, reason): - pass + if ProxyClientFactory._CLIENT_PROXY_.has_key(self._name): + del ProxyClientFactory._CLIENT_PROXY_[self._name] def clientConnectionFailed(self, connector, reason): + if ProxyClientFactory._CLIENT_PROXY_.has_key(self._name): + del ProxyClientFactory._CLIENT_PROXY_[self._name] + +class CredentialProvider(object): + """ + Credential provider for proxy + """ + def __init__(self, config): + """ + @param config: rdp proxy config + """ + self._config = config + + def getCredentials(self, domain, username, password): + """ + @param condig: rdp config + @param domain: domain to check + @param username: username in domain + @param password: password in domain + @return: (ip, port, domain, username, password) or None if error + """ + if not self._config['domain'].has_key(domain): + raise error.InvalidExpectedDataException("Unknown domain %s"%(domain)) + for user in self._config['domain'][domain]: + if user['username'] == username and user['password'] == password: + return str(user['credentials']['ip']), user['credentials']['port'], str(user['credentials']['domain']), str(user['credentials']['username']), str(user['credentials']['password']) + raise error.InvalidExpectedDataException("Unknown credential %s\%s"%(domain, username)) + + def isAdmin(self, domain, username, password): + """ + @return: True if credential match admin credential + """ + return self._config['admin']['domain'] == domain and self._config['admin']['username'] == username and self._config['admin']['password'] == password + +class AdminGUI(IProxyClient): + """ + Simple Administration GUI + """ + def __init__(self, server): + """ + @param server: ProxyServer + @param colorDepth: color depth use to generate screen + """ + self._server = server + self._colorDepth = self._server._controller.getColorDepth() + self._activeSessions = [ (x, y) for x, y in ProxyClientFactory._CLIENT_PROXY_.iteritems() ] + self._current = 0 + self.display() + + def getColorDepth(self): + return self._colorDepth + + def sendKeyEventScancode(self, code, isPressed): + #enter key + if code == 28: + clientController = self._activeSessions[self._current][1]._controller + self._server.clientConnected(ProxyClient(clientController, self._server)) + #force refresh for new admin screen + width, height = self._server._controller.getScreen() + clientController.sendRefreshOrder(0, 0, width, height) + + def sendPointerEvent(self, x, y, button, isPressed): pass + + def display(self): + """ + Draw GUI that list active session + """ + i = 0 + for name, session in self._activeSessions: + screen = QtGui.QImage(200, 20, QtGui.QImage.Format_RGB16) + if i == self._current: + screen.fill(QtCore.Qt.darkGray) + else: + screen.fill(QtCore.Qt.black) + + with QtGui.QPainter(screen) as qp: + if i == self._current: + qp.setPen(QtCore.Qt.black) + else: + qp.setPen(QtCore.Qt.gray) + qp.setFont(QtGui.QFont('arial', 12)) + qp.drawText(screen.rect(), QtCore.Qt.AlignCenter, name) + + ptr = screen.bits() + ptr.setsize(screen.byteCount()) + self._server._controller.sendUpdate(0, i*25, 199, 19, 200, 20, self._colorDepth, False, ptr.asstring()) + + i+= 1 def help(): """ - Print help in consoe + Print help in console """ print "Usage: rdpy-rdpproxy -f config_file_path listen_port" @@ -223,37 +367,6 @@ def loadConfig(configFilePath): return config -class CredentialProvider(object): - """ - Credential provider for proxy - """ - def __init__(self, config): - """ - @param config: rdp proxy config - """ - self._config = config - - def getCredentials(self, domain, username, password): - """ - @param condig: rdp config - @param domain: domain to check - @param username: username in domain - @param password: password in domain - @return: (ip, port, domain, username, password) or None if error - """ - if not self._config['domain'].has_key(domain): - raise error.InvalidExpectedDataException("Unknown domain %s"%(domain)) - for user in self._config['domain'][domain]: - if user['username'] == username and user['password'] == password: - return user['credentials']['ip'], user['credentials']['port'], user['credentials']['domain'], user['credentials']['username'], user['credentials']['password'] - raise error.InvalidExpectedDataException("Unknown credential %s\%s"%(domain, username)) - - def isAdmin(self, domain, username, password): - """ - @return: True if credential match admin credential - """ - return self._config['admin']['domain'] == domain and self._config['admin']['username'] == username and self._config['admin']['password'] == password - if __name__ == '__main__': configFilePath = None try: @@ -278,5 +391,8 @@ if __name__ == '__main__': log.error("Bad configuration file") sys.exit() + #use to init font + app = QtGui.QApplication(sys.argv) + reactor.listenTCP(int(args[0]), ProxyServerFactory(CredentialProvider(config))) reactor.run() \ No newline at end of file diff --git a/rdpy/network/layer.py b/rdpy/network/layer.py index e6e6242..80b60ab 100644 --- a/rdpy/network/layer.py +++ b/rdpy/network/layer.py @@ -25,7 +25,7 @@ RDPY use Layer Protocol design (like twisted) from rdpy.base.error import CallPureVirtualFuntion -class StreamListener(object): +class IStreamListener(object): """ Interface use to inform that we can handle receive stream """ @@ -36,9 +36,9 @@ class StreamListener(object): default is to pass data to presentation layer @param s: raw Stream receive from transport layer """ - raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "StreamListener")) + raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener")) -class StreamSender(object): +class IStreamSender(object): """ Interface use to show stream sender capability """ @@ -47,7 +47,7 @@ class StreamSender(object): 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", "StreamSender")) + raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "send", "IStreamSender")) class Layer(object): """ @@ -82,7 +82,7 @@ class Layer(object): if not self._transport is None: self._transport.close() -class LayerAutomata(Layer, StreamListener): +class LayerAutomata(Layer, IStreamListener): """ Layer with automata state we can set next recv function used for Stream packet @@ -111,7 +111,7 @@ from twisted.internet import protocol #first that handle stream from type import Stream -class RawLayer(protocol.Protocol, LayerAutomata, StreamSender): +class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender): """ Inherit from protocol twisted class allow this protocol to wait until expected size of packet diff --git a/rdpy/network/proxy.py b/rdpy/network/proxy.py new file mode 100644 index 0000000..0a25c63 --- /dev/null +++ b/rdpy/network/proxy.py @@ -0,0 +1,53 @@ +# +# 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 . +# + +""" +Proxy Interface +client -> ProxyServer | ProxyClient -> server +""" + +from rdpy.base.error import CallPureVirtualFuntion + +class IProxyClient(object): + """ + Proxy interface for client side + """ + def getColorDepth(self): + """ + @return: color depth of session (15,16,24,32) + """ + raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onUpdate", "IProxyClient")) + + def sendKeyEventScancode(self, code, isPressed): + """ + Send key event with scan code + @param code: scan code + @param isPressed: True if keyboard key is pressed + """ + raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onUpdate", "IProxyClient")) + + def sendPointerEvent(self, x, y, button, isPressed): + """ + Send Pointer event + @param x: x position + @param y: y position + @param button: mouse button 1|2|3 + """ + raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onUpdate", "IProxyClient")) + diff --git a/rdpy/protocol/rdp/mcs.py b/rdpy/protocol/rdp/mcs.py index a60cb76..18e7380 100644 --- a/rdpy/protocol/rdp/mcs.py +++ b/rdpy/protocol/rdp/mcs.py @@ -24,7 +24,7 @@ Each channel have a particular role. The main channel is the graphical channel. 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, IStreamSender, Layer from rdpy.network.type import sizeof, Stream, UInt8, UInt16Le, String from rdpy.base.error import InvalidExpectedDataException, InvalidValue, InvalidSize from rdpy.protocol.rdp.ber import writeLength @@ -65,7 +65,7 @@ class MCSLayer(LayerAutomata): the main layer of RDP protocol is why he can do everything and more! """ - class MCSProxySender(Layer, StreamSender): + class MCSProxySender(Layer, IStreamSender): """ Proxy use to set as transport layer for upper channel use to abstract channel id for presentation layer diff --git a/rdpy/protocol/rdp/pdu/data.py b/rdpy/protocol/rdp/pdu/data.py index 0413231..0d6ae22 100644 --- a/rdpy/protocol/rdp/pdu/data.py +++ b/rdpy/protocol/rdp/pdu/data.py @@ -260,6 +260,14 @@ class FastPathOutputCompression(object): """ FASTPATH_OUTPUT_COMPRESSION_USED = 0x2 +class Display(object): + """ + Use in supress output PDU + @see: http://msdn.microsoft.com/en-us/library/cc240648.aspx + """ + SUPPRESS_DISPLAY_UPDATES = 0x00 + ALLOW_DISPLAY_UPDATES = 0x01 + class ErrorInfo(object): """ Error code use in Error info PDU @@ -638,7 +646,7 @@ class DataPDU(CompositeType): """ Create object in accordance self.shareDataHeader.pduType2 value """ - for c in [UpdateDataPDU, SynchronizeDataPDU, ControlDataPDU, ErrorInfoDataPDU, FontListDataPDU, FontMapDataPDU, PersistentListPDU, ClientInputEventPDU, ShutdownDeniedPDU, ShutdownRequestPDU]: + for c in [UpdateDataPDU, SynchronizeDataPDU, ControlDataPDU, ErrorInfoDataPDU, FontListDataPDU, FontMapDataPDU, PersistentListPDU, ClientInputEventPDU, ShutdownDeniedPDU, ShutdownRequestPDU, SuppressOutputDataPDU]: if self.shareDataHeader.pduType2.value == c._PDUTYPE2_: return c() log.debug("unknown PDU data type : %s"%hex(self.shareDataHeader.pduType2.value)) @@ -799,6 +807,41 @@ class ShutdownDeniedPDU(CompositeType): def __init__(self): CompositeType.__init__(self) +class InclusiveRectangle(CompositeType): + """ + @see: http://msdn.microsoft.com/en-us/library/cc240643.aspx + """ + def __init__(self, conditional = lambda:True): + CompositeType.__init__(self) + self.left = UInt16Le() + self.top = UInt16Le() + self.right = UInt16Le() + self.bottom = UInt16Le() + +class SuppressOutputDataPDU(CompositeType): + """ + @see: http://msdn.microsoft.com/en-us/library/cc240648.aspx + """ + _PDUTYPE2_ = PDUType2.PDUTYPE2_SUPPRESS_OUTPUT + + def __init__(self, readLen = None): + CompositeType.__init__(self, readLen = readLen) + self.allowDisplayUpdates = UInt8() + self.pad3Octets = (UInt8(), UInt8(), UInt8()) + self.desktopRect = InclusiveRectangle(conditional = lambda:(self.allowDisplayUpdates.value == Display.ALLOW_DISPLAY_UPDATES)) + +class RefreshRectPDU(CompositeType): + """ + @see: http://msdn.microsoft.com/en-us/library/cc240646.aspx + """ + _PDUTYPE2_ = PDUType2.PDUTYPE2_REFRESH_RECT + + def __init__(self, readLen = None): + CompositeType.__init__(self, readLen = readLen) + self.numberOfAreas = UInt8(lambda:len(self.areasToRefresh._array)) + self.pad3Octets = (UInt8(), UInt8(), UInt8()) + self.areasToRefresh = ArrayType(InclusiveRectangle, readLen = self.numberOfAreas) + class UpdateDataPDU(CompositeType): """ Update data PDU use by server to inform update image or palet diff --git a/rdpy/protocol/rdp/pdu/layer.py b/rdpy/protocol/rdp/pdu/layer.py index 8633c9d..8dfae6b 100644 --- a/rdpy/protocol/rdp/pdu/layer.py +++ b/rdpy/protocol/rdp/pdu/layer.py @@ -124,7 +124,7 @@ class PDULayer(LayerAutomata): """ self.sendPDU(data.DataPDU(pduData, self._shareId)) -class Client(PDULayer, tpkt.FastPathListener): +class Client(PDULayer, tpkt.IFastPathListener): """ Client automata of PDU layer """ @@ -159,7 +159,7 @@ class Client(PDULayer, tpkt.FastPathListener): def setFastPathSender(self, fastPathSender): """ @param fastPathSender: tpkt.FastPathSender - @note: implement tpkt.FastPathListener + @note: implement tpkt.IFastPathListener """ self._fastPathSender = fastPathSender @@ -301,7 +301,7 @@ class Client(PDULayer, tpkt.FastPathListener): def recvFastPath(self, fastPathS): """ - Implement FastPathListener interface + Implement IFastPathListener interface Fast path is needed by RDP 8.0 @param fastPathS: Stream that contain fast path data """ @@ -410,7 +410,7 @@ class Client(PDULayer, tpkt.FastPathListener): pdu.slowPathInputEvents._array = [data.SlowPathInputEvent(x) for x in pointerEvents] self.sendDataPDU(pdu) -class Server(PDULayer, tpkt.FastPathListener): +class Server(PDULayer, tpkt.IFastPathListener): """ Server Automata of PDU layer """ @@ -433,7 +433,7 @@ class Server(PDULayer, tpkt.FastPathListener): def setFastPathSender(self, fastPathSender): """ @param fastPathSender: tpkt.FastPathSender - @note: implement tpkt.FastPathListener + @note: implement tpkt.IFastPathListener """ self._fastPathSender = fastPathSender @@ -577,7 +577,7 @@ class Server(PDULayer, tpkt.FastPathListener): def recvFastPath(self, fastPathS): """ - Implement FastPathListener interface + Implement IFastPathListener interface Fast path is needed by RDP 8.0 @param fastPathS: Stream that contain fast path data """ diff --git a/rdpy/protocol/rdp/rdp.py b/rdpy/protocol/rdp/rdp.py index 9a2742a..1961611 100644 --- a/rdpy/protocol/rdp/rdp.py +++ b/rdpy/protocol/rdp/rdp.py @@ -213,6 +213,23 @@ class RDPClientController(pdu.layer.PDUClientListener): except InvalidValue: log.info("try send bad key event") + def sendRefreshOrder(self, left, top, right, bottom): + """ + Force server to resend a particular zone + @param left: left coordinate + @param top: top coordinate + @param right: right coordinate + @param bottom: bottom coordinate + """ + refreshPDU = pdu.data.RefreshRectPDU() + rect = pdu.data.InclusiveRectangle() + rect.left.value = left + rect.top.value = top + rect.right.value = right + rect.bottom.value = bottom + refreshPDU.areasToRefresh._array.append(rect) + self._pduLayer.sendDataPDU(refreshPDU) + def close(self): """ Close protocol stack @@ -279,6 +296,12 @@ class RDPServerController(pdu.layer.PDUServerListener): """ return (self.getDomain(), self.getUsername(), self.getPassword()) + def getColorDepth(self): + """ + @return: color depth define by server + """ + return self._colorDepth + def getScreen(self): """ @return: tuple(width, height) of client asked screen @@ -299,6 +322,9 @@ class RDPServerController(pdu.layer.PDUServerListener): if PDU stack is already connected send a deactive-reactive sequence @param colorDepth: depth of session (15, 16, 24) """ + self._colorDepth = colorDepth + if self._pduLayer._serverCapabilities[pdu.caps.CapsType.CAPSTYPE_BITMAP].capability.preferredBitsPerPixel.value == colorDepth: + return self._pduLayer._serverCapabilities[pdu.caps.CapsType.CAPSTYPE_BITMAP].capability.preferredBitsPerPixel.value = colorDepth if self._isReady: #restart connection sequence diff --git a/rdpy/protocol/rdp/tpdu.py b/rdpy/protocol/rdp/tpdu.py index 125abe3..7dda76f 100644 --- a/rdpy/protocol/rdp/tpdu.py +++ b/rdpy/protocol/rdp/tpdu.py @@ -24,7 +24,7 @@ This layer have main goal to negociate SSL transport RDP basic security is not supported by RDPY (because is not a true security layer...) """ -from rdpy.network.layer import LayerAutomata, StreamSender +from rdpy.network.layer import LayerAutomata, IStreamSender from rdpy.network.type import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof from rdpy.base.error import InvalidExpectedDataException @@ -107,7 +107,7 @@ class Negotiation(CompositeType): 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, StreamSender): +class TPDULayer(LayerAutomata, IStreamSender): """ TPDU layer management there is an connection automata diff --git a/rdpy/protocol/rdp/tpkt.py b/rdpy/protocol/rdp/tpkt.py index 8b773b1..b0e18df 100644 --- a/rdpy/protocol/rdp/tpkt.py +++ b/rdpy/protocol/rdp/tpkt.py @@ -34,7 +34,7 @@ class Action(object): FASTPATH_ACTION_FASTPATH = 0x0 FASTPATH_ACTION_X224 = 0x3 -class FastPathListener(object): +class IFastPathListener(object): """ Fast path packet listener Usually PDU layer @@ -48,11 +48,11 @@ class FastPathListener(object): def setFastPathSender(self, fastPathSender): """ - @param fastPathSender: FastPathSender + @param fastPathSender: IFastPathSender """ raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "setFastPathSender", "recvFastPath")) -class FastPathSender(object): +class IFastPathSender(object): """ Fast path send capability """ @@ -60,9 +60,9 @@ class FastPathSender(object): """ @param fastPathS: type transform to stream and send as fastpath """ - raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendFastPath", "FastPathSender")) + raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "sendFastPath", "IFastPathSender")) -class TPKT(RawLayer, FastPathSender): +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 @@ -70,7 +70,7 @@ class TPKT(RawLayer, FastPathSender): def __init__(self, presentation, fastPathListener): """ @param presentation: presentation layer, in RDP case is TPDU layer - @param fastPathListener: FastPathListener + @param fastPathListener: IFastPathListener """ RawLayer.__init__(self, presentation) #last packet version read from header diff --git a/rdpy/ui/qt4.py b/rdpy/ui/qt4.py index 82b1df0..135d8de 100644 --- a/rdpy/ui/qt4.py +++ b/rdpy/ui/qt4.py @@ -299,6 +299,7 @@ class QRemoteDesktop(QtGui.QWidget): #draw in widget with QtGui.QPainter(self) as qp: qp.drawImage(0, 0, self._buffer) + self._refresh = [] def mouseMoveEvent(self, event):