bug fix on server side, add log engine, change lib to core

This commit is contained in:
citronneur
2014-07-20 14:59:53 +02:00
parent f51ef15865
commit 67845e50ad
31 changed files with 187 additions and 171 deletions

2
.gitignore vendored
View File

@@ -2,7 +2,7 @@
.project .project
.pydevproject .pydevproject
README.md~ README.md~
lib/build/* rdpy/core/tmp/*
*.so *.so
*.os *.os
.sconsign.dblite .sconsign.dblite

View File

@@ -1,43 +0,0 @@
#!/usr/bin/python
#
# 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/>.
#
import sys, os
# Change path so we find rdpy
sys.path.insert(1, os.path.join(sys.path[0], '..'))
import unittest, rdpy.tests.network.type, rdpy.tests.network.const, rdpy.tests.network.layer
def headerTest(name):
print "*"*70
print name
print "*"*70
if __name__ == '__main__':
headerTest("Test case rdpy.test.network.type.TypeCase")
suite = unittest.TestLoader().loadTestsFromTestCase(rdpy.tests.network.type.TypeCase)
unittest.TextTestRunner(verbosity=2).run(suite)
headerTest("Test case rdpy.test.network.const.ConstCase")
suite = unittest.TestLoader().loadTestsFromTestCase(rdpy.tests.network.const.ConstCase)
unittest.TextTestRunner(verbosity=2).run(suite)
headerTest("Test case rdpy.test.network.type.layer.LayerCase")
suite = unittest.TestLoader().loadTestsFromTestCase(rdpy.tests.network.layer.LayerCase)
unittest.TextTestRunner(verbosity=2).run(suite)

57
rdpy/base/log.py Normal file
View File

@@ -0,0 +1,57 @@
#
# 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/>.
#
"""
Log engine in RDPY
Actually very basic log engine
"""
class Level(object):
"""
Level log
"""
DEBUG = 0
INFO = 1
WARNING = 2
ERROR = 3
_LOG_LEVEL = Level.DEBUG
def log(message):
print message
def error(message):
if _LOG_LEVEL > Level.ERROR:
return
log("ERROR : %s"%message)
def warning(message):
if _LOG_LEVEL > Level.WARNING:
return
log("WARNING : %s"%message)
def info(message):
if _LOG_LEVEL > Level.INFO:
return
log("INFO : %s"%message)
def debug(message):
if _LOG_LEVEL > Level.DEBUG:
return
log("DEBUG : %s"%message)

View File

@@ -2,7 +2,7 @@ import os
import sipconfig import sipconfig
script_dir = os.path.dirname(os.path.realpath(Dir("#/Sconstruct").abspath)) script_dir = os.path.dirname(os.path.realpath(Dir("#/Sconstruct").abspath))
build_dir = os.path.join(script_dir, "build") tmp_dir = os.path.join(script_dir, "tmp")
src_dir = os.path.join(script_dir, "src") src_dir = os.path.join(script_dir, "src")
sip_dir = os.path.join(script_dir, "sip") sip_dir = os.path.join(script_dir, "sip")
@@ -14,11 +14,11 @@ def build_sip(target, source, env):
os.system(" ".join([config.sip_bin, "-c", os.path.dirname(str(target[0])), str(source[0])])) os.system(" ".join([config.sip_bin, "-c", os.path.dirname(str(target[0])), str(source[0])]))
def build_module(name, install_dir, env): def build_module(name, install_dir, env):
targetName = os.path.join(build_dir, name, "%s.so"%name) targetName = os.path.join(tmp_dir, name, "%s.so"%name)
sources = [Glob(os.path.join(src_dir, name,'*.c')), os.path.join(build_dir, name, "sip%scmodule.c"%name)] sources = [Glob(os.path.join(src_dir, name,'*.c')), os.path.join(tmp_dir, name, "sip%scmodule.c"%name)]
env.Sip(os.path.join(build_dir, name, "sip%scmodule.c"%name), os.path.join(sip_dir, "%s.sip"%name)) env.Sip(os.path.join(tmp_dir, name, "sip%scmodule.c"%name), os.path.join(sip_dir, "%s.sip"%name))
#sources.append(sip) #sources.append(sip)
lib = env.SharedLibrary(target = targetName, source = sources, SHLIBPREFIX='') lib = env.SharedLibrary(target = targetName, source = sources, SHLIBPREFIX='')
@@ -31,6 +31,6 @@ def build_module(name, install_dir, env):
env = Environment() env = Environment()
env.Append(BUILDERS = {'Sip' : Builder(action = build_sip)}) env.Append(BUILDERS = {'Sip' : Builder(action = build_sip)})
env.Append(CPPPATH = ["/usr/include/python2.7"]); env.Append(CPPPATH = ["/usr/include/python2.7"]);
env.VariantDir('build', 'src', duplicate=0) env.VariantDir('tmp', 'src', duplicate=0)
build_module("rle", os.path.join(script_dir, "..", "rdpy", "ui"), env) build_module("rle", script_dir, env)

View File

@@ -23,7 +23,7 @@ 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 from rdpy.base.error import CallPureVirtualFuntion
class LayerMode(object): class LayerMode(object):
NONE = 0 NONE = 0

View File

@@ -27,8 +27,8 @@ We are in python we can use that!
import struct import struct
from copy import deepcopy from copy import deepcopy
from StringIO import StringIO from StringIO import StringIO
from error import InvalidValue from rdpy.base.error import InvalidExpectedDataException, InvalidSize, CallPureVirtualFuntion, InvalidValue
from rdpy.network.error import InvalidExpectedDataException, InvalidSize, CallPureVirtualFuntion import rdpy.base.log as log
def sizeof(element): def sizeof(element):
""" """
@@ -432,7 +432,7 @@ class CompositeType(Type):
raise InvalidSize("Impossible to read type %s : read length is too small"%(self.__class__)) raise InvalidSize("Impossible to read type %s : read length is too small"%(self.__class__))
except Exception as e: except Exception as e:
print "Error during read %s::%s"%(self.__class__, name) log.error("Error during read %s::%s"%(self.__class__, name))
#roll back already read #roll back already read
for tmpName in self._typeName: for tmpName in self._typeName:
if tmpName == name: if tmpName == name:
@@ -440,7 +440,7 @@ class CompositeType(Type):
s.pos -= sizeof(self.__dict__[tmpName]) s.pos -= sizeof(self.__dict__[tmpName])
raise e raise e
if not self._readLen is None and readLen < self._readLen.value: 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__ log.warning("still have correct data in packet %s, read it as padding"%self.__class__)
s.read(self._readLen.value - readLen) s.read(self._readLen.value - readLen)
def __write__(self, s): def __write__(self, s):
@@ -452,7 +452,7 @@ class CompositeType(Type):
try: try:
s.writeType(self.__dict__[name]) s.writeType(self.__dict__[name])
except Exception as e: except Exception as e:
print "Error during write %s::%s"%(self.__class__, name) log.error("Error during write %s::%s"%(self.__class__, name))
raise e raise e
def __sizeof__(self): def __sizeof__(self):
@@ -949,16 +949,4 @@ def CheckValueOnRead(cls):
if self != old: if self != old:
raise InvalidValue("CheckValueOnRead %s != %s"%(self, old)) raise InvalidValue("CheckValueOnRead %s != %s"%(self, old))
cls.read = read cls.read = read
return cls return cls
def hexDump(src, length=16):
'''
print hex representation of str
@param src: string
'''
FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or '.' for x in range(256)])
for c in xrange(0, len(src), length):
chars = src[c:c+length]
hexa = ' '.join(["%02x" % ord(x) for x in chars])
printable = ''.join(["%s" % ((ord(x) <= 127 and FILTER[ord(x)]) or '.') for x in chars])
print "%04x %-*s %s" % (c, length*3, hexa, printable)

View File

@@ -23,7 +23,7 @@ ASN.1 standard
""" """
from rdpy.network.type import UInt8, UInt16Be, UInt32Be, String from rdpy.network.type import UInt8, UInt16Be, UInt32Be, String
from rdpy.network.error import InvalidExpectedDataException, InvalidSize from rdpy.base.error import InvalidExpectedDataException, InvalidSize
class BerPc(object): class BerPc(object):
BER_PC_MASK = 0x20 BER_PC_MASK = 0x20

View File

@@ -16,7 +16,8 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from rdpy.network.error import InvalidExpectedDataException from rdpy.base.error import InvalidExpectedDataException
import rdpy.base.log as log
""" """
Definition of structure use for capabilities nego Definition of structure use for capabilities nego
@@ -237,7 +238,7 @@ class Capability(CompositeType):
for c in [GeneralCapability, BitmapCapability, OrderCapability, BitmapCacheCapability, PointerCapability, InputCapability, BrushCapability, GlyphCapability, OffscreenBitmapCacheCapability, VirtualChannelCapability, SoundCapability, ControlCapability, WindowActivationCapability, FontCapability, ColorCacheCapability, ShareCapability]: 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_: if self.capabilitySetType.value == c._TYPE_:
return c(readLen = self.lengthCapability - 4) return c(readLen = self.lengthCapability - 4)
print "WARNING : unknown Capability type : %s"%hex(self.capabilitySetType.value) log.debug("unknown Capability type : %s"%hex(self.capabilitySetType.value))
#read entire packet #read entire packet
return String(readLen = self.lengthCapability - 4) return String(readLen = self.lengthCapability - 4)

View File

@@ -23,8 +23,9 @@ http://msdn.microsoft.com/en-us/library/cc240508.aspx
""" """
from rdpy.network.type import UInt8, UInt16Le, UInt32Le, CompositeType, String, Stream, sizeof, FactoryType, ArrayType from rdpy.network.type import UInt8, UInt16Le, UInt32Le, CompositeType, String, Stream, sizeof, FactoryType, ArrayType
import per import per, mcs
from rdpy.network.error import InvalidExpectedDataException from rdpy.base.error import InvalidExpectedDataException
import rdpy.base.log as log
t124_02_98_oid = ( 0, 0, 20, 124, 0, 1 ) t124_02_98_oid = ( 0, 0, 20, 124, 0, 1 )
@@ -204,7 +205,7 @@ class DataBlock(CompositeType):
for c in [ClientCoreData, ClientSecurityData, ClientNetworkData, ServerCoreData, ServerNetworkData, ServerSecurityData]: for c in [ClientCoreData, ClientSecurityData, ClientNetworkData, ServerCoreData, ServerNetworkData, ServerSecurityData]:
if self.type.value == c._TYPE_: if self.type.value == c._TYPE_:
return c(readLen = self.length - 4) return c(readLen = self.length - 4)
print "WARNING : unknown GCC block type : %s"%hex(self.type.value) log.debug("unknown GCC block type : %s"%hex(self.type.value))
#read entire packet #read entire packet
return String(readLen = self.length - 4) return String(readLen = self.length - 4)
@@ -285,8 +286,7 @@ class ServerSecurityData(CompositeType):
def __init__(self, readLen = None): def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen) CompositeType.__init__(self, readLen = readLen)
self.encryptionMethod = UInt32Le() self.encryptionMethod = UInt32Le()
self.encryptionLevel = UInt32Le() self.encryptionLevel = UInt32Le()
class ChannelDef(CompositeType): class ChannelDef(CompositeType):
""" """
@@ -310,7 +310,7 @@ class ClientNetworkData(CompositeType):
def __init__(self, readLen = None): def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen) CompositeType.__init__(self, readLen = readLen)
self.channelCount = UInt32Le() self.channelCount = UInt32Le(lambda:len(self.channelDefArray._array))
self.channelDefArray = ArrayType(ChannelDef, readLen = self.channelCount) self.channelDefArray = ArrayType(ChannelDef, readLen = self.channelCount)
class ServerNetworkData(CompositeType): class ServerNetworkData(CompositeType):
@@ -323,7 +323,7 @@ class ServerNetworkData(CompositeType):
def __init__(self, readLen = None): def __init__(self, readLen = None):
CompositeType.__init__(self, readLen = readLen) CompositeType.__init__(self, readLen = readLen)
self.MCSChannelId = UInt16Le() self.MCSChannelId = UInt16Le(mcs.Channel.MCS_GLOBAL_CHANNEL)
self.channelCount = UInt16Le(lambda:len(self.channelIdArray._array)) self.channelCount = UInt16Le(lambda:len(self.channelIdArray._array))
self.channelIdArray = ArrayType(UInt16Le, readLen = self.channelCount) 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))

View File

@@ -23,7 +23,8 @@ RDP extended license
""" """
from rdpy.network.type import CompositeType, UInt8, UInt16Le, UInt32Le, String, sizeof, FactoryType, ArrayType from rdpy.network.type import CompositeType, UInt8, UInt16Le, UInt32Le, String, sizeof, FactoryType, ArrayType
from rdpy.network.error import InvalidExpectedDataException from rdpy.base.error import InvalidExpectedDataException
import rdpy.base.log as log
class MessageType(object): class MessageType(object):
""" """
@@ -193,7 +194,7 @@ class LicPacket(CompositeType):
for c in [LicensingErrorMessage, ServerLicenseRequest, ClientNewLicenseRequest]: for c in [LicensingErrorMessage, ServerLicenseRequest, ClientNewLicenseRequest]:
if self.bMsgtype.value == c._MESSAGE_TYPE_: if self.bMsgtype.value == c._MESSAGE_TYPE_:
return c() return c()
print "WARNING : unknown license message : %s"%self.bMsgtype.value log.debug("unknown license message : %s"%self.bMsgtype.value)
return String() return String()
if message is None: if message is None:

View File

@@ -26,8 +26,9 @@ It exist channel for file system order, audio channel, clipboard etc...
""" """
from rdpy.network.layer import LayerAutomata, StreamSender, Layer, LayerMode from rdpy.network.layer import LayerAutomata, StreamSender, Layer, LayerMode
from rdpy.network.type import sizeof, Stream, UInt8, UInt16Le from rdpy.network.type import sizeof, Stream, UInt8, UInt16Le
from rdpy.network.error import InvalidExpectedDataException, InvalidValue, InvalidSize from rdpy.base.error import InvalidExpectedDataException, InvalidValue, InvalidSize
from rdpy.protocol.rdp.ber import writeLength from rdpy.protocol.rdp.ber import writeLength
import rdpy.base.log as log
import ber, gcc, per import ber, gcc, per
@@ -115,10 +116,11 @@ class MCS(LayerAutomata):
return self._mcs._serverSettings return self._mcs._serverSettings
def __init__(self, mode, presentation): def __init__(self, mode, presentation, virtualChannels = []):
""" """
@param mode: mode of MCS layer @param mode: mode of MCS layer
@param presentation: presentation layer @param presentation: presentation layer
@param virtualChannels: list additional channels like rdpsnd... [tuple(mcs.ChannelDef, layer)]
""" """
LayerAutomata.__init__(self, mode, presentation) LayerAutomata.__init__(self, mode, presentation)
self._clientSettings = gcc.clientSettings() self._clientSettings = gcc.clientSettings()
@@ -126,7 +128,13 @@ class MCS(LayerAutomata):
#default user Id #default user Id
self._userId = 1 + Channel.MCS_USERCHANNEL_BASE self._userId = 1 + Channel.MCS_USERCHANNEL_BASE
#list of channel use in this layer and connection state #list of channel use in this layer and connection state
self._channelIds = {Channel.MCS_GLOBAL_CHANNEL: presentation} self._channels = {Channel.MCS_GLOBAL_CHANNEL: presentation}
#virtual channels
self._virtualChannels = virtualChannels
#nb join and confirm channel
self._nbJoinAndConfirmChannel = 0
self._isGlobalChannelRequested = False
self._isUserChannelRequested = False
#use to record already requested channel #use to record already requested channel
self._channelIdsRequested = {} self._channelIdsRequested = {}
@@ -137,7 +145,12 @@ class MCS(LayerAutomata):
""" """
if self._mode == LayerMode.CLIENT: if self._mode == LayerMode.CLIENT:
self._clientSettings.getBlock(gcc.MessageType.CS_CORE).serverSelectedProtocol.value = self._transport._selectedProtocol self._clientSettings.getBlock(gcc.MessageType.CS_CORE).serverSelectedProtocol.value = self._transport._selectedProtocol
#ask for virtual channel
self._clientSettings.getBlock(gcc.MessageType.CS_NET).channelDefArray._array = [x for (x, _) in self._virtualChannels]
#send connect initial
self.sendConnectInitial() self.sendConnectInitial()
#next wait response
self.setNextState(self.recvConnectResponse)
else: else:
self._serverSettings.getBlock(gcc.MessageType.SC_CORE).clientRequestedProtocol.value = self._transport._requestedProtocol self._serverSettings.getBlock(gcc.MessageType.SC_CORE).clientRequestedProtocol.value = self._transport._requestedProtocol
self.setNextState(self.recvConnectInitial) self.setNextState(self.recvConnectInitial)
@@ -147,21 +160,41 @@ class MCS(LayerAutomata):
Send sendChannelJoinRequest message on next disconnect channel Send sendChannelJoinRequest message on next disconnect channel
client automata function client automata function
""" """
for (channelId, layer) in self._channelIds.iteritems(): self.setNextState(self.recvChannelJoinConfirm)
#for each disconnect channel send a request #global channel
if not self._channelIdsRequested.has_key(channelId): if not self._isGlobalChannelRequested:
self.sendChannelJoinRequest(channelId) self.sendChannelJoinRequest(Channel.MCS_GLOBAL_CHANNEL)
self.setNextState(self.recvChannelJoinConfirm) self._isGlobalChannelRequested = True
return return
#user channel
if not self._isUserChannelRequested:
self.sendChannelJoinRequest(self._userId)
self._isUserChannelRequested = True
return
#static virtual channel
if self._nbJoinAndConfirmChannel < self._serverSettings.getBlock(gcc.MessageType.SC_NET).channelCount.value:
channelId = self._serverSettings.getBlock(gcc.MessageType.SC_NET).channelIdArray._array[self._nbJoinAndConfirmChannel]
self._nbJoinAndConfirmChannel += 1
self.sendChannelJoinRequest(channelId)
return
self.allChannelConnected()
def allChannelConnected(self):
"""
All channels are connected to MCS layer
Send connect to upper channel
And prepare MCS layer to receive data
"""
#connection is done #connection is done
self.setNextState(self.recvData) self.setNextState(self.recvData)
#try connection on all requested channel #try connection on all requested channel
for (channelId, layer) in self._channelIds.iteritems(): for (channelId, layer) in self._channels.iteritems():
if self._channelIdsRequested[channelId] and not layer is None: #use proxy for each channel
#use proxy for each channel layer._transport = MCS.MCSProxySender(self, channelId)
layer._transport = MCS.MCSProxySender(self, channelId) layer.connect()
layer.connect()
def sendConnectInitial(self): def sendConnectInitial(self):
""" """
@@ -178,8 +211,6 @@ class MCS(LayerAutomata):
self.writeDomainParams(0xffff, 0xfc17, 0xffff, 0xffff), self.writeDomainParams(0xffff, 0xfc17, 0xffff, 0xffff),
ber.writeOctetstring(ccReqStream.getvalue())) ber.writeOctetstring(ccReqStream.getvalue()))
self._transport.send((ber.writeApplicationTag(Message.MCS_TYPE_CONNECT_INITIAL, sizeof(tmp)), tmp)) self._transport.send((ber.writeApplicationTag(Message.MCS_TYPE_CONNECT_INITIAL, sizeof(tmp)), tmp))
#we must receive a connect response
self.setNextState(self.recvConnectResponse)
def sendConnectResponse(self): def sendConnectResponse(self):
""" """
@@ -194,8 +225,6 @@ class MCS(LayerAutomata):
ber.writeOctetstring(ccReqStream.getvalue())) ber.writeOctetstring(ccReqStream.getvalue()))
self._transport.send((ber.writeApplicationTag(Message.MCS_TYPE_CONNECT_RESPONSE, sizeof(tmp)), tmp)) self._transport.send((ber.writeApplicationTag(Message.MCS_TYPE_CONNECT_RESPONSE, sizeof(tmp)), tmp))
self.setNextState(self.recvErectDomainRequest)
def sendErectDomainRequest(self): def sendErectDomainRequest(self):
""" """
Send a formated erect domain request for RDP connection Send a formated erect domain request for RDP connection
@@ -217,7 +246,7 @@ class MCS(LayerAutomata):
Send attach user confirm Send attach user confirm
server automata function server automata function
""" """
self._transport.send((self.writeMCSPDUHeader(UInt8(DomainMCSPDU.ATTACH_USER_CONFIRM)), self._transport.send((self.writeMCSPDUHeader(UInt8(DomainMCSPDU.ATTACH_USER_CONFIRM), 2),
per.writeEnumerates(0), per.writeEnumerates(0),
per.writeInteger16(self._userId, Channel.MCS_USERCHANNEL_BASE))) per.writeInteger16(self._userId, Channel.MCS_USERCHANNEL_BASE)))
@@ -237,7 +266,7 @@ class MCS(LayerAutomata):
@param channelId: id of channel @param channelId: id of channel
@param confirm: connection state @param confirm: connection state
""" """
self._transport.send((self.writeMCSPDUHeader(UInt8(DomainMCSPDU.CHANNEL_JOIN_CONFIRM)), self._transport.send((self.writeMCSPDUHeader(UInt8(DomainMCSPDU.CHANNEL_JOIN_CONFIRM), 2),
per.writeEnumerates(int(confirm)), per.writeEnumerates(int(confirm)),
per.writeInteger16(self._userId, Channel.MCS_USERCHANNEL_BASE), per.writeInteger16(self._userId, Channel.MCS_USERCHANNEL_BASE),
per.writeInteger16(channelId), per.writeInteger16(channelId),
@@ -276,6 +305,7 @@ class MCS(LayerAutomata):
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._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() self.sendConnectResponse()
self.setNextState(self.recvErectDomainRequest)
def recvConnectResponse(self, data): def recvConnectResponse(self, data):
""" """
@@ -350,10 +380,6 @@ class MCS(LayerAutomata):
self._userId = per.readInteger16(data, Channel.MCS_USERCHANNEL_BASE) 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] = None
self.connectNextChannel() self.connectNextChannel()
def recvChannelJoinRequest(self, data): def recvChannelJoinRequest(self, data):
@@ -374,7 +400,12 @@ class MCS(LayerAutomata):
raise InvalidExpectedDataException("Invalid MCS User Id") raise InvalidExpectedDataException("Invalid MCS User Id")
channelId = per.readInteger16(data) channelId = per.readInteger16(data)
self.sendChannelJoinConfirm(channelId, channelId in self._channelIds.keys() or channelId == self._userId) #TODO check if it's a virtual channel too
#actually algo support virtual channel but not RDPY
self.sendChannelJoinConfirm(channelId, channelId in self._channels.keys() or channelId == self._userId)
self._nbJoinAndConfirmChannel += 1
if self._nbJoinAndConfirmChannel == self._serverSettings.getBlock(gcc.MessageType.SC_NET).channelCount.value + 2:
self.allChannelConnected()
def recvChannelJoinConfirm(self, data): def recvChannelJoinConfirm(self, data):
""" """
@@ -395,8 +426,16 @@ class MCS(LayerAutomata):
raise InvalidExpectedDataException("Invalid MCS User Id") raise InvalidExpectedDataException("Invalid MCS User Id")
channelId = per.readInteger16(data) channelId = per.readInteger16(data)
#save state of channel #must confirm global channel and user channel
self._channelIdsRequested[channelId] = (confirm == 0) if (confirm != 0) and (channelId == Channel.MCS_GLOBAL_CHANNEL or channelId == self._userId):
raise InvalidExpectedDataException("Server must confirm static channel")
if confirm ==0:
serverNet = self._serverSettings.getBlock(gcc.MessageType.SC_NET)
for i in range(0, serverNet.channelCount.value):
if channelId == serverNet.channelIdArray._array[i].value:
self._channels[channelId] = self._virtualChannels[i][1]
self.connectNextChannel() self.connectNextChannel()
def recvData(self, data): def recvData(self, data):
@@ -408,7 +447,7 @@ class MCS(LayerAutomata):
data.readType(opcode) data.readType(opcode)
if self.readMCSPDUHeader(opcode.value, DomainMCSPDU.DISCONNECT_PROVIDER_ULTIMATUM): if self.readMCSPDUHeader(opcode.value, DomainMCSPDU.DISCONNECT_PROVIDER_ULTIMATUM):
print "INFO : MCS DISCONNECT_PROVIDER_ULTIMATUM" log.info("MCS DISCONNECT_PROVIDER_ULTIMATUM")
self._transport.close() self._transport.close()
return return
@@ -424,16 +463,11 @@ class MCS(LayerAutomata):
per.readLength(data) per.readLength(data)
#channel id doesn't match a requested layer #channel id doesn't match a requested layer
if not self._channelIdsRequested.has_key(channelId): if not self._channels.has_key(channelId):
print "ERROR : receive data for an unrequested layer" log.error("receive data for an unconnected layer")
return return
#channel id math an unconnected layer self._channels[channelId].recv(data)
if not self._channelIdsRequested[channelId]:
print "ERROR : receive data for an unconnected layer"
return
self._channelIds[channelId].recv(data)
def writeDomainParams(self, maxChannels, maxUsers, maxTokens, maxPduSize): def writeDomainParams(self, maxChannels, maxUsers, maxTokens, maxPduSize):
""" """

View File

@@ -25,8 +25,8 @@ In this layer are managed all mains bitmap update orders end user inputs
from rdpy.network.layer import LayerAutomata, LayerMode from rdpy.network.layer import LayerAutomata, LayerMode
from rdpy.network.type import CompositeType, 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 from rdpy.base.error import InvalidExpectedDataException, CallPureVirtualFuntion, InvalidType
import rdpy.base.log as log
import gcc, lic, caps, tpkt import gcc, lic, caps, tpkt
class SecurityFlag(object): class SecurityFlag(object):
@@ -562,7 +562,7 @@ class PDU(CompositeType):
for c in [DemandActivePDU, ConfirmActivePDU, DataPDU, DeactiveAllPDU]: for c in [DemandActivePDU, ConfirmActivePDU, DataPDU, DeactiveAllPDU]:
if self.shareControlHeader.pduType.value == c._PDUTYPE_: if self.shareControlHeader.pduType.value == c._PDUTYPE_:
return c() return c()
print "WARNING : unknown PDU type : %s"%hex(self.shareControlHeader.pduType.value) log.debug("unknown PDU type : %s"%hex(self.shareControlHeader.pduType.value))
#read entire packet #read entire packet
return String() return String()
@@ -643,7 +643,7 @@ class DataPDU(CompositeType):
for c in [UpdateDataPDU, SynchronizeDataPDU, ControlDataPDU, ErrorInfoDataPDU, FontListDataPDU, FontMapDataPDU, PersistentListPDU, ClientInputEventPDU, ShutdownDeniedPDU, ShutdownRequestPDU]: for c in [UpdateDataPDU, SynchronizeDataPDU, ControlDataPDU, ErrorInfoDataPDU, FontListDataPDU, FontMapDataPDU, PersistentListPDU, ClientInputEventPDU, ShutdownDeniedPDU, ShutdownRequestPDU]:
if self.shareDataHeader.pduType2.value == c._PDUTYPE2_: if self.shareDataHeader.pduType2.value == c._PDUTYPE2_:
return c() return c()
print "WARNING : unknown PDU data type : %s"%hex(self.shareDataHeader.pduType2.value) log.debug("unknown PDU data type : %s"%hex(self.shareDataHeader.pduType2.value))
return String() return String()
if pduData is None: if pduData is None:
@@ -936,7 +936,7 @@ class SlowPathInputEvent(CompositeType):
for c in [PointerEvent, ScancodeKeyEvent, UnicodeKeyEvent]: for c in [PointerEvent, ScancodeKeyEvent, UnicodeKeyEvent]:
if self.messageType.value == c._INPUT_MESSAGE_TYPE_: if self.messageType.value == c._INPUT_MESSAGE_TYPE_:
return c() return c()
print "WARNING : unknown slow path input : %s"%hex(self.messageType.value) log.debug("unknown slow path input : %s"%hex(self.messageType.value))
return String() return String()
if messageData is None: if messageData is None:
@@ -1219,7 +1219,7 @@ class PDULayer(LayerAutomata, tpkt.FastPathListener):
if ErrorInfo._MESSAGES_.has_key(dataPDU.pduData.errorInfo): if ErrorInfo._MESSAGES_.has_key(dataPDU.pduData.errorInfo):
message = ErrorInfo._MESSAGES_[dataPDU.pduData.errorInfo] message = ErrorInfo._MESSAGES_[dataPDU.pduData.errorInfo]
print "Error INFO PDU : %s"%message log.error("INFO PDU : %s"%message)
elif dataPDU.shareDataHeader.pduType2.value == PDUType2.PDUTYPE2_SHUTDOWN_DENIED: elif dataPDU.shareDataHeader.pduType2.value == PDUType2.PDUTYPE2_SHUTDOWN_DENIED:
#may be an event to ask to user #may be an event to ask to user
self._transport.close() self._transport.close()

View File

@@ -3,7 +3,7 @@
''' '''
from rdpy.network.type import UInt8, UInt16Be, UInt32Be, String from rdpy.network.type import UInt8, UInt16Be, UInt32Be, String
from rdpy.network.error import InvalidValue, InvalidExpectedDataException from rdpy.base.error import InvalidValue, InvalidExpectedDataException
def readLength(s): def readLength(s):
''' '''

View File

@@ -22,8 +22,9 @@ Use to manage RDP stack in twisted
""" """
from twisted.internet import protocol from twisted.internet import protocol
from rdpy.network.error import CallPureVirtualFuntion, InvalidValue from rdpy.base.error import CallPureVirtualFuntion, InvalidValue
from rdpy.network.layer import LayerMode from rdpy.network.layer import LayerMode
import rdpy.base.log as log
import tpkt, tpdu, mcs, pdu, gcc import tpkt, tpdu, mcs, pdu, gcc
class RDPClientController(pdu.PDUClientListener): class RDPClientController(pdu.PDUClientListener):
@@ -153,7 +154,7 @@ class RDPClientController(pdu.PDUClientListener):
self._pduLayer.sendInputEvents([event]) self._pduLayer.sendInputEvents([event])
except InvalidValue: except InvalidValue:
print "try send pointer event with incorrect position" log.info("try send pointer event with incorrect position")
def sendKeyEventScancode(self, code, isPressed): def sendKeyEventScancode(self, code, isPressed):
""" """
@@ -176,7 +177,7 @@ class RDPClientController(pdu.PDUClientListener):
self._pduLayer.sendInputEvents([event]) self._pduLayer.sendInputEvents([event])
except InvalidValue: except InvalidValue:
print "try send bad key event" log.info("try send bad key event")
def sendKeyEventUnicode(self, code, isPressed): def sendKeyEventUnicode(self, code, isPressed):
""" """
@@ -197,7 +198,7 @@ class RDPClientController(pdu.PDUClientListener):
self._pduLayer.sendInputEvents([event]) self._pduLayer.sendInputEvents([event])
except InvalidValue: except InvalidValue:
print "try send bad key event" log.info("try send bad key event")
def close(self): def close(self):
""" """

View File

@@ -26,7 +26,7 @@ RDP basic security is not supported by RDPY (because is not a true security laye
from rdpy.network.layer import LayerAutomata, LayerMode, StreamSender 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.base.error import InvalidExpectedDataException
class MessageType(object): class MessageType(object):
""" """

View File

@@ -24,7 +24,7 @@ Use to build correct size packet and handle slow path and fast path mode
""" """
from rdpy.network.layer import RawLayer, LayerMode from rdpy.network.layer import RawLayer, LayerMode
from rdpy.network.type import UInt8, UInt16Be, sizeof from rdpy.network.type import UInt8, UInt16Be, sizeof
from rdpy.network.error import CallPureVirtualFuntion from rdpy.base.error import CallPureVirtualFuntion
class FastPathListener(object): class FastPathListener(object):
""" """

View File

@@ -29,7 +29,7 @@ Implement Remote FrameBuffer protocol use in VNC client and server
from twisted.internet import protocol from twisted.internet import protocol
from rdpy.network.layer import RawLayer, LayerMode from rdpy.network.layer import RawLayer, LayerMode
from rdpy.network.type import UInt8, UInt16Be, UInt32Be, SInt32Be, String, CompositeType from rdpy.network.type import UInt8, UInt16Be, UInt32Be, SInt32Be, String, CompositeType
from rdpy.network.error import InvalidValue, CallPureVirtualFuntion, InvalidType from rdpy.base.error import InvalidValue, CallPureVirtualFuntion, InvalidType
class ProtocolVersion(object): class ProtocolVersion(object):
""" """

View File

@@ -26,8 +26,14 @@ QRemoteDesktop is a widget use for render in rdpy
from PyQt4 import QtGui, QtCore from PyQt4 import QtGui, QtCore
from rdpy.protocol.rfb.rfb import RFBClientObserver from rdpy.protocol.rfb.rfb import RFBClientObserver
from rdpy.protocol.rdp.rdp import RDPClientObserver from rdpy.protocol.rdp.rdp import RDPClientObserver
from rdpy.network.error import CallPureVirtualFuntion from rdpy.base.error import CallPureVirtualFuntion
import rle
import rdpy.base.log as log
try:
import rdpy.core.rle as rle
except:
log.error("Please build core package before using RLE algorithm : scons -C rdpy/core install")
class QAdaptor(object): class QAdaptor(object):
@@ -97,7 +103,7 @@ class RFBClientQt(RFBClientObserver, QAdaptor):
if pixelFormat.BitsPerPixel.value == 32 and pixelFormat.RedShift.value == 16: if pixelFormat.BitsPerPixel.value == 32 and pixelFormat.RedShift.value == 16:
imageFormat = QtGui.QImage.Format_RGB32 imageFormat = QtGui.QImage.Format_RGB32
else: else:
print "Receive image in bad format" log.error("Receive image in bad format")
return return
image = QtGui.QImage(data, width, height, imageFormat) image = QtGui.QImage(data, width, height, imageFormat)
@@ -218,7 +224,7 @@ class RDPClientQt(RDPClientObserver, QAdaptor):
else: else:
image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB32) image = QtGui.QImage(data, width, height, QtGui.QImage.Format_RGB32)
else: else:
print "Receive image in bad format" log.error("Receive image in bad format")
return return
#if image need to be cut #if image need to be cut
@@ -290,8 +296,6 @@ class QRemoteDesktop(QtGui.QWidget):
Call when mouse move Call when mouse move
@param event: QMouseEvent @param event: QMouseEvent
""" """
if self._adaptor is None:
print "No adaptor to send mouse move event"
self._adaptor.sendMouseEvent(event, False) self._adaptor.sendMouseEvent(event, False)
def mousePressEvent(self, event): def mousePressEvent(self, event):

View File

@@ -2,19 +2,19 @@
@author: sylvain @author: sylvain
''' '''
import unittest import unittest
import rdpy.network.const import rdpy.base.const
import rdpy.network.type import rdpy.network.type
class ConstCase(unittest.TestCase): class ConstCase(unittest.TestCase):
''' '''
represent test case for all classes and function represent test case for all classes and function
present in rdpy.network.const present in rdpy.base.const
''' '''
def test_type_attributes(self): def test_type_attributes(self):
''' '''
test if type attributes decorator works test if type attributes decorator works
''' '''
@rdpy.network.const.TypeAttributes(rdpy.network.type.UInt16Le) @rdpy.base.const.TypeAttributes(rdpy.network.type.UInt16Le)
class Test: class Test:
MEMBER_1 = 1 MEMBER_1 = 1
MEMBER_2 = 2 MEMBER_2 = 2
@@ -26,7 +26,7 @@ class ConstCase(unittest.TestCase):
''' '''
test if get on const class member generate new object each test if get on const class member generate new object each
''' '''
@rdpy.network.const.ConstAttributes @rdpy.base.const.ConstAttributes
class Test: class Test:
MEMBER_1 = 1 MEMBER_1 = 1
MEMBER_2 = 2 MEMBER_2 = 2

View File

@@ -26,17 +26,6 @@ class LayerCase(unittest.TestCase):
self.assertRaises(LayerCase.LayerCaseException, rdpy.network.layer.Layer(presentation = TestConnect()).connect) self.assertRaises(LayerCase.LayerCaseException, rdpy.network.layer.Layer(presentation = TestConnect()).connect)
def test_layer_receive_event(self):
'''
test if recv event is send from transport to presentation
'''
class TestConnect(rdpy.network.layer.Layer):
def recv(self, s):
if s == "message":
raise LayerCase.LayerCaseException()
self.assertRaises(LayerCase.LayerCaseException, rdpy.network.layer.Layer(presentation = TestConnect()).recv, "message")
def test_layer_automata_more_than_expected(self): def test_layer_automata_more_than_expected(self):
''' '''
test layer automata mechanism if data received is more than expected test layer automata mechanism if data received is more than expected

View File

@@ -331,20 +331,4 @@ class TypeCase(unittest.TestCase):
except Exception: except Exception:
self.assertEqual(s.readLen(), 0, "invalid stream roll back operation") self.assertEqual(s.readLen(), 0, "invalid stream roll back operation")
return return
self.assertTrue(False, "Constant constraint fail") self.assertTrue(False, "Constant constraint fail")
def test_stream_composite_type_force_read_length_optional(self):
'''
test where type have readLen forced and have optional subtype which have
length greater than last subtype of composite type
'''
class TestType(rdpy.network.type.CompositeType):
def __init__(self, readLen = None):
rdpy.network.type.CompositeType.__init__(self, readLen = readLen)
self.t1 = rdpy.network.type.UInt32Le(0, optional = True)
self.t2 = rdpy.network.type.UInt16Le(0, optional = True)
s = rdpy.network.type.Stream("\x00\x00\x00\x00\x00\x00\x00")
t = TestType(readLen = rdpy.network.type.UInt8(2))
s.readType(t)
self.assertTrue(not t.t1._is_readed and t.t2._is_readed, "Invalid optional reading when length is forced")