add server side for mcs layer

This commit is contained in:
speyrefitte
2014-07-18 18:37:25 +02:00
parent c40d2cd600
commit 5d1a929d7c
10 changed files with 330 additions and 248 deletions

View File

@@ -11,7 +11,7 @@ from rdpy.protocol.rdp import rdp
class TestServerFactory(rdp.ServerFactory):
def __init__(self):
rdp.ServerFactory.__init__(self, "/home/sylvain/dev/certificate/rdpy.key", "/home/sylvain/dev/certificate/rdpy.crt")
rdp.ServerFactory.__init__(self, "/home/speyrefitte/dev/certificate/rdpy.key", "/home/speyrefitte/dev/certificate/rdpy.crt")
def startedConnecting(self, connector):
pass

View File

@@ -439,6 +439,9 @@ class CompositeType(Type):
break
s.pos -= sizeof(self.__dict__[tmpName])
raise e
if not self._readLen is None and readLen < self._readLen.value:
print "WARNING : still have correct data in packet %s, read it as padding"%self.__class__
s.read(self._readLen.value - readLen)
def __write__(self, s):
"""
@@ -453,10 +456,10 @@ class CompositeType(Type):
raise e
def __sizeof__(self):
'''
call sizeof on each subtype
"""
Call sizeof on each sub type
@return: sum of sizeof of each public type attributes
'''
"""
size = 0
for name in self._typeName:
size += sizeof(self.__dict__[name])
@@ -665,7 +668,7 @@ class String(Type, CallableValue):
'''
String network type
'''
def __init__(self, value = "", readLen = UInt32Le(), conditional = lambda:True, optional = False, constant = False):
def __init__(self, value = "", readLen = UInt32Le(), conditional = lambda:True, optional = False, constant = False, unicode = False):
'''
constructor with new string
@param value: python string use for inner value
@@ -673,11 +676,13 @@ class String(Type, CallableValue):
@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
@param unicode: Encode and decode value as unicode
'''
Type.__init__(self, conditional = conditional, optional = optional, constant = constant)
CallableValue.__init__(self, value)
#type use to know read length
self._readLen = readLen
self._unicode = unicode
def __eq__(self, other):
'''
@@ -702,52 +707,60 @@ class String(Type, CallableValue):
return self.value
def __write__(self, s):
'''
write the entire raw value
"""
Write the entire raw value
@param s: Stream
'''
s.write(self.value)
"""
if self._unicode:
s.write(encodeUnicode(self.value))
else:
s.write(self.value)
def __read__(self, s):
'''
read all stream if len of inner value is zero
else read the len of inner string
"""
read all stream if length of inner value is zero
else read the length of inner string
@param s: Stream
'''
"""
if self._readLen.value == 0:
self.value = s.getvalue()
else:
self.value = s.read(self._readLen.value)
def __sizeof__(self):
'''
return len of string
@return: len of inner string
'''
return len(self.value)
class UniString(String):
'''
string with unicode representation
'''
def write(self, s):
'''
separate each char with null char
and end with double null char
@param s: Stream
'''
for c in self.value:
s.writeType(UInt8(ord(c)))
s.writeType(UInt8(0))
s.writeType(UInt16Le(0))
if self._unicode:
self.value = decodeUnicode(self.value)
def __sizeof__(self):
'''
return len of uni string
@return: 2*len + 2
'''
return len(self.value) * 2 + 2
"""
return length of string
@return: length of inner string
"""
if self._unicode:
return 2 * len(self.value) + 2
else:
return len(self.value)
def encodeUnicode(s):
"""
Encode string in unicode
@param s: str python
@return: unicode string
"""
return "".join([c + "\x00" for c in s]) + "\x00\x00"
def decodeUnicode(s):
"""
Decode Unicode string
@param s: unicode string
@return: str python
"""
i = 0
r = ""
while i < len(s) - 2:
if i % 2 == 0:
r += s[i]
i += 1
return r
class Stream(StringIO):
'''
@@ -849,6 +862,8 @@ class ArrayType(Type):
element = self._typeFactory()
element._optional = self._readLen is None
s.readType(element)
if not element._is_readed:
break
self._array.append(element)
i += 1

View File

@@ -71,7 +71,7 @@ def readLength(s):
length = UInt8()
s.readType(length)
byte = length.value
if (byte & 0x80):
if byte & 0x80:
byte &= ~0x80
if byte == 1:
size = UInt8()
@@ -166,7 +166,7 @@ def writeBoolean(b):
"""
Return structure that represent boolean in BER specification
@param b: boolean
@return: BER boolean structure
@return: BER boolean block
"""
boolean = UInt8(0)
if b:
@@ -209,7 +209,7 @@ def writeInteger(value):
"""
Write integer value
@param param: INT or Python long
@return: BER integer structure
@return: BER integer block
"""
if value <= 0xff:
return (writeUniversalTag(Tag.BER_TAG_INTEGER, False), writeLength(1), UInt8(value))
@@ -233,7 +233,7 @@ def writeOctetstring(value):
"""
Write string in BER representation
@param value: string
@return: string BER structure
@return: BER octet string block
"""
return (writeUniversalTag(Tag.BER_TAG_OCTET_STRING, False), writeLength(len(value)), String(value))
@@ -250,3 +250,11 @@ def readEnumerated(s):
enumer = UInt8()
s.readType(enumer)
return enumer.value
def writeEnumerated(enumerated):
"""
Write enumerated structure
@param s: Stream
@return: BER enumerated block
"""
return (writeUniversalTag(Tag.BER_TAG_ENUMERATED, False), writeLength(1), UInt8(enumerated))

View File

@@ -16,6 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from rdpy.network.error import InvalidExpectedDataException
"""
Definition of structure use for capabilities nego
@@ -233,43 +234,17 @@ class Capability(CompositeType):
"""
Closure for capability factory
"""
if self.capabilitySetType.value == CapsType.CAPSTYPE_GENERAL:
return GeneralCapability(readLen = UInt16Le(lambda:self.lengthCapability.value - 4))
elif self.capabilitySetType.value == CapsType.CAPSTYPE_BITMAP:
return BitmapCapability(readLen = UInt16Le(lambda:self.lengthCapability.value - 4))
elif self.capabilitySetType.value == CapsType.CAPSTYPE_ORDER:
return OrderCapability(readLen = UInt16Le(lambda:self.lengthCapability.value - 4))
elif self.capabilitySetType.value == CapsType.CAPSTYPE_BITMAPCACHE:
return BitmapCacheCapability(readLen = UInt16Le(lambda:self.lengthCapability.value - 4))
elif self.capabilitySetType.value == CapsType.CAPSTYPE_POINTER:
return PointerCapability(readLen = UInt16Le(lambda:self.lengthCapability.value - 4))
elif self.capabilitySetType.value == CapsType.CAPSTYPE_INPUT:
return InputCapability(readLen = UInt16Le(lambda:self.lengthCapability.value - 4))
elif self.capabilitySetType.value == CapsType.CAPSTYPE_BRUSH:
return BrushCapability(readLen = UInt16Le(lambda:self.lengthCapability.value - 4))
elif self.capabilitySetType.value == CapsType.CAPSTYPE_GLYPHCACHE:
return GlyphCapability(readLen = UInt16Le(lambda:self.lengthCapability.value - 4))
elif self.capabilitySetType.value == CapsType.CAPSTYPE_OFFSCREENCACHE:
return OffscreenBitmapCacheCapability(readLen = UInt16Le(lambda:self.lengthCapability.value - 4))
elif self.capabilitySetType.value == CapsType.CAPSTYPE_VIRTUALCHANNEL:
return VirtualChannelCapability(readLen = UInt16Le(lambda:self.lengthCapability.value - 4))
elif self.capabilitySetType.value == CapsType.CAPSTYPE_SOUND:
return SoundCapability(readLen = UInt16Le(lambda:self.lengthCapability.value - 4))
elif self.capabilitySetType.value == CapsType.CAPSTYPE_CONTROL:
return ControlCapability(readLen = UInt16Le(lambda:self.lengthCapability.value - 4))
elif self.capabilitySetType.value == CapsType.CAPSTYPE_ACTIVATION:
return WindowActivationCapability(readLen = UInt16Le(lambda:self.lengthCapability.value - 4))
elif self.capabilitySetType.value == CapsType.CAPSTYPE_FONT:
return FontCapability(readLen = UInt16Le(lambda:self.lengthCapability.value - 4))
elif self.capabilitySetType.value == CapsType.CAPSTYPE_COLORCACHE:
return ColorCacheCapability(readLen = UInt16Le(lambda:self.lengthCapability.value - 4))
elif self.capabilitySetType.value == CapsType.CAPSTYPE_SHARE:
return ShareCapability(readLen = UInt16Le(lambda:self.lengthCapability.value - 4))
else:
return String(readLen = UInt16Le(lambda:self.lengthCapability.value - 4))
for c in [GeneralCapability, BitmapCapability, OrderCapability, BitmapCacheCapability, PointerCapability, InputCapability, BrushCapability, GlyphCapability, OffscreenBitmapCacheCapability, VirtualChannelCapability, SoundCapability, ControlCapability, WindowActivationCapability, FontCapability, ColorCacheCapability, ShareCapability]:
if self.capabilitySetType.value == c._TYPE_:
return c(readLen = self.lengthCapability - 4)
print "WARNING : unknown Capability type : %s"%hex(self.capabilitySetType.value)
#read entire packet
return String(readLen = self.lengthCapability - 4)
if capability is None:
capability = FactoryType(CapabilityFactory)
elif not "_TYPE_" in capability.__class__.__dict__:
raise InvalidExpectedDataException("Try to send an invalid capability block")
self.capability = capability
@@ -280,6 +255,8 @@ class GeneralCapability(CompositeType):
server -> client
@see: http://msdn.microsoft.com/en-us/library/cc240549.aspx
"""
_TYPE_ = CapsType.CAPSTYPE_GENERAL
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.osMajorType = UInt16Le()
@@ -301,6 +278,8 @@ class BitmapCapability(CompositeType):
server -> client
@see: http://msdn.microsoft.com/en-us/library/cc240554.aspx
"""
_TYPE_ = CapsType.CAPSTYPE_BITMAP
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.preferredBitsPerPixel = UInt16Le()
@@ -324,6 +303,8 @@ class OrderCapability(CompositeType):
server -> client
@see: http://msdn.microsoft.com/en-us/library/cc240556.aspx
"""
_TYPE_ = CapsType.CAPSTYPE_ORDER
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.terminalDescriptor = String("\x00" * 16, readLen = UInt8(16))
@@ -350,6 +331,8 @@ class BitmapCacheCapability(CompositeType):
client -> server
@see: http://msdn.microsoft.com/en-us/library/cc240559.aspx
"""
_TYPE_ = CapsType.CAPSTYPE_BITMAPCACHE
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.pad1 = UInt32Le()
@@ -373,6 +356,8 @@ class PointerCapability(CompositeType):
server -> client
@see: http://msdn.microsoft.com/en-us/library/cc240562.aspx
"""
_TYPE_ = CapsType.CAPSTYPE_POINTER
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.colorPointerFlag = UInt16Le()
@@ -386,6 +371,8 @@ class InputCapability(CompositeType):
server -> client
@see: http://msdn.microsoft.com/en-us/library/cc240563.aspx
"""
_TYPE_ = CapsType.CAPSTYPE_INPUT
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.inputFlags = UInt16Le()
@@ -407,6 +394,8 @@ class BrushCapability(CompositeType):
client -> server
@see: http://msdn.microsoft.com/en-us/library/cc240564.aspx
"""
_TYPE_ = CapsType.CAPSTYPE_BRUSH
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.brushSupportLevel = UInt32Le(BrushSupport.BRUSH_DEFAULT)
@@ -417,6 +406,8 @@ class GlyphCapability(CompositeType):
client -> server
@see: http://msdn.microsoft.com/en-us/library/cc240565.aspx
"""
_TYPE_ = CapsType.CAPSTYPE_GLYPHCACHE
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.glyphCache = ArrayType(CacheEntry, init = [CacheEntry() for _ in range(0,10)], readLen = UInt8(10))
@@ -431,6 +422,8 @@ class OffscreenBitmapCacheCapability(CompositeType):
client -> server
@see: http://msdn.microsoft.com/en-us/library/cc240550.aspx
"""
_TYPE_ = CapsType.CAPSTYPE_OFFSCREENCACHE
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.offscreenSupportLevel = UInt32Le(OffscreenSupportLevel.FALSE)
@@ -444,6 +437,8 @@ class VirtualChannelCapability(CompositeType):
server -> client
@see: http://msdn.microsoft.com/en-us/library/cc240551.aspx
"""
_TYPE_ = CapsType.CAPSTYPE_VIRTUALCHANNEL
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.flags = UInt32Le(VirtualChannelCompressionFlag.VCCAPS_NO_COMPR)
@@ -455,6 +450,8 @@ class SoundCapability(CompositeType):
client -> server
@see: http://msdn.microsoft.com/en-us/library/cc240552.aspx
"""
_TYPE_ = CapsType.CAPSTYPE_SOUND
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.soundFlags = UInt16Le(SoundFlag.NONE)
@@ -465,6 +462,8 @@ class ControlCapability(CompositeType):
client -> server but server ignore contents! Thanks krosoft for brandwidth
@see: http://msdn.microsoft.com/en-us/library/cc240568.aspx
"""
_TYPE_ = CapsType.CAPSTYPE_CONTROL
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.controlFlags = UInt16Le()
@@ -477,6 +476,8 @@ class WindowActivationCapability(CompositeType):
client -> server but server ignore contents! Thanks krosoft for brandwidth
@see: http://msdn.microsoft.com/en-us/library/cc240569.aspx
"""
_TYPE_ = CapsType.CAPSTYPE_ACTIVATION
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.helpKeyFlag = UInt16Le()
@@ -491,6 +492,8 @@ class FontCapability(CompositeType):
server -> client
@see: http://msdn.microsoft.com/en-us/library/cc240571.aspx
"""
_TYPE_ = CapsType.CAPSTYPE_FONT
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.fontSupportFlags = UInt16Le(0x0001)
@@ -502,6 +505,8 @@ class ColorCacheCapability(CompositeType):
server -> client
@see: http://msdn.microsoft.com/en-us/library/cc241564.aspx
"""
_TYPE_ = CapsType.CAPSTYPE_COLORCACHE
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.colorTableCacheSize = UInt16Le(0x0006)
@@ -514,6 +519,8 @@ class ShareCapability(CompositeType):
server -> client
@see: http://msdn.microsoft.com/en-us/library/cc240570.aspx
"""
_TYPE_ = CapsType.CAPSTYPE_SHARE
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.nodeId = UInt16Le()

View File

@@ -22,8 +22,7 @@ Implement GCC structure use in RDP protocol
http://msdn.microsoft.com/en-us/library/cc240508.aspx
"""
from rdpy.network.type import UInt8, UInt16Le, UInt32Le, CompositeType, String, UniString, Stream, sizeof, FactoryType,\
ArrayType
from rdpy.network.type import UInt8, UInt16Le, UInt32Le, CompositeType, String, Stream, sizeof, FactoryType, ArrayType
import per
from rdpy.network.error import InvalidExpectedDataException
@@ -204,10 +203,10 @@ class DataBlock(CompositeType):
"""
for c in [ClientCoreData, ClientSecurityData, ClientNetworkData, ServerCoreData, ServerNetworkData, ServerSecurityData]:
if self.type.value == c._TYPE_:
return c()
print "WARNING : unknown GCC block type : %s"%self.type.value
return c(readLen = self.length - 4)
print "WARNING : unknown GCC block type : %s"%hex(self.type.value)
#read entire packet
return String(readLen = self.length)
return String(readLen = self.length - 4)
if dataBlock is None:
dataBlock = FactoryType(DataBlockFactory)
@@ -223,8 +222,8 @@ class ClientCoreData(CompositeType):
"""
_TYPE_ = MessageType.CS_CORE
def __init__(self):
CompositeType.__init__(self)
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.rdpVersion = UInt32Le(Version.RDP_VERSION_5_PLUS)
self.desktopWidth = UInt16Le(1280)
self.desktopHeight = UInt16Le(800)
@@ -232,7 +231,7 @@ class ClientCoreData(CompositeType):
self.sasSequence = UInt16Le(Sequence.RNS_UD_SAS_DEL)
self.kbdLayout = UInt32Le(KeyboardLayout.FRENCH)
self.clientBuild = UInt32Le(3790)
self.clientName = UniString("rdpy" + "\x00"*11, readLen = UInt8(30))
self.clientName = String("rdpy" + "\x00"*11, readLen = UInt8(32), unicode = True)
self.keyboardType = UInt32Le(KeyboardType.IBM_101_102_KEYS)
self.keyboardSubType = UInt32Le(0)
self.keyboardFnKeys = UInt32Le(12)
@@ -255,8 +254,8 @@ class ServerCoreData(CompositeType):
"""
_TYPE_ = MessageType.SC_CORE
def __init__(self):
CompositeType.__init__(self)
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.rdpVersion = UInt32Le(Version.RDP_VERSION_5_PLUS)
self.clientRequestedProtocol = UInt32Le()
@@ -268,8 +267,8 @@ class ClientSecurityData(CompositeType):
"""
_TYPE_ = MessageType.CS_SECURITY
def __init__(self):
CompositeType.__init__(self)
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.encryptionMethods = UInt32Le()
self.extEncryptionMethods = UInt32Le()
@@ -283,8 +282,8 @@ class ServerSecurityData(CompositeType):
"""
_TYPE_ = MessageType.SC_SECURITY
def __init__(self):
CompositeType.__init__(self)
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.encryptionMethod = UInt32Le()
self.encryptionLevel = UInt32Le()
@@ -309,8 +308,8 @@ class ClientNetworkData(CompositeType):
"""
_TYPE_ = MessageType.CS_NET
def __init__(self):
CompositeType.__init__(self)
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.channelCount = UInt32Le()
self.channelDefArray = ArrayType(ChannelDef, readLen = self.channelCount)
@@ -322,19 +321,19 @@ class ServerNetworkData(CompositeType):
"""
_TYPE_ = MessageType.SC_NET
def __init__(self):
CompositeType.__init__(self)
def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.MCSChannelId = UInt16Le()
self.channelCount = UInt16Le(lambda:len(self.channelIdArray._array))
self.channelIdArray = ArrayType(UInt16Le, readLen = self.channelCount)
self.pad = UInt16Le(conditional = lambda:(self.channelCount.value % 2 == 1))
self.pad = UInt16Le(conditional = lambda:((self.channelCount.value % 2) == 1))
class Settings(CompositeType):
"""
Class which group all clients settings supported by RDPY
"""
def __init__(self, init = []):
CompositeType.__init__(self)
def __init__(self, init = [], readLen = None):
CompositeType.__init__(self, readLen = readLen)
self.settings = ArrayType(DataBlock, [DataBlock(i) for i in init])
def getBlock(self, messageType):
@@ -347,18 +346,6 @@ class Settings(CompositeType):
return i.dataBlock
return None
class ServerSettings(object):
"""
Server settings
"""
def __init__(self):
#core settings of server
self.core = ServerCoreData()
#unuse security informations
self.security = ServerSecurityData()
#channel id accepted by server
self.channelsId = []
def clientSettings():
"""
Build settings for client
@@ -371,13 +358,14 @@ def serverSettings():
Build settings for server
@return Settings
"""
return Settings([ServerCoreData(), ServerSecurityData(), ServerSecurityData()])
return Settings([ServerCoreData(), ServerSecurityData(), ServerNetworkData()])
def readConferenceCreateRequest(s):
"""
Read a response from client
GCC create request
@param s: Stream
@param client settings (Settings)
"""
per.readChoice(s)
per.readObjectIdentifier(s, t124_02_98_oid)
@@ -394,6 +382,10 @@ def readConferenceCreateRequest(s):
raise InvalidExpectedDataException("Invalid choice in readConferenceCreateRequest")
per.readOctetStream(s, h221_cs_key, 4)
length = per.readLength(s)
clientSettings = Settings(readLen = UInt32Le(length))
s.readType(clientSettings)
return clientSettings
def readConferenceCreateResponse(s):
"""
@@ -413,59 +405,11 @@ def readConferenceCreateResponse(s):
per.readChoice(s)
if not per.readOctetStream(s, h221_sc_key, 4):
raise InvalidExpectedDataException("cannot read h221_sc_key")
#serverSettings = Settings()
#s.readType(serverSettings)
#return serverSettings
return readServerDataBlocks(s)
def readServerDataBlocks(s):
"""
Read GCC server data blocks
And return result in Server Settings object
@param s: Stream
@return: ServerSettings
"""
settings = ServerSettings()
length = per.readLength(s)
while length > 0:
marker = s.readLen()
blockType = UInt16Le()
blockLength = UInt16Le()
s.readType((blockType, blockLength))
#read core block
if blockType.value == MessageType.SC_CORE:
s.readType(settings.core)
#read network block
elif blockType.value == MessageType.SC_NET:
settings.channelsId = readServerSecurityData(s)
#read security block
#unused in rdpy because use SSL layer
elif blockType.value == MessageType.SC_SECURITY:
s.readType(settings.security)
else:
print "Unknown server block %s"%hex(type)
length -= blockLength.value
s.seek(marker + blockLength.value)
return settings
def readServerSecurityData(s):
"""
Read server security and fill it in settings
Read all channels accepted by server by server
@param s: Stream
@return: list of channel id selected by server
@see: http://msdn.microsoft.com/en-us/library/cc240522.aspx
"""
channelsId = []
channelId = UInt16Le()
numberOfChannels = UInt16Le()
s.readType((channelId, numberOfChannels))
for _ in range(0, numberOfChannels.value):
channelId = UInt16Le()
s.readType(channelId)
channelsId.append(channelId)
return channelsId
serverSettings = Settings(readLen = UInt32Le(length))
s.readType(serverSettings)
return serverSettings
def writeConferenceCreateRequest(userData):
"""
@@ -482,20 +426,17 @@ def writeConferenceCreateRequest(userData):
per.writeNumberOfSet(1), per.writeChoice(0xc0),
per.writeOctetStream(h221_cs_key, 4), per.writeOctetStream(userDataStream.getvalue()))
def writeConferenceCreateResponse(settings):
def writeConferenceCreateResponse(serverData):
"""
Write a conference create response packet
@param settings: ServerSettingsDataBlock
@param serverData: Settings for server
@return: gcc packet
"""
pass
serverDataStream = Stream()
serverDataStream.writeType(serverData)
def writeClientDataBlocks(settings):
"""
Write all blocks for client
and return GCC valid structure
@param settings: ClientSettings
"""
return (DataBlock(settings.core),
DataBlock(settings.security),
DataBlock(settings.network))
return (per.writeChoice(0), per.writeObjectIdentifier(t124_02_98_oid),
per.writeLength(len(serverDataStream.getvalue()) + 14), per.writeChoice(0x14),
per.writeInteger16(0x79F3, 1001), per.writeInteger(1), per.writeEnumerates(16),
per.writeNumberOfSet(1), per.writeChoice(0xc0),
per.writeOctetStream(h221_sc_key, 4), per.writeOctetStream(serverDataStream.getvalue()))

View File

@@ -25,7 +25,7 @@ The main channel is the graphical channel.
It exist channel for file system order, audio channel, clipboard etc...
"""
from rdpy.network.layer import LayerAutomata, StreamSender, Layer, LayerMode
from rdpy.network.type import sizeof, Stream, UInt8, UInt16Be
from rdpy.network.type import sizeof, Stream, UInt8, UInt16Le
from rdpy.network.error import InvalidExpectedDataException, InvalidValue, InvalidSize
from rdpy.protocol.rdp.ber import writeLength
@@ -60,7 +60,7 @@ class Channel:
class MCS(LayerAutomata):
"""
Multi Channel Service layer
Multiple Channel Service layer
the main layer of RDP protocol
is why he can do everything and more!
"""
@@ -122,13 +122,13 @@ class MCS(LayerAutomata):
"""
LayerAutomata.__init__(self, mode, presentation)
self._clientSettings = gcc.clientSettings()
self._serverSettings = gcc.ServerSettings()
self._serverSettings = gcc.serverSettings()
#default user Id
self._userId = 1
self._userId = 1 + Channel.MCS_USERCHANNEL_BASE
#list of channel use in this layer and connection state
self._channelIds = {Channel.MCS_GLOBAL_CHANNEL: presentation}
#use to record already requested channel
self._channelIdsRequest = {}
self._channelIdsRequested = {}
def connect(self):
"""
@@ -143,27 +143,29 @@ class MCS(LayerAutomata):
def connectNextChannel(self):
"""
Send sendChannelJoinRequest message on next unconnect channel
Send sendChannelJoinRequest message on next disconnect channel
client automata function
"""
for (channelId, layer) in self._channelIds.iteritems():
#for each unconnect channel send a request
if not self._channelIdsRequest.has_key(channelId):
#for each disconnect channel send a request
if not self._channelIdsRequested.has_key(channelId):
self.sendChannelJoinRequest(channelId)
self.setNextState(self.recvChannelJoinConfirm)
return
#connection is done reinit class
#connection is done
self.setNextState(self.recvData)
#try connection on all requested channel
for (channelId, layer) in self._channelIds.iteritems():
if self._channelIdsRequest[channelId] and not layer is None:
#use proxy foreach channell
if self._channelIdsRequested[channelId] and not layer is None:
#use proxy for each channel
layer._transport = MCS.MCSProxySender(self, channelId)
layer.connect()
def sendConnectInitial(self):
"""
Send connect initial packet
client automata function
"""
ccReq = gcc.writeConferenceCreateRequest(self._clientSettings)
ccReqStream = Stream()
@@ -179,25 +181,66 @@ class MCS(LayerAutomata):
self.setNextState(self.recvConnectResponse)
def sendConnectResponse(self):
pass
"""
Send connect response
server automata function
"""
ccReq = gcc.writeConferenceCreateResponse(self._serverSettings)
ccReqStream = Stream()
ccReqStream.writeType(ccReq)
tmp = (ber.writeEnumerated(0), ber.writeInteger(0), self.writeDomainParams(22, 3, 0, 0xfff8),
ber.writeOctetstring(ccReqStream.getvalue()))
self._transport.send((ber.writeApplicationTag(Message.MCS_TYPE_CONNECT_RESPONSE, sizeof(tmp)), tmp))
self.setNextState(self.recvErectDomainRequest)
def sendErectDomainRequest(self):
"""
Send a formated erect domain request for RDP connection
client automata function
"""
self._transport.send((self.writeMCSPDUHeader(UInt8(DomainMCSPDU.ERECT_DOMAIN_REQUEST)), per.writeInteger(0), per.writeInteger(0)))
self._transport.send((self.writeMCSPDUHeader(UInt8(DomainMCSPDU.ERECT_DOMAIN_REQUEST)),
per.writeInteger(0),
per.writeInteger(0)))
def sendAttachUserRequest(self):
"""
Send a formated attach user request for RDP connection
client automata function
"""
self._transport.send(self.writeMCSPDUHeader(UInt8(DomainMCSPDU.ATTACH_USER_REQUEST)))
def sendAttachUserConfirm(self):
"""
Send attach user confirm
server automata function
"""
self._transport.send((self.writeMCSPDUHeader(UInt8(DomainMCSPDU.ATTACH_USER_CONFIRM)),
per.writeEnumerates(0),
per.writeInteger16(self._userId, Channel.MCS_USERCHANNEL_BASE)))
def sendChannelJoinRequest(self, channelId):
"""
Send a formated Channel join request from client to server
client automata function
@param channelId: id of channel requested
"""
self._transport.send((self.writeMCSPDUHeader(UInt8(DomainMCSPDU.CHANNEL_JOIN_REQUEST)), UInt16Be(self._userId), UInt16Be(channelId)))
self._transport.send((self.writeMCSPDUHeader(UInt8(DomainMCSPDU.CHANNEL_JOIN_REQUEST)),
per.writeInteger16(self._userId, Channel.MCS_USERCHANNEL_BASE),
per.writeInteger16(channelId)))
def sendChannelJoinConfirm(self, channelId, confirm):
"""
Send a confirm channel (or not) to client
@param channelId: id of channel
@param confirm: connection state
"""
self._transport.send((self.writeMCSPDUHeader(UInt8(DomainMCSPDU.CHANNEL_JOIN_CONFIRM)),
per.writeEnumerates(int(confirm)),
per.writeInteger16(self._userId, Channel.MCS_USERCHANNEL_BASE),
per.writeInteger16(channelId),
per.writeInteger16(channelId)))
def send(self, channelId, data):
"""
@@ -205,11 +248,16 @@ class MCS(LayerAutomata):
@param channelId: Channel use to send
@param data: message to send
"""
self._transport.send((self.writeMCSPDUHeader(UInt8(DomainMCSPDU.SEND_DATA_REQUEST)), UInt16Be(self._userId), UInt16Be(channelId), UInt8(0x70), UInt16Be(sizeof(data)) | UInt16Be(0x8000), data))
self._transport.send((self.writeMCSPDUHeader(UInt8(DomainMCSPDU.SEND_DATA_REQUEST)),
per.writeInteger16(self._userId, Channel.MCS_USERCHANNEL_BASE),
per.writeInteger16(channelId),
UInt8(0x70),
per.writeLength(sizeof(data)), data))
def recvConnectInitial(self, data):
"""
Receive MCS connect initial from client
server automata function
@param data: Stream
"""
ber.readApplicationTag(data, UInt8(Message.MCS_TYPE_CONNECT_INITIAL))
@@ -222,11 +270,16 @@ class MCS(LayerAutomata):
self.readDomainParams(data)
self.readDomainParams(data)
self.readDomainParams(data)
gcc.readConferenceCreateRequest(Stream(ber.readOctetString(data)))
self._clientSettings = gcc.readConferenceCreateRequest(Stream(ber.readOctetString(data)))
self._serverSettings.getBlock(gcc.MessageType.SC_NET).channelIdArray._array = [UInt16Le(x + Channel.MCS_GLOBAL_CHANNEL) for x in range(1, len(self._clientSettings.getBlock(gcc.MessageType.CS_NET).channelDefArray._array) + 1)]
self.sendConnectResponse()
def recvConnectResponse(self, data):
"""
Receive MCS connect response from server
client automata function
@param data: Stream
"""
ber.readApplicationTag(data, UInt8(Message.MCS_TYPE_CONNECT_RESPONSE))
@@ -237,7 +290,7 @@ class MCS(LayerAutomata):
raise InvalidExpectedDataException("invalid expected BER tag")
gccRequestLength = ber.readLength(data)
if data.dataLen() != gccRequestLength:
raise InvalidSize("bad size of gcc request")
raise InvalidSize("bad size of GCC request")
self._serverSettings = gcc.readConferenceCreateResponse(data)
#send domain request
@@ -247,49 +300,102 @@ class MCS(LayerAutomata):
#now wait user confirm from server
self.setNextState(self.recvAttachUserConfirm)
def recvAttachUserConfirm(self, data):
def recvErectDomainRequest(self, data):
"""
Receive an attach user confirm
Receive erect domain request
server automata function
@param data: Stream
"""
opcode = UInt8()
confirm = UInt8()
userId = UInt16Be()
data.readType((opcode, confirm))
data.readType(opcode)
if not self.readMCSPDUHeader(opcode.value, DomainMCSPDU.ERECT_DOMAIN_REQUEST):
raise InvalidExpectedDataException("Invalid MCS PDU : ERECT_DOMAIN_REQUEST expected")
per.readInteger(data)
per.readInteger(data)
self.setNextState(self.recvAttachUserRequest)
def recvAttachUserRequest(self, data):
"""
Receive Attach user request
server automata function
@param data: Stream
"""
opcode = UInt8()
data.readType(opcode)
if not self.readMCSPDUHeader(opcode.value, DomainMCSPDU.ATTACH_USER_REQUEST):
raise InvalidExpectedDataException("Invalid MCS PDU : ATTACH_USER_REQUEST expected")
self.sendAttachUserConfirm()
self.setNextState(self.recvChannelJoinRequest)
def recvAttachUserConfirm(self, data):
"""
Receive an attach user confirm
client automata function
@param data: Stream
"""
opcode = UInt8()
data.readType(opcode)
if not self.readMCSPDUHeader(opcode.value, DomainMCSPDU.ATTACH_USER_CONFIRM):
raise InvalidExpectedDataException("invalid MCS PDU")
if confirm != 0:
raise Exception("server reject user")
if opcode & UInt8(2) == UInt8(2):
data.readType(userId)
self._userId = userId.value
raise InvalidExpectedDataException("Invalid MCS PDU : ATTACH_USER_CONFIRM expected")
if per.readEnumerates(data) != 0:
raise InvalidExpectedDataException("Server reject user")
self._userId = per.readInteger16(data, Channel.MCS_USERCHANNEL_BASE)
#build channel list because we have user id
#add default channel + channels accepted by gcc connection sequence
self._channelIds[self._userId + Channel.MCS_USERCHANNEL_BASE] = None
#add default channel + channels accepted by GCC connection sequence
self._channelIds[self._userId] = None
self.connectNextChannel()
def recvChannelJoinRequest(self, data):
"""
Receive for each client channel a request
server automata function
@param data: Stream
"""
opcode = UInt8()
data.readType(opcode)
if not self.readMCSPDUHeader(opcode.value, DomainMCSPDU.CHANNEL_JOIN_REQUEST):
raise InvalidExpectedDataException("Invalid MCS PDU : CHANNEL_JOIN_REQUEST expected")
userId = per.readInteger16(data, Channel.MCS_USERCHANNEL_BASE)
if self._userId != userId:
raise InvalidExpectedDataException("Invalid MCS User Id")
channelId = per.readInteger16(data)
self.sendChannelJoinConfirm(channelId, channelId in self._channelIds.keys() or channelId == self._userId)
def recvChannelJoinConfirm(self, data):
"""
Receive a channel join confirm from server
client automata function
@param data: Stream
"""
opcode = UInt8()
confirm = UInt8()
data.readType((opcode, confirm))
data.readType(opcode)
if not self.readMCSPDUHeader(opcode.value, DomainMCSPDU.CHANNEL_JOIN_CONFIRM):
raise InvalidExpectedDataException("invalid MCS PDU")
userId = UInt16Be()
channelId = UInt16Be()
data.readType((userId, channelId))
raise InvalidExpectedDataException("Invalid MCS PDU : CHANNEL_JOIN_CONFIRM expected")
confirm = per.readEnumerates(data)
userId = per.readInteger16(data, Channel.MCS_USERCHANNEL_BASE)
if self._userId != userId:
raise InvalidExpectedDataException("Invalid MCS User Id")
channelId = per.readInteger16(data)
#save state of channel
self._channelIdsRequest[channelId] = confirm == 0
if confirm == 0:
print "server accept channel %d"%channelId.value
else:
print "server refused channel %d"%channelId.value
self._channelIdsRequested[channelId] = (confirm == 0)
self.connectNextChannel()
def recvData(self, data):
@@ -301,32 +407,29 @@ class MCS(LayerAutomata):
data.readType(opcode)
if self.readMCSPDUHeader(opcode.value, DomainMCSPDU.DISCONNECT_PROVIDER_ULTIMATUM):
print "receive DISCONNECT_PROVIDER_ULTIMATUM"
self.close()
print "INFO : MCS DISCONNECT_PROVIDER_ULTIMATUM"
self._transport.close()
return
elif not self.readMCSPDUHeader(opcode.value, DomainMCSPDU.SEND_DATA_INDICATION):
raise InvalidExpectedDataException("invalid expected mcs opcode")
raise InvalidExpectedDataException("Invalid expected MCS opcode")
userId = UInt16Be()
channelId = UInt16Be()
flags = UInt8()
length = UInt8()
#server user id
per.readInteger16(data, Channel.MCS_USERCHANNEL_BASE)
data.readType((userId, channelId, flags, length))
channelId = per.readInteger16(data)
if length & UInt8(0x80) == UInt8(0x80):
lengthP2 = UInt8()
data.readType(lengthP2)
length = UInt16Be(length.value & 0x7f << 8 | lengthP2.value)
per.readEnumerates(data)
per.readLength(data)
#channel id doesn't match a requested layer
if not self._channelIdsRequest.has_key(channelId):
print "receive data for an unrequested layer"
if not self._channelIdsRequested.has_key(channelId):
print "ERROR : receive data for an unrequested layer"
return
#channel id math an unconnected layer
if not self._channelIdsRequest[channelId]:
print "receive data for an unconnected layer"
if not self._channelIdsRequested[channelId]:
print "ERROR : receive data for an unconnected layer"
return
self._channelIds[channelId].recv(data)

View File

@@ -24,7 +24,7 @@ In this layer are managed all mains bitmap update orders end user inputs
"""
from rdpy.network.layer import LayerAutomata, LayerMode
from rdpy.network.type import CompositeType, UniString, String, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType
from rdpy.network.type import CompositeType, String, UInt8, UInt16Le, UInt32Le, sizeof, ArrayType, FactoryType
from rdpy.network.error import InvalidExpectedDataException, CallPureVirtualFuntion, InvalidType
import gcc, lic, caps, tpkt
@@ -491,13 +491,13 @@ class RDPInfo(CompositeType):
self.cbAlternateShell = UInt16Le(lambda:sizeof(self.alternateShell) - 2)
self.cbWorkingDir = UInt16Le(lambda:sizeof(self.workingDir) - 2)
#microsoft domain
self.domain = UniString(readLen = UInt16Le(lambda:self.cbDomain.value - 2))
self.userName = UniString(readLen = UInt16Le(lambda:self.cbUserName.value - 2))
self.password = UniString(readLen = UInt16Le(lambda:self.cbPassword.value - 2))
self.domain = String(readLen = UInt16Le(lambda:self.cbDomain.value - 2), unicode = True)
self.userName = String(readLen = UInt16Le(lambda:self.cbUserName.value - 2), unicode = True)
self.password = String(readLen = UInt16Le(lambda:self.cbPassword.value - 2), unicode = True)
#shell execute at start of session
self.alternateShell = UniString(readLen = UInt16Le(lambda:self.cbAlternateShell.value - 2))
self.alternateShell = String(readLen = UInt16Le(lambda:self.cbAlternateShell.value - 2), unicode = True)
#working directory for session
self.workingDir = UniString(readLen = UInt16Le(lambda:self.cbWorkingDir.value - 2))
self.workingDir = String(readLen = UInt16Le(lambda:self.cbWorkingDir.value - 2), unicode = True)
self.extendedInfo = RDPExtendedInfo(conditional = extendedInfoConditional)
class RDPExtendedInfo(CompositeType):
@@ -508,9 +508,9 @@ class RDPExtendedInfo(CompositeType):
CompositeType.__init__(self, conditional = conditional)
self.clientAddressFamily = UInt16Le(AfInet.AF_INET)
self.cbClientAddress = UInt16Le(lambda:sizeof(self.clientAddress))
self.clientAddress = UniString(readLen = self.cbClientAddress)
self.clientAddress = String(readLen = self.cbClientAddress, unicode = True)
self.cbClientDir = UInt16Le(lambda:sizeof(self.clientDir))
self.clientDir = UniString(readLen = self.cbClientDir)
self.clientDir = String(readLen = self.cbClientDir, unicode = True)
#TODO make tiomezone
self.clientTimeZone = String("\x00" * 172)
self.clientSessionId = UInt32Le()
@@ -530,7 +530,7 @@ class ShareControlHeader(CompositeType):
#share control header
self.totalLength = UInt16Le(totalLength)
self.pduType = UInt16Le(pduType)
self.PDUSource = UInt16Le(userId + 1001)
self.PDUSource = UInt16Le(userId)
class ShareDataHeader(CompositeType):
"""
@@ -562,7 +562,7 @@ class PDU(CompositeType):
for c in [DemandActivePDU, ConfirmActivePDU, DataPDU, DeactiveAllPDU]:
if self.shareControlHeader.pduType.value == c._PDUTYPE_:
return c()
print "WARNING : unknown PDU type : %s"%self.shareControlHeader.pduType.value
print "WARNING : unknown PDU type : %s"%hex(self.shareControlHeader.pduType.value)
#read entire packet
return String()
@@ -643,7 +643,7 @@ class DataPDU(CompositeType):
for c in [UpdateDataPDU, SynchronizeDataPDU, ControlDataPDU, ErrorInfoDataPDU, FontListDataPDU, FontMapDataPDU, PersistentListPDU, ClientInputEventPDU, ShutdownDeniedPDU, ShutdownRequestPDU]:
if self.shareDataHeader.pduType2.value == c._PDUTYPE2_:
return c()
print "WARNING : unknown PDU data type : %s"%self.shareDataHeader.pduType2.value
print "WARNING : unknown PDU data type : %s"%hex(self.shareDataHeader.pduType2.value)
return String()
if pduData is None:
@@ -936,7 +936,7 @@ class SlowPathInputEvent(CompositeType):
for c in [PointerEvent, ScancodeKeyEvent, UnicodeKeyEvent]:
if self.messageType.value == c._INPUT_MESSAGE_TYPE_:
return c()
print "WARNING : unknown slow path input : %s"%self.messageType.value
print "WARNING : unknown slow path input : %s"%hex(self.messageType.value)
return String()
if messageData is None:
@@ -1037,7 +1037,7 @@ class PDULayer(LayerAutomata, tpkt.FastPathListener):
LayerAutomata.__init__(self, mode, None)
#logon info send from client to server
self._info = RDPInfo(extendedInfoConditional = lambda:(self._transport.getGCCServerSettings().core.rdpVersion.value == gcc.Version.RDP_VERSION_5_PLUS))
self._info = RDPInfo(extendedInfoConditional = lambda:(self._transport.getGCCServerSettings().getBlock(gcc.MessageType.SC_CORE).rdpVersion.value == gcc.Version.RDP_VERSION_5_PLUS))
#server capabilities
self._serverCapabilities = {
caps.CapsType.CAPSTYPE_GENERAL : caps.Capability(caps.CapsType.CAPSTYPE_GENERAL, caps.GeneralCapability()),

View File

@@ -15,7 +15,7 @@ def readLength(s):
s.readType(byte)
size = 0
if byte.value & 0x80:
byte.value &= 0x80
byte.value &= ~0x80
size = byte.value << 8
s.readType(byte)
size += byte.value

View File

@@ -214,7 +214,7 @@ class RDPServerController(pdu.PDUServerListener):
@param privateKeyFileName: file contain server private key
@param certficiateFileName: file that contain public key
"""
self._pduLayer = pdu.PDU(self)
self._pduLayer = pdu.PDULayer(self)
#multi channel service
self._mcsLayer = mcs.MCS(LayerMode.SERVER, self._pduLayer)
#transport pdu layer

View File

@@ -294,4 +294,12 @@ class ServerTLSContext(ssl.DefaultOpenSSLContextFactory):
@param certificateFileName: Name of a file containing a certificate
"""
def __init__(self, privateKeyFileName, certificateFileName):
ssl.DefaultOpenSSLContextFactory.__init__(self, privateKeyFileName, certificateFileName, SSL.TLSv1_METHOD)
class TPDUSSLContext(SSL.Context):
def __init__(self, method):
SSL.Context.__init__(method)
self.set_options(0x00020000)#SSL_OP_NO_COMPRESSION
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.TLSv1_METHOD, TPDUSSLContext)