add string readlen arg to avoid recurcive loop
This commit is contained in:
@@ -5,12 +5,15 @@
|
|||||||
import struct
|
import struct
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
from error import InvalidValue, InvalidSize
|
from error import InvalidValue
|
||||||
from rdpy.protocol.network.error import InvalidExpectedDataException
|
from rdpy.protocol.network.error import InvalidExpectedDataException
|
||||||
|
|
||||||
def sizeof(element):
|
def sizeof(element):
|
||||||
'''
|
'''
|
||||||
byte size of type
|
byte size of type
|
||||||
|
sum sizeof of tuple element
|
||||||
|
and count only element that condition
|
||||||
|
is true at sizeof call
|
||||||
@param element: Type or Tuple(Type | Tuple,)
|
@param element: Type or Tuple(Type | Tuple,)
|
||||||
@return: size of element in byte
|
@return: size of element in byte
|
||||||
'''
|
'''
|
||||||
@@ -26,18 +29,31 @@ def sizeof(element):
|
|||||||
|
|
||||||
class Type(object):
|
class Type(object):
|
||||||
'''
|
'''
|
||||||
root type
|
root type object inheritance
|
||||||
|
record conditional optional of constant
|
||||||
|
mechanism
|
||||||
'''
|
'''
|
||||||
def __init__(self, conditional = lambda:True, optional = False, constant = False):
|
def __init__(self, conditional = lambda:True, optional = False, constant = False):
|
||||||
|
'''
|
||||||
|
constructor of any type object
|
||||||
|
@param conditional : function call before read or write type
|
||||||
|
@param optional: boolean check before read if there is still data in stream
|
||||||
|
@param constant: if true check any changement of object during reading
|
||||||
|
'''
|
||||||
self._conditional = conditional
|
self._conditional = conditional
|
||||||
self._optional = optional
|
self._optional = optional
|
||||||
self._constant = constant
|
self._constant = constant
|
||||||
self._is_writed = False
|
#use to record read state
|
||||||
|
#if type is optional and not present during read
|
||||||
|
#this boolean stay false
|
||||||
self._is_readed = False
|
self._is_readed = False
|
||||||
|
#use to know if type was written
|
||||||
|
self._is_writed = False
|
||||||
|
|
||||||
def write(self, s):
|
def write(self, s):
|
||||||
'''
|
'''
|
||||||
interface definition of write function
|
write type into stream if conditional is true
|
||||||
|
and call private
|
||||||
@param s: Stream which will be written
|
@param s: Stream which will be written
|
||||||
'''
|
'''
|
||||||
self._is_writed = self._conditional()
|
self._is_writed = self._conditional()
|
||||||
@@ -47,7 +63,8 @@ class Type(object):
|
|||||||
|
|
||||||
def read(self, s):
|
def read(self, s):
|
||||||
'''
|
'''
|
||||||
interface definition of read value
|
read type from stream s if conditional
|
||||||
|
is true and check constantness
|
||||||
@param s: Stream
|
@param s: Stream
|
||||||
'''
|
'''
|
||||||
self._is_readed = self._conditional()
|
self._is_readed = self._conditional()
|
||||||
@@ -58,6 +75,20 @@ class Type(object):
|
|||||||
#check constant value
|
#check constant value
|
||||||
if self._constant and old != self:
|
if self._constant and old != self:
|
||||||
raise InvalidExpectedDataException("const value expected")
|
raise InvalidExpectedDataException("const value expected")
|
||||||
|
|
||||||
|
def __read__(self, s):
|
||||||
|
'''
|
||||||
|
interface definition of private read funtion
|
||||||
|
@param s: Stream
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __write__(self, s):
|
||||||
|
'''
|
||||||
|
interface definition of private write funtion
|
||||||
|
@param s: Stream
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
def __sizeof__(self):
|
def __sizeof__(self):
|
||||||
'''
|
'''
|
||||||
@@ -68,27 +99,33 @@ class Type(object):
|
|||||||
|
|
||||||
class CallableValue(object):
|
class CallableValue(object):
|
||||||
'''
|
'''
|
||||||
type that wrap an inner type
|
wrap access of callable value.
|
||||||
acces with value getter and setter
|
When use getter value is call.
|
||||||
value can be a callable which is call
|
Constant value can also be wrap
|
||||||
at each access of value
|
and will be transformed into callable value(lambda function)
|
||||||
'''
|
'''
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
|
'''
|
||||||
|
construtor
|
||||||
|
@param value: value will be wrapped (constant | lambda | function)
|
||||||
|
'''
|
||||||
self._value = None
|
self._value = None
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
def __getValue__(self):
|
def __getValue__(self):
|
||||||
'''
|
'''
|
||||||
shortcut to access inner value
|
can be overwritten to add specific check before
|
||||||
call lambda value
|
self.value is call
|
||||||
@return: inner value(python type value)
|
@return: result of callbale value
|
||||||
'''
|
'''
|
||||||
return self._value()
|
return self._value()
|
||||||
|
|
||||||
def __setValue__(self, value):
|
def __setValue__(self, value):
|
||||||
'''
|
'''
|
||||||
setter of value wrap in lambda value
|
can be overwritten to add specific check before
|
||||||
@param value: new value encompass in valuetype object
|
self.value = value is call
|
||||||
|
check if value is callable and if not transform it
|
||||||
|
@param value: new value wrapped if constant -> lambda function
|
||||||
'''
|
'''
|
||||||
value_callable = lambda:value
|
value_callable = lambda:value
|
||||||
if callable(value):
|
if callable(value):
|
||||||
@@ -100,7 +137,8 @@ class CallableValue(object):
|
|||||||
def value(self):
|
def value(self):
|
||||||
'''
|
'''
|
||||||
shortcut to access inner value
|
shortcut to access inner value
|
||||||
@return: inner value(python type value)
|
main getter of value
|
||||||
|
@return: result of callable value
|
||||||
'''
|
'''
|
||||||
return self.__getValue__()
|
return self.__getValue__()
|
||||||
|
|
||||||
@@ -108,6 +146,7 @@ class CallableValue(object):
|
|||||||
def value(self, value):
|
def value(self, value):
|
||||||
'''
|
'''
|
||||||
setter of value after check it
|
setter of value after check it
|
||||||
|
main setter of value
|
||||||
@param value: new value encompass in valuetype object
|
@param value: new value encompass in valuetype object
|
||||||
'''
|
'''
|
||||||
self.__setValue__(value)
|
self.__setValue__(value)
|
||||||
@@ -122,7 +161,10 @@ class SimpleType(Type, CallableValue):
|
|||||||
@param structFormat: letter that represent type in struct package
|
@param structFormat: letter that represent type in struct package
|
||||||
@param typeSize: size in byte of type
|
@param typeSize: size in byte of type
|
||||||
@param signed: true if type represent a signed type
|
@param signed: true if type represent a signed type
|
||||||
@param value: value recorded in this object
|
@param value: value recorded in this object (can be callable value which be call when is acces usefull with closure)
|
||||||
|
@param conditional : function call before read or write type
|
||||||
|
@param optional: boolean check before read if there is still data in stream
|
||||||
|
@param constant: if true check any changement of object during reading
|
||||||
'''
|
'''
|
||||||
self._signed = signed
|
self._signed = signed
|
||||||
self._typeSize = typeSize
|
self._typeSize = typeSize
|
||||||
@@ -132,8 +174,10 @@ class SimpleType(Type, CallableValue):
|
|||||||
|
|
||||||
def __getValue__(self):
|
def __getValue__(self):
|
||||||
'''
|
'''
|
||||||
shortcut to access inner value
|
CallableValue overwrite
|
||||||
@return: inner value(python type value)
|
check mask type of value
|
||||||
|
use CallableValue access
|
||||||
|
@return: python value wrap into type
|
||||||
@raise InvalidValue: if value doesn't respect type range
|
@raise InvalidValue: if value doesn't respect type range
|
||||||
'''
|
'''
|
||||||
value = CallableValue.__getValue__(self)
|
value = CallableValue.__getValue__(self)
|
||||||
@@ -147,8 +191,9 @@ class SimpleType(Type, CallableValue):
|
|||||||
|
|
||||||
def __setValue__(self, value):
|
def __setValue__(self, value):
|
||||||
'''
|
'''
|
||||||
setter of value after check it
|
CallableValue overwrite
|
||||||
@param value: new value encompass in simpletype object
|
check mask type of value
|
||||||
|
@param value: new value encompass in object (respect python type | lambda | function)
|
||||||
@raise InvalidValue: if value doesn't respect type range
|
@raise InvalidValue: if value doesn't respect type range
|
||||||
'''
|
'''
|
||||||
#check static value range
|
#check static value range
|
||||||
@@ -304,6 +349,9 @@ class CompositeType(Type):
|
|||||||
'''
|
'''
|
||||||
keep ordering declaration of simple type
|
keep ordering declaration of simple type
|
||||||
in list and transparent for other type
|
in list and transparent for other type
|
||||||
|
@param conditional : function call before read or write type
|
||||||
|
@param optional: boolean check before read if there is still data in stream
|
||||||
|
@param constant: if true check any changement of object during reading
|
||||||
'''
|
'''
|
||||||
def __init__(self, conditional = lambda:True, optional = False, constant = False):
|
def __init__(self, conditional = lambda:True, optional = False, constant = False):
|
||||||
'''
|
'''
|
||||||
@@ -376,6 +424,13 @@ class UInt8(SimpleType):
|
|||||||
unsigned byte
|
unsigned byte
|
||||||
'''
|
'''
|
||||||
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
|
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
|
||||||
|
'''
|
||||||
|
constructor
|
||||||
|
@param value: python value wrap
|
||||||
|
@param conditional : function call before read or write type
|
||||||
|
@param optional: boolean check before read if there is still data in stream
|
||||||
|
@param constant: if true check any changement of object during reading
|
||||||
|
'''
|
||||||
SimpleType.__init__(self, "B", 1, False, value, conditional = conditional, optional = optional, constant = constant)
|
SimpleType.__init__(self, "B", 1, False, value, conditional = conditional, optional = optional, constant = constant)
|
||||||
|
|
||||||
class SInt8(SimpleType):
|
class SInt8(SimpleType):
|
||||||
@@ -383,6 +438,12 @@ class SInt8(SimpleType):
|
|||||||
signed byte
|
signed byte
|
||||||
'''
|
'''
|
||||||
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
|
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
|
||||||
|
'''
|
||||||
|
constructor
|
||||||
|
@param conditional : function call before read or write type
|
||||||
|
@param optional: boolean check before read if there is still data in stream
|
||||||
|
@param constant: if true check any changement of object during reading
|
||||||
|
'''
|
||||||
SimpleType.__init__(self, "b", 1, True, value, conditional = conditional, optional = optional, constant = constant)
|
SimpleType.__init__(self, "b", 1, True, value, conditional = conditional, optional = optional, constant = constant)
|
||||||
|
|
||||||
|
|
||||||
@@ -393,6 +454,12 @@ class UInt16Be(SimpleType):
|
|||||||
Big endian is just for read or write in stream
|
Big endian is just for read or write in stream
|
||||||
'''
|
'''
|
||||||
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
|
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
|
||||||
|
'''
|
||||||
|
constructor
|
||||||
|
@param conditional : function call before read or write type
|
||||||
|
@param optional: boolean check before read if there is still data in stream
|
||||||
|
@param constant: if true check any changement of object during reading
|
||||||
|
'''
|
||||||
SimpleType.__init__(self, ">H", 2, False, value, conditional = conditional, optional = optional, constant = constant)
|
SimpleType.__init__(self, ">H", 2, False, value, conditional = conditional, optional = optional, constant = constant)
|
||||||
|
|
||||||
class UInt16Le(SimpleType):
|
class UInt16Le(SimpleType):
|
||||||
@@ -402,6 +469,12 @@ class UInt16Le(SimpleType):
|
|||||||
Big endian is just for read or write in stream
|
Big endian is just for read or write in stream
|
||||||
'''
|
'''
|
||||||
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
|
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
|
||||||
|
'''
|
||||||
|
constructor
|
||||||
|
@param conditional : function call before read or write type
|
||||||
|
@param optional: boolean check before read if there is still data in stream
|
||||||
|
@param constant: if true check any changement of object during reading
|
||||||
|
'''
|
||||||
SimpleType.__init__(self, "<H", 2, False, value, conditional = conditional, optional = optional, constant = constant)
|
SimpleType.__init__(self, "<H", 2, False, value, conditional = conditional, optional = optional, constant = constant)
|
||||||
|
|
||||||
class UInt32Be(SimpleType):
|
class UInt32Be(SimpleType):
|
||||||
@@ -411,6 +484,12 @@ class UInt32Be(SimpleType):
|
|||||||
Big endian is just for read or write in stream
|
Big endian is just for read or write in stream
|
||||||
'''
|
'''
|
||||||
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
|
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
|
||||||
|
'''
|
||||||
|
constructor
|
||||||
|
@param conditional : function call before read or write type
|
||||||
|
@param optional: boolean check before read if there is still data in stream
|
||||||
|
@param constant: if true check any changement of object during reading
|
||||||
|
'''
|
||||||
SimpleType.__init__(self, ">I", 4, False, value, conditional = conditional, optional = optional, constant = constant)
|
SimpleType.__init__(self, ">I", 4, False, value, conditional = conditional, optional = optional, constant = constant)
|
||||||
|
|
||||||
class UInt32Le(SimpleType):
|
class UInt32Le(SimpleType):
|
||||||
@@ -420,6 +499,12 @@ class UInt32Le(SimpleType):
|
|||||||
Big endian is just for read or write in stream
|
Big endian is just for read or write in stream
|
||||||
'''
|
'''
|
||||||
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
|
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
|
||||||
|
'''
|
||||||
|
constructor
|
||||||
|
@param conditional : function call before read or write type
|
||||||
|
@param optional: boolean check before read if there is still data in stream
|
||||||
|
@param constant: if true check any changement of object during reading
|
||||||
|
'''
|
||||||
SimpleType.__init__(self, "<I", 4, False, value, conditional = conditional, optional = optional, constant = constant)
|
SimpleType.__init__(self, "<I", 4, False, value, conditional = conditional, optional = optional, constant = constant)
|
||||||
|
|
||||||
class SInt32Le(SimpleType):
|
class SInt32Le(SimpleType):
|
||||||
@@ -429,6 +514,12 @@ class SInt32Le(SimpleType):
|
|||||||
Big endian is just for read or write in stream
|
Big endian is just for read or write in stream
|
||||||
'''
|
'''
|
||||||
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
|
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
|
||||||
|
'''
|
||||||
|
constructor
|
||||||
|
@param conditional : function call before read or write type
|
||||||
|
@param optional: boolean check before read if there is still data in stream
|
||||||
|
@param constant: if true check any changement of object during reading
|
||||||
|
'''
|
||||||
SimpleType.__init__(self, "<I", 4, True, value, conditional = conditional, optional = optional, constant = constant)
|
SimpleType.__init__(self, "<I", 4, True, value, conditional = conditional, optional = optional, constant = constant)
|
||||||
|
|
||||||
class SInt32Be(SimpleType):
|
class SInt32Be(SimpleType):
|
||||||
@@ -438,6 +529,12 @@ class SInt32Be(SimpleType):
|
|||||||
Big endian is just for read or write in stream
|
Big endian is just for read or write in stream
|
||||||
'''
|
'''
|
||||||
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
|
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
|
||||||
|
'''
|
||||||
|
constructor
|
||||||
|
@param conditional : function call before read or write type
|
||||||
|
@param optional: boolean check before read if there is still data in stream
|
||||||
|
@param constant: if true check any changement of object during reading
|
||||||
|
'''
|
||||||
SimpleType.__init__(self, ">I", 4, True, value, conditional = conditional, optional = optional, constant = constant)
|
SimpleType.__init__(self, ">I", 4, True, value, conditional = conditional, optional = optional, constant = constant)
|
||||||
|
|
||||||
class UInt24Be(SimpleType):
|
class UInt24Be(SimpleType):
|
||||||
@@ -447,6 +544,12 @@ class UInt24Be(SimpleType):
|
|||||||
Big endian is just for read or write in stream
|
Big endian is just for read or write in stream
|
||||||
'''
|
'''
|
||||||
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
|
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
|
||||||
|
'''
|
||||||
|
constructor
|
||||||
|
@param conditional : function call before read or write type
|
||||||
|
@param optional: boolean check before read if there is still data in stream
|
||||||
|
@param constant: if true check any changement of object during reading
|
||||||
|
'''
|
||||||
SimpleType.__init__(self, ">I", 3, False, value, conditional = conditional, optional = optional, constant = constant)
|
SimpleType.__init__(self, ">I", 3, False, value, conditional = conditional, optional = optional, constant = constant)
|
||||||
|
|
||||||
def __write__(self, s):
|
def __write__(self, s):
|
||||||
@@ -462,6 +565,12 @@ class UInt24Le(SimpleType):
|
|||||||
Big endian is just for read or write in stream
|
Big endian is just for read or write in stream
|
||||||
'''
|
'''
|
||||||
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
|
def __init__(self, value = 0, conditional = lambda:True, optional = False, constant = False):
|
||||||
|
'''
|
||||||
|
constructor
|
||||||
|
@param conditional : function call before read or write type
|
||||||
|
@param optional: boolean check before read if there is still data in stream
|
||||||
|
@param constant: if true check any changement of object during reading
|
||||||
|
'''
|
||||||
SimpleType.__init__(self, "<I", 3, False, value, conditional = conditional, optional = optional, constant = constant)
|
SimpleType.__init__(self, "<I", 3, False, value, conditional = conditional, optional = optional, constant = constant)
|
||||||
|
|
||||||
def __write__(self, s):
|
def __write__(self, s):
|
||||||
@@ -476,13 +585,19 @@ class String(Type, CallableValue):
|
|||||||
'''
|
'''
|
||||||
String network type
|
String network type
|
||||||
'''
|
'''
|
||||||
def __init__(self, value = "", conditional = lambda:True, optional = False, constant = False):
|
def __init__(self, value = "", readLen = UInt32Le(), conditional = lambda:True, optional = False, constant = False):
|
||||||
'''
|
'''
|
||||||
constructor with new string
|
constructor with new string
|
||||||
@param value: python string use for inner value
|
@param value: python string use for inner value
|
||||||
|
@param readLen: length use to read in stream (SimpleType) if 0 read entire stream
|
||||||
|
@param conditional : function call before read or write type
|
||||||
|
@param optional: boolean check before read if there is still data in stream
|
||||||
|
@param constant: if true check any changement of object during reading
|
||||||
'''
|
'''
|
||||||
Type.__init__(self, conditional = conditional, optional = optional, constant = constant)
|
Type.__init__(self, conditional = conditional, optional = optional, constant = constant)
|
||||||
CallableValue.__init__(self, value)
|
CallableValue.__init__(self, value)
|
||||||
|
#type use to know read length
|
||||||
|
self._readLen = readLen
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
'''
|
'''
|
||||||
@@ -519,10 +634,10 @@ class String(Type, CallableValue):
|
|||||||
else read the len of inner string
|
else read the len of inner string
|
||||||
@param s: Stream
|
@param s: Stream
|
||||||
'''
|
'''
|
||||||
if len(self.value) == 0:
|
if self._readLen.value == 0:
|
||||||
self.value = s.getvalue()
|
self.value = s.getvalue()
|
||||||
else:
|
else:
|
||||||
self.value = s.read(len(self.value))
|
self.value = s.read(self._readLen.value)
|
||||||
|
|
||||||
def __sizeof__(self):
|
def __sizeof__(self):
|
||||||
'''
|
'''
|
||||||
@@ -579,13 +694,16 @@ class Stream(StringIO):
|
|||||||
or iterate over tuple elements
|
or iterate over tuple elements
|
||||||
@param value: (tuple | Type) object
|
@param value: (tuple | Type) object
|
||||||
'''
|
'''
|
||||||
if sizeof(value) > self.dataLen() and not value._optional:
|
|
||||||
raise InvalidSize("stream is too short to read non optional value")
|
|
||||||
#read each tuple
|
#read each tuple
|
||||||
if isinstance(value, tuple):
|
if isinstance(value, tuple):
|
||||||
for element in value:
|
for element in value:
|
||||||
self.readType(element)
|
self.readType(element)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
#optional value not present
|
||||||
|
if self.dataLen() == 0 and value._optional:
|
||||||
|
return
|
||||||
|
|
||||||
value.read(self)
|
value.read(self)
|
||||||
|
|
||||||
def readNextType(self, t):
|
def readNextType(self, t):
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ class ServerToClientMessage(object):
|
|||||||
'''
|
'''
|
||||||
Server to Client block
|
Server to Client block
|
||||||
gcc conference messages
|
gcc conference messages
|
||||||
|
@see: http://msdn.microsoft.com/en-us/library/cc240509.aspx
|
||||||
'''
|
'''
|
||||||
SC_CORE = 0x0C01
|
SC_CORE = 0x0C01
|
||||||
SC_SECURITY = 0x0C02
|
SC_SECURITY = 0x0C02
|
||||||
@@ -29,6 +30,7 @@ class ClientToServerMessage(object):
|
|||||||
'''
|
'''
|
||||||
Client to Server block
|
Client to Server block
|
||||||
gcc conference messages
|
gcc conference messages
|
||||||
|
@see: http://msdn.microsoft.com/en-us/library/cc240509.aspx
|
||||||
'''
|
'''
|
||||||
CS_CORE = 0xC001
|
CS_CORE = 0xC001
|
||||||
CS_SECURITY = 0xC002
|
CS_SECURITY = 0xC002
|
||||||
@@ -41,6 +43,7 @@ class ClientToServerMessage(object):
|
|||||||
class ColorDepth(object):
|
class ColorDepth(object):
|
||||||
'''
|
'''
|
||||||
depth color
|
depth color
|
||||||
|
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
|
||||||
'''
|
'''
|
||||||
RNS_UD_COLOR_8BPP = 0xCA01
|
RNS_UD_COLOR_8BPP = 0xCA01
|
||||||
RNS_UD_COLOR_16BPP_555 = 0xCA02
|
RNS_UD_COLOR_16BPP_555 = 0xCA02
|
||||||
@@ -52,6 +55,7 @@ class ColorDepth(object):
|
|||||||
class HighColor(object):
|
class HighColor(object):
|
||||||
'''
|
'''
|
||||||
high color of client
|
high color of client
|
||||||
|
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
|
||||||
'''
|
'''
|
||||||
HIGH_COLOR_4BPP = 0x0004
|
HIGH_COLOR_4BPP = 0x0004
|
||||||
HIGH_COLOR_8BPP = 0x0008
|
HIGH_COLOR_8BPP = 0x0008
|
||||||
@@ -64,6 +68,7 @@ class HighColor(object):
|
|||||||
class Support(object):
|
class Support(object):
|
||||||
'''
|
'''
|
||||||
support depth flag
|
support depth flag
|
||||||
|
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
|
||||||
'''
|
'''
|
||||||
RNS_UD_24BPP_SUPPORT = 0x0001
|
RNS_UD_24BPP_SUPPORT = 0x0001
|
||||||
RNS_UD_16BPP_SUPPORT = 0x0002
|
RNS_UD_16BPP_SUPPORT = 0x0002
|
||||||
@@ -74,8 +79,8 @@ class Support(object):
|
|||||||
@TypeAttributes(UInt16Le)
|
@TypeAttributes(UInt16Le)
|
||||||
class CapabilityFlags(object):
|
class CapabilityFlags(object):
|
||||||
'''
|
'''
|
||||||
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
|
|
||||||
for more details on each flags click above
|
for more details on each flags click above
|
||||||
|
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
|
||||||
'''
|
'''
|
||||||
RNS_UD_CS_SUPPORT_ERRINFO_PDU = 0x0001
|
RNS_UD_CS_SUPPORT_ERRINFO_PDU = 0x0001
|
||||||
RNS_UD_CS_WANT_32BPP_SESSION = 0x0002
|
RNS_UD_CS_WANT_32BPP_SESSION = 0x0002
|
||||||
@@ -110,6 +115,7 @@ class ConnectionType(object):
|
|||||||
class Version(object):
|
class Version(object):
|
||||||
'''
|
'''
|
||||||
supported version of RDP
|
supported version of RDP
|
||||||
|
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
|
||||||
'''
|
'''
|
||||||
RDP_VERSION_4 = 0x00080001
|
RDP_VERSION_4 = 0x00080001
|
||||||
RDP_VERSION_5_PLUS = 0x00080004
|
RDP_VERSION_5_PLUS = 0x00080004
|
||||||
@@ -125,6 +131,7 @@ class Encryption(object):
|
|||||||
'''
|
'''
|
||||||
encryption method supported
|
encryption method supported
|
||||||
@deprecated: because rdpy use ssl but need to send to server...
|
@deprecated: because rdpy use ssl but need to send to server...
|
||||||
|
@see: http://msdn.microsoft.com/en-us/library/cc240511.aspx
|
||||||
'''
|
'''
|
||||||
ENCRYPTION_FLAG_40BIT = 0x00000001
|
ENCRYPTION_FLAG_40BIT = 0x00000001
|
||||||
ENCRYPTION_FLAG_128BIT = 0x00000002
|
ENCRYPTION_FLAG_128BIT = 0x00000002
|
||||||
@@ -153,6 +160,7 @@ class ChannelOptions(object):
|
|||||||
class ClientCoreSettings(CompositeType):
|
class ClientCoreSettings(CompositeType):
|
||||||
'''
|
'''
|
||||||
class that represent core setting of client
|
class that represent core setting of client
|
||||||
|
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
|
||||||
'''
|
'''
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
CompositeType.__init__(self)
|
CompositeType.__init__(self)
|
||||||
@@ -163,18 +171,18 @@ class ClientCoreSettings(CompositeType):
|
|||||||
self.sasSequence = Sequence.RNS_UD_SAS_DEL
|
self.sasSequence = Sequence.RNS_UD_SAS_DEL
|
||||||
self.kbdLayout = UInt32Le(0x409)
|
self.kbdLayout = UInt32Le(0x409)
|
||||||
self.clientBuild = UInt32Le(3790)
|
self.clientBuild = UInt32Le(3790)
|
||||||
self.clientName = UniString("rdpy" + "\x00"*11)
|
self.clientName = UniString("rdpy" + "\x00"*11, readLen = UInt8(30))
|
||||||
self.keyboardType = UInt32Le(4)
|
self.keyboardType = UInt32Le(4)
|
||||||
self.keyboardSubType = UInt32Le(0)
|
self.keyboardSubType = UInt32Le(0)
|
||||||
self.keyboardFnKeys = UInt32Le(12)
|
self.keyboardFnKeys = UInt32Le(12)
|
||||||
self.imeFileName = String("\x00"*64)
|
self.imeFileName = String("\x00"*64, readLen = UInt8(64))
|
||||||
self.postBeta2ColorDepth = ColorDepth.RNS_UD_COLOR_8BPP
|
self.postBeta2ColorDepth = ColorDepth.RNS_UD_COLOR_8BPP
|
||||||
self.clientProductId = UInt16Le(1)
|
self.clientProductId = UInt16Le(1)
|
||||||
self.serialNumber = UInt32Le(0)
|
self.serialNumber = UInt32Le(0)
|
||||||
self.highColorDepth = HighColor.HIGH_COLOR_24BPP
|
self.highColorDepth = HighColor.HIGH_COLOR_24BPP
|
||||||
self.supportedColorDepths = Support.RNS_UD_24BPP_SUPPORT | Support.RNS_UD_16BPP_SUPPORT | Support.RNS_UD_15BPP_SUPPORT
|
self.supportedColorDepths = Support.RNS_UD_24BPP_SUPPORT | Support.RNS_UD_16BPP_SUPPORT | Support.RNS_UD_15BPP_SUPPORT
|
||||||
self.earlyCapabilityFlags = CapabilityFlags.RNS_UD_CS_SUPPORT_ERRINFO_PDU
|
self.earlyCapabilityFlags = CapabilityFlags.RNS_UD_CS_SUPPORT_ERRINFO_PDU
|
||||||
self.clientDigProductId = String("\x00"*64)
|
self.clientDigProductId = String("\x00"*64, readLen = UInt8(64))
|
||||||
self.connectionType = UInt8()
|
self.connectionType = UInt8()
|
||||||
self.pad1octet = UInt8()
|
self.pad1octet = UInt8()
|
||||||
self.serverSelectedProtocol = UInt32Le()
|
self.serverSelectedProtocol = UInt32Le()
|
||||||
@@ -182,6 +190,7 @@ class ClientCoreSettings(CompositeType):
|
|||||||
class ServerCoreSettings(CompositeType):
|
class ServerCoreSettings(CompositeType):
|
||||||
'''
|
'''
|
||||||
server side core settings structure
|
server side core settings structure
|
||||||
|
@see: http://msdn.microsoft.com/en-us/library/cc240517.aspx
|
||||||
'''
|
'''
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
CompositeType.__init__(self)
|
CompositeType.__init__(self)
|
||||||
@@ -192,6 +201,7 @@ class ClientSecuritySettings(CompositeType):
|
|||||||
'''
|
'''
|
||||||
client security setting
|
client security setting
|
||||||
@deprecated: because we use ssl
|
@deprecated: because we use ssl
|
||||||
|
@see: http://msdn.microsoft.com/en-us/library/cc240511.aspx
|
||||||
'''
|
'''
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
CompositeType.__init__(self)
|
CompositeType.__init__(self)
|
||||||
@@ -204,6 +214,7 @@ class ServerSecuritySettings(CompositeType):
|
|||||||
may be ignore because rdpy don't use
|
may be ignore because rdpy don't use
|
||||||
RDP security level
|
RDP security level
|
||||||
@deprecated: because we use ssl
|
@deprecated: because we use ssl
|
||||||
|
@see: http://msdn.microsoft.com/en-us/library/cc240518.aspx
|
||||||
'''
|
'''
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
CompositeType.__init__(self)
|
CompositeType.__init__(self)
|
||||||
@@ -215,11 +226,13 @@ class ClientRequestedChannel(CompositeType):
|
|||||||
'''
|
'''
|
||||||
channels structure share between
|
channels structure share between
|
||||||
client and server
|
client and server
|
||||||
|
@see: http://msdn.microsoft.com/en-us/library/cc240512.aspx
|
||||||
|
@see: http://msdn.microsoft.com/en-us/library/cc240513.aspx
|
||||||
'''
|
'''
|
||||||
def __init__(self, name = "", options = UInt32Le()):
|
def __init__(self, name = "", options = UInt32Le()):
|
||||||
CompositeType.__init__(self)
|
CompositeType.__init__(self)
|
||||||
#name of channel
|
#name of channel
|
||||||
self.name = String(name[0:8] + "\x00" * (8 - len(name)))
|
self.name = String(name[0:8] + "\x00" * (8 - len(name)), readLen = UInt8(8))
|
||||||
#unknown
|
#unknown
|
||||||
self.options = options
|
self.options = options
|
||||||
|
|
||||||
@@ -355,6 +368,7 @@ def readServerSecurityData(s):
|
|||||||
read all channels accepted by server by server
|
read all channels accepted by server by server
|
||||||
@param s: Stream
|
@param s: Stream
|
||||||
@return: list of channel id selected by server
|
@return: list of channel id selected by server
|
||||||
|
@see: http://msdn.microsoft.com/en-us/library/cc240522.aspx
|
||||||
'''
|
'''
|
||||||
channelsId = []
|
channelsId = []
|
||||||
channelId = UInt16Le()
|
channelId = UInt16Le()
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from rdpy.utils.const import ConstAttributes, TypeAttributes
|
|||||||
from rdpy.protocol.network.error import InvalidExpectedDataException
|
from rdpy.protocol.network.error import InvalidExpectedDataException
|
||||||
|
|
||||||
import gcc
|
import gcc
|
||||||
|
import lic
|
||||||
|
|
||||||
@ConstAttributes
|
@ConstAttributes
|
||||||
@TypeAttributes(UInt16Le)
|
@TypeAttributes(UInt16Le)
|
||||||
@@ -70,7 +71,7 @@ class RDPInfo(CompositeType):
|
|||||||
client informations
|
client informations
|
||||||
contains credentials (very important packet)
|
contains credentials (very important packet)
|
||||||
'''
|
'''
|
||||||
def __init__(self, initForWrite, extendedInfoConditional):
|
def __init__(self, extendedInfoConditional):
|
||||||
CompositeType.__init__(self)
|
CompositeType.__init__(self)
|
||||||
#code page
|
#code page
|
||||||
self.codePage = UInt32Le()
|
self.codePage = UInt32Le()
|
||||||
@@ -86,37 +87,36 @@ class RDPInfo(CompositeType):
|
|||||||
self.cbAlternateShell = UInt16Le(lambda:sizeof(self.alternateShell) - 2)
|
self.cbAlternateShell = UInt16Le(lambda:sizeof(self.alternateShell) - 2)
|
||||||
#length of working directory unistring less 2 byte null terminate
|
#length of working directory unistring less 2 byte null terminate
|
||||||
self.cbWorkingDir = UInt16Le(lambda:sizeof(self.workingDir) - 2)
|
self.cbWorkingDir = UInt16Le(lambda:sizeof(self.workingDir) - 2)
|
||||||
#to avoid recurcive loop init differ from reading and writing
|
|
||||||
#microsoft domain
|
#microsoft domain
|
||||||
self.domain = UniString("" if initForWrite else lambda:"\x00" * self.cbDomain.value)
|
self.domain = UniString(readLen = self.cbDomain)
|
||||||
#session username
|
#session username
|
||||||
self.userName = UniString("" if initForWrite else lambda:"\x00" * self.cbUserName.value)
|
self.userName = UniString(readLen = self.cbUserName)
|
||||||
#associate password
|
#associate password
|
||||||
self.password = UniString("" if initForWrite else lambda:"\x00" * self.cbPassword.value)
|
self.password = UniString(readLen = self.cbPassword)
|
||||||
#shell execute at start of session
|
#shell execute at start of session
|
||||||
self.alternateShell = UniString("" if initForWrite else lambda:"\x00" * self.cbAlternateShell.value)
|
self.alternateShell = UniString(readLen = self.cbAlternateShell)
|
||||||
#working directory for session
|
#working directory for session
|
||||||
self.workingDir = UniString("" if initForWrite else lambda:"\x00" * self.cbWorkingDir.value)
|
self.workingDir = UniString(readLen = self.cbWorkingDir)
|
||||||
#more client informations
|
#more client informations
|
||||||
self.extendedInfo = RDPExtendedInfo(initForWrite, conditional = extendedInfoConditional)
|
self.extendedInfo = RDPExtendedInfo(conditional = extendedInfoConditional)
|
||||||
|
|
||||||
class RDPExtendedInfo(CompositeType):
|
class RDPExtendedInfo(CompositeType):
|
||||||
'''
|
'''
|
||||||
add more client informations
|
add more client informations
|
||||||
use for performance flag!!!
|
use for performance flag!!!
|
||||||
'''
|
'''
|
||||||
def __init__(self, initForWrite, conditional):
|
def __init__(self, conditional):
|
||||||
CompositeType.__init__(self, conditional = conditional)
|
CompositeType.__init__(self, conditional = conditional)
|
||||||
#is an ip v4 or v6 adresse
|
#is an ip v4 or v6 adresse
|
||||||
self.clientAddressFamily = AfInet.AF_INET
|
self.clientAddressFamily = AfInet.AF_INET
|
||||||
#len of adress field
|
#len of adress field
|
||||||
self.cbClientAddress = UInt16Le(lambda:sizeof(self.clientAddress))
|
self.cbClientAddress = UInt16Le(lambda:sizeof(self.clientAddress))
|
||||||
#adress of client
|
#adress of client
|
||||||
self.clientAddress = UniString("" if initForWrite else lambda:"\x00" * self.cbClientAddress.value)
|
self.clientAddress = UniString(readLen = self.cbClientAddress)
|
||||||
#len of client directory
|
#len of client directory
|
||||||
self.cbClientDir = UInt16Le(lambda:sizeof(self.clientDir))
|
self.cbClientDir = UInt16Le(lambda:sizeof(self.clientDir))
|
||||||
#self client directory
|
#self client directory
|
||||||
self.clientDir = UniString("" if initForWrite else lambda:"\x00" * self.cbClientDir.value)
|
self.clientDir = UniString(readLen = self.cbClientDir)
|
||||||
#TODO make tiomezone
|
#TODO make tiomezone
|
||||||
#self.performanceFlags = PerfFlag.PERF_DISABLE_WALLPAPER | PerfFlag.PERF_DISABLE_MENUANIMATIONS | PerfFlag.PERF_DISABLE_CURSOR_SHADOW
|
#self.performanceFlags = PerfFlag.PERF_DISABLE_WALLPAPER | PerfFlag.PERF_DISABLE_MENUANIMATIONS | PerfFlag.PERF_DISABLE_CURSOR_SHADOW
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ class GDL(LayerAutomata):
|
|||||||
#set by mcs layer channel init
|
#set by mcs layer channel init
|
||||||
self._channelId = UInt16Be()
|
self._channelId = UInt16Be()
|
||||||
#logon info send from client to server
|
#logon info send from client to server
|
||||||
self._info = RDPInfo(initForWrite = True, extendedInfoConditional = lambda:self._transport._serverSettings.core.rdpVersion == gcc.Version.RDP_VERSION_5_PLUS)
|
self._info = RDPInfo(extendedInfoConditional = lambda:self._transport._serverSettings.core.rdpVersion == gcc.Version.RDP_VERSION_5_PLUS)
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
'''
|
'''
|
||||||
@@ -147,7 +147,7 @@ class GDL(LayerAutomata):
|
|||||||
|
|
||||||
def sendInfoPkt(self):
|
def sendInfoPkt(self):
|
||||||
'''
|
'''
|
||||||
send a logon info packet for RDP version 5 protocol
|
send a logon info packet
|
||||||
'''
|
'''
|
||||||
#always send extended info because rdpy only accept rdp version 5 and more
|
#always send extended info because rdpy only accept rdp version 5 and more
|
||||||
self._transport.send(self._channelId, (SecurityFlag.SEC_INFO_PKT, UInt16Le(), self._info))
|
self._transport.send(self._channelId, (SecurityFlag.SEC_INFO_PKT, UInt16Le(), self._info))
|
||||||
@@ -158,4 +158,13 @@ class GDL(LayerAutomata):
|
|||||||
data.readType((securityFlag, securityFlagHi))
|
data.readType((securityFlag, securityFlagHi))
|
||||||
|
|
||||||
if securityFlag & SecurityFlag.SEC_LICENSE_PKT != SecurityFlag.SEC_LICENSE_PKT:
|
if securityFlag & SecurityFlag.SEC_LICENSE_PKT != SecurityFlag.SEC_LICENSE_PKT:
|
||||||
raise InvalidExpectedDataException("waiting license packet")
|
raise InvalidExpectedDataException("waiting license packet")
|
||||||
|
|
||||||
|
validClientPdu = lic.LicPacket()
|
||||||
|
data.readType(validClientPdu)
|
||||||
|
|
||||||
|
if not validClientPdu.errorMessage._is_readed:
|
||||||
|
raise InvalidExpectedDataException("waiting valid client pdu : rdpy doesn't support licensing neg")
|
||||||
|
|
||||||
|
if not (validClientPdu.errorMessage.dwErrorCode == lic.ErrorCode.STATUS_VALID_CLIENT and validClientPdu.errorMessage.dwStateTransition == lic.StateTransition.ST_NO_TRANSITION):
|
||||||
|
raise InvalidExpectedDataException("server refuse licensing negotiation")
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
'''
|
'''
|
||||||
@author: sylvain
|
@author: sylvain
|
||||||
'''
|
'''
|
||||||
from rdpy.protocol.network.type import CompositeType, UInt8, UInt16Le, sizeof
|
from rdpy.protocol.network.type import CompositeType, UInt8, UInt16Le, UInt32Le, String, sizeof
|
||||||
from rdpy.utils.const import ConstAttributes, TypeAttributes
|
from rdpy.utils.const import ConstAttributes, TypeAttributes
|
||||||
|
|
||||||
@ConstAttributes
|
@ConstAttributes
|
||||||
@TypeAttributes(UInt8)
|
@TypeAttributes(UInt8)
|
||||||
class MessageType(object):
|
class MessageType(object):
|
||||||
|
'''
|
||||||
|
License packet message type
|
||||||
|
'''
|
||||||
LICENSE_REQUEST = 0x01
|
LICENSE_REQUEST = 0x01
|
||||||
PLATFORM_CHALLENGE = 0x02
|
PLATFORM_CHALLENGE = 0x02
|
||||||
NEW_LICENSE = 0x03
|
NEW_LICENSE = 0x03
|
||||||
@@ -15,11 +18,54 @@ class MessageType(object):
|
|||||||
NEW_LICENSE_REQUEST = 0x13
|
NEW_LICENSE_REQUEST = 0x13
|
||||||
PLATFORM_CHALLENGE_RESPONSE = 0x15
|
PLATFORM_CHALLENGE_RESPONSE = 0x15
|
||||||
ERROR_ALERT = 0xFF
|
ERROR_ALERT = 0xFF
|
||||||
|
|
||||||
|
@ConstAttributes
|
||||||
|
@TypeAttributes(UInt32Le)
|
||||||
|
class ErrorCode(object):
|
||||||
|
'''
|
||||||
|
license error message code
|
||||||
|
'''
|
||||||
|
ERR_INVALID_SERVER_CERTIFICATE = 0x00000001
|
||||||
|
ERR_NO_LICENSE = 0x00000002
|
||||||
|
ERR_INVALID_SCOPE = 0x00000004
|
||||||
|
ERR_NO_LICENSE_SERVER = 0x00000006
|
||||||
|
STATUS_VALID_CLIENT = 0x00000007
|
||||||
|
ERR_INVALID_CLIENT = 0x00000008
|
||||||
|
ERR_INVALID_PRODUCTID = 0x0000000B
|
||||||
|
ERR_INVALID_MESSAGE_LEN = 0x0000000C
|
||||||
|
ERR_INVALID_MAC = 0x00000003
|
||||||
|
|
||||||
|
@ConstAttributes
|
||||||
|
@TypeAttributes(UInt32Le)
|
||||||
|
class StateTransition(object):
|
||||||
|
'''
|
||||||
|
automata state transition
|
||||||
|
'''
|
||||||
|
ST_TOTAL_ABORT = 0x00000001
|
||||||
|
ST_NO_TRANSITION = 0x00000002
|
||||||
|
ST_RESET_PHASE_TO_START = 0x00000003
|
||||||
|
ST_RESEND_LAST_MESSAGE = 0x00000004
|
||||||
|
|
||||||
|
class LicenceBinaryBlob(CompositeType):
|
||||||
|
def __init__(self):
|
||||||
|
CompositeType.__init__(self)
|
||||||
|
self.wBlobType = UInt16Le()
|
||||||
|
self.wBlobLen = UInt16Le(lambda:sizeof(self.blobData))
|
||||||
|
self.blobData = String(readLen = self.wBlobLen, conditional = lambda:self.wBlobLen.value > 0)
|
||||||
|
|
||||||
|
class LicensingErrorMessage(CompositeType):
|
||||||
|
def __init__(self, conditional = lambda:True):
|
||||||
|
CompositeType.__init__(self, conditional = conditional)
|
||||||
|
self.dwErrorCode = UInt32Le()
|
||||||
|
self.dwStateTransition = UInt32Le()
|
||||||
|
self.blob = LicenceBinaryBlob()
|
||||||
|
|
||||||
class LicPacket(CompositeType):
|
class LicPacket(CompositeType):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
CompositeType.__init__(self)
|
||||||
#preambule
|
#preambule
|
||||||
self.bMsgtype = UInt8()
|
self.bMsgtype = UInt8()
|
||||||
self.flag = UInt8()
|
self.flag = UInt8()
|
||||||
self.wMsgSize = UInt16Le(lambda: sizeof(self))
|
self.wMsgSize = UInt16Le(lambda: sizeof(self))
|
||||||
|
self.errorMessage = LicensingErrorMessage(conditional = lambda:self.bMsgtype == MessageType.ERROR_ALERT)
|
||||||
|
|
||||||
@@ -77,6 +77,9 @@ class TPDUDataHeader(CompositeType):
|
|||||||
class Negotiation(CompositeType):
|
class Negotiation(CompositeType):
|
||||||
'''
|
'''
|
||||||
negociation request message
|
negociation request message
|
||||||
|
@see: request -> http://msdn.microsoft.com/en-us/library/cc240500.aspx
|
||||||
|
@see: response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx
|
||||||
|
@see: failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx
|
||||||
'''
|
'''
|
||||||
def __init__(self, optional = False):
|
def __init__(self, optional = False):
|
||||||
CompositeType.__init__(self, optional = optional)
|
CompositeType.__init__(self, optional = optional)
|
||||||
@@ -118,6 +121,8 @@ class TPDU(LayerAutomata):
|
|||||||
next state is recvData
|
next state is recvData
|
||||||
call connect on presentation layer if all is good
|
call connect on presentation layer if all is good
|
||||||
@param data: Stream that contain connection confirm
|
@param data: Stream that contain connection confirm
|
||||||
|
@see: response -> http://msdn.microsoft.com/en-us/library/cc240506.aspx
|
||||||
|
@see: failure ->http://msdn.microsoft.com/en-us/library/cc240507.aspx
|
||||||
'''
|
'''
|
||||||
message = TPDUConnectMessage()
|
message = TPDUConnectMessage()
|
||||||
data.readType(message)
|
data.readType(message)
|
||||||
@@ -161,6 +166,7 @@ class TPDU(LayerAutomata):
|
|||||||
'''
|
'''
|
||||||
write connection request message
|
write connection request message
|
||||||
next state is recvConnectionConfirm
|
next state is recvConnectionConfirm
|
||||||
|
@see: http://msdn.microsoft.com/en-us/library/cc240500.aspx
|
||||||
'''
|
'''
|
||||||
message = TPDUConnectMessage()
|
message = TPDUConnectMessage()
|
||||||
message.code = MessageType.X224_TPDU_CONNECTION_REQUEST
|
message.code = MessageType.X224_TPDU_CONNECTION_REQUEST
|
||||||
|
|||||||
@@ -134,8 +134,6 @@ class Rfb(RawLayer):
|
|||||||
server imposed security level
|
server imposed security level
|
||||||
'''
|
'''
|
||||||
#TODO!!!
|
#TODO!!!
|
||||||
self._version = data.read_beuint32()
|
|
||||||
|
|
||||||
|
|
||||||
def recvSecurityList(self, data):
|
def recvSecurityList(self, data):
|
||||||
'''
|
'''
|
||||||
|
|||||||
Reference in New Issue
Block a user