diff --git a/rdpy/protocol/network/type.py b/rdpy/protocol/network/type.py index 6c3d92b..1a80ae9 100644 --- a/rdpy/protocol/network/type.py +++ b/rdpy/protocol/network/type.py @@ -94,9 +94,12 @@ class SimpleType(Type): ''' compare inner value magic function of python use for any compare operators - @param other: Type value which will be compared with self value + @param other: SimpleType value which will be compared with self value + or try to construct same type as self around other value @return: python value compare ''' + if not isinstance(other, SimpleType): + other = self.__class__(other) return self.value.__cmp__(other.value) def write(self, s): @@ -159,38 +162,68 @@ class SimpleType(Type): def __add__(self, other): ''' implement addition operator - @attention: type overflow are not handle - @param other: SimpleType value + @param other: SimpleType value or try to construct same type as self + around other value @return: self.__class__ object with add result @raise InvalidValue: if new value is out of bound ''' + if not isinstance(other, SimpleType): + other = self.__class__(other) return self.__class__(self.value.__add__(other.value)) def __sub__(self, other): ''' implement sub operator - @attention: type overflow are not handle - @param other: SimpleType value + @param other: SimpleType value or try to construct same type as self + around other value @return: self.__class__ object with sub result @raise InvalidValue: if new value is out of bound ''' + if not isinstance(other, SimpleType): + other = self.__class__(other) return self.__class__(self.value.__sub__(other.value)) def __and__(self, other): ''' implement bitwise and operator - @param other: SimpleType value + @param other: SimpleType value or try to construct same type as self + around other value @return: self.__class__ object with and result ''' + if not isinstance(other, SimpleType): + other = self.__class__(other) return self.__class__(self.value.__and__(other.value)) def __or__(self, other): ''' implement bitwise and operator - @param other: SimpleType value + @param other: SimpleType value or try to construct same type as self + around other value @return: self.__class__ object with or result ''' + if not isinstance(other, SimpleType): + other = self.__class__(other) return self.__class__(self.value.__or__(other.value)) + + def __lshift__(self, other): + ''' + left shift operator + @param other: python int + @return: self.__class__ object with or result + ''' + if not isinstance(other, SimpleType): + other = self.__class__(other) + return self.__class__(self.value.__lshift__(other.value)) + + def __rshift__(self, other): + ''' + left shift operator + @param other: python int + @return: self.__class__ object with or result + ''' + if not isinstance(other, SimpleType): + other = self.__class__(other) + return self.__class__(self.value.__rshift__(other.value)) class CompositeType(Type): diff --git a/rdpy/protocol/rdp/gcc.py b/rdpy/protocol/rdp/gcc.py index 9720275..a294c2f 100644 --- a/rdpy/protocol/rdp/gcc.py +++ b/rdpy/protocol/rdp/gcc.py @@ -1,7 +1,7 @@ ''' @author sylvain @summary gcc language -@contact: http://msdn.microsoft.com/en-us/library/cc240510.aspx +@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx ''' from rdpy.utils.const import ConstAttributes, TypeAttributes from rdpy.protocol.network.type import UInt8, UInt16Le, UInt32Le, CompositeType, String, UniString, Stream, sizeof @@ -74,7 +74,7 @@ class Support(object): @TypeAttributes(UInt16Le) class CapabilityFlags(object): ''' - @contact: http://msdn.microsoft.com/en-us/library/cc240510.aspx + @see: http://msdn.microsoft.com/en-us/library/cc240510.aspx for more details on each flags click above ''' RNS_UD_CS_SUPPORT_ERRINFO_PDU = 0x0001 @@ -95,7 +95,7 @@ class ConnectionType(object): ''' this information is correct if RNS_UD_CS_VALID_CONNECTION_TYPE flag is set on capabilityFlag - @contact: http://msdn.microsoft.com/en-us/library/cc240510.aspx + @see: http://msdn.microsoft.com/en-us/library/cc240510.aspx ''' CONNECTION_TYPE_MODEM = 0x01 CONNECTION_TYPE_BROADBAND_LOW = 0x02 @@ -130,7 +130,25 @@ class Encryption(object): ENCRYPTION_FLAG_128BIT = 0x00000002 ENCRYPTION_FLAG_56BIT = 0x00000008 FIPS_ENCRYPTION_FLAG = 0x00000010 - + +@ConstAttributes +@TypeAttributes(UInt32Le) +class ChannelOptions(object): + ''' + channel options + @see: http://msdn.microsoft.com/en-us/library/cc240513.aspx + ''' + CHANNEL_OPTION_INITIALIZED = 0x80000000 + CHANNEL_OPTION_ENCRYPT_RDP = 0x40000000 + CHANNEL_OPTION_ENCRYPT_SC = 0x20000000 + CHANNEL_OPTION_ENCRYPT_CS = 0x10000000 + CHANNEL_OPTION_PRI_HIGH = 0x08000000 + CHANNEL_OPTION_PRI_MED = 0x04000000 + CHANNEL_OPTION_PRI_LOW = 0x02000000 + CHANNEL_OPTION_COMPRESS_RDP = 0x00800000 + CHANNEL_OPTION_COMPRESS = 0x00400000 + CHANNEL_OPTION_SHOW_PROTOCOL = 0x00200000 + REMOTE_CONTROL_PERSISTENT = 0x00100000 class ClientCoreSettings(CompositeType): ''' @@ -212,7 +230,7 @@ class ClientSettings(object): def __init__(self): self.core = ClientCoreSettings() #list of ClientRequestedChannel read network gcc packet - self.networkChannels = [] + self.networkChannels = [ClientRequestedChannel("rdpdr", ChannelOptions.CHANNEL_OPTION_INITIALIZED)] self.security = ClientSecuritySettings() class ServerSettings(object): @@ -271,8 +289,8 @@ def writeClientDataBlocks(settings): @param settings: ClientSettings ''' return (writeClientCoreData(settings.core), - writeClientNetworkData(settings.networkChannels), - writeClientSecurityData(settings.security)) + writeClientSecurityData(settings.security), + writeClientNetworkData(settings.networkChannels)) def readServerDataBlocks(s): ''' @@ -295,6 +313,7 @@ def readServerDataBlocks(s): elif blockType == ServerToClientMessage.SC_NET: settings.channelsId = readServerSecurityData(s) #read security block + #unused in rdpy because use SSL layer elif blockType == ServerToClientMessage.SC_SECURITY: s.readType(settings.security) else: @@ -327,7 +346,7 @@ def writeClientNetworkData(channels): ''' if len(channels) == 0: return () - return (ClientToServerMessage.CS_NET, UInt16Le(len(channels) * sizeof(ClientRequestedChannel()) + 4), UInt32Le(len(channels)), tuple(channels)) + return (ClientToServerMessage.CS_NET, UInt16Le(len(channels) * sizeof(ClientRequestedChannel()) + 8), UInt32Le(len(channels)), tuple(channels)) def readServerSecurityData(s): ''' diff --git a/rdpy/protocol/rdp/mcs.py b/rdpy/protocol/rdp/mcs.py index d09be3f..8e3bcca 100644 --- a/rdpy/protocol/rdp/mcs.py +++ b/rdpy/protocol/rdp/mcs.py @@ -4,11 +4,11 @@ from rdpy.utils.const import ConstAttributes, TypeAttributes from rdpy.protocol.network.layer import LayerAutomata -from rdpy.protocol.network.type import sizeof, Stream, UInt8 +from rdpy.protocol.network.type import sizeof, Stream, UInt8, UInt16Be from rdpy.protocol.rdp.ber import writeLength from rdpy.protocol.network.error import InvalidExpectedDataException, InvalidValue, InvalidSize -import ber, gcc +import ber, gcc, per @ConstAttributes @TypeAttributes(UInt8) @@ -18,14 +18,16 @@ class Message(object): ''' MCS_TYPE_CONNECT_INITIAL = 0x65 MCS_TYPE_CONNECT_RESPONSE = 0x66 - MCS_EDRQ = 1 - MCS_DPUM = 8 - MCS_AURQ = 10 - MCS_AUCF = 11 - MCS_CJRQ = 14 - MCS_CJCF = 15 - MCS_SDRQ = 25 - MCS_SDIN = 26 + +@ConstAttributes +@TypeAttributes(UInt8) +class DomainMCSPDU: + ''' + domain mcs pdu header + ''' + ERECT_DOMAIN_REQUEST = 1 + ATTACH_USER_REQUEST = 10 + ATTACH_USER_CONFIRM = 11 class Channel: MCS_GLOBAL_CHANNEL = 1003 @@ -37,7 +39,6 @@ class MCS(LayerAutomata): the main layer of RDP protocol is why he can do everything and more! ''' - def __init__(self, presentation = None): ''' ctor call base class ctor @@ -45,6 +46,8 @@ class MCS(LayerAutomata): ''' LayerAutomata.__init__(self, presentation) self._clientSettings = gcc.ClientSettings() + #default user Id + self._userId = UInt16Be(1) def connect(self): ''' @@ -71,6 +74,18 @@ class MCS(LayerAutomata): #we must receive a connect response self.setNextState(self.recvConnectResponse) + def sendErectDomainRequest(self): + ''' + send a formated erect domain request for RDP connection + ''' + self._transport.send((self.writeMCSPDUHeader(DomainMCSPDU.ERECT_DOMAIN_REQUEST), per.writeInteger(0), per.writeInteger(0))) + + def sendAttachUserRequest(self): + ''' + send a formated attach user request for RDP connection + ''' + self._transport.send(self.writeMCSPDUHeader(DomainMCSPDU.ATTACH_USER_REQUEST)) + def recvConnectResponse(self, data): ''' receive mcs connect response from server @@ -81,11 +96,32 @@ class MCS(LayerAutomata): ber.readInteger(data) self.readDomainParams(data) if not ber.readUniversalTag(data, ber.Tag.BER_TAG_OCTET_STRING, False): - raise InvalidExpectedDataException("invalid expected tag") + raise InvalidExpectedDataException("invalid expected ber tag") gccRequestLength = ber.readLength(data) if data.dataLen() != gccRequestLength: raise InvalidSize("bad size of gcc request") gcc.readConferenceCreateResponse(data) + #send domain request + self.sendErectDomainRequest() + #send attach user request + self.sendAttachUserRequest() + #now wait user confirm from server + self.setNextState(self.recvAttachUserConfirm) + + def recvAttachUserConfirm(self, data): + ''' + recaive a attach user confirm + @param data: Stream + ''' + opcode = UInt8() + confirm = UInt8() + data.readType((opcode, confirm)) + if not self.readMCSPDUHeader(opcode, 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(self._userId) def writeDomainParams(self, maxChannels, maxUsers, maxTokens, maxPduSize): ''' @@ -102,6 +138,24 @@ class MCS(LayerAutomata): ber.writeInteger(maxPduSize), ber.writeInteger(2)) return (ber.writeUniversalTag(ber.Tag.BER_TAG_SEQUENCE, True), writeLength(sizeof(domainParam)), domainParam) + def writeMCSPDUHeader(self, mcsPdu, options = 0): + ''' + write mcs pdu header + @param mcsPdu: pdu code + @param options: option contains in header + @return: UInt8 + ''' + return (mcsPdu << 2) | options + + def readMCSPDUHeader(self, opcode, mcsPdu): + ''' + read mcsPdu header and return options parameter + @param opcode: UInt8 opcode + @param mcsPdu: mcsPdu will be checked + @return: true if opcode is correct + ''' + return (opcode >> 2) == mcsPdu + def readDomainParams(self, s): ''' read domain params structure