Start python3
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,3 +7,5 @@ README.md~
|
|||||||
dist/*
|
dist/*
|
||||||
build/*
|
build/*
|
||||||
rdpy.egg-info/*
|
rdpy.egg-info/*
|
||||||
|
*.pyd
|
||||||
|
.idea
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ In a nutshell RDPY can be used as a protocol library with a twisted engine.
|
|||||||
### Simple RDP Client
|
### Simple RDP Client
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from rdpy.protocol.rdp import rdp
|
from rdpy.core import rdp
|
||||||
|
|
||||||
class MyRDPFactory(rdp.ClientFactory):
|
class MyRDPFactory(rdp.ClientFactory):
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ reactor.run()
|
|||||||
|
|
||||||
### Simple RDP Server
|
### Simple RDP Server
|
||||||
```python
|
```python
|
||||||
from rdpy.protocol.rdp import rdp
|
from rdpy.core import rdp
|
||||||
|
|
||||||
class MyRDPFactory(rdp.ServerFactory):
|
class MyRDPFactory(rdp.ServerFactory):
|
||||||
|
|
||||||
|
|||||||
@@ -23,13 +23,13 @@ example of use rdpy as rdp client
|
|||||||
|
|
||||||
import sys, os, getopt, socket
|
import sys, os, getopt, socket
|
||||||
|
|
||||||
from PyQt4 import QtGui, QtCore
|
from PyQt5 import QtWidgets
|
||||||
from rdpy.ui.qt4 import RDPClientQt
|
from rdpy.ui.qt4 import RDPClientQt
|
||||||
from rdpy.protocol.rdp import rdp
|
from rdpy.model.error import RDPSecurityNegoFail
|
||||||
from rdpy.core.error import RDPSecurityNegoFail
|
from rdpy.model import rss
|
||||||
from rdpy.core import rss
|
from rdpy.core import rdp
|
||||||
|
|
||||||
import rdpy.core.log as log
|
import rdpy.model.log as log
|
||||||
log._LOG_LEVEL = log.Level.INFO
|
log._LOG_LEVEL = log.Level.INFO
|
||||||
|
|
||||||
|
|
||||||
@@ -87,6 +87,7 @@ class RDPClientQtRecorder(RDPClientQt):
|
|||||||
self._rssRecorder.close()
|
self._rssRecorder.close()
|
||||||
RDPClientQt.closeEvent(self, e)
|
RDPClientQt.closeEvent(self, e)
|
||||||
|
|
||||||
|
|
||||||
class RDPClientQtFactory(rdp.ClientFactory):
|
class RDPClientQtFactory(rdp.ClientFactory):
|
||||||
"""
|
"""
|
||||||
@summary: Factory create a RDP GUI client
|
@summary: Factory create a RDP GUI client
|
||||||
@@ -211,7 +212,7 @@ def autoDetectKeyboardLayout():
|
|||||||
return "en"
|
return "en"
|
||||||
|
|
||||||
def help():
|
def help():
|
||||||
print """
|
print("""
|
||||||
Usage: rdpy-rdpclient [options] ip[:port]"
|
Usage: rdpy-rdpclient [options] ip[:port]"
|
||||||
\t-u: user name
|
\t-u: user name
|
||||||
\t-p: password
|
\t-p: password
|
||||||
@@ -222,7 +223,7 @@ def help():
|
|||||||
\t-k: keyboard layout [en|fr] [default : en]
|
\t-k: keyboard layout [en|fr] [default : en]
|
||||||
\t-o: optimized session (disable costly effect) [default : False]
|
\t-o: optimized session (disable costly effect) [default : False]
|
||||||
\t-r: rss_filepath Recorded Session Scenario [default : None]
|
\t-r: rss_filepath Recorded Session Scenario [default : None]
|
||||||
"""
|
""")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
@@ -236,7 +237,7 @@ if __name__ == '__main__':
|
|||||||
optimized = False
|
optimized = False
|
||||||
recodedPath = None
|
recodedPath = None
|
||||||
keyboardLayout = autoDetectKeyboardLayout()
|
keyboardLayout = autoDetectKeyboardLayout()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
opts, args = getopt.getopt(sys.argv[1:], "hfou:p:d:w:l:k:r:")
|
opts, args = getopt.getopt(sys.argv[1:], "hfou:p:d:w:l:k:r:")
|
||||||
except getopt.GetoptError:
|
except getopt.GetoptError:
|
||||||
@@ -270,19 +271,11 @@ if __name__ == '__main__':
|
|||||||
ip, port = args[0], "3389"
|
ip, port = args[0], "3389"
|
||||||
|
|
||||||
#create application
|
#create application
|
||||||
app = QtGui.QApplication(sys.argv)
|
app = QtWidgets.QApplication(sys.argv)
|
||||||
|
|
||||||
#add qt4 reactor
|
|
||||||
import qt4reactor
|
|
||||||
qt4reactor.install()
|
|
||||||
|
|
||||||
if fullscreen:
|
if fullscreen:
|
||||||
width = QtGui.QDesktopWidget().screenGeometry().width()
|
width = QtWidgets.QDesktopWidget().screenGeometry().width()
|
||||||
height = QtGui.QDesktopWidget().screenGeometry().height()
|
height = QtWidgets.QDesktopWidget().screenGeometry().height()
|
||||||
|
|
||||||
log.info("keyboard layout set to %s"%keyboardLayout)
|
log.info("keyboard layout set to %s"%keyboardLayout)
|
||||||
|
sys.exit(app.exec_())
|
||||||
from twisted.internet import reactor
|
|
||||||
reactor.connectTCP(ip, int(port), RDPClientQtFactory(width, height, username, password, domain, fullscreen, keyboardLayout, optimized, "nego", recodedPath))
|
|
||||||
reactor.runReturn()
|
|
||||||
app.exec_()
|
|
||||||
@@ -22,10 +22,10 @@
|
|||||||
RDP Honey pot use Rss scenario file to simulate RDP server
|
RDP Honey pot use Rss scenario file to simulate RDP server
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys, os, getopt, time, datetime
|
import sys, getopt, datetime
|
||||||
|
|
||||||
from rdpy.core import log, error, rss
|
from rdpy.core import log, rss
|
||||||
from rdpy.protocol.rdp import rdp
|
from rdpy.core import rdp
|
||||||
from twisted.internet import reactor
|
from twisted.internet import reactor
|
||||||
|
|
||||||
log._LOG_LEVEL = log.Level.INFO
|
log._LOG_LEVEL = log.Level.INFO
|
||||||
|
|||||||
@@ -29,13 +29,12 @@ Client RDP -> | ProxyServer | ProxyClient | -> Server RDP
|
|||||||
-----------------
|
-----------------
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
import argparse
|
import argparse
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from rdpy.core import log, error, rss
|
from rdpy.core import log, rss
|
||||||
from rdpy.protocol.rdp import rdp
|
from rdpy.core import rdp
|
||||||
from twisted.internet import reactor
|
from twisted.internet import reactor
|
||||||
|
|
||||||
log._LOG_LEVEL = log.Level.INFO
|
log._LOG_LEVEL = log.Level.INFO
|
||||||
|
|||||||
@@ -24,15 +24,13 @@ take screenshot of login page
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import getopt
|
import getopt
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from PyQt4 import QtCore, QtGui
|
from PyQt4 import QtGui
|
||||||
from rdpy.protocol.rdp import rdp
|
from rdpy.core import rdp
|
||||||
from rdpy.ui.qt4 import RDPBitmapToQtImage
|
from rdpy.ui.qt4 import RDPBitmapToQtImage
|
||||||
import rdpy.core.log as log
|
import rdpy.core.log as log
|
||||||
from rdpy.core.error import RDPSecurityNegoFail
|
from rdpy.core.error import RDPSecurityNegoFail
|
||||||
from twisted.internet import task
|
|
||||||
|
|
||||||
# set log level
|
# set log level
|
||||||
log._LOG_LEVEL = log.Level.INFO
|
log._LOG_LEVEL = log.Level.INFO
|
||||||
|
|||||||
13
ext/rle.c
13
ext/rle.c
@@ -938,10 +938,19 @@ static PyMethodDef rle_methods[] =
|
|||||||
{"bitmap_decompress", bitmap_decompress_wrapper, METH_VARARGS, "decompress bitmap from microsoft rle algorithm."},
|
{"bitmap_decompress", bitmap_decompress_wrapper, METH_VARARGS, "decompress bitmap from microsoft rle algorithm."},
|
||||||
{NULL, NULL, 0, NULL}
|
{NULL, NULL, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct PyModuleDef rle =
|
||||||
|
{
|
||||||
|
PyModuleDef_HEAD_INIT,
|
||||||
|
"rle", /* name of module */
|
||||||
|
"", /* module documentation, may be NULL */
|
||||||
|
-1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */
|
||||||
|
rle_methods
|
||||||
|
};
|
||||||
|
|
||||||
PyMODINIT_FUNC
|
PyMODINIT_FUNC
|
||||||
initrle(void)
|
PyInit_rle(void)
|
||||||
{
|
{
|
||||||
(void) Py_InitModule("rle", rle_methods);
|
(void) PyModule_Create(&rle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,11 +22,11 @@
|
|||||||
@see: http://msdn.microsoft.com/en-us/library/cc241880.aspx
|
@see: http://msdn.microsoft.com/en-us/library/cc241880.aspx
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from rdpy.core.type import CompositeType, CallableValue, UInt8, UInt16Le, UInt32Le, String, sizeof, FactoryType, ArrayType, Stream
|
from rdpy.model.type import CompositeType, CallableValue, UInt8, UInt16Le, UInt32Le, String, sizeof, FactoryType, ArrayType, Stream
|
||||||
from rdpy.core.error import InvalidExpectedDataException
|
from rdpy.model.error import InvalidExpectedDataException
|
||||||
import rdpy.core.log as log
|
import rdpy.model.log as log
|
||||||
import sec
|
from rdpy.core import sec
|
||||||
from t125 import gcc
|
from rdpy.core.t125 import gcc
|
||||||
from rdpy.security import rc4
|
from rdpy.security import rc4
|
||||||
from rdpy.security import rsa_wrapper as rsa
|
from rdpy.security import rsa_wrapper as rsa
|
||||||
|
|
||||||
@@ -27,11 +27,9 @@ import pyasn1.codec.der.encoder as der_encoder
|
|||||||
import pyasn1.codec.der.decoder as der_decoder
|
import pyasn1.codec.der.decoder as der_decoder
|
||||||
import pyasn1.codec.ber.encoder as ber_encoder
|
import pyasn1.codec.ber.encoder as ber_encoder
|
||||||
|
|
||||||
from rdpy.core.type import Stream
|
from rdpy.model.type import Stream
|
||||||
from twisted.internet import protocol
|
|
||||||
from OpenSSL import crypto
|
|
||||||
from rdpy.security import x509
|
from rdpy.security import x509
|
||||||
from rdpy.core import error
|
from rdpy.model import error
|
||||||
|
|
||||||
class NegoToken(univ.Sequence):
|
class NegoToken(univ.Sequence):
|
||||||
componentType = namedtype.NamedTypes(
|
componentType = namedtype.NamedTypes(
|
||||||
@@ -175,7 +173,7 @@ def encodeDERTCredentials(domain, username, password):
|
|||||||
|
|
||||||
return der_encoder.encode(credentials)
|
return der_encoder.encode(credentials)
|
||||||
|
|
||||||
class CSSP(protocol.Protocol):
|
class CSSP:
|
||||||
"""
|
"""
|
||||||
@summary: Handle CSSP connection
|
@summary: Handle CSSP connection
|
||||||
Proxy class for authentication
|
Proxy class for authentication
|
||||||
@@ -23,12 +23,12 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import hashlib, hmac, struct, datetime
|
import hashlib, hmac, struct, datetime
|
||||||
import sspi
|
from rdpy.core.nla import sspi
|
||||||
import rdpy.security.pyDes as pyDes
|
import rdpy.security.pyDes as pyDes
|
||||||
import rdpy.security.rc4 as rc4
|
import rdpy.security.rc4 as rc4
|
||||||
from rdpy.security.rsa_wrapper import random
|
from rdpy.security.rsa_wrapper import random
|
||||||
from rdpy.core.type import CompositeType, CallableValue, String, UInt8, UInt16Le, UInt24Le, UInt32Le, sizeof, Stream
|
from rdpy.model.type import CompositeType, CallableValue, String, UInt8, UInt16Le, UInt24Le, UInt32Le, sizeof, Stream
|
||||||
from rdpy.core import filetimes, error
|
from rdpy.model import filetimes, error
|
||||||
|
|
||||||
class MajorVersion(object):
|
class MajorVersion(object):
|
||||||
"""
|
"""
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
@summary: security service provider interface (Microsoft)
|
@summary: security service provider interface (Microsoft)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from rdpy.core.error import CallPureVirtualFuntion
|
from rdpy.model.error import CallPureVirtualFuntion
|
||||||
|
|
||||||
class IAuthenticationProtocol(object):
|
class IAuthenticationProtocol(object):
|
||||||
"""
|
"""
|
||||||
@@ -16,16 +16,17 @@
|
|||||||
# 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 rdpy.core.error import InvalidExpectedDataException
|
from rdpy.model.error import InvalidExpectedDataException
|
||||||
import rdpy.core.log as log
|
import rdpy.model.log as log
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Definition of structure use for capabilities nego
|
Definition of structure use for capabilities nego
|
||||||
Use in PDU layer
|
Use in PDU layer
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from rdpy.core.type import CompositeType, CallableValue, String, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType
|
from rdpy.model.type import CompositeType, CallableValue, String, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType
|
||||||
|
|
||||||
|
|
||||||
class CapsType(object):
|
class CapsType(object):
|
||||||
"""
|
"""
|
||||||
@summary: Different type of capabilities
|
@summary: Different type of capabilities
|
||||||
@@ -22,10 +22,10 @@ Implement the main graphic layer
|
|||||||
|
|
||||||
In this layer are managed all mains bitmap update orders end user inputs
|
In this layer are managed all mains bitmap update orders end user inputs
|
||||||
"""
|
"""
|
||||||
from rdpy.core.type import CompositeType, CallableValue, String, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType
|
from rdpy.model.type import CompositeType, CallableValue, String, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType
|
||||||
from rdpy.core.error import InvalidExpectedDataException
|
from rdpy.model.error import InvalidExpectedDataException
|
||||||
import rdpy.core.log as log
|
import rdpy.model.log as log
|
||||||
import caps, order
|
from rdpy.core.pdu import caps, order
|
||||||
|
|
||||||
class PDUType(object):
|
class PDUType(object):
|
||||||
"""
|
"""
|
||||||
@@ -23,12 +23,13 @@ Implement the main graphic layer
|
|||||||
In this layer are managed all mains bitmap update orders end user inputs
|
In this layer are managed all mains bitmap update orders end user inputs
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from rdpy.core.layer import LayerAutomata
|
from rdpy.model.layer import LayerAutomata
|
||||||
from rdpy.core.error import CallPureVirtualFuntion
|
from rdpy.model.error import CallPureVirtualFuntion
|
||||||
from rdpy.core.type import ArrayType
|
from rdpy.model.type import ArrayType
|
||||||
import rdpy.core.log as log
|
import rdpy.model.log as log
|
||||||
import rdpy.protocol.rdp.tpkt as tpkt
|
from rdpy.core import tpkt
|
||||||
import data, caps
|
from rdpy.core.pdu import data, caps
|
||||||
|
|
||||||
|
|
||||||
class PDUClientListener(object):
|
class PDUClientListener(object):
|
||||||
"""
|
"""
|
||||||
@@ -21,9 +21,9 @@
|
|||||||
GDI order structure
|
GDI order structure
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from rdpy.core import log
|
from rdpy.model import log
|
||||||
from rdpy.core.error import InvalidExpectedDataException
|
from rdpy.model.error import InvalidExpectedDataException
|
||||||
from rdpy.core.type import CompositeType, UInt8, String, FactoryType, SInt8, SInt16Le
|
from rdpy.model.type import CompositeType, UInt8, String, FactoryType, SInt8, SInt16Le
|
||||||
|
|
||||||
class ControlFlag(object):
|
class ControlFlag(object):
|
||||||
"""
|
"""
|
||||||
@@ -21,15 +21,19 @@
|
|||||||
Use to manage RDP stack in twisted
|
Use to manage RDP stack in twisted
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from rdpy.core import layer
|
from rdpy.model import layer
|
||||||
from rdpy.core.error import CallPureVirtualFuntion, InvalidValue
|
from rdpy.model.error import CallPureVirtualFuntion, InvalidValue
|
||||||
import pdu.layer
|
from rdpy.core.pdu.layer import PDUClientListener, PDUServerListener
|
||||||
import pdu.data
|
from rdpy.core.pdu import data
|
||||||
import pdu.caps
|
from rdpy.core.pdu import caps
|
||||||
import rdpy.core.log as log
|
from rdpy.core.pdu import layer as pdu
|
||||||
import tpkt, x224, sec
|
import rdpy.model.log as log
|
||||||
from t125 import mcs, gcc
|
import rdpy.core.tpkt as tpkt
|
||||||
from nla import cssp, ntlm
|
import rdpy.core.x224 as x224
|
||||||
|
import rdpy.core.sec as sec
|
||||||
|
from rdpy.core.t125 import mcs, gcc
|
||||||
|
from rdpy.core.nla import cssp, ntlm
|
||||||
|
|
||||||
|
|
||||||
class SecurityLevel(object):
|
class SecurityLevel(object):
|
||||||
"""
|
"""
|
||||||
@@ -39,7 +43,8 @@ class SecurityLevel(object):
|
|||||||
RDP_LEVEL_SSL = 1
|
RDP_LEVEL_SSL = 1
|
||||||
RDP_LEVEL_NLA = 2
|
RDP_LEVEL_NLA = 2
|
||||||
|
|
||||||
class RDPClientController(pdu.layer.PDUClientListener):
|
|
||||||
|
class RDPClientController(PDUClientListener):
|
||||||
"""
|
"""
|
||||||
Manage RDP stack as client
|
Manage RDP stack as client
|
||||||
"""
|
"""
|
||||||
@@ -47,7 +52,7 @@ class RDPClientController(pdu.layer.PDUClientListener):
|
|||||||
#list of observer
|
#list of observer
|
||||||
self._clientObserver = []
|
self._clientObserver = []
|
||||||
#PDU layer
|
#PDU layer
|
||||||
self._pduLayer = pdu.layer.Client(self)
|
self._pduLayer = pdu.Client(self)
|
||||||
#secure layer
|
#secure layer
|
||||||
self._secLayer = sec.Client(self._pduLayer)
|
self._secLayer = sec.Client(self._pduLayer)
|
||||||
#multi channel service
|
#multi channel service
|
||||||
@@ -365,7 +370,8 @@ class RDPClientController(pdu.layer.PDUClientListener):
|
|||||||
"""
|
"""
|
||||||
self._pduLayer.close()
|
self._pduLayer.close()
|
||||||
|
|
||||||
class RDPServerController(pdu.layer.PDUServerListener):
|
|
||||||
|
class RDPServerController(PDUServerListener):
|
||||||
"""
|
"""
|
||||||
@summary: Controller use in server side mode
|
@summary: Controller use in server side mode
|
||||||
"""
|
"""
|
||||||
@@ -585,49 +591,50 @@ class ClientFactory(layer.RawLayerClientFactory):
|
|||||||
"""
|
"""
|
||||||
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(layer.RawLayerServerFactory):
|
|
||||||
"""
|
# class ServerFactory(RawLayerServerFactory):
|
||||||
@summary: Factory of Server RDP protocol
|
# """
|
||||||
"""
|
# @summary: Factory of Server RDP protocol
|
||||||
def __init__(self, colorDepth, privateKeyFileName = None, certificateFileName = None):
|
# """
|
||||||
"""
|
# def __init__(self, colorDepth, privateKeyFileName = None, certificateFileName = None):
|
||||||
@param colorDepth: color depth of session
|
# """
|
||||||
@param privateKeyFileName: file contain server private key (if none -> back to standard RDP security)
|
# @param colorDepth: color depth of session
|
||||||
@param certficiateFileName: file that contain public key (if none -> back to standard RDP security)
|
# @param privateKeyFileName: file contain server private key (if none -> back to standard RDP security)
|
||||||
"""
|
# @param certficiateFileName: file that contain public key (if none -> back to standard RDP security)
|
||||||
self._colorDepth = colorDepth
|
# """
|
||||||
self._privateKeyFileName = privateKeyFileName
|
# self._colorDepth = colorDepth
|
||||||
self._certificateFileName = certificateFileName
|
# self._privateKeyFileName = privateKeyFileName
|
||||||
|
# self._certificateFileName = certificateFileName
|
||||||
def connectionLost(self, tpktLayer, reason):
|
#
|
||||||
"""
|
# def connectionLost(self, tpktLayer, reason):
|
||||||
@param reason: twisted reason
|
# """
|
||||||
"""
|
# @param reason: twisted reason
|
||||||
#retrieve controller
|
# """
|
||||||
x224Layer = tpktLayer._presentation
|
# #retrieve controller
|
||||||
mcsLayer = x224Layer._presentation
|
# x224Layer = tpktLayer._presentation
|
||||||
secLayer = mcsLayer._channels[mcs.Channel.MCS_GLOBAL_CHANNEL]
|
# mcsLayer = x224Layer._presentation
|
||||||
pduLayer = secLayer._presentation
|
# secLayer = mcsLayer._channels[mcs.Channel.MCS_GLOBAL_CHANNEL]
|
||||||
controller = pduLayer._listener
|
# pduLayer = secLayer._presentation
|
||||||
controller.onClose()
|
# controller = pduLayer._listener
|
||||||
|
# controller.onClose()
|
||||||
def buildRawLayer(self, addr):
|
#
|
||||||
"""
|
# def buildRawLayer(self, addr):
|
||||||
@summary: Function call from twisted and build rdp protocol stack
|
# """
|
||||||
@param addr: destination address
|
# @summary: Function call from twisted and build rdp protocol stack
|
||||||
"""
|
# @param addr: destination address
|
||||||
controller = RDPServerController(self._colorDepth, self._privateKeyFileName, self._certificateFileName)
|
# """
|
||||||
self.buildObserver(controller, addr)
|
# controller = RDPServerController(self._colorDepth, self._privateKeyFileName, self._certificateFileName)
|
||||||
return controller.getProtocol()
|
# self.buildObserver(controller, addr)
|
||||||
|
# return controller.getProtocol()
|
||||||
def buildObserver(self, controller, addr):
|
#
|
||||||
"""
|
# def buildObserver(self, controller, addr):
|
||||||
@summary: Build observer use for connection
|
# """
|
||||||
@param controller: RDP stack controller
|
# @summary: Build observer use for connection
|
||||||
@param addr: destination address
|
# @param controller: RDP stack controller
|
||||||
"""
|
# @param addr: destination address
|
||||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "buildObserver", "ServerFactory"))
|
# """
|
||||||
|
# raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "buildObserver", "ServerFactory"))
|
||||||
|
#
|
||||||
class RDPClientObserver(object):
|
class RDPClientObserver(object):
|
||||||
"""
|
"""
|
||||||
@summary: Class use to inform all RDP event handle by RDPY
|
@summary: Class use to inform all RDP event handle by RDPY
|
||||||
@@ -21,13 +21,14 @@
|
|||||||
RDP Standard security layer
|
RDP Standard security layer
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sha, md5
|
from hashlib import sha1 as sha
|
||||||
import lic, tpkt
|
from hashlib import md5
|
||||||
from t125 import gcc, mcs
|
from rdpy.core import tpkt, lic
|
||||||
from rdpy.core.type import CompositeType, CallableValue, Stream, UInt32Le, UInt16Le, String, sizeof, UInt8
|
from rdpy.core.t125 import gcc, mcs
|
||||||
from rdpy.core.layer import LayerAutomata, IStreamSender
|
from rdpy.model.type import CompositeType, CallableValue, Stream, UInt32Le, UInt16Le, String, sizeof, UInt8
|
||||||
from rdpy.core.error import InvalidExpectedDataException
|
from rdpy.model.layer import LayerAutomata, IStreamSender
|
||||||
from rdpy.core import log
|
from rdpy.model.error import InvalidExpectedDataException
|
||||||
|
from rdpy.model import log
|
||||||
from rdpy.security import rc4
|
from rdpy.security import rc4
|
||||||
import rdpy.security.rsa_wrapper as rsa
|
import rdpy.security.rsa_wrapper as rsa
|
||||||
|
|
||||||
@@ -22,8 +22,8 @@ Basic Encoding Rules use in RDP.
|
|||||||
ASN.1 standard
|
ASN.1 standard
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from rdpy.core.type import UInt8, UInt16Be, UInt32Be, String
|
from rdpy.model.type import UInt8, UInt16Be, UInt32Be, String
|
||||||
from rdpy.core.error import InvalidExpectedDataException, InvalidSize
|
from rdpy.model.error import InvalidExpectedDataException, InvalidSize
|
||||||
|
|
||||||
class BerPc(object):
|
class BerPc(object):
|
||||||
BER_PC_MASK = 0x20
|
BER_PC_MASK = 0x20
|
||||||
@@ -22,11 +22,11 @@ Implement GCC structure use in RDP protocol
|
|||||||
http://msdn.microsoft.com/en-us/library/cc240508.aspx
|
http://msdn.microsoft.com/en-us/library/cc240508.aspx
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import md5
|
from hashlib import md5
|
||||||
from rdpy.core.type import UInt8, UInt16Le, UInt32Le, CompositeType, CallableValue, String, Stream, sizeof, FactoryType, ArrayType
|
from rdpy.model.type import UInt8, UInt16Le, UInt32Le, CompositeType, CallableValue, String, Stream, sizeof, FactoryType, ArrayType
|
||||||
import per, mcs
|
from rdpy.core.t125 import per, mcs
|
||||||
from rdpy.core.error import InvalidExpectedDataException
|
from rdpy.model.error import InvalidExpectedDataException
|
||||||
from rdpy.core import log
|
from rdpy.model import log
|
||||||
from rdpy.security import x509
|
from rdpy.security import x509
|
||||||
import rdpy.security.rsa_wrapper as rsa
|
import rdpy.security.rsa_wrapper as rsa
|
||||||
|
|
||||||
@@ -24,13 +24,13 @@ Each channel have a particular role.
|
|||||||
The main channel is the graphical channel.
|
The main channel is the graphical channel.
|
||||||
It exist channel for file system order, audio channel, clipboard etc...
|
It exist channel for file system order, audio channel, clipboard etc...
|
||||||
"""
|
"""
|
||||||
from rdpy.core.layer import LayerAutomata, IStreamSender, Layer
|
from rdpy.model.layer import LayerAutomata, IStreamSender, Layer
|
||||||
from rdpy.core.type import sizeof, Stream, UInt8, UInt16Le, String
|
from rdpy.model.type import sizeof, Stream, UInt8, UInt16Le, String
|
||||||
from rdpy.core.error import InvalidExpectedDataException, InvalidValue, InvalidSize, CallPureVirtualFuntion
|
from rdpy.model.error import InvalidExpectedDataException, InvalidValue, InvalidSize, CallPureVirtualFuntion
|
||||||
from ber import writeLength
|
from rdpy.core.t125.ber import writeLength
|
||||||
import rdpy.core.log as log
|
import rdpy.model.log as log
|
||||||
|
|
||||||
import ber, gcc, per
|
from rdpy.core.t125 import ber, gcc, per
|
||||||
import rdpy.security.rsa_wrapper as rsa
|
import rdpy.security.rsa_wrapper as rsa
|
||||||
|
|
||||||
class Message(object):
|
class Message(object):
|
||||||
@@ -21,8 +21,8 @@
|
|||||||
Per encoded function
|
Per encoded function
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from rdpy.core.type import UInt8, UInt16Be, UInt32Be, String
|
from rdpy.model.type import UInt8, UInt16Be, UInt32Be, String
|
||||||
from rdpy.core.error import InvalidValue, InvalidExpectedDataException
|
from rdpy.model.error import InvalidValue, InvalidExpectedDataException
|
||||||
|
|
||||||
def readLength(s):
|
def readLength(s):
|
||||||
"""
|
"""
|
||||||
@@ -22,9 +22,10 @@ Transport packet layer implementation
|
|||||||
|
|
||||||
Use to build correct size packet and handle slow path and fast path mode
|
Use to build correct size packet and handle slow path and fast path mode
|
||||||
"""
|
"""
|
||||||
from rdpy.core.layer import RawLayer
|
from rdpy.model.layer import RawLayer
|
||||||
from rdpy.core.type import UInt8, UInt16Be, sizeof
|
from rdpy.model.type import UInt8, UInt16Be, sizeof
|
||||||
from rdpy.core.error import CallPureVirtualFuntion
|
from rdpy.model.error import CallPureVirtualFuntion
|
||||||
|
|
||||||
|
|
||||||
class Action(object):
|
class Action(object):
|
||||||
"""
|
"""
|
||||||
@@ -23,11 +23,11 @@ Implement transport PDU layer
|
|||||||
This layer have main goal to negociate SSL transport
|
This layer have main goal to negociate SSL transport
|
||||||
RDP basic security is supported only on client side
|
RDP basic security is supported only on client side
|
||||||
"""
|
"""
|
||||||
from rdpy.core import log
|
from rdpy.model import log
|
||||||
|
|
||||||
from rdpy.core.layer import LayerAutomata, IStreamSender
|
from rdpy.model.layer import LayerAutomata, IStreamSender
|
||||||
from rdpy.core.type import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof, String
|
from rdpy.model.type import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof, String
|
||||||
from rdpy.core.error import InvalidExpectedDataException, RDPSecurityNegoFail
|
from rdpy.model.error import InvalidExpectedDataException, RDPSecurityNegoFail
|
||||||
|
|
||||||
class MessageType(object):
|
class MessageType(object):
|
||||||
"""
|
"""
|
||||||
@@ -303,38 +303,8 @@ class Server(X224Layer):
|
|||||||
if self._selectedProtocol == Protocols.PROTOCOL_SSL:
|
if self._selectedProtocol == Protocols.PROTOCOL_SSL:
|
||||||
log.debug("*" * 10 + " select SSL layer " + "*" * 10)
|
log.debug("*" * 10 + " select SSL layer " + "*" * 10)
|
||||||
#_transport is TPKT and transport is TCP layer of twisted
|
#_transport is TPKT and transport is TCP layer of twisted
|
||||||
self._transport.startTLS(ServerTLSContext(self._serverPrivateKeyFileName, self._serverCertificateFileName))
|
#self._transport.startTLS(ServerTLSContext(self._serverPrivateKeyFileName, self._serverCertificateFileName))
|
||||||
|
|
||||||
#connection is done send to presentation
|
#connection is done send to presentation
|
||||||
self.setNextState(self.recvData)
|
self.setNextState(self.recvData)
|
||||||
self._presentation.connect()
|
self._presentation.connect()
|
||||||
|
|
||||||
#open ssl needed
|
|
||||||
from twisted.internet import ssl
|
|
||||||
from OpenSSL import SSL
|
|
||||||
|
|
||||||
class ClientTLSContext(ssl.ClientContextFactory):
|
|
||||||
"""
|
|
||||||
@summary: client context factory for open ssl
|
|
||||||
"""
|
|
||||||
def getContext(self):
|
|
||||||
context = SSL.Context(SSL.TLSv1_METHOD)
|
|
||||||
context.set_options(SSL.OP_DONT_INSERT_EMPTY_FRAGMENTS)
|
|
||||||
context.set_options(SSL.OP_TLS_BLOCK_PADDING_BUG)
|
|
||||||
return context
|
|
||||||
|
|
||||||
class ServerTLSContext(ssl.DefaultOpenSSLContextFactory):
|
|
||||||
"""
|
|
||||||
@summary: Server context factory for open ssl
|
|
||||||
@param privateKeyFileName: Name of a file containing a private key
|
|
||||||
@param certificateFileName: Name of a file containing a certificate
|
|
||||||
"""
|
|
||||||
def __init__(self, privateKeyFileName, certificateFileName):
|
|
||||||
class TPDUSSLContext(SSL.Context):
|
|
||||||
def __init__(self, method):
|
|
||||||
SSL.Context.__init__(self, method)
|
|
||||||
self.set_options(SSL.OP_DONT_INSERT_EMPTY_FRAGMENTS)
|
|
||||||
self.set_options(SSL.OP_TLS_BLOCK_PADDING_BUG)
|
|
||||||
|
|
||||||
ssl.DefaultOpenSSLContextFactory.__init__(self, privateKeyFileName, certificateFileName, SSL.SSLv23_METHOD, TPDUSSLContext)
|
|
||||||
|
|
||||||
@@ -22,8 +22,9 @@ Join RDPY design with twisted design
|
|||||||
|
|
||||||
RDPY use Layer Protocol design (like twisted)
|
RDPY use Layer Protocol design (like twisted)
|
||||||
"""
|
"""
|
||||||
|
import asyncio
|
||||||
|
from rdpy.model.error import CallPureVirtualFuntion
|
||||||
|
|
||||||
from rdpy.core.error import CallPureVirtualFuntion
|
|
||||||
|
|
||||||
class IStreamListener(object):
|
class IStreamListener(object):
|
||||||
"""
|
"""
|
||||||
@@ -35,7 +36,8 @@ class IStreamListener(object):
|
|||||||
@param s: Stream
|
@param s: Stream
|
||||||
"""
|
"""
|
||||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener"))
|
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener"))
|
||||||
|
|
||||||
|
|
||||||
class IStreamSender(object):
|
class IStreamSender(object):
|
||||||
"""
|
"""
|
||||||
@summary: Interface use to inform stream sender capability
|
@summary: Interface use to inform stream sender capability
|
||||||
@@ -46,7 +48,8 @@ class IStreamSender(object):
|
|||||||
@param data: Type or tuple element handle by transport layer
|
@param data: Type or tuple element handle by transport layer
|
||||||
"""
|
"""
|
||||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "send", "IStreamSender"))
|
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "send", "IStreamSender"))
|
||||||
|
|
||||||
|
|
||||||
class Layer(object):
|
class Layer(object):
|
||||||
"""
|
"""
|
||||||
@summary: A simple double linked list with presentation and transport layer
|
@summary: A simple double linked list with presentation and transport layer
|
||||||
@@ -79,7 +82,8 @@ class Layer(object):
|
|||||||
"""
|
"""
|
||||||
if not self._transport is None:
|
if not self._transport is None:
|
||||||
self._transport.close()
|
self._transport.close()
|
||||||
|
|
||||||
|
|
||||||
class LayerAutomata(Layer, IStreamListener):
|
class LayerAutomata(Layer, IStreamListener):
|
||||||
"""
|
"""
|
||||||
@summary: Layer with automata callback
|
@summary: Layer with automata callback
|
||||||
@@ -103,13 +107,8 @@ class LayerAutomata(Layer, IStreamListener):
|
|||||||
|
|
||||||
self.recv = callback
|
self.recv = callback
|
||||||
|
|
||||||
#twisted layer concept
|
|
||||||
from twisted.internet import protocol
|
|
||||||
from twisted.internet.abstract import FileDescriptor
|
|
||||||
#first that handle stream
|
|
||||||
from type import Stream
|
|
||||||
|
|
||||||
class RawLayerClientFactory(protocol.ClientFactory):
|
class RawLayerClientFactory(asyncio.Protocol):
|
||||||
"""
|
"""
|
||||||
@summary: Abstract class for Raw layer client factory
|
@summary: Abstract class for Raw layer client factory
|
||||||
"""
|
"""
|
||||||
@@ -136,37 +135,38 @@ class RawLayerClientFactory(protocol.ClientFactory):
|
|||||||
@param reason: twisted reason
|
@param reason: twisted reason
|
||||||
"""
|
"""
|
||||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "connectionLost", "RawLayerClientFactory"))
|
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "connectionLost", "RawLayerClientFactory"))
|
||||||
|
|
||||||
class RawLayerServerFactory(protocol.ServerFactory):
|
|
||||||
"""
|
|
||||||
@summary: Abstract class for Raw layer server factory
|
|
||||||
"""
|
|
||||||
def buildProtocol(self, addr):
|
|
||||||
"""
|
|
||||||
@summary: Function call from twisted
|
|
||||||
@param addr: destination address
|
|
||||||
"""
|
|
||||||
rawLayer = self.buildRawLayer(addr)
|
|
||||||
rawLayer.setFactory(self)
|
|
||||||
return rawLayer
|
|
||||||
|
|
||||||
def buildRawLayer(self, addr):
|
|
||||||
"""
|
|
||||||
@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, reason):
|
|
||||||
"""
|
|
||||||
@summary: Override this method to handle connection lost
|
|
||||||
@param rawlayer: rawLayer that cause connectionLost event
|
|
||||||
@param reason: twisted reason
|
|
||||||
"""
|
|
||||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener"))
|
|
||||||
|
|
||||||
|
|
||||||
class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender):
|
|
||||||
|
# class RawLayerServerFactory(protocol.ServerFactory):
|
||||||
|
# """
|
||||||
|
# @summary: Abstract class for Raw layer server factory
|
||||||
|
# """
|
||||||
|
# def buildProtocol(self, addr):
|
||||||
|
# """
|
||||||
|
# @summary: Function call from twisted
|
||||||
|
# @param addr: destination address
|
||||||
|
# """
|
||||||
|
# rawLayer = self.buildRawLayer(addr)
|
||||||
|
# rawLayer.setFactory(self)
|
||||||
|
# return rawLayer
|
||||||
|
#
|
||||||
|
# def buildRawLayer(self, addr):
|
||||||
|
# """
|
||||||
|
# @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, reason):
|
||||||
|
# """
|
||||||
|
# @summary: Override this method to handle connection lost
|
||||||
|
# @param rawlayer: rawLayer that cause connectionLost event
|
||||||
|
# @param reason: twisted reason
|
||||||
|
# """
|
||||||
|
# raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "IStreamListener"))
|
||||||
|
#
|
||||||
|
#
|
||||||
|
class RawLayer(asyncio.Protocol, LayerAutomata, IStreamSender):
|
||||||
"""
|
"""
|
||||||
@summary: Wait event from twisted engine
|
@summary: Wait event from twisted engine
|
||||||
And format correct size packet
|
And format correct size packet
|
||||||
@@ -183,14 +183,14 @@ class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender):
|
|||||||
#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
|
self._factory = None
|
||||||
|
|
||||||
def setFactory(self, factory):
|
def setFactory(self, factory):
|
||||||
"""
|
"""
|
||||||
@summary: Call by RawLayer Factory
|
@summary: Call by RawLayer Factory
|
||||||
@param param: RawLayerClientFactory or RawLayerFactory
|
@param param: RawLayerClientFactory or RawLayerFactory
|
||||||
"""
|
"""
|
||||||
self._factory = factory
|
self._factory = factory
|
||||||
|
|
||||||
def dataReceived(self, data):
|
def dataReceived(self, data):
|
||||||
"""
|
"""
|
||||||
@summary: Inherit from twisted.protocol class
|
@summary: Inherit from twisted.protocol class
|
||||||
@@ -207,27 +207,27 @@ class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender):
|
|||||||
self._buffer = self._buffer[self._expectedLen:]
|
self._buffer = self._buffer[self._expectedLen:]
|
||||||
#call recv function
|
#call recv function
|
||||||
self.recv(expectedData)
|
self.recv(expectedData)
|
||||||
|
|
||||||
def connectionMade(self):
|
def connectionMade(self):
|
||||||
"""
|
"""
|
||||||
@summary: inherit from twisted protocol
|
@summary: inherit from twisted protocol
|
||||||
"""
|
"""
|
||||||
#join two scheme
|
#join two scheme
|
||||||
self.connect()
|
self.connect()
|
||||||
|
|
||||||
def connectionLost(self, reason):
|
def connectionLost(self, reason):
|
||||||
"""
|
"""
|
||||||
@summary: Call from twisted engine when protocol is closed
|
@summary: Call from twisted engine when protocol is closed
|
||||||
@param reason: str represent reason of close connection
|
@param reason: str represent reason of close connection
|
||||||
"""
|
"""
|
||||||
self._factory.connectionLost(self, reason)
|
self._factory.connectionLost(self, reason)
|
||||||
|
|
||||||
def getDescriptor(self):
|
def getDescriptor(self):
|
||||||
"""
|
"""
|
||||||
@return: the twited file descriptor
|
@return: the twited file descriptor
|
||||||
"""
|
"""
|
||||||
return self.transport
|
return self.transport
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""
|
"""
|
||||||
@summary: Close raw layer
|
@summary: Close raw layer
|
||||||
@@ -235,10 +235,10 @@ class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender):
|
|||||||
Because is bugged
|
Because is bugged
|
||||||
"""
|
"""
|
||||||
FileDescriptor.loseConnection(self.getDescriptor())
|
FileDescriptor.loseConnection(self.getDescriptor())
|
||||||
|
|
||||||
def expect(self, expectedLen, callback = None):
|
def expect(self, expectedLen, callback = None):
|
||||||
"""
|
"""
|
||||||
@summary: Set next automata callback,
|
@summary: Set next automata callback,
|
||||||
But this callback will be only called when
|
But this callback will be only called when
|
||||||
data have expectedLen
|
data have expectedLen
|
||||||
@param expectedLen: in bytes length use to call next state
|
@param expectedLen: in bytes length use to call next state
|
||||||
@@ -247,7 +247,7 @@ class RawLayer(protocol.Protocol, LayerAutomata, IStreamSender):
|
|||||||
self._expectedLen = expectedLen
|
self._expectedLen = expectedLen
|
||||||
#default callback is recv from LayerAutomata
|
#default callback is recv from LayerAutomata
|
||||||
self.setNextState(callback)
|
self.setNextState(callback)
|
||||||
|
|
||||||
def send(self, message):
|
def send(self, message):
|
||||||
"""
|
"""
|
||||||
@summary: Send Stream on TCP layer
|
@summary: Send Stream on TCP layer
|
||||||
@@ -44,7 +44,7 @@ def log(message):
|
|||||||
f = open(_LOG_FILE, "a+")
|
f = open(_LOG_FILE, "a+")
|
||||||
f.write("%s\n"%message)
|
f.write("%s\n"%message)
|
||||||
f.close()
|
f.close()
|
||||||
print "[*] %s"%message
|
print("[*] %s"%message)
|
||||||
|
|
||||||
def error(message):
|
def error(message):
|
||||||
"""
|
"""
|
||||||
@@ -22,8 +22,8 @@ Remote Session Scenario File format
|
|||||||
Private protocol format to save events
|
Private protocol format to save events
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from rdpy.core.type import CompositeType, FactoryType, UInt8, UInt16Le, UInt32Le, String, sizeof, Stream
|
from rdpy.model.type import CompositeType, FactoryType, UInt8, UInt16Le, UInt32Le, String, sizeof, Stream
|
||||||
from rdpy.core import log, error
|
from rdpy.model import log, error
|
||||||
import time
|
import time
|
||||||
|
|
||||||
class EventType(object):
|
class EventType(object):
|
||||||
@@ -26,9 +26,10 @@ We are in python!
|
|||||||
|
|
||||||
import struct
|
import struct
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from StringIO import StringIO
|
from io import BytesIO
|
||||||
from rdpy.core.error import InvalidExpectedDataException, InvalidSize, CallPureVirtualFuntion, InvalidValue
|
from rdpy.model.error import InvalidExpectedDataException, InvalidSize, CallPureVirtualFuntion, InvalidValue
|
||||||
import rdpy.core.log as log
|
import rdpy.model.log as log
|
||||||
|
|
||||||
|
|
||||||
def sizeof(element):
|
def sizeof(element):
|
||||||
"""
|
"""
|
||||||
@@ -852,7 +853,8 @@ def decodeUnicode(s):
|
|||||||
i += 1
|
i += 1
|
||||||
return r
|
return r
|
||||||
|
|
||||||
class Stream(StringIO):
|
|
||||||
|
class Stream(BytesIO):
|
||||||
"""
|
"""
|
||||||
@summary: Stream use to read all types
|
@summary: Stream use to read all types
|
||||||
"""
|
"""
|
||||||
@@ -1,765 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2014-2015 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/>.
|
|
||||||
#
|
|
||||||
|
|
||||||
"""
|
|
||||||
Implement Remote FrameBuffer protocol use in VNC client and server
|
|
||||||
@see: http://www.realvnc.com/docs/rfbproto.pdf
|
|
||||||
|
|
||||||
@todo: server side of protocol
|
|
||||||
@todo: more encoding rectangle
|
|
||||||
"""
|
|
||||||
|
|
||||||
from rdpy.core.layer import RawLayer, RawLayerClientFactory
|
|
||||||
from rdpy.core.type import UInt8, UInt16Be, UInt32Be, SInt32Be, String, CompositeType
|
|
||||||
from rdpy.core.error import InvalidValue, CallPureVirtualFuntion
|
|
||||||
from rdpy.security.pyDes import des
|
|
||||||
import rdpy.core.log as log
|
|
||||||
|
|
||||||
class ProtocolVersion(object):
|
|
||||||
"""
|
|
||||||
@summary: Different protocol version
|
|
||||||
"""
|
|
||||||
UNKNOWN = ""
|
|
||||||
RFB003003 = "RFB 003.003\n"
|
|
||||||
RFB003007 = "RFB 003.007\n"
|
|
||||||
RFB003008 = "RFB 003.008\n"
|
|
||||||
|
|
||||||
class SecurityType(object):
|
|
||||||
"""
|
|
||||||
@summary: Security type supported
|
|
||||||
"""
|
|
||||||
INVALID = 0
|
|
||||||
NONE = 1
|
|
||||||
VNC = 2
|
|
||||||
|
|
||||||
class Pointer(object):
|
|
||||||
"""
|
|
||||||
@summary: Mouse event code (which button)
|
|
||||||
actually in RFB specification only
|
|
||||||
three buttons are supported
|
|
||||||
"""
|
|
||||||
BUTTON1 = 0x1
|
|
||||||
BUTTON2 = 0x2
|
|
||||||
BUTTON3 = 0x4
|
|
||||||
|
|
||||||
class Encoding(object):
|
|
||||||
"""
|
|
||||||
@summary: Encoding types of FrameBuffer update
|
|
||||||
"""
|
|
||||||
RAW = 0
|
|
||||||
|
|
||||||
class ClientToServerMessages(object):
|
|
||||||
"""
|
|
||||||
@summary: Client to server messages types
|
|
||||||
"""
|
|
||||||
PIXEL_FORMAT = 0
|
|
||||||
ENCODING = 2
|
|
||||||
FRAME_BUFFER_UPDATE_REQUEST = 3
|
|
||||||
KEY_EVENT = 4
|
|
||||||
POINTER_EVENT = 5
|
|
||||||
CUT_TEXT = 6
|
|
||||||
|
|
||||||
class PixelFormat(CompositeType):
|
|
||||||
"""
|
|
||||||
@summary: Pixel format structure
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
CompositeType.__init__(self)
|
|
||||||
self.BitsPerPixel = UInt8(32)
|
|
||||||
self.Depth = UInt8(24)
|
|
||||||
self.BigEndianFlag = UInt8(False)
|
|
||||||
self.TrueColorFlag = UInt8(True)
|
|
||||||
self.RedMax = UInt16Be(255)
|
|
||||||
self.GreenMax = UInt16Be(255)
|
|
||||||
self.BlueMax = UInt16Be(255)
|
|
||||||
self.RedShift = UInt8(16)
|
|
||||||
self.GreenShift = UInt8(8)
|
|
||||||
self.BlueShift = UInt8(0)
|
|
||||||
self.padding = (UInt16Be(), UInt8())
|
|
||||||
|
|
||||||
class ServerInit(CompositeType):
|
|
||||||
"""
|
|
||||||
@summary: Server init structure
|
|
||||||
FrameBuffer configuration
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
CompositeType.__init__(self)
|
|
||||||
self.width = UInt16Be()
|
|
||||||
self.height = UInt16Be()
|
|
||||||
self.pixelFormat = PixelFormat()
|
|
||||||
|
|
||||||
class FrameBufferUpdateRequest(CompositeType):
|
|
||||||
"""
|
|
||||||
@summary: FrameBuffer update request send from client to server
|
|
||||||
Incremental means that server send update with a specific
|
|
||||||
order, and client must draw orders in same order
|
|
||||||
"""
|
|
||||||
def __init__(self, incremental = False, x = 0, y = 0, width = 0, height = 0):
|
|
||||||
CompositeType.__init__(self)
|
|
||||||
self.incremental = UInt8(incremental)
|
|
||||||
self.x = UInt16Be(x)
|
|
||||||
self.y = UInt16Be(y)
|
|
||||||
self.width = UInt16Be(width)
|
|
||||||
self.height = UInt16Be(height)
|
|
||||||
|
|
||||||
|
|
||||||
class Rectangle(CompositeType):
|
|
||||||
"""
|
|
||||||
@summary: Header message of update rectangle
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
CompositeType.__init__(self)
|
|
||||||
self.x = UInt16Be()
|
|
||||||
self.y = UInt16Be()
|
|
||||||
self.width = UInt16Be()
|
|
||||||
self.height = UInt16Be()
|
|
||||||
self.encoding = SInt32Be()
|
|
||||||
|
|
||||||
class KeyEvent(CompositeType):
|
|
||||||
"""
|
|
||||||
@summary: Key event structure message
|
|
||||||
Use to send a keyboard event
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
CompositeType.__init__(self)
|
|
||||||
self.downFlag = UInt8(False)
|
|
||||||
self.padding = UInt16Be()
|
|
||||||
self.key = UInt32Be()
|
|
||||||
|
|
||||||
class PointerEvent(CompositeType):
|
|
||||||
"""
|
|
||||||
@summary: Pointer event structure message
|
|
||||||
Use to send mouse event
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
CompositeType.__init__(self)
|
|
||||||
self.mask = UInt8()
|
|
||||||
self.x = UInt16Be()
|
|
||||||
self.y = UInt16Be()
|
|
||||||
|
|
||||||
class ClientCutText(CompositeType):
|
|
||||||
"""
|
|
||||||
@summary: Client cut text message message
|
|
||||||
Use to simulate copy paste (ctrl-c ctrl-v) only for text
|
|
||||||
"""
|
|
||||||
def __init__(self, text = ""):
|
|
||||||
CompositeType.__init__(self)
|
|
||||||
self.padding = (UInt16Be(), UInt8())
|
|
||||||
self.size = UInt32Be(len(text))
|
|
||||||
self.message = String(text)
|
|
||||||
|
|
||||||
class ServerCutTextHeader(CompositeType):
|
|
||||||
"""
|
|
||||||
@summary: Cut text header send from server to client
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
CompositeType.__init__(self)
|
|
||||||
self.padding = (UInt16Be(), UInt8())
|
|
||||||
self.size = UInt32Be()
|
|
||||||
|
|
||||||
class RFB(RawLayer):
|
|
||||||
"""
|
|
||||||
@summary: Implement RFB protocol
|
|
||||||
"""
|
|
||||||
def __init__(self, listener):
|
|
||||||
"""
|
|
||||||
@param listener: listener use to inform new orders
|
|
||||||
"""
|
|
||||||
RawLayer.__init__(self)
|
|
||||||
#set client listener
|
|
||||||
self._clientListener = listener
|
|
||||||
#useful for RFB protocol
|
|
||||||
self._callbackBody = None
|
|
||||||
#protocol version negotiated
|
|
||||||
self._version = String(ProtocolVersion.RFB003008)
|
|
||||||
#number security launch by server
|
|
||||||
self._securityLevel = UInt8(SecurityType.INVALID)
|
|
||||||
#shared FrameBuffer client init message
|
|
||||||
self._sharedFlag = UInt8(False)
|
|
||||||
#server init message
|
|
||||||
#which contain FrameBuffer dim and pixel format
|
|
||||||
self._serverInit = ServerInit()
|
|
||||||
#client pixel format
|
|
||||||
self._pixelFormat = PixelFormat()
|
|
||||||
#server name
|
|
||||||
self._serverName = String()
|
|
||||||
#nb rectangle
|
|
||||||
self._nbRect = 0
|
|
||||||
#current rectangle header
|
|
||||||
self._currentRect = Rectangle()
|
|
||||||
#for vnc security type
|
|
||||||
self._password = '\0' * 8
|
|
||||||
|
|
||||||
def expectWithHeader(self, expectedHeaderLen, callbackBody):
|
|
||||||
"""
|
|
||||||
2nd level of waiting event
|
|
||||||
read expectedHeaderLen that contain body size
|
|
||||||
@param expectedHeaderLen: contains the number of bytes, which body length needs to be encoded
|
|
||||||
@param callbackBody: next state use when expected date from expectedHeaderLen
|
|
||||||
are received
|
|
||||||
"""
|
|
||||||
self._callbackBody = callbackBody
|
|
||||||
self.expect(expectedHeaderLen, self.expectedBody)
|
|
||||||
|
|
||||||
def expectedBody(self, data):
|
|
||||||
"""
|
|
||||||
Read header and wait header value to call next state
|
|
||||||
@param data: Stream that length are to header length (1|2|4 bytes)
|
|
||||||
set next state to callBack body when length read from header
|
|
||||||
are received
|
|
||||||
"""
|
|
||||||
bodyLen = None
|
|
||||||
if data.len == 1:
|
|
||||||
bodyLen = UInt8()
|
|
||||||
elif data.len == 2:
|
|
||||||
bodyLen = UInt16Be()
|
|
||||||
elif data.len == 4:
|
|
||||||
bodyLen = UInt32Be()
|
|
||||||
else:
|
|
||||||
log.error("invalid header length")
|
|
||||||
return
|
|
||||||
data.readType(bodyLen)
|
|
||||||
self.expect(bodyLen.value, self._callbackBody)
|
|
||||||
|
|
||||||
def connect(self):
|
|
||||||
"""
|
|
||||||
Call when transport layer connection is made
|
|
||||||
in Client mode -> wait protocol version
|
|
||||||
"""
|
|
||||||
self.expect(12, self.recvProtocolVersion)
|
|
||||||
|
|
||||||
def readProtocolVersion(self, data):
|
|
||||||
"""
|
|
||||||
Read protocol version
|
|
||||||
@param data: Stream may contain protocol version string (ProtocolVersion)
|
|
||||||
"""
|
|
||||||
data.readType(self._version)
|
|
||||||
if not self._version.value in [ProtocolVersion.RFB003003, ProtocolVersion.RFB003007, ProtocolVersion.RFB003008]:
|
|
||||||
self._version.value = ProtocolVersion.UNKNOWN
|
|
||||||
|
|
||||||
def recvProtocolVersion(self, data):
|
|
||||||
"""
|
|
||||||
Read handshake packet
|
|
||||||
If protocol receive from client is unknown
|
|
||||||
try best version of protocol version (ProtocolVersion.RFB003008)
|
|
||||||
@param data: Stream
|
|
||||||
"""
|
|
||||||
self.readProtocolVersion(data)
|
|
||||||
if self._version.value == ProtocolVersion.UNKNOWN:
|
|
||||||
log.info("Unknown protocol version %s send 003.008"%data.getvalue())
|
|
||||||
#protocol version is unknown try best version we can handle
|
|
||||||
self._version.value = ProtocolVersion.RFB003008
|
|
||||||
#send same version of
|
|
||||||
self.send(self._version)
|
|
||||||
|
|
||||||
#next state read security
|
|
||||||
if self._version.value == ProtocolVersion.RFB003003:
|
|
||||||
self.expect(4, self.recvSecurityServer)
|
|
||||||
else:
|
|
||||||
self.expectWithHeader(1, self.recvSecurityList)
|
|
||||||
|
|
||||||
def recvSecurityServer(self, data):
|
|
||||||
"""
|
|
||||||
Security handshake for 33 RFB version
|
|
||||||
Server imposed security level
|
|
||||||
@param data: well formed packet
|
|
||||||
"""
|
|
||||||
#TODO!!!
|
|
||||||
pass
|
|
||||||
|
|
||||||
def recvSecurityList(self, data):
|
|
||||||
"""
|
|
||||||
Read security list packet send from server to client
|
|
||||||
@param data: Stream that contains well formed packet
|
|
||||||
"""
|
|
||||||
securityList = []
|
|
||||||
while data.dataLen() > 0:
|
|
||||||
securityElement = UInt8()
|
|
||||||
data.readType(securityElement)
|
|
||||||
securityList.append(securityElement)
|
|
||||||
#select high security level
|
|
||||||
for s in securityList:
|
|
||||||
if s.value in [SecurityType.NONE, SecurityType.VNC] and s > self._securityLevel:
|
|
||||||
self._securityLevel = s
|
|
||||||
break
|
|
||||||
#send back security level choosen
|
|
||||||
self.send(self._securityLevel)
|
|
||||||
if self._securityLevel.value == SecurityType.VNC:
|
|
||||||
self.expect(16, self.recvVNCChallenge)
|
|
||||||
else:
|
|
||||||
self.expect(4, self.recvSecurityResult)
|
|
||||||
|
|
||||||
def recvVNCChallenge(self, data):
|
|
||||||
"""
|
|
||||||
@summary: receive challenge in VNC authentication case
|
|
||||||
@param data: Stream that contain well formed packet
|
|
||||||
"""
|
|
||||||
key = (self._password + '\0' * 8)[:8]
|
|
||||||
newkey = []
|
|
||||||
for ki in range(len(key)):
|
|
||||||
bsrc = ord(key[ki])
|
|
||||||
btgt = 0
|
|
||||||
for i in range(8):
|
|
||||||
if bsrc & (1 << i):
|
|
||||||
btgt = btgt | (1 << 7-i)
|
|
||||||
newkey.append(chr(btgt))
|
|
||||||
|
|
||||||
algo = des(newkey)
|
|
||||||
self.send(String(algo.encrypt(data.getvalue())))
|
|
||||||
self.expect(4, self.recvSecurityResult)
|
|
||||||
|
|
||||||
def recvSecurityResult(self, data):
|
|
||||||
"""
|
|
||||||
Read security result packet
|
|
||||||
Use by server to inform connection status of client
|
|
||||||
@param data: Stream that contain well formed packet
|
|
||||||
"""
|
|
||||||
result = UInt32Be()
|
|
||||||
data.readType(result)
|
|
||||||
if result == UInt32Be(1):
|
|
||||||
log.info("Authentification failed")
|
|
||||||
if self._version.value == ProtocolVersion.RFB003008:
|
|
||||||
self.expectWithHeader(4, self.recvSecurityFailed)
|
|
||||||
else:
|
|
||||||
log.debug("Authentification OK")
|
|
||||||
self.sendClientInit()
|
|
||||||
|
|
||||||
def recvSecurityFailed(self, data):
|
|
||||||
"""
|
|
||||||
Send by server to inform reason of why it's refused client
|
|
||||||
@param data: Stream that contains well formed packet
|
|
||||||
"""
|
|
||||||
log.info("Security failed cause to %s"%data.getvalue())
|
|
||||||
|
|
||||||
def recvServerInit(self, data):
|
|
||||||
"""
|
|
||||||
Read server init packet
|
|
||||||
@param data: Stream that contains well formed packet
|
|
||||||
"""
|
|
||||||
data.readType(self._serverInit)
|
|
||||||
self.expectWithHeader(4, self.recvServerName)
|
|
||||||
|
|
||||||
def recvServerName(self, data):
|
|
||||||
"""
|
|
||||||
@summary: Read server name
|
|
||||||
@param data: Stream that contains well formed packet
|
|
||||||
"""
|
|
||||||
data.readType(self._serverName)
|
|
||||||
log.info("Server name %s"%str(self._serverName))
|
|
||||||
#end of handshake
|
|
||||||
#send pixel format
|
|
||||||
self.sendPixelFormat(self._pixelFormat)
|
|
||||||
#write encoding
|
|
||||||
self.sendSetEncoding()
|
|
||||||
#request entire zone
|
|
||||||
self.sendFramebufferUpdateRequest(False, 0, 0, self._serverInit.width.value, self._serverInit.height.value)
|
|
||||||
#now i'm ready to send event
|
|
||||||
self._clientListener.onReady()
|
|
||||||
self.expect(1, self.recvServerOrder)
|
|
||||||
|
|
||||||
def recvServerOrder(self, data):
|
|
||||||
"""
|
|
||||||
@summary: Read order receive from server
|
|
||||||
Main function for bitmap update from server to client
|
|
||||||
@param data: Stream that contains well formed packet
|
|
||||||
"""
|
|
||||||
packetType = UInt8()
|
|
||||||
data.readType(packetType)
|
|
||||||
if packetType.value == 0:
|
|
||||||
self.expect(3, self.recvFrameBufferUpdateHeader)
|
|
||||||
elif packetType.value == 2:
|
|
||||||
self._clientListener.onBell()
|
|
||||||
elif packetType.value == 3:
|
|
||||||
self.expect(7, self.recvServerCutTextHeader)
|
|
||||||
else:
|
|
||||||
log.error("Unknown message type %s"%packetType.value)
|
|
||||||
|
|
||||||
def recvFrameBufferUpdateHeader(self, data):
|
|
||||||
"""
|
|
||||||
@summary: Read frame buffer update packet header
|
|
||||||
@param data: Stream that contains well formed packet
|
|
||||||
"""
|
|
||||||
#padding
|
|
||||||
nbRect = UInt16Be()
|
|
||||||
self._nbRect = data.readType((UInt8(), nbRect))
|
|
||||||
self._nbRect = nbRect.value
|
|
||||||
self.expect(12, self.recvRectHeader)
|
|
||||||
|
|
||||||
def recvRectHeader(self, data):
|
|
||||||
"""
|
|
||||||
@summary: Read rectangle header
|
|
||||||
@param data: Stream that contains well formed packet
|
|
||||||
"""
|
|
||||||
data.readType(self._currentRect)
|
|
||||||
if self._currentRect.encoding.value == Encoding.RAW:
|
|
||||||
self.expect(self._currentRect.width.value * self._currentRect.height.value * (self._pixelFormat.BitsPerPixel.value / 8), self.recvRectBody)
|
|
||||||
|
|
||||||
def recvRectBody(self, data):
|
|
||||||
"""
|
|
||||||
@summary: Read body of rectangle update
|
|
||||||
@param data: Stream that contains well formed packet
|
|
||||||
"""
|
|
||||||
self._clientListener.recvRectangle(self._currentRect, self._pixelFormat, data.getvalue())
|
|
||||||
|
|
||||||
self._nbRect -= 1
|
|
||||||
#if there is another rect to read
|
|
||||||
if self._nbRect == 0:
|
|
||||||
#job is finish send a request
|
|
||||||
self.sendFramebufferUpdateRequest(True, 0, 0, self._serverInit.width.value, self._serverInit.height.value)
|
|
||||||
self.expect(1, self.recvServerOrder)
|
|
||||||
else:
|
|
||||||
self.expect(12, self.recvRectHeader)
|
|
||||||
|
|
||||||
def recvServerCutTextHeader(self, data):
|
|
||||||
"""
|
|
||||||
@summary: callback when expect server cut text message
|
|
||||||
@param data: Stream that contains well formed packet
|
|
||||||
"""
|
|
||||||
header = ServerCutTextHeader()
|
|
||||||
data.readType(header)
|
|
||||||
self.expect(header.size.value, self.recvServerCutTextBody)
|
|
||||||
|
|
||||||
def recvServerCutTextBody(self, data):
|
|
||||||
"""
|
|
||||||
@summary: Receive server cut text body
|
|
||||||
@param data: Stream that contains well formed packet
|
|
||||||
"""
|
|
||||||
self._clientListener.onCutText(data.getvalue())
|
|
||||||
self.expect(1, self.recvServerOrder)
|
|
||||||
|
|
||||||
def sendClientInit(self):
|
|
||||||
"""
|
|
||||||
@summary: Send client init packet
|
|
||||||
"""
|
|
||||||
self.send(self._sharedFlag)
|
|
||||||
self.expect(20, self.recvServerInit)
|
|
||||||
|
|
||||||
def sendPixelFormat(self, pixelFormat):
|
|
||||||
"""
|
|
||||||
@summary: Send pixel format structure
|
|
||||||
Very important packet that inform the image struct supported by the client
|
|
||||||
@param pixelFormat: PixelFormat struct
|
|
||||||
"""
|
|
||||||
self.send((UInt8(ClientToServerMessages.PIXEL_FORMAT), UInt16Be(), UInt8(), pixelFormat))
|
|
||||||
|
|
||||||
def sendSetEncoding(self):
|
|
||||||
"""
|
|
||||||
@summary: Send set encoding packet
|
|
||||||
Actually only RAW bitmap encoding are used
|
|
||||||
"""
|
|
||||||
self.send((UInt8(ClientToServerMessages.ENCODING), UInt8(), UInt16Be(1), SInt32Be(Encoding.RAW)))
|
|
||||||
|
|
||||||
def sendFramebufferUpdateRequest(self, incremental, x, y, width, height):
|
|
||||||
"""
|
|
||||||
@summary: Request server the specified zone
|
|
||||||
incremental means request only change before last update
|
|
||||||
"""
|
|
||||||
self.send((UInt8(ClientToServerMessages.FRAME_BUFFER_UPDATE_REQUEST), FrameBufferUpdateRequest(incremental, x, y, width, height)))
|
|
||||||
|
|
||||||
def sendKeyEvent(self, keyEvent):
|
|
||||||
"""
|
|
||||||
@summary: Write key event packet
|
|
||||||
@param keyEvent: KeyEvent struct to send
|
|
||||||
"""
|
|
||||||
self.send((UInt8(ClientToServerMessages.KEY_EVENT), keyEvent))
|
|
||||||
|
|
||||||
def sendPointerEvent(self, pointerEvent):
|
|
||||||
"""
|
|
||||||
@summary: Write pointer event packet
|
|
||||||
@param pointerEvent: PointerEvent struct use
|
|
||||||
"""
|
|
||||||
self.send((UInt8(ClientToServerMessages.POINTER_EVENT), pointerEvent))
|
|
||||||
|
|
||||||
def sendClientCutText(self, text):
|
|
||||||
"""
|
|
||||||
@summary: write client cut text event packet
|
|
||||||
"""
|
|
||||||
self.send((UInt8(ClientToServerMessages.CUT_TEXT), ClientCutText(text)))
|
|
||||||
|
|
||||||
class RFBClientListener(object):
|
|
||||||
"""
|
|
||||||
@summary: Interface use to expose event receive from RFB layer
|
|
||||||
"""
|
|
||||||
def recvRectangle(self, rectangle, pixelFormat, data):
|
|
||||||
"""
|
|
||||||
@summary: Receive rectangle order
|
|
||||||
Main update order type
|
|
||||||
@param rectangle: Rectangle type header of packet
|
|
||||||
@param pixelFormat: pixelFormat struct of current session
|
|
||||||
@param data: image data
|
|
||||||
"""
|
|
||||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recvRectangle", "RFBClientListener"))
|
|
||||||
|
|
||||||
def onBell(self):
|
|
||||||
"""
|
|
||||||
@summary: receive bip from server
|
|
||||||
"""
|
|
||||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onBell", "RFBClientListener"))
|
|
||||||
|
|
||||||
def onCutText(self, text):
|
|
||||||
"""
|
|
||||||
@summary: Receive cut text from server
|
|
||||||
@param text: text inner cut text event
|
|
||||||
"""
|
|
||||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onCutText", "RFBClientListener"))
|
|
||||||
|
|
||||||
|
|
||||||
class RFBClientController(RFBClientListener):
|
|
||||||
"""
|
|
||||||
@summary: Class use to manage RFB order and dispatch throw observers for client side
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
self._clientObservers = []
|
|
||||||
#rfb layer to send client orders
|
|
||||||
self._rfbLayer = RFB(self)
|
|
||||||
self._isReady = False
|
|
||||||
|
|
||||||
def getProtocol(self):
|
|
||||||
"""
|
|
||||||
@return: RFB layer build by controller
|
|
||||||
"""
|
|
||||||
return self._rfbLayer
|
|
||||||
|
|
||||||
def addClientObserver(self, observer):
|
|
||||||
"""
|
|
||||||
@summary: Add new observer for this protocol
|
|
||||||
@param observer: new observer
|
|
||||||
"""
|
|
||||||
self._clientObservers.append(observer)
|
|
||||||
observer._clientListener = self
|
|
||||||
|
|
||||||
def getWidth(self):
|
|
||||||
"""
|
|
||||||
@return: width of framebuffer
|
|
||||||
"""
|
|
||||||
return self._rfbLayer._serverInit.width.value
|
|
||||||
|
|
||||||
def getHeight(self):
|
|
||||||
"""
|
|
||||||
@return: height of framebuffer
|
|
||||||
"""
|
|
||||||
return self._rfbLayer._serverInit.height.value
|
|
||||||
|
|
||||||
def getScreen(self):
|
|
||||||
"""
|
|
||||||
@return: (width, height) of screen
|
|
||||||
"""
|
|
||||||
return (self.getWidth(), self.getHeight())
|
|
||||||
|
|
||||||
def setPassword(self, password):
|
|
||||||
"""
|
|
||||||
@summary: set password for vnc authentication type
|
|
||||||
@param password: password for session
|
|
||||||
"""
|
|
||||||
self._rfbLayer._password = password
|
|
||||||
|
|
||||||
def onReady(self):
|
|
||||||
"""
|
|
||||||
@summary: rfb stack is reday to send or receive event
|
|
||||||
"""
|
|
||||||
self._isReady = True
|
|
||||||
for observer in self._clientObservers:
|
|
||||||
observer.onReady()
|
|
||||||
|
|
||||||
def recvRectangle(self, rectangle, pixelFormat, data):
|
|
||||||
"""
|
|
||||||
@summary: Receive rectangle order
|
|
||||||
Main update order type
|
|
||||||
@param rectangle: Rectangle type header of packet
|
|
||||||
@param pixelFormat: pixelFormat struct of current session
|
|
||||||
@param data: image data
|
|
||||||
"""
|
|
||||||
for observer in self._clientObservers:
|
|
||||||
observer.onUpdate(rectangle.width.value, rectangle.height.value, rectangle.x.value, rectangle.y.value, pixelFormat, rectangle.encoding, data)
|
|
||||||
|
|
||||||
def onBell(self):
|
|
||||||
"""
|
|
||||||
@summary: biiiip event
|
|
||||||
"""
|
|
||||||
for observer in self._clientObservers:
|
|
||||||
observer.onBell()
|
|
||||||
|
|
||||||
def onCutText(self, text):
|
|
||||||
"""
|
|
||||||
@summary: receive cut text event
|
|
||||||
@param text: text in cut text event
|
|
||||||
"""
|
|
||||||
for observer in self._clientObservers:
|
|
||||||
observer.onCutText(text)
|
|
||||||
|
|
||||||
def onClose(self):
|
|
||||||
"""
|
|
||||||
@summary: handle on close events
|
|
||||||
"""
|
|
||||||
if not self._isReady:
|
|
||||||
log.debug("Close on non ready layer means authentication error")
|
|
||||||
return
|
|
||||||
for observer in self._clientObservers:
|
|
||||||
observer.onClose()
|
|
||||||
|
|
||||||
def sendKeyEvent(self, isDown, key):
|
|
||||||
"""
|
|
||||||
@summary: Send a key event throw RFB protocol
|
|
||||||
@param isDown: boolean notify if key is pressed or not (True if key is pressed)
|
|
||||||
@param key: ASCII code of key
|
|
||||||
"""
|
|
||||||
if not self._isReady:
|
|
||||||
log.info("Try to send key event on non ready layer")
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
event = KeyEvent()
|
|
||||||
event.downFlag.value = isDown
|
|
||||||
event.key.value = key
|
|
||||||
|
|
||||||
self._rfbLayer.sendKeyEvent(event)
|
|
||||||
except InvalidValue:
|
|
||||||
log.debug("Try to send an invalid key event")
|
|
||||||
|
|
||||||
def sendPointerEvent(self, mask, x, y):
|
|
||||||
"""
|
|
||||||
@summary: Send a pointer event throw RFB protocol
|
|
||||||
@param mask: mask of button if button 1 and 3 are pressed then mask is 00000101
|
|
||||||
@param x: x coordinate of mouse pointer
|
|
||||||
@param y: y pointer of mouse pointer
|
|
||||||
"""
|
|
||||||
if not self._isReady:
|
|
||||||
log.info("Try to send pointer event on non ready layer")
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
event = PointerEvent()
|
|
||||||
event.mask.value = mask
|
|
||||||
event.x.value = x
|
|
||||||
event.y.value = y
|
|
||||||
|
|
||||||
self._rfbLayer.sendPointerEvent(event)
|
|
||||||
except InvalidValue:
|
|
||||||
log.debug("Try to send an invalid pointer event")
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
"""
|
|
||||||
@summary: close rfb stack
|
|
||||||
"""
|
|
||||||
self._rfbLayer.close()
|
|
||||||
|
|
||||||
|
|
||||||
class ClientFactory(RawLayerClientFactory):
|
|
||||||
"""
|
|
||||||
@summary: Twisted Factory of RFB protocol
|
|
||||||
"""
|
|
||||||
def buildRawLayer(self, addr):
|
|
||||||
"""
|
|
||||||
@summary: Function call by twisted on connection
|
|
||||||
@param addr: address where client try to connect
|
|
||||||
"""
|
|
||||||
controller = RFBClientController()
|
|
||||||
self.buildObserver(controller, addr)
|
|
||||||
return controller.getProtocol()
|
|
||||||
|
|
||||||
def connectionLost(self, rfblayer, reason):
|
|
||||||
"""
|
|
||||||
@summary: Override this method to handle connection lost
|
|
||||||
@param rfblayer: rfblayer that cause connectionLost event
|
|
||||||
@param reason: twisted reason
|
|
||||||
"""
|
|
||||||
#call controller
|
|
||||||
rfblayer._clientListener.onClose()
|
|
||||||
|
|
||||||
def buildObserver(self, controller, addr):
|
|
||||||
"""
|
|
||||||
@summary: Build an RFB observer object
|
|
||||||
@param controller: controller use for rfb session
|
|
||||||
@param addr: destination
|
|
||||||
"""
|
|
||||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "buildObserver", "ClientFactory"))
|
|
||||||
|
|
||||||
|
|
||||||
class RFBClientObserver(object):
|
|
||||||
"""
|
|
||||||
@summary: RFB client protocol observer
|
|
||||||
"""
|
|
||||||
def __init__(self, controller):
|
|
||||||
self._controller = controller
|
|
||||||
self._controller.addClientObserver(self)
|
|
||||||
|
|
||||||
def getController(self):
|
|
||||||
"""
|
|
||||||
@return: RFB controller use by observer
|
|
||||||
"""
|
|
||||||
return self._controller
|
|
||||||
|
|
||||||
def keyEvent(self, isPressed, key):
|
|
||||||
"""
|
|
||||||
@summary: Send a key event
|
|
||||||
@param isPressed: state of key
|
|
||||||
@param key: ASCII code of key
|
|
||||||
"""
|
|
||||||
self._controller.sendKeyEvent(isPressed, key)
|
|
||||||
|
|
||||||
def mouseEvent(self, button, x, y):
|
|
||||||
"""
|
|
||||||
@summary: Send a mouse event to RFB Layer
|
|
||||||
@param button: button number which is pressed (0,1,2,3,4,5,6,7)
|
|
||||||
@param x: x coordinate of mouse pointer
|
|
||||||
@param y: y coordinate of mouse pointer
|
|
||||||
"""
|
|
||||||
mask = 0
|
|
||||||
if button == 1:
|
|
||||||
mask = 1
|
|
||||||
elif button > 1:
|
|
||||||
mask = 1 << button - 1
|
|
||||||
|
|
||||||
self._controller.sendPointerEvent(mask, x, y)
|
|
||||||
|
|
||||||
def onReady(self):
|
|
||||||
"""
|
|
||||||
@summary: Event when network stack is ready to receive or send event
|
|
||||||
"""
|
|
||||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onReady", "RFBClientObserver"))
|
|
||||||
|
|
||||||
def onClose(self):
|
|
||||||
"""
|
|
||||||
@summary: On close event
|
|
||||||
"""
|
|
||||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onClose", "RFBClientObserver"))
|
|
||||||
|
|
||||||
def onUpdate(self, width, height, x, y, pixelFormat, encoding, data):
|
|
||||||
"""
|
|
||||||
@summary: Receive FrameBuffer update
|
|
||||||
@param width : width of image
|
|
||||||
@param height : height of image
|
|
||||||
@param x : x position
|
|
||||||
@param y : y position
|
|
||||||
@param pixelFormat : pixel format struct from rfb.types
|
|
||||||
@param encoding : encoding struct from rfb.types
|
|
||||||
@param data : in respect of dataFormat and pixelFormat
|
|
||||||
"""
|
|
||||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onUpdate", "RFBClientObserver"))
|
|
||||||
|
|
||||||
def onCutText(self, text):
|
|
||||||
"""
|
|
||||||
@summary: event when server send cut text event
|
|
||||||
@param text: text received
|
|
||||||
"""
|
|
||||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onCutText", "RFBClientObserver"))
|
|
||||||
|
|
||||||
def onBell(self):
|
|
||||||
"""
|
|
||||||
@summary: event when server send biiip
|
|
||||||
"""
|
|
||||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "onBell", "RFBClientObserver"))
|
|
||||||
145
rdpy/ui/qt4.py
145
rdpy/ui/qt4.py
@@ -23,13 +23,12 @@ Qt specific code
|
|||||||
QRemoteDesktop is a widget use for render in rdpy
|
QRemoteDesktop is a widget use for render in rdpy
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from PyQt4 import QtGui, QtCore
|
from PyQt5 import QtWidgets
|
||||||
from rdpy.protocol.rfb.rfb import RFBClientObserver
|
from rdpy.core.rdp import RDPClientObserver
|
||||||
from rdpy.protocol.rdp.rdp import RDPClientObserver
|
from rdpy.model.error import CallPureVirtualFuntion
|
||||||
from rdpy.core.error import CallPureVirtualFuntion
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import rdpy.core.log as log
|
import rdpy.model.log as log
|
||||||
import rle
|
import rle
|
||||||
|
|
||||||
class QAdaptor(object):
|
class QAdaptor(object):
|
||||||
@@ -72,112 +71,10 @@ def qtImageFormatFromRFBPixelFormat(pixelFormat):
|
|||||||
@summary: convert RFB pixel format to QtGui.QImage format
|
@summary: convert RFB pixel format to QtGui.QImage format
|
||||||
"""
|
"""
|
||||||
if pixelFormat.BitsPerPixel.value == 32:
|
if pixelFormat.BitsPerPixel.value == 32:
|
||||||
return QtGui.QImage.Format_RGB32
|
return QtWidgets.QImage.Format_RGB32
|
||||||
elif pixelFormat.BitsPerPixel.value == 16:
|
elif pixelFormat.BitsPerPixel.value == 16:
|
||||||
return QtGui.QImage.Format_RGB16
|
return QtWidgets.QImage.Format_RGB16
|
||||||
|
|
||||||
class RFBClientQt(RFBClientObserver, QAdaptor):
|
|
||||||
"""
|
|
||||||
@summary: QAdaptor for specific RFB protocol stack
|
|
||||||
is to an RFB observer
|
|
||||||
"""
|
|
||||||
def __init__(self, controller):
|
|
||||||
"""
|
|
||||||
@param controller: controller for observer
|
|
||||||
@param width: width of widget
|
|
||||||
@param height: height of widget
|
|
||||||
"""
|
|
||||||
RFBClientObserver.__init__(self, controller)
|
|
||||||
self._widget = QRemoteDesktop(1024, 800, self)
|
|
||||||
|
|
||||||
def getWidget(self):
|
|
||||||
"""
|
|
||||||
@return: widget use for render
|
|
||||||
"""
|
|
||||||
return self._widget
|
|
||||||
|
|
||||||
def onUpdate(self, width, height, x, y, pixelFormat, encoding, data):
|
|
||||||
"""
|
|
||||||
@summary: Implement RFBClientObserver interface
|
|
||||||
@param width: width of new image
|
|
||||||
@param height: height of new image
|
|
||||||
@param x: x position of new image
|
|
||||||
@param y: y position of new image
|
|
||||||
@param pixelFormat: pixefFormat structure in rfb.message.PixelFormat
|
|
||||||
@param encoding: encoding type rfb.message.Encoding
|
|
||||||
@param data: image data in accordance with pixel format and encoding
|
|
||||||
"""
|
|
||||||
imageFormat = qtImageFormatFromRFBPixelFormat(pixelFormat)
|
|
||||||
if imageFormat is None:
|
|
||||||
log.error("Receive image in bad format")
|
|
||||||
return
|
|
||||||
|
|
||||||
image = QtGui.QImage(data, width, height, imageFormat)
|
|
||||||
self._widget.notifyImage(x, y, image, width, height)
|
|
||||||
|
|
||||||
def onCutText(self, text):
|
|
||||||
"""
|
|
||||||
@summary: event when server send cut text event
|
|
||||||
@param text: text received
|
|
||||||
"""
|
|
||||||
|
|
||||||
def onBell(self):
|
|
||||||
"""
|
|
||||||
@summary: event when server send biiip
|
|
||||||
"""
|
|
||||||
|
|
||||||
def onReady(self):
|
|
||||||
"""
|
|
||||||
@summary: Event when network stack is ready to receive or send event
|
|
||||||
"""
|
|
||||||
(width, height) = self._controller.getScreen()
|
|
||||||
self._widget.resize(width, height)
|
|
||||||
|
|
||||||
def sendMouseEvent(self, e, isPressed):
|
|
||||||
"""
|
|
||||||
@summary: Convert Qt mouse event to RFB mouse event
|
|
||||||
@param e: qMouseEvent
|
|
||||||
@param isPressed: event come from press or release action
|
|
||||||
"""
|
|
||||||
button = e.button()
|
|
||||||
buttonNumber = 0
|
|
||||||
if button == QtCore.Qt.LeftButton:
|
|
||||||
buttonNumber = 1
|
|
||||||
elif button == QtCore.Qt.MidButton:
|
|
||||||
buttonNumber = 2
|
|
||||||
elif button == QtCore.Qt.RightButton:
|
|
||||||
buttonNumber = 3
|
|
||||||
self.mouseEvent(buttonNumber, e.pos().x(), e.pos().y())
|
|
||||||
|
|
||||||
def sendKeyEvent(self, e, isPressed):
|
|
||||||
"""
|
|
||||||
@summary: Convert Qt key press event to RFB press event
|
|
||||||
@param e: qKeyEvent
|
|
||||||
@param isPressed: event come from press or release action
|
|
||||||
"""
|
|
||||||
self.keyEvent(isPressed, e.nativeVirtualKey())
|
|
||||||
|
|
||||||
def sendWheelEvent(self, e):
|
|
||||||
"""
|
|
||||||
@summary: Convert Qt wheel event to RFB Wheel event
|
|
||||||
@param e: QKeyEvent
|
|
||||||
@param isPressed: event come from press or release action
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def closeEvent(self, e):
|
|
||||||
"""
|
|
||||||
@summary: Call when you want to close connection
|
|
||||||
@param: QCloseEvent
|
|
||||||
"""
|
|
||||||
self._controller.close()
|
|
||||||
|
|
||||||
def onClose(self):
|
|
||||||
"""
|
|
||||||
@summary: Call when stack is close
|
|
||||||
"""
|
|
||||||
#do something maybe a message
|
|
||||||
pass
|
|
||||||
|
|
||||||
def RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data):
|
def RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data):
|
||||||
"""
|
"""
|
||||||
@@ -195,36 +92,36 @@ def RDPBitmapToQtImage(width, height, bitsPerPixel, isCompress, data):
|
|||||||
if isCompress:
|
if isCompress:
|
||||||
buf = bytearray(width * height * 2)
|
buf = bytearray(width * height * 2)
|
||||||
rle.bitmap_decompress(buf, width, height, data, 2)
|
rle.bitmap_decompress(buf, width, height, data, 2)
|
||||||
image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB555)
|
image = QtWidgets.QImage(buf, width, height, QtWidgets.QImage.Format_RGB555)
|
||||||
else:
|
else:
|
||||||
image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB555).transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
|
image = QtWidgets.QImage(data, width, height, QtWidgets.QImage.Format_RGB555).transformed(QtWidgets.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
|
||||||
|
|
||||||
elif bitsPerPixel == 16:
|
elif bitsPerPixel == 16:
|
||||||
if isCompress:
|
if isCompress:
|
||||||
buf = bytearray(width * height * 2)
|
buf = bytearray(width * height * 2)
|
||||||
rle.bitmap_decompress(buf, width, height, data, 2)
|
rle.bitmap_decompress(buf, width, height, data, 2)
|
||||||
image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB16)
|
image = QtWidgets.QImage(buf, width, height, QtWidgets.QImage.Format_RGB16)
|
||||||
else:
|
else:
|
||||||
image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB16).transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
|
image = QtWidgets.QImage(data, width, height, QtWidgets.QImage.Format_RGB16).transformed(QtWidgets.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
|
||||||
|
|
||||||
elif bitsPerPixel == 24:
|
elif bitsPerPixel == 24:
|
||||||
if isCompress:
|
if isCompress:
|
||||||
buf = bytearray(width * height * 3)
|
buf = bytearray(width * height * 3)
|
||||||
rle.bitmap_decompress(buf, width, height, data, 3)
|
rle.bitmap_decompress(buf, width, height, data, 3)
|
||||||
image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB888)
|
image = QtWidgets.QImage(buf, width, height, QtWidgets.QImage.Format_RGB888)
|
||||||
else:
|
else:
|
||||||
image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB888).transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
|
image = QtWidgets.QImage(data, width, height, QtWidgets.QImage.Format_RGB888).transformed(QtWidgets.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
|
||||||
|
|
||||||
elif bitsPerPixel == 32:
|
elif bitsPerPixel == 32:
|
||||||
if isCompress:
|
if isCompress:
|
||||||
buf = bytearray(width * height * 4)
|
buf = bytearray(width * height * 4)
|
||||||
rle.bitmap_decompress(buf, width, height, data, 4)
|
rle.bitmap_decompress(buf, width, height, data, 4)
|
||||||
image = QtGui.QImage(buf, width, height, QtGui.QImage.Format_RGB32)
|
image = QtWidgets.QImage(buf, width, height, QtWidgets.QImage.Format_RGB32)
|
||||||
else:
|
else:
|
||||||
image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB32).transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
|
image = QtWidgets.QImage(data, width, height, QtWidgets.QImage.Format_RGB32).transformed(QtWidgets.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
|
||||||
else:
|
else:
|
||||||
log.error("Receive image in bad format")
|
log.error("Receive image in bad format")
|
||||||
image = QtGui.QImage(width, height, QtGui.QImage.Format_RGB32)
|
image = QtWidgets.QImage(width, height, QtWidgets.QImage.Format_RGB32)
|
||||||
return image
|
return image
|
||||||
|
|
||||||
class RDPClientQt(RDPClientObserver, QAdaptor):
|
class RDPClientQt(RDPClientObserver, QAdaptor):
|
||||||
@@ -330,7 +227,7 @@ class RDPClientQt(RDPClientObserver, QAdaptor):
|
|||||||
#do something maybe a message
|
#do something maybe a message
|
||||||
|
|
||||||
|
|
||||||
class QRemoteDesktop(QtGui.QWidget):
|
class QRemoteDesktop(QtWidgets.QWidget):
|
||||||
"""
|
"""
|
||||||
@summary: Qt display widget
|
@summary: Qt display widget
|
||||||
"""
|
"""
|
||||||
@@ -348,7 +245,7 @@ class QRemoteDesktop(QtGui.QWidget):
|
|||||||
#bind mouse event
|
#bind mouse event
|
||||||
self.setMouseTracking(True)
|
self.setMouseTracking(True)
|
||||||
#buffer image
|
#buffer image
|
||||||
self._buffer = QtGui.QImage(width, height, QtGui.QImage.Format_RGB32)
|
self._buffer = QtWidgets.QImage(width, height, QtWidgets.QImage.Format_RGB32)
|
||||||
|
|
||||||
def notifyImage(self, x, y, qimage, width, height):
|
def notifyImage(self, x, y, qimage, width, height):
|
||||||
"""
|
"""
|
||||||
@@ -358,7 +255,7 @@ class QRemoteDesktop(QtGui.QWidget):
|
|||||||
@param qimage: new QImage
|
@param qimage: new QImage
|
||||||
"""
|
"""
|
||||||
#fill buffer image
|
#fill buffer image
|
||||||
with QtGui.QPainter(self._buffer) as qp:
|
with QtWidgets.QPainter(self._buffer) as qp:
|
||||||
qp.drawImage(x, y, qimage, 0, 0, width, height)
|
qp.drawImage(x, y, qimage, 0, 0, width, height)
|
||||||
#force update
|
#force update
|
||||||
self.update()
|
self.update()
|
||||||
@@ -369,8 +266,8 @@ class QRemoteDesktop(QtGui.QWidget):
|
|||||||
@param width: {int} width of widget
|
@param width: {int} width of widget
|
||||||
@param height: {int} height of widget
|
@param height: {int} height of widget
|
||||||
"""
|
"""
|
||||||
self._buffer = QtGui.QImage(width, height, QtGui.QImage.Format_RGB32)
|
self._buffer = QtWidgets.QImage(width, height, QtWidgets.QImage.Format_RGB32)
|
||||||
QtGui.QWidget.resize(self, width, height)
|
QtWidgets.QWidget.resize(self, width, height)
|
||||||
|
|
||||||
def paintEvent(self, e):
|
def paintEvent(self, e):
|
||||||
"""
|
"""
|
||||||
@@ -378,7 +275,7 @@ class QRemoteDesktop(QtGui.QWidget):
|
|||||||
@param e: QEvent
|
@param e: QEvent
|
||||||
"""
|
"""
|
||||||
#draw in widget
|
#draw in widget
|
||||||
with QtGui.QPainter(self) as qp:
|
with QtWidgets.QPainter(self) as qp:
|
||||||
qp.drawImage(0, 0, self._buffer)
|
qp.drawImage(0, 0, self._buffer)
|
||||||
|
|
||||||
def mouseMoveEvent(self, event):
|
def mouseMoveEvent(self, event):
|
||||||
|
|||||||
20
setup.py
20
setup.py
@@ -4,7 +4,7 @@ import setuptools
|
|||||||
from distutils.core import setup, Extension
|
from distutils.core import setup, Extension
|
||||||
|
|
||||||
setup(name='rdpy',
|
setup(name='rdpy',
|
||||||
version='1.3.2',
|
version='2.0.0',
|
||||||
description='Remote Desktop Protocol in Python',
|
description='Remote Desktop Protocol in Python',
|
||||||
long_description="""
|
long_description="""
|
||||||
RDPY is a pure Python implementation of the Microsoft RDP (Remote Desktop Protocol) protocol (Client and Server side). RDPY is built over the event driven network engine Twisted.
|
RDPY is a pure Python implementation of the Microsoft RDP (Remote Desktop Protocol) protocol (Client and Server side). RDPY is built over the event driven network engine Twisted.
|
||||||
@@ -16,14 +16,11 @@ setup(name='rdpy',
|
|||||||
url='https://github.com/citronneur/rdpy',
|
url='https://github.com/citronneur/rdpy',
|
||||||
packages=[
|
packages=[
|
||||||
'rdpy',
|
'rdpy',
|
||||||
'rdpy.core',
|
'rdpy.model',
|
||||||
'rdpy.security',
|
'rdpy.security',
|
||||||
'rdpy.protocol',
|
'rdpy.core.pdu',
|
||||||
'rdpy.protocol.rdp',
|
'rdpy.core.nla',
|
||||||
'rdpy.protocol.rdp.pdu',
|
'rdpy.core.t125',
|
||||||
'rdpy.protocol.rdp.nla',
|
|
||||||
'rdpy.protocol.rdp.t125',
|
|
||||||
'rdpy.protocol.rfb',
|
|
||||||
'rdpy.ui'
|
'rdpy.ui'
|
||||||
],
|
],
|
||||||
ext_modules=[Extension('rle', ['ext/rle.c'])],
|
ext_modules=[Extension('rle', ['ext/rle.c'])],
|
||||||
@@ -37,10 +34,9 @@ setup(name='rdpy',
|
|||||||
'bin/rdpy-vncscreenshot.py'
|
'bin/rdpy-vncscreenshot.py'
|
||||||
],
|
],
|
||||||
install_requires=[
|
install_requires=[
|
||||||
'twisted',
|
'PyQt5',
|
||||||
'pyopenssl',
|
'PyQt5-sip',
|
||||||
'service_identity',
|
'service_identity',
|
||||||
'qt4reactor',
|
|
||||||
'rsa',
|
'rsa',
|
||||||
'pyasn1'
|
'pyasn1'
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ import os, sys
|
|||||||
sys.path.insert(1, os.path.join(sys.path[0], '..'))
|
sys.path.insert(1, os.path.join(sys.path[0], '..'))
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
import rdpy.protocol.rdp.t125.ber as ber
|
import rdpy.core.t125.ber as ber
|
||||||
import rdpy.core.type as type
|
import rdpy.core.type as type
|
||||||
import rdpy.core.error as error
|
|
||||||
|
|
||||||
class BERTest(unittest.TestCase):
|
class BERTest(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import os, sys
|
|||||||
# Change path so we find rdpy
|
# Change path so we find rdpy
|
||||||
sys.path.insert(1, os.path.join(sys.path[0], '..'))
|
sys.path.insert(1, os.path.join(sys.path[0], '..'))
|
||||||
|
|
||||||
from rdpy.protocol.rdp.nla import cssp, ntlm
|
from rdpy.core.nla import ntlm, cssp
|
||||||
from rdpy.security import rc4
|
from rdpy.security import rc4
|
||||||
|
|
||||||
pubKeyHex = """
|
pubKeyHex = """
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import os, sys
|
|||||||
sys.path.insert(1, os.path.join(sys.path[0], '..'))
|
sys.path.insert(1, os.path.join(sys.path[0], '..'))
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from rdpy.protocol.rdp import lic, sec
|
from rdpy.core import lic, sec
|
||||||
import rdpy.core.type as type
|
import rdpy.core.type as type
|
||||||
|
|
||||||
#dump of server request
|
#dump of server request
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import os, sys
|
|||||||
sys.path.insert(1, os.path.join(sys.path[0], '..'))
|
sys.path.insert(1, os.path.join(sys.path[0], '..'))
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
import rdpy.protocol.rdp.t125.per as per
|
import rdpy.core.t125.per as per
|
||||||
import rdpy.core.type as type
|
import rdpy.core.type as type
|
||||||
import rdpy.core.error as error
|
import rdpy.core.error as error
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ class PERTest(unittest.TestCase):
|
|||||||
s.writeType((per.writeLength(type.sizeof(v)), v))
|
s.writeType((per.writeLength(type.sizeof(v)), v))
|
||||||
s.pos = 0
|
s.pos = 0
|
||||||
|
|
||||||
self.assertTrue(per.readInteger(s) == 3, "invalid readLength for type %s"%t)
|
self.assertTrue(per.readInteger(s) == 3, "invalid readLength for type %s" % t)
|
||||||
|
|
||||||
#error case
|
#error case
|
||||||
for l in [0, 3, 5]:
|
for l in [0, 3, 5]:
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ import os, sys
|
|||||||
sys.path.insert(1, os.path.join(sys.path[0], '..'))
|
sys.path.insert(1, os.path.join(sys.path[0], '..'))
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
import rdpy.protocol.rdp.tpkt as tpkt
|
import rdpy.core.tpkt as tpkt
|
||||||
import rdpy.core.type as type
|
import rdpy.core.type as type
|
||||||
import rdpy.core.error as error
|
|
||||||
|
|
||||||
class TPKTTest(unittest.TestCase):
|
class TPKTTest(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import os, sys
|
|||||||
sys.path.insert(1, os.path.join(sys.path[0], '..'))
|
sys.path.insert(1, os.path.join(sys.path[0], '..'))
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
import rdpy.protocol.rdp.x224 as x224
|
import rdpy.core.x224 as x224
|
||||||
import rdpy.core.type as type
|
import rdpy.core.type as type
|
||||||
import rdpy.core.error as error
|
import rdpy.core.error as error
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user