code refactoring
This commit is contained in:
@@ -45,7 +45,9 @@ def decode(src, width, height, colorType):
|
|||||||
insertMix = False
|
insertMix = False
|
||||||
fom_mask = 0
|
fom_mask = 0
|
||||||
mask = 0
|
mask = 0
|
||||||
dst = Stream("\x00" * (width * height * sizeof(colorType())))
|
line = 0
|
||||||
|
typeSize = sizeof(colorType())
|
||||||
|
dst = Stream("\x00" * (width * height * typeSize))
|
||||||
|
|
||||||
while src.dataLen() > 0:
|
while src.dataLen() > 0:
|
||||||
#compute orders
|
#compute orders
|
||||||
@@ -107,7 +109,10 @@ def decode(src, width, height, colorType):
|
|||||||
raise InvalidExpectedDataException("In RLE decompression height must be greater than 0")
|
raise InvalidExpectedDataException("In RLE decompression height must be greater than 0")
|
||||||
x = 0
|
x = 0
|
||||||
height -= 1
|
height -= 1
|
||||||
#prevline = line
|
prevline = line
|
||||||
|
line = width * height * typeSize
|
||||||
|
|
||||||
|
|
||||||
return dst
|
return dst
|
||||||
|
|
||||||
|
|
||||||
@@ -21,6 +21,16 @@
|
|||||||
All exceptions error use in RDPY
|
All exceptions error use in RDPY
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
class CallPureVirtualFuntion(Exception):
|
||||||
|
"""
|
||||||
|
Raise when a virtual function is called and not implemented
|
||||||
|
"""
|
||||||
|
def __init__(self, message = ""):
|
||||||
|
"""
|
||||||
|
@param message: message show when exception is raised
|
||||||
|
"""
|
||||||
|
Exception.__init__(self, message)
|
||||||
|
|
||||||
class InvalidValue(Exception):
|
class InvalidValue(Exception):
|
||||||
"""
|
"""
|
||||||
Raise when invalid value type occurred
|
Raise when invalid value type occurred
|
||||||
|
|||||||
@@ -23,88 +23,94 @@ Join RDPY design with twisted design
|
|||||||
RDPY use Layer Protocol design (like twisted)
|
RDPY use Layer Protocol design (like twisted)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from rdpy.network.error import CallPureVirtualFuntion
|
||||||
|
|
||||||
class LayerMode(object):
|
class LayerMode(object):
|
||||||
NONE = 0
|
NONE = 0
|
||||||
SERVER = 1
|
SERVER = 1
|
||||||
CLIENT = 2
|
CLIENT = 2
|
||||||
|
|
||||||
|
|
||||||
|
class StreamListener(object):
|
||||||
|
"""
|
||||||
|
Interface use to inform that we can handle receive stream
|
||||||
|
"""
|
||||||
|
def recv(self, s):
|
||||||
|
"""
|
||||||
|
Signal that data is available for this layer
|
||||||
|
call by transport layer
|
||||||
|
default is to pass data to presentation layer
|
||||||
|
@param s: raw Stream receive from transport layer
|
||||||
|
"""
|
||||||
|
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "recv", "StreamListener"))
|
||||||
|
|
||||||
|
class StreamSender(object):
|
||||||
|
"""
|
||||||
|
Interface use to show stream sender capability
|
||||||
|
"""
|
||||||
|
def send(self, data):
|
||||||
|
'''
|
||||||
|
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"))
|
||||||
|
|
||||||
class Layer(object):
|
class Layer(object):
|
||||||
'''
|
"""
|
||||||
Network abstraction for protocol
|
A simple double linked list with presentation and transport layer
|
||||||
Try as possible to divide user protocol in layer
|
and a subset of event (connect and close)
|
||||||
default implementation is a transparent layer
|
"""
|
||||||
'''
|
def __init__(self, mode, presentation = None):
|
||||||
def __init__(self, mode = LayerMode.NONE, presentation = None):
|
"""
|
||||||
'''
|
@param mode: LayerMode use
|
||||||
Constructor
|
@param presentation: presentation layer
|
||||||
@param presentation: Layer which handled connect and recv messages
|
"""
|
||||||
'''
|
|
||||||
#presentation layer higher layer in model
|
#presentation layer higher layer in model
|
||||||
self._presentation = presentation
|
self._presentation = presentation
|
||||||
#transport layer under layer in model
|
#transport layer under layer in model
|
||||||
self._transport = None
|
self._transport = None
|
||||||
#register layer mode
|
#network layer mode
|
||||||
self._mode = mode
|
self._mode = mode
|
||||||
#auto set transport layer of own presentation layer
|
#auto set transport layer of own presentation layer
|
||||||
if not self._presentation is None:
|
if not self._presentation is None:
|
||||||
self._presentation._transport = self
|
self._presentation._transport = self
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
'''
|
"""
|
||||||
call when transport layer is connected
|
Call when transport layer is connected
|
||||||
default is send connect event to presentation layer
|
default is send connect event to presentation layer
|
||||||
'''
|
"""
|
||||||
if not self._presentation is None:
|
if not self._presentation is None:
|
||||||
self._presentation.connect()
|
self._presentation.connect()
|
||||||
|
|
||||||
def recv(self, s):
|
|
||||||
'''
|
|
||||||
signal that data is available for this layer
|
|
||||||
call by transport layer
|
|
||||||
default is to pass data to presentation layer
|
|
||||||
@param s: raw Stream receive from transport layer
|
|
||||||
'''
|
|
||||||
if not self._presentation is None:
|
|
||||||
self._presentation.recv(s)
|
|
||||||
|
|
||||||
def send(self, data):
|
|
||||||
'''
|
|
||||||
classical use by presentation layer
|
|
||||||
write data for this layer
|
|
||||||
default pass data to transport layer
|
|
||||||
@param data: Type or tuple element handle by transport layer
|
|
||||||
'''
|
|
||||||
if not self._transport is None:
|
|
||||||
self._transport.send(data)
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
'''
|
"""
|
||||||
close layer and send close signal
|
Close layer event
|
||||||
to transport layer
|
default is sent to transport layer
|
||||||
'''
|
"""
|
||||||
if not self._transport is None:
|
if not self._transport is None:
|
||||||
self._transport.close()
|
self._transport.close()
|
||||||
|
|
||||||
class LayerAutomata(Layer):
|
class LayerAutomata(Layer, StreamListener):
|
||||||
'''
|
"""
|
||||||
layer with automata state
|
Layer with automata state
|
||||||
we can set next recv function used
|
we can set next recv function used for Stream packet
|
||||||
'''
|
"""
|
||||||
def __init__(self, mode, presentation = None):
|
def __init__(self, mode, presentation = None):
|
||||||
'''
|
"""
|
||||||
Constructor
|
@param mode: LayerMode use
|
||||||
@param presentation: presentation Layer
|
@param presentation: presentation Layer
|
||||||
'''
|
"""
|
||||||
#call parent constructor
|
#call parent constructor
|
||||||
Layer.__init__(self, mode, presentation)
|
Layer.__init__(self, mode, presentation)
|
||||||
|
|
||||||
def setNextState(self, callback = None):
|
def setNextState(self, callback = None):
|
||||||
'''
|
"""
|
||||||
set recv function to next callback or
|
Set receive function to next callback or
|
||||||
current self.recv function if it's None
|
current self.recv function if it's None
|
||||||
@param callback: a callable object that can
|
@param callback: a callable object that can
|
||||||
receive Layer, Stream parameters
|
receive Layer, Stream parameters
|
||||||
'''
|
"""
|
||||||
if callback is None:
|
if callback is None:
|
||||||
callback = self.__class__.recv
|
callback = self.__class__.recv
|
||||||
|
|
||||||
@@ -115,16 +121,17 @@ from twisted.internet import protocol
|
|||||||
#first that handle stream
|
#first that handle stream
|
||||||
from type import Stream
|
from type import Stream
|
||||||
|
|
||||||
class RawLayer(protocol.Protocol, LayerAutomata):
|
class RawLayer(protocol.Protocol, LayerAutomata, StreamSender):
|
||||||
'''
|
"""
|
||||||
Inherit from protocol twisted class
|
Inherit from protocol twisted class
|
||||||
allow this protocol to wait until expected size of packet
|
allow this protocol to wait until expected size of packet
|
||||||
and use Layer automata to call next automata state
|
and use Layer automata to call next automata state
|
||||||
'''
|
"""
|
||||||
def __init__(self, mode, presentation = None):
|
def __init__(self, mode, presentation = None):
|
||||||
'''
|
"""
|
||||||
Constructor
|
@param mode: LayerMode use
|
||||||
'''
|
@param presentation: presentation layer in layer list
|
||||||
|
"""
|
||||||
#call parent automata
|
#call parent automata
|
||||||
LayerAutomata.__init__(self, mode, presentation)
|
LayerAutomata.__init__(self, mode, presentation)
|
||||||
#data buffer received from twisted network layer
|
#data buffer received from twisted network layer
|
||||||
@@ -133,11 +140,11 @@ class RawLayer(protocol.Protocol, LayerAutomata):
|
|||||||
self._expectedLen = 0
|
self._expectedLen = 0
|
||||||
|
|
||||||
def dataReceived(self, data):
|
def dataReceived(self, data):
|
||||||
'''
|
"""
|
||||||
inherit from protocol class
|
Inherit from protocol class
|
||||||
main event of received data
|
main event of received data
|
||||||
@param data: string data receive from twisted
|
@param data: string data receive from twisted
|
||||||
'''
|
"""
|
||||||
#add in buffer
|
#add in buffer
|
||||||
self._buffer += data
|
self._buffer += data
|
||||||
#while buffer have expected size call local callback
|
#while buffer have expected size call local callback
|
||||||
@@ -150,29 +157,29 @@ class RawLayer(protocol.Protocol, LayerAutomata):
|
|||||||
self.recv(expectedData)
|
self.recv(expectedData)
|
||||||
|
|
||||||
def connectionMade(self):
|
def connectionMade(self):
|
||||||
'''
|
"""
|
||||||
inherit from twisted protocol
|
inherit from twisted protocol
|
||||||
'''
|
"""
|
||||||
#join two scheme
|
#join two scheme
|
||||||
self.connect()
|
self.connect()
|
||||||
|
|
||||||
def expect(self, expectedLen, callback = None):
|
def expect(self, expectedLen, callback = None):
|
||||||
'''
|
"""
|
||||||
configure layer to change next state with callback only
|
Configure layer to change next state with callback only
|
||||||
when expectLen bytes is received from transport layer
|
when expectLen bytes is received from transport layer
|
||||||
@param expectedLen: in bytes len use to call nextstate
|
@param expectedLen: in bytes length use to call next state
|
||||||
@param callback: callback call when expectedlen bytes is received
|
@param callback: callback call when expected length bytes is received
|
||||||
'''
|
"""
|
||||||
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):
|
||||||
'''
|
"""
|
||||||
send stream on tcp layer
|
Send Stream on TCP layer
|
||||||
format message into raw stream understood by transport layer
|
format message into raw stream understood by transport layer
|
||||||
@param message: (tuple | Type)
|
@param message: (tuple | Type)
|
||||||
'''
|
"""
|
||||||
s = Stream()
|
s = Stream()
|
||||||
s.writeType(message)
|
s.writeType(message)
|
||||||
self.transport.write(s.getvalue())
|
self.transport.write(s.getvalue())
|
||||||
@@ -1,6 +1,27 @@
|
|||||||
'''
|
#
|
||||||
@author: sylvain
|
# Copyright (c) 2014 Sylvain Peyrefitte
|
||||||
'''
|
#
|
||||||
|
# This file is part of rdpy.
|
||||||
|
#
|
||||||
|
# rdpy is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Basic Encoding Rules use in RDP.
|
||||||
|
ASN.1 standard
|
||||||
|
"""
|
||||||
|
|
||||||
from rdpy.network.type import UInt8, UInt16Be, UInt32Be, String
|
from rdpy.network.type import UInt8, UInt16Be, UInt32Be, String
|
||||||
from rdpy.network.const import ConstAttributes, TypeAttributes
|
from rdpy.network.const import ConstAttributes, TypeAttributes
|
||||||
from rdpy.network.error import InvalidExpectedDataException, InvalidSize
|
from rdpy.network.error import InvalidExpectedDataException, InvalidSize
|
||||||
@@ -35,24 +56,24 @@ class Tag(object):
|
|||||||
BER_TAG_SEQUENCE_OF = 0x10
|
BER_TAG_SEQUENCE_OF = 0x10
|
||||||
|
|
||||||
def berPC(pc):
|
def berPC(pc):
|
||||||
'''
|
"""
|
||||||
return BER_CONSTRUCT if true
|
Return BER_CONSTRUCT if true
|
||||||
BER_PRIMITIVE if false
|
BER_PRIMITIVE if false
|
||||||
@param pc: boolean
|
@param pc: boolean
|
||||||
@return: BerPc value
|
@return: BerPc value
|
||||||
'''
|
"""
|
||||||
if pc:
|
if pc:
|
||||||
return BerPc.BER_CONSTRUCT
|
return BerPc.BER_CONSTRUCT
|
||||||
else:
|
else:
|
||||||
return BerPc.BER_PRIMITIVE
|
return BerPc.BER_PRIMITIVE
|
||||||
|
|
||||||
def readLength(s):
|
def readLength(s):
|
||||||
'''
|
"""
|
||||||
read length of ber structure
|
Read length of BER structure
|
||||||
length be on 1 2 or 3 bytes
|
length be on 1 2 or 3 bytes
|
||||||
@param s: stream
|
@param s: stream
|
||||||
@return: int or python long
|
@return: int or Python long
|
||||||
'''
|
"""
|
||||||
size = None
|
size = None
|
||||||
length = UInt8()
|
length = UInt8()
|
||||||
s.readType(length)
|
s.readType(length)
|
||||||
@@ -64,50 +85,50 @@ def readLength(s):
|
|||||||
elif byte == 2:
|
elif byte == 2:
|
||||||
size = UInt16Be()
|
size = UInt16Be()
|
||||||
else:
|
else:
|
||||||
raise InvalidExpectedDataException("ber length may be 1 or 2")
|
raise InvalidExpectedDataException("BER length may be 1 or 2")
|
||||||
s.readType(size)
|
s.readType(size)
|
||||||
else:
|
else:
|
||||||
size = length
|
size = length
|
||||||
return size.value
|
return size.value
|
||||||
|
|
||||||
def writeLength(size):
|
def writeLength(size):
|
||||||
'''
|
"""
|
||||||
return strcture length as expected in Ber specification
|
Return structure length as expected in BER specification
|
||||||
@param size: int or python long
|
@param size: int or python long
|
||||||
@return: UInt8 or (UInt8(0x82), UInt16Be)
|
@return: UInt8 or (UInt8(0x82), UInt16Be)
|
||||||
'''
|
"""
|
||||||
if size > 0x7f:
|
if size > 0x7f:
|
||||||
return (UInt8(0x82), UInt16Be(size))
|
return (UInt8(0x82), UInt16Be(size))
|
||||||
else:
|
else:
|
||||||
return UInt8(size)
|
return UInt8(size)
|
||||||
|
|
||||||
def readUniversalTag(s, tag, pc):
|
def readUniversalTag(s, tag, pc):
|
||||||
'''
|
"""
|
||||||
read tag of ber packet
|
Read tag of BER packet
|
||||||
@param tag: Tag class attributes
|
@param tag: Tag class attributes
|
||||||
@param pc: boolean
|
@param pc: boolean
|
||||||
@return: true if tag is correctly read
|
@return: true if tag is correctly read
|
||||||
'''
|
"""
|
||||||
byte = UInt8()
|
byte = UInt8()
|
||||||
s.readType(byte)
|
s.readType(byte)
|
||||||
return byte == ((Class.BER_CLASS_UNIV | berPC(pc)) | (Tag.BER_TAG_MASK & tag))
|
return byte == ((Class.BER_CLASS_UNIV | berPC(pc)) | (Tag.BER_TAG_MASK & tag))
|
||||||
|
|
||||||
def writeUniversalTag(tag, pc):
|
def writeUniversalTag(tag, pc):
|
||||||
'''
|
"""
|
||||||
return universal tag byte
|
Return universal tag byte
|
||||||
@param tag: tag class attributes
|
@param tag: tag class attributes
|
||||||
@param pc: boolean
|
@param pc: boolean
|
||||||
@return: UInt8
|
@return: UInt8
|
||||||
'''
|
"""
|
||||||
return ((Class.BER_CLASS_UNIV | berPC(pc)) | (Tag.BER_TAG_MASK & tag))
|
return ((Class.BER_CLASS_UNIV | berPC(pc)) | (Tag.BER_TAG_MASK & tag))
|
||||||
|
|
||||||
def readApplicationTag(s, tag):
|
def readApplicationTag(s, tag):
|
||||||
'''
|
"""
|
||||||
read application tag
|
Read application tag
|
||||||
@param s: stream
|
@param s: stream
|
||||||
@param tag: tag class attributes
|
@param tag: tag class attributes
|
||||||
@return: length of application packet
|
@return: length of application packet
|
||||||
'''
|
"""
|
||||||
byte = UInt8()
|
byte = UInt8()
|
||||||
s.readType(byte)
|
s.readType(byte)
|
||||||
if tag > UInt8(30):
|
if tag > UInt8(30):
|
||||||
@@ -123,22 +144,22 @@ def readApplicationTag(s, tag):
|
|||||||
return readLength(s)
|
return readLength(s)
|
||||||
|
|
||||||
def writeApplicationTag(tag, size):
|
def writeApplicationTag(tag, size):
|
||||||
'''
|
"""
|
||||||
return struct that represent ber application tag
|
Return structure that represent BER application tag
|
||||||
@param tag: UINt8
|
@param tag: UINt8
|
||||||
@param size: size to rest of packet
|
@param size: size to rest of packet
|
||||||
'''
|
"""
|
||||||
if tag > UInt8(30):
|
if tag > UInt8(30):
|
||||||
return (((Class.BER_CLASS_APPL | BerPc.BER_CONSTRUCT) | Tag.BER_TAG_MASK), tag, writeLength(size))
|
return (((Class.BER_CLASS_APPL | BerPc.BER_CONSTRUCT) | Tag.BER_TAG_MASK), tag, writeLength(size))
|
||||||
else:
|
else:
|
||||||
return (((Class.BER_CLASS_APPL | BerPc.BER_CONSTRUCT) | (Tag.BER_TAG_MASK & tag)), writeLength(size))
|
return (((Class.BER_CLASS_APPL | BerPc.BER_CONSTRUCT) | (Tag.BER_TAG_MASK & tag)), writeLength(size))
|
||||||
|
|
||||||
def readBoolean(s):
|
def readBoolean(s):
|
||||||
'''
|
"""
|
||||||
return boolean
|
Return boolean
|
||||||
@param s: stream
|
@param s: stream
|
||||||
@return: boolean
|
@return: boolean
|
||||||
'''
|
"""
|
||||||
if not readUniversalTag(s, Tag.BER_TAG_BOOLEAN, False):
|
if not readUniversalTag(s, Tag.BER_TAG_BOOLEAN, False):
|
||||||
raise InvalidExpectedDataException("bad boolean tag")
|
raise InvalidExpectedDataException("bad boolean tag")
|
||||||
size = readLength(s)
|
size = readLength(s)
|
||||||
@@ -149,24 +170,24 @@ def readBoolean(s):
|
|||||||
return bool(b.value)
|
return bool(b.value)
|
||||||
|
|
||||||
def writeBoolean(b):
|
def writeBoolean(b):
|
||||||
'''
|
"""
|
||||||
return structure that represent boolean in ber specification
|
Return structure that represent boolean in BER specification
|
||||||
@param b: boolean
|
@param b: boolean
|
||||||
@return: ber boolean structure
|
@return: BER boolean structure
|
||||||
'''
|
"""
|
||||||
boolean = UInt8(0)
|
boolean = UInt8(0)
|
||||||
if b:
|
if b:
|
||||||
boolean = UInt8(0xff)
|
boolean = UInt8(0xff)
|
||||||
return (writeUniversalTag(Tag.BER_TAG_BOOLEAN, False), writeLength(1), boolean)
|
return (writeUniversalTag(Tag.BER_TAG_BOOLEAN, False), writeLength(1), boolean)
|
||||||
|
|
||||||
def readInteger(s):
|
def readInteger(s):
|
||||||
'''
|
"""
|
||||||
read integer structure from stream
|
Read integer structure from stream
|
||||||
@param s: stream
|
@param s: stream
|
||||||
@return: int or long python
|
@return: int or long python
|
||||||
'''
|
"""
|
||||||
if not readUniversalTag(s, Tag.BER_TAG_INTEGER, False):
|
if not readUniversalTag(s, Tag.BER_TAG_INTEGER, False):
|
||||||
raise InvalidExpectedDataException("bad integer tag")
|
raise InvalidExpectedDataException("Bad integer tag")
|
||||||
|
|
||||||
size = readLength(s)
|
size = readLength(s)
|
||||||
|
|
||||||
@@ -189,14 +210,14 @@ def readInteger(s):
|
|||||||
s.readType(integer)
|
s.readType(integer)
|
||||||
return integer.value
|
return integer.value
|
||||||
else:
|
else:
|
||||||
raise InvalidExpectedDataException("wrong integer size")
|
raise InvalidExpectedDataException("Wrong integer size")
|
||||||
|
|
||||||
def writeInteger(value):
|
def writeInteger(value):
|
||||||
'''
|
"""
|
||||||
write integer value
|
Write integer value
|
||||||
@param param: int or python long
|
@param param: int or python long
|
||||||
@return ber interger structure
|
@return: BER integer structure
|
||||||
'''
|
"""
|
||||||
if value <= 0xff:
|
if value <= 0xff:
|
||||||
return (writeUniversalTag(Tag.BER_TAG_INTEGER, False), writeLength(1), UInt8(value))
|
return (writeUniversalTag(Tag.BER_TAG_INTEGER, False), writeLength(1), UInt8(value))
|
||||||
elif value <= 0xffff:
|
elif value <= 0xffff:
|
||||||
@@ -205,30 +226,30 @@ def writeInteger(value):
|
|||||||
return (writeUniversalTag(Tag.BER_TAG_INTEGER, False), writeLength(4), UInt32Be(value))
|
return (writeUniversalTag(Tag.BER_TAG_INTEGER, False), writeLength(4), UInt32Be(value))
|
||||||
|
|
||||||
def readOctetString(s):
|
def readOctetString(s):
|
||||||
'''
|
"""
|
||||||
read ber string structure
|
Read BER string structure
|
||||||
@param s: stream
|
@param s: stream
|
||||||
@return: String
|
@return: String
|
||||||
'''
|
"""
|
||||||
if not readUniversalTag(s, Tag.BER_TAG_OCTET_STRING, False):
|
if not readUniversalTag(s, Tag.BER_TAG_OCTET_STRING, False):
|
||||||
raise InvalidExpectedDataException("unexpected ber tag")
|
raise InvalidExpectedDataException("Unexpected BER tag")
|
||||||
size = readLength(s)
|
size = readLength(s)
|
||||||
return String(s.read(size.value))
|
return String(s.read(size.value))
|
||||||
|
|
||||||
def writeOctetstring(value):
|
def writeOctetstring(value):
|
||||||
'''
|
"""
|
||||||
write string in ber representation
|
Write string in ber representation
|
||||||
@param value: string
|
@param value: string
|
||||||
@return: string ber structure
|
@return: string ber structure
|
||||||
'''
|
"""
|
||||||
return (writeUniversalTag(Tag.BER_TAG_OCTET_STRING, False), writeLength(len(value)), String(value))
|
return (writeUniversalTag(Tag.BER_TAG_OCTET_STRING, False), writeLength(len(value)), String(value))
|
||||||
|
|
||||||
def readEnumerated(s):
|
def readEnumerated(s):
|
||||||
'''
|
"""
|
||||||
read enumerated structure
|
Read enumerated structure
|
||||||
@param s: Stream
|
@param s: Stream
|
||||||
@return: int or long
|
@return: int or long
|
||||||
'''
|
"""
|
||||||
if not readUniversalTag(s, Tag.BER_TAG_ENUMERATED, False):
|
if not readUniversalTag(s, Tag.BER_TAG_ENUMERATED, False):
|
||||||
raise InvalidExpectedDataException("invalid ber tag")
|
raise InvalidExpectedDataException("invalid ber tag")
|
||||||
if readLength(s) != 1:
|
if readLength(s) != 1:
|
||||||
|
|||||||
@@ -1,9 +1,32 @@
|
|||||||
'''
|
#
|
||||||
@author: citronneur
|
# Copyright (c) 2014 Sylvain Peyrefitte
|
||||||
'''
|
#
|
||||||
|
# This file is part of rdpy.
|
||||||
|
#
|
||||||
|
# rdpy is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Implement Multi Channel Service
|
||||||
|
|
||||||
|
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.const import ConstAttributes, TypeAttributes
|
from rdpy.network.const import ConstAttributes, TypeAttributes
|
||||||
from rdpy.network.layer import LayerAutomata, Layer, LayerMode
|
from rdpy.network.layer import LayerAutomata, LayerMode, StreamSender
|
||||||
from rdpy.network.type import sizeof, Stream, UInt8, UInt16Be
|
from rdpy.network.type import sizeof, Stream, UInt8, UInt16Be
|
||||||
from rdpy.network.error import InvalidExpectedDataException, InvalidValue, InvalidSize
|
from rdpy.network.error import InvalidExpectedDataException, InvalidValue, InvalidSize
|
||||||
from rdpy.protocol.rdp.ber import writeLength
|
from rdpy.protocol.rdp.ber import writeLength
|
||||||
@@ -13,18 +36,18 @@ import ber, gcc, per
|
|||||||
@ConstAttributes
|
@ConstAttributes
|
||||||
@TypeAttributes(UInt8)
|
@TypeAttributes(UInt8)
|
||||||
class Message(object):
|
class Message(object):
|
||||||
'''
|
"""
|
||||||
message type
|
Message type
|
||||||
'''
|
"""
|
||||||
MCS_TYPE_CONNECT_INITIAL = 0x65
|
MCS_TYPE_CONNECT_INITIAL = 0x65
|
||||||
MCS_TYPE_CONNECT_RESPONSE = 0x66
|
MCS_TYPE_CONNECT_RESPONSE = 0x66
|
||||||
|
|
||||||
@ConstAttributes
|
@ConstAttributes
|
||||||
@TypeAttributes(UInt8)
|
@TypeAttributes(UInt8)
|
||||||
class DomainMCSPDU:
|
class DomainMCSPDU:
|
||||||
'''
|
"""
|
||||||
domain mcs pdu header
|
Domain MCS PDU header
|
||||||
'''
|
"""
|
||||||
ERECT_DOMAIN_REQUEST = 1
|
ERECT_DOMAIN_REQUEST = 1
|
||||||
DISCONNECT_PROVIDER_ULTIMATUM = 8
|
DISCONNECT_PROVIDER_ULTIMATUM = 8
|
||||||
ATTACH_USER_REQUEST = 10
|
ATTACH_USER_REQUEST = 10
|
||||||
@@ -37,27 +60,28 @@ class DomainMCSPDU:
|
|||||||
@ConstAttributes
|
@ConstAttributes
|
||||||
@TypeAttributes(UInt16Be)
|
@TypeAttributes(UInt16Be)
|
||||||
class Channel:
|
class Channel:
|
||||||
|
"""
|
||||||
|
Channel id of main channels use in RDP
|
||||||
|
"""
|
||||||
MCS_GLOBAL_CHANNEL = 1003
|
MCS_GLOBAL_CHANNEL = 1003
|
||||||
MCS_USERCHANNEL_BASE = 1001
|
MCS_USERCHANNEL_BASE = 1001
|
||||||
|
|
||||||
class MCS(LayerAutomata):
|
class MCS(LayerAutomata):
|
||||||
'''
|
"""
|
||||||
Multi Channel Service layer
|
Multi Channel Service layer
|
||||||
the main layer of RDP protocol
|
the main layer of RDP protocol
|
||||||
is why he can do everything and more!
|
is why he can do everything and more!
|
||||||
'''
|
"""
|
||||||
|
class MCSProxySender(StreamSender):
|
||||||
class MCSProxySender(Layer):
|
"""
|
||||||
'''
|
Proxy use to set as transport layer for upper channel
|
||||||
Proxy use to set as trnsport layer for upper channel
|
|
||||||
use to abstract channel id for presentation layer
|
use to abstract channel id for presentation layer
|
||||||
'''
|
"""
|
||||||
def __init__(self, mcs, channelId):
|
def __init__(self, mcs, channelId):
|
||||||
'''
|
"""
|
||||||
ctor
|
@param mcs: MCS layer use as proxy
|
||||||
@param mcs: mcs layer use as proxy
|
|
||||||
@param channelId: channel id for presentation layer
|
@param channelId: channel id for presentation layer
|
||||||
'''
|
"""
|
||||||
self._mcs = mcs
|
self._mcs = mcs
|
||||||
self._channelId = channelId
|
self._channelId = channelId
|
||||||
|
|
||||||
@@ -94,11 +118,10 @@ class MCS(LayerAutomata):
|
|||||||
|
|
||||||
|
|
||||||
def __init__(self, mode, presentation):
|
def __init__(self, mode, presentation):
|
||||||
'''
|
"""
|
||||||
ctor call base class ctor
|
@param mode: mode of MCS layer
|
||||||
@param mode: mode of mcs layer
|
|
||||||
@param presentation: presentation layer
|
@param presentation: presentation layer
|
||||||
'''
|
"""
|
||||||
LayerAutomata.__init__(self, mode, presentation)
|
LayerAutomata.__init__(self, mode, presentation)
|
||||||
self._clientSettings = gcc.ClientSettings()
|
self._clientSettings = gcc.ClientSettings()
|
||||||
self._serverSettings = gcc.ServerSettings()
|
self._serverSettings = gcc.ServerSettings()
|
||||||
@@ -110,17 +133,17 @@ class MCS(LayerAutomata):
|
|||||||
self._channelIdsRequest = {}
|
self._channelIdsRequest = {}
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
'''
|
"""
|
||||||
connection send for client mode
|
Connection send for client mode
|
||||||
a write connect initial packet
|
a write connect initial packet
|
||||||
'''
|
"""
|
||||||
self._clientSettings.core.serverSelectedProtocol = self._transport._selectedProtocol
|
self._clientSettings.core.serverSelectedProtocol = self._transport._selectedProtocol
|
||||||
self.sendConnectInitial()
|
self.sendConnectInitial()
|
||||||
|
|
||||||
def connectNextChannel(self):
|
def connectNextChannel(self):
|
||||||
'''
|
"""
|
||||||
send sendChannelJoinRequest message on next unconnect channel
|
Send sendChannelJoinRequest message on next unconnect channel
|
||||||
'''
|
"""
|
||||||
for (channelId, layer) in self._channelIds.iteritems():
|
for (channelId, layer) in self._channelIds.iteritems():
|
||||||
#for each unconnect channel send a request
|
#for each unconnect channel send a request
|
||||||
if not self._channelIdsRequest.has_key(channelId):
|
if not self._channelIdsRequest.has_key(channelId):
|
||||||
@@ -138,9 +161,9 @@ class MCS(LayerAutomata):
|
|||||||
layer.connect()
|
layer.connect()
|
||||||
|
|
||||||
def sendConnectInitial(self):
|
def sendConnectInitial(self):
|
||||||
'''
|
"""
|
||||||
send connect initial packet
|
Send connect initial packet
|
||||||
'''
|
"""
|
||||||
ccReq = gcc.writeConferenceCreateRequest(self._clientSettings)
|
ccReq = gcc.writeConferenceCreateRequest(self._clientSettings)
|
||||||
ccReqStream = Stream()
|
ccReqStream = Stream()
|
||||||
ccReqStream.writeType(ccReq)
|
ccReqStream.writeType(ccReq)
|
||||||
@@ -155,28 +178,28 @@ class MCS(LayerAutomata):
|
|||||||
self.setNextState(self.recvConnectResponse)
|
self.setNextState(self.recvConnectResponse)
|
||||||
|
|
||||||
def sendErectDomainRequest(self):
|
def sendErectDomainRequest(self):
|
||||||
'''
|
"""
|
||||||
send a formated erect domain request for RDP connection
|
Send a formated erect domain request for RDP connection
|
||||||
'''
|
"""
|
||||||
self._transport.send((self.writeMCSPDUHeader(DomainMCSPDU.ERECT_DOMAIN_REQUEST), per.writeInteger(0), per.writeInteger(0)))
|
self._transport.send((self.writeMCSPDUHeader(DomainMCSPDU.ERECT_DOMAIN_REQUEST), per.writeInteger(0), per.writeInteger(0)))
|
||||||
|
|
||||||
def sendAttachUserRequest(self):
|
def sendAttachUserRequest(self):
|
||||||
'''
|
"""
|
||||||
send a formated attach user request for RDP connection
|
Send a formated attach user request for RDP connection
|
||||||
'''
|
"""
|
||||||
self._transport.send(self.writeMCSPDUHeader(DomainMCSPDU.ATTACH_USER_REQUEST))
|
self._transport.send(self.writeMCSPDUHeader(DomainMCSPDU.ATTACH_USER_REQUEST))
|
||||||
|
|
||||||
def sendChannelJoinRequest(self, channelId):
|
def sendChannelJoinRequest(self, channelId):
|
||||||
'''
|
"""
|
||||||
send a formated Channel join request from client to server
|
Send a formated Channel join request from client to server
|
||||||
'''
|
"""
|
||||||
self._transport.send((self.writeMCSPDUHeader(DomainMCSPDU.CHANNEL_JOIN_REQUEST), self._userId, channelId))
|
self._transport.send((self.writeMCSPDUHeader(DomainMCSPDU.CHANNEL_JOIN_REQUEST), self._userId, channelId))
|
||||||
|
|
||||||
def recvConnectResponse(self, data):
|
def recvConnectResponse(self, data):
|
||||||
'''
|
"""
|
||||||
receive mcs connect response from server
|
receive MCS connect response from server
|
||||||
@param data: Stream
|
@param data: Stream
|
||||||
'''
|
"""
|
||||||
ber.readApplicationTag(data, Message.MCS_TYPE_CONNECT_RESPONSE)
|
ber.readApplicationTag(data, Message.MCS_TYPE_CONNECT_RESPONSE)
|
||||||
ber.readEnumerated(data)
|
ber.readEnumerated(data)
|
||||||
ber.readInteger(data)
|
ber.readInteger(data)
|
||||||
@@ -196,10 +219,10 @@ class MCS(LayerAutomata):
|
|||||||
self.setNextState(self.recvAttachUserConfirm)
|
self.setNextState(self.recvAttachUserConfirm)
|
||||||
|
|
||||||
def recvAttachUserConfirm(self, data):
|
def recvAttachUserConfirm(self, data):
|
||||||
'''
|
"""
|
||||||
receive an attach user confirm
|
Receive an attach user confirm
|
||||||
@param data: Stream
|
@param data: Stream
|
||||||
'''
|
"""
|
||||||
opcode = UInt8()
|
opcode = UInt8()
|
||||||
confirm = UInt8()
|
confirm = UInt8()
|
||||||
data.readType((opcode, confirm))
|
data.readType((opcode, confirm))
|
||||||
@@ -217,10 +240,10 @@ class MCS(LayerAutomata):
|
|||||||
self.connectNextChannel()
|
self.connectNextChannel()
|
||||||
|
|
||||||
def recvChannelJoinConfirm(self, data):
|
def recvChannelJoinConfirm(self, data):
|
||||||
'''
|
"""
|
||||||
receive a channel join confirm from server
|
Receive a channel join confirm from server
|
||||||
@param data: Stream
|
@param data: Stream
|
||||||
'''
|
"""
|
||||||
opcode = UInt8()
|
opcode = UInt8()
|
||||||
confirm = UInt8()
|
confirm = UInt8()
|
||||||
data.readType((opcode, confirm))
|
data.readType((opcode, confirm))
|
||||||
@@ -239,10 +262,10 @@ class MCS(LayerAutomata):
|
|||||||
self.connectNextChannel()
|
self.connectNextChannel()
|
||||||
|
|
||||||
def recvData(self, data):
|
def recvData(self, data):
|
||||||
'''
|
"""
|
||||||
main receive method
|
Main receive method
|
||||||
@param data: Stream
|
@param data: Stream
|
||||||
'''
|
"""
|
||||||
opcode = UInt8()
|
opcode = UInt8()
|
||||||
data.readType(opcode)
|
data.readType(opcode)
|
||||||
|
|
||||||
@@ -278,51 +301,52 @@ class MCS(LayerAutomata):
|
|||||||
self._channelIds[channelId].recv(data)
|
self._channelIds[channelId].recv(data)
|
||||||
|
|
||||||
def send(self, channelId, data):
|
def send(self, channelId, data):
|
||||||
'''
|
"""
|
||||||
specific send function for channelId
|
Specific send function for channelId
|
||||||
|
@param channelId: Channel use to send
|
||||||
@param data: message to send
|
@param data: message to send
|
||||||
'''
|
"""
|
||||||
self._transport.send((self.writeMCSPDUHeader(DomainMCSPDU.SEND_DATA_REQUEST), self._userId, channelId, UInt8(0x70), UInt16Be(sizeof(data)) | UInt16Be(0x8000), data))
|
self._transport.send((self.writeMCSPDUHeader(DomainMCSPDU.SEND_DATA_REQUEST), self._userId, channelId, UInt8(0x70), UInt16Be(sizeof(data)) | UInt16Be(0x8000), data))
|
||||||
|
|
||||||
|
|
||||||
def writeDomainParams(self, maxChannels, maxUsers, maxTokens, maxPduSize):
|
def writeDomainParams(self, maxChannels, maxUsers, maxTokens, maxPduSize):
|
||||||
'''
|
"""
|
||||||
write a special domain param structure
|
Write a special domain parameter structure
|
||||||
use in connection sequence
|
use in connection sequence
|
||||||
@param maxChannels: number of mcs channel use
|
@param maxChannels: number of MCS channel use
|
||||||
@param maxUsers: number of mcs user used (1)
|
@param maxUsers: number of MCS user used (1)
|
||||||
@param maxTokens: unknown
|
@param maxTokens: unknown
|
||||||
@param maxPduSize: unknown
|
@param maxPduSize: unknown
|
||||||
@return: domain param structure
|
@return: domain parameter structure
|
||||||
'''
|
"""
|
||||||
domainParam = (ber.writeInteger(maxChannels), ber.writeInteger(maxUsers), ber.writeInteger(maxTokens),
|
domainParam = (ber.writeInteger(maxChannels), ber.writeInteger(maxUsers), ber.writeInteger(maxTokens),
|
||||||
ber.writeInteger(1), ber.writeInteger(0), ber.writeInteger(1),
|
ber.writeInteger(1), ber.writeInteger(0), ber.writeInteger(1),
|
||||||
ber.writeInteger(maxPduSize), ber.writeInteger(2))
|
ber.writeInteger(maxPduSize), ber.writeInteger(2))
|
||||||
return (ber.writeUniversalTag(ber.Tag.BER_TAG_SEQUENCE, True), writeLength(sizeof(domainParam)), domainParam)
|
return (ber.writeUniversalTag(ber.Tag.BER_TAG_SEQUENCE, True), writeLength(sizeof(domainParam)), domainParam)
|
||||||
|
|
||||||
def writeMCSPDUHeader(self, mcsPdu, options = 0):
|
def writeMCSPDUHeader(self, mcsPdu, options = 0):
|
||||||
'''
|
"""
|
||||||
write mcs pdu header
|
Write MCS PDU header
|
||||||
@param mcsPdu: pdu code
|
@param mcsPdu: PDU code
|
||||||
@param options: option contains in header
|
@param options: option contains in header
|
||||||
@return: UInt8
|
@return: UInt8
|
||||||
'''
|
"""
|
||||||
return (mcsPdu << 2) | options
|
return (mcsPdu << 2) | options
|
||||||
|
|
||||||
def readMCSPDUHeader(self, opcode, mcsPdu):
|
def readMCSPDUHeader(self, opcode, mcsPdu):
|
||||||
'''
|
"""
|
||||||
read mcsPdu header and return options parameter
|
Read mcsPdu header and return options parameter
|
||||||
@param opcode: UInt8 opcode
|
@param opcode: UInt8 opcode
|
||||||
@param mcsPdu: mcsPdu will be checked
|
@param mcsPdu: mcsPdu will be checked
|
||||||
@return: true if opcode is correct
|
@return: true if opcode is correct
|
||||||
'''
|
"""
|
||||||
return (opcode >> 2) == mcsPdu
|
return (opcode >> 2) == mcsPdu
|
||||||
|
|
||||||
def readDomainParams(self, s):
|
def readDomainParams(self, s):
|
||||||
'''
|
"""
|
||||||
read domain params structure
|
Read domain parameters structure
|
||||||
@return: (max_channels, max_users, max_tokens, max_pdu_size)
|
@return: (max_channels, max_users, max_tokens, max_pdu_size)
|
||||||
'''
|
"""
|
||||||
if not ber.readUniversalTag(s, ber.Tag.BER_TAG_SEQUENCE, True):
|
if not ber.readUniversalTag(s, ber.Tag.BER_TAG_SEQUENCE, True):
|
||||||
raise InvalidValue("bad BER tags")
|
raise InvalidValue("bad BER tags")
|
||||||
ber.readLength(s)#length
|
ber.readLength(s)#length
|
||||||
|
|||||||
@@ -2,16 +2,12 @@
|
|||||||
@author: citronneur
|
@author: citronneur
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from rdpy.network.layer import LayerAutomata, LayerMode
|
from rdpy.network.layer import LayerAutomata
|
||||||
from rdpy.network.type import CompositeType, UniString, String, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType,\
|
from rdpy.network.type import CompositeType, UniString, String, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType
|
||||||
FactoryType
|
|
||||||
from rdpy.network.const import ConstAttributes, TypeAttributes
|
from rdpy.network.const import ConstAttributes, TypeAttributes
|
||||||
from rdpy.network.error import InvalidExpectedDataException, ErrorReportedFromPeer
|
from rdpy.network.error import InvalidExpectedDataException, ErrorReportedFromPeer
|
||||||
|
|
||||||
import gcc
|
import gcc, lic, caps
|
||||||
import lic
|
|
||||||
import caps
|
|
||||||
import rdp
|
|
||||||
|
|
||||||
@ConstAttributes
|
@ConstAttributes
|
||||||
@TypeAttributes(UInt16Le)
|
@TypeAttributes(UInt16Le)
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
@author: sylvain
|
@author: sylvain
|
||||||
'''
|
'''
|
||||||
from twisted.internet import protocol
|
from twisted.internet import protocol
|
||||||
import tpkt, tpdu, mcs, pdu
|
|
||||||
from rdpy.network.layer import LayerMode
|
from rdpy.network.layer import LayerMode
|
||||||
|
import tpkt, tpdu, mcs, pdu
|
||||||
|
|
||||||
class RDPController(object):
|
class RDPController(object):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -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...)
|
RDP basic security is not supported by RDPY (because is not a true security layer...)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from rdpy.network.layer import LayerAutomata, LayerMode
|
from rdpy.network.layer import LayerAutomata, LayerMode, StreamSender
|
||||||
from rdpy.network.type import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof
|
from rdpy.network.type import UInt8, UInt16Le, UInt16Be, UInt32Le, CompositeType, sizeof
|
||||||
from rdpy.network.error import InvalidExpectedDataException
|
from rdpy.network.error import InvalidExpectedDataException
|
||||||
from rdpy.network.const import ConstAttributes, TypeAttributes
|
from rdpy.network.const import ConstAttributes, TypeAttributes
|
||||||
@@ -116,7 +116,7 @@ class Negotiation(CompositeType):
|
|||||||
self.selectedProtocol = UInt32Le(conditional = lambda: self.code == NegociationType.TYPE_RDP_NEG_RSP)
|
self.selectedProtocol = UInt32Le(conditional = lambda: self.code == NegociationType.TYPE_RDP_NEG_RSP)
|
||||||
self.failureCode = UInt32Le(conditional = lambda: self.code == NegociationType.TYPE_RDP_NEG_FAILURE)
|
self.failureCode = UInt32Le(conditional = lambda: self.code == NegociationType.TYPE_RDP_NEG_FAILURE)
|
||||||
|
|
||||||
class TPDU(LayerAutomata):
|
class TPDU(LayerAutomata, StreamSender):
|
||||||
"""
|
"""
|
||||||
TPDU layer management
|
TPDU layer management
|
||||||
there is an connection automata
|
there is an connection automata
|
||||||
@@ -223,7 +223,7 @@ class TPDU(LayerAutomata):
|
|||||||
"""
|
"""
|
||||||
header = TPDUDataHeader()
|
header = TPDUDataHeader()
|
||||||
data.readType(header)
|
data.readType(header)
|
||||||
LayerAutomata.recv(self, data)
|
self._presentation.recv(data)
|
||||||
|
|
||||||
def sendConnectionRequest(self):
|
def sendConnectionRequest(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user