diff --git a/rdpy/protocol/rdp/ber.py b/rdpy/protocol/rdp/ber.py index 9a91928..40d61f8 100644 --- a/rdpy/protocol/rdp/ber.py +++ b/rdpy/protocol/rdp/ber.py @@ -72,7 +72,7 @@ def readLength(s): s.readType(length) byte = length.value if (byte & 0x80): - byte &= 0x80 + byte &= ~0x80 if byte == 1: size = UInt8() elif byte == 2: @@ -227,7 +227,7 @@ def readOctetString(s): if not readUniversalTag(s, Tag.BER_TAG_OCTET_STRING, False): raise InvalidExpectedDataException("Unexpected BER tag") size = readLength(s) - return s.read(size.value) + return s.read(size) def writeOctetstring(value): """ diff --git a/rdpy/protocol/rdp/gcc.py b/rdpy/protocol/rdp/gcc.py index 79833cf..b767b77 100644 --- a/rdpy/protocol/rdp/gcc.py +++ b/rdpy/protocol/rdp/gcc.py @@ -27,6 +27,7 @@ import per from rdpy.network.error import InvalidExpectedDataException t124_02_98_oid = ( 0, 0, 20, 124, 0, 1 ) + h221_cs_key = "Duca"; h221_sc_key = "McDn"; @@ -292,21 +293,27 @@ class ServerSettings(object): #channel id accepted by server self.channelsId = [] -def writeConferenceCreateRequest(settings): +def readConferenceCreateRequest(s): """ - Write conference create request structure - @param settings: ClientSettings - @return: structure that represent + Read a response from client + GCC create request + @param s: Stream """ - userData = writeClientDataBlocks(settings) - userDataStream = Stream() - userDataStream.writeType(userData) + per.readChoice(s) + per.readObjectIdentifier(s, t124_02_98_oid) + per.readLength(s) + per.readChoice(s) + per.readSelection(s) + per.readNumericString(s, 1) + per.readPadding(s, 1) - return (per.writeChoice(0), per.writeObjectIdentifier(t124_02_98_oid), - per.writeLength(len(userDataStream.getvalue()) + 14), per.writeChoice(0), - per.writeSelection(0x08), per.writeNumericString("1", 1), per.writePadding(1), - per.writeNumberOfSet(1), per.writeChoice(0xc0), - per.writeOctetStream(h221_cs_key, 4), per.writeOctetStream(userDataStream.getvalue())) + if per.readNumberOfSet(s) != 1: + raise InvalidExpectedDataException("Invalid number of set in readConferenceCreateRequest") + + if per.readChoice(s) != 0xc0: + raise InvalidExpectedDataException("Invalid choice in readConferenceCreateRequest") + + per.readOctetStream(s, h221_cs_key, 4) def readConferenceCreateResponse(s): """ @@ -328,17 +335,6 @@ def readConferenceCreateResponse(s): raise InvalidExpectedDataException("cannot read h221_sc_key") return readServerDataBlocks(s) - -def writeClientDataBlocks(settings): - """ - Write all blocks for client - and return GCC valid structure - @param settings: ClientSettings - """ - return (writeClientCoreData(settings.core), - writeClientSecurityData(settings.security), - writeClientNetworkData(settings.networkChannels)) - def readServerDataBlocks(s): """ Read GCC server data blocks @@ -370,6 +366,50 @@ def readServerDataBlocks(s): 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 + +def writeConferenceCreateRequest(settings): + """ + Write conference create request structure + @param settings: ClientSettings + @return: structure that represent + """ + userData = writeClientDataBlocks(settings) + userDataStream = Stream() + userDataStream.writeType(userData) + + return (per.writeChoice(0), per.writeObjectIdentifier(t124_02_98_oid), + per.writeLength(len(userDataStream.getvalue()) + 14), per.writeChoice(0), + per.writeSelection(0x08), per.writeNumericString("1", 1), per.writePadding(1), + per.writeNumberOfSet(1), per.writeChoice(0xc0), + per.writeOctetStream(h221_cs_key, 4), per.writeOctetStream(userDataStream.getvalue())) + +def writeClientDataBlocks(settings): + """ + Write all blocks for client + and return GCC valid structure + @param settings: ClientSettings + """ + return (writeClientCoreData(settings.core), + writeClientSecurityData(settings.security), + writeClientNetworkData(settings.networkChannels)) + def writeClientCoreData(core): """ Write client settings in GCC language @@ -395,22 +435,4 @@ def writeClientNetworkData(channels): if len(channels) == 0: return () return (UInt16Le(ClientToServerMessage.CS_NET), UInt16Le(len(channels) * sizeof(ClientRequestedChannel()) + 8), UInt32Le(len(channels)), tuple(channels)) - -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 \ No newline at end of file diff --git a/rdpy/protocol/rdp/mcs.py b/rdpy/protocol/rdp/mcs.py index 83e57b6..e6cf040 100644 --- a/rdpy/protocol/rdp/mcs.py +++ b/rdpy/protocol/rdp/mcs.py @@ -24,7 +24,7 @@ Each channel have a particular role. The main channel is the graphical channel. It exist channel for file system order, audio channel, clipboard etc... """ -from rdpy.network.layer import LayerAutomata, StreamSender, Layer +from rdpy.network.layer import LayerAutomata, StreamSender, Layer, LayerMode from rdpy.network.type import sizeof, Stream, UInt8, UInt16Be from rdpy.network.error import InvalidExpectedDataException, InvalidValue, InvalidSize from rdpy.protocol.rdp.ber import writeLength @@ -135,8 +135,11 @@ class MCS(LayerAutomata): Connection send for client mode a write connect initial packet """ - self._clientSettings.core.serverSelectedProtocol.value = self._transport._selectedProtocol - self.sendConnectInitial() + if self._mode == LayerMode.CLIENT: + self._clientSettings.core.serverSelectedProtocol.value = self._transport._selectedProtocol + self.sendConnectInitial() + else: + self.setNextState(self.recvConnectInitial) def connectNextChannel(self): """ @@ -192,10 +195,27 @@ class MCS(LayerAutomata): Send a formated Channel join request from client to server """ self._transport.send((self.writeMCSPDUHeader(UInt8(DomainMCSPDU.CHANNEL_JOIN_REQUEST)), UInt16Be(self._userId), UInt16Be(channelId))) + + def recvConnectInitial(self, data): + """ + Receive MCS connect initial from client + @param data: Stream + """ + ber.readApplicationTag(data, UInt8(Message.MCS_TYPE_CONNECT_INITIAL)) + ber.readOctetString(data) + ber.readOctetString(data) + if not ber.readBoolean(data): + raise InvalidExpectedDataException("invalid expected BER boolean tag") + + self.readDomainParams(data) + self.readDomainParams(data) + self.readDomainParams(data) + gcc.readConferenceCreateRequest(Stream(ber.readOctetString(data))) + def recvConnectResponse(self, data): """ - receive MCS connect response from server + Receive MCS connect response from server @param data: Stream """ ber.readApplicationTag(data, UInt8(Message.MCS_TYPE_CONNECT_RESPONSE)) @@ -203,7 +223,7 @@ 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 ber tag") + raise InvalidExpectedDataException("invalid expected BER tag") gccRequestLength = ber.readLength(data) if data.dataLen() != gccRequestLength: raise InvalidSize("bad size of gcc request") diff --git a/rdpy/protocol/rdp/per.py b/rdpy/protocol/rdp/per.py index cf4f99a..f32fadd 100644 --- a/rdpy/protocol/rdp/per.py +++ b/rdpy/protocol/rdp/per.py @@ -13,15 +13,15 @@ def readLength(s): ''' byte = UInt8() s.readType(byte) - size = None - if (byte & UInt8(0x80)) == UInt8(0x80): - byte &= ~UInt8(0x80) - size = UInt16Be(byte.value << 8) + size = 0 + if byte.value & 0x80: + byte.value &= 0x80 + size = byte.value << 8 s.readType(byte) - size += s.value + byte + size += byte.value else: - size = UInt16Be(byte.value) - return size.value + size = byte.value + return size def writeLength(value): ''' @@ -187,13 +187,23 @@ def readObjectIdentifier(s, oid): raise InvalidExpectedDataException("invalid object identifier") def writeObjectIdentifier(oid): - ''' - create tuble of 6 UInt8 with oid values + """ + Create tuple of 6 UInt8 with oid values @param oid: tuple of 6 int @return: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) - ''' + """ return (UInt8(5), UInt8((oid[0] << 4) & (oid[1] & 0x0f)), UInt8(oid[2]), UInt8(oid[3]), UInt8(oid[4]), UInt8(oid[5])) +def readNumericString(s, minValue): + """ + Read numeric string + @param s: Stream + @param minValue: offset + """ + length = readLength(s) + length = (length + minValue + 1) / 2 + s.read(length) + def writeNumericString(nStr, minValue): ''' write string in per format