612 lines
22 KiB
Python
612 lines
22 KiB
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/>.
|
|
#
|
|
|
|
"""
|
|
Implement GCC structure use in RDP protocol
|
|
http://msdn.microsoft.com/en-us/library/cc240508.aspx
|
|
"""
|
|
|
|
import md5
|
|
from rdpy.core.type import UInt8, UInt16Le, UInt32Le, CompositeType, String, Stream, sizeof, FactoryType, ArrayType
|
|
import per, mcs
|
|
from rdpy.core.error import InvalidExpectedDataException
|
|
from rdpy.core import log
|
|
from rdpy.security import x509
|
|
import rdpy.security.rsa_wrapper as rsa
|
|
|
|
t124_02_98_oid = ( 0, 0, 20, 124, 0, 1 )
|
|
|
|
h221_cs_key = "Duca";
|
|
h221_sc_key = "McDn";
|
|
|
|
class MessageType(object):
|
|
"""
|
|
@summary: Server to Client block
|
|
GCC conference messages
|
|
@see: http://msdn.microsoft.com/en-us/library/cc240509.aspx
|
|
"""
|
|
#server -> client
|
|
SC_CORE = 0x0C01
|
|
SC_SECURITY = 0x0C02
|
|
SC_NET = 0x0C03
|
|
#client -> server
|
|
CS_CORE = 0xC001
|
|
CS_SECURITY = 0xC002
|
|
CS_NET = 0xC003
|
|
CS_CLUSTER = 0xC004
|
|
CS_MONITOR = 0xC005
|
|
|
|
|
|
class ColorDepth(object):
|
|
"""
|
|
@summary: Depth color
|
|
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
|
|
"""
|
|
RNS_UD_COLOR_8BPP = 0xCA01
|
|
RNS_UD_COLOR_16BPP_555 = 0xCA02
|
|
RNS_UD_COLOR_16BPP_565 = 0xCA03
|
|
RNS_UD_COLOR_24BPP = 0xCA04
|
|
|
|
class HighColor(object):
|
|
"""
|
|
@summary: High color of client
|
|
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
|
|
"""
|
|
HIGH_COLOR_4BPP = 0x0004
|
|
HIGH_COLOR_8BPP = 0x0008
|
|
HIGH_COLOR_15BPP = 0x000f
|
|
HIGH_COLOR_16BPP = 0x0010
|
|
HIGH_COLOR_24BPP = 0x0018
|
|
|
|
class Support(object):
|
|
"""
|
|
@summary: Supported depth flag
|
|
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
|
|
"""
|
|
RNS_UD_24BPP_SUPPORT = 0x0001
|
|
RNS_UD_16BPP_SUPPORT = 0x0002
|
|
RNS_UD_15BPP_SUPPORT = 0x0004
|
|
RNS_UD_32BPP_SUPPORT = 0x0008
|
|
|
|
class CapabilityFlags(object):
|
|
"""
|
|
@summary: For more details on each flags click above
|
|
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
|
|
"""
|
|
RNS_UD_CS_SUPPORT_ERRINFO_PDU = 0x0001
|
|
RNS_UD_CS_WANT_32BPP_SESSION = 0x0002
|
|
RNS_UD_CS_SUPPORT_STATUSINFO_PDU = 0x0004
|
|
RNS_UD_CS_STRONG_ASYMMETRIC_KEYS = 0x0008
|
|
RNS_UD_CS_UNUSED = 0x0010
|
|
RNS_UD_CS_VALID_CONNECTION_TYPE = 0x0020
|
|
RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU = 0x0040
|
|
RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT = 0x0080
|
|
RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL = 0x0100
|
|
RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE = 0x0200
|
|
RNS_UD_CS_SUPPORT_HEARTBEAT_PDU = 0x0400
|
|
|
|
class ConnectionType(object):
|
|
"""
|
|
@summary: This information is correct if
|
|
RNS_UD_CS_VALID_CONNECTION_TYPE flag is set on capabilityFlag
|
|
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
|
|
"""
|
|
CONNECTION_TYPE_MODEM = 0x01
|
|
CONNECTION_TYPE_BROADBAND_LOW = 0x02
|
|
CONNECTION_TYPE_SATELLITE = 0x03
|
|
CONNECTION_TYPE_BROADBAND_HIGH = 0x04
|
|
CONNECTION_TYPE_WAN = 0x05
|
|
CONNECTION_TYPE_LAN = 0x06
|
|
CONNECTION_TYPE_AUTODETECT = 0x07
|
|
|
|
class Version(object):
|
|
"""
|
|
@summary: Supported version of RDP
|
|
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
|
|
"""
|
|
RDP_VERSION_4 = 0x00080001
|
|
RDP_VERSION_5_PLUS = 0x00080004
|
|
|
|
class Sequence(object):
|
|
RNS_UD_SAS_DEL = 0xAA03
|
|
|
|
class EncryptionMethod(object):
|
|
"""
|
|
@summary: Encryption methods supported
|
|
@see: http://msdn.microsoft.com/en-us/library/cc240511.aspx
|
|
"""
|
|
ENCRYPTION_FLAG_40BIT = 0x00000001
|
|
ENCRYPTION_FLAG_128BIT = 0x00000002
|
|
ENCRYPTION_FLAG_56BIT = 0x00000008
|
|
FIPS_ENCRYPTION_FLAG = 0x00000010
|
|
|
|
class EncryptionLevel(object):
|
|
"""
|
|
@summary: level of 'security'
|
|
@see: http://msdn.microsoft.com/en-us/library/cc240518.aspx
|
|
"""
|
|
ENCRYPTION_LEVEL_NONE = 0x00000000
|
|
ENCRYPTION_LEVEL_LOW = 0x00000001
|
|
ENCRYPTION_LEVEL_CLIENT_COMPATIBLE = 0x00000002
|
|
ENCRYPTION_LEVEL_HIGH = 0x00000003
|
|
ENCRYPTION_LEVEL_FIPS = 0x00000004
|
|
|
|
class ChannelOptions(object):
|
|
"""
|
|
@summary: 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 KeyboardType(object):
|
|
"""
|
|
@summary: Keyboard type
|
|
@see: IBM_101_102_KEYS is the most common keyboard type
|
|
"""
|
|
IBM_PC_XT_83_KEY = 0x00000001
|
|
OLIVETTI = 0x00000002
|
|
IBM_PC_AT_84_KEY = 0x00000003
|
|
IBM_101_102_KEYS = 0x00000004
|
|
NOKIA_1050 = 0x00000005
|
|
NOKIA_9140 = 0x00000006
|
|
JAPANESE = 0x00000007
|
|
|
|
class KeyboardLayout(object):
|
|
"""
|
|
@summary: Keyboard layout definition
|
|
@see: http://technet.microsoft.com/en-us/library/cc766503%28WS.10%29.aspx
|
|
"""
|
|
ARABIC = 0x00000401
|
|
BULGARIAN = 0x00000402
|
|
CHINESE_US_KEYBOARD = 0x00000404
|
|
CZECH = 0x00000405
|
|
DANISH = 0x00000406
|
|
GERMAN = 0x00000407
|
|
GREEK = 0x00000408
|
|
US = 0x00000409
|
|
SPANISH = 0x0000040a
|
|
FINNISH = 0x0000040b
|
|
FRENCH = 0x0000040c
|
|
HEBREW = 0x0000040d
|
|
HUNGARIAN = 0x0000040e
|
|
ICELANDIC = 0x0000040f
|
|
ITALIAN = 0x00000410
|
|
JAPANESE = 0x00000411
|
|
KOREAN = 0x00000412
|
|
DUTCH = 0x00000413
|
|
NORWEGIAN = 0x00000414
|
|
|
|
class CertificateType(object):
|
|
"""
|
|
@see: http://msdn.microsoft.com/en-us/library/cc240521.aspx
|
|
"""
|
|
CERT_CHAIN_VERSION_1 = 0x00000001
|
|
CERT_CHAIN_VERSION_2 = 0x00000002
|
|
|
|
class DataBlock(CompositeType):
|
|
"""
|
|
@summary: Block settings
|
|
"""
|
|
def __init__(self, dataBlock = None):
|
|
CompositeType.__init__(self)
|
|
self.type = UInt16Le(lambda:self.dataBlock.__class__._TYPE_)
|
|
self.length = UInt16Le(lambda:sizeof(self))
|
|
|
|
def DataBlockFactory():
|
|
"""
|
|
@summary: build settings in accordance of type self.type.value
|
|
"""
|
|
for c in [ClientCoreData, ClientSecurityData, ClientNetworkData, ServerCoreData, ServerNetworkData, ServerSecurityData]:
|
|
if self.type.value == c._TYPE_:
|
|
return c(readLen = self.length - 4)
|
|
log.debug("unknown GCC block type : %s"%hex(self.type.value))
|
|
#read entire packet
|
|
return String(readLen = self.length - 4)
|
|
|
|
if dataBlock is None:
|
|
dataBlock = FactoryType(DataBlockFactory)
|
|
elif not "_TYPE_" in dataBlock.__class__.__dict__:
|
|
raise InvalidExpectedDataException("Try to send an invalid GCC blocks")
|
|
|
|
self.dataBlock = dataBlock
|
|
|
|
class ClientCoreData(CompositeType):
|
|
"""
|
|
@summary: Class that represent core setting of client
|
|
@see: http://msdn.microsoft.com/en-us/library/cc240510.aspx
|
|
"""
|
|
_TYPE_ = MessageType.CS_CORE
|
|
|
|
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)
|
|
self.colorDepth = UInt16Le(ColorDepth.RNS_UD_COLOR_8BPP)
|
|
self.sasSequence = UInt16Le(Sequence.RNS_UD_SAS_DEL)
|
|
self.kbdLayout = UInt32Le(KeyboardLayout.US)
|
|
self.clientBuild = UInt32Le(3790)
|
|
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)
|
|
self.imeFileName = String("\x00"*64, readLen = UInt8(64))
|
|
self.postBeta2ColorDepth = UInt16Le(ColorDepth.RNS_UD_COLOR_8BPP)
|
|
self.clientProductId = UInt16Le(1)
|
|
self.serialNumber = UInt32Le(0)
|
|
self.highColorDepth = UInt16Le(HighColor.HIGH_COLOR_24BPP)
|
|
self.supportedColorDepths = UInt16Le(Support.RNS_UD_15BPP_SUPPORT | Support.RNS_UD_16BPP_SUPPORT | Support.RNS_UD_24BPP_SUPPORT | Support.RNS_UD_32BPP_SUPPORT)
|
|
self.earlyCapabilityFlags = UInt16Le(CapabilityFlags.RNS_UD_CS_SUPPORT_ERRINFO_PDU)
|
|
self.clientDigProductId = String("\x00"*64, readLen = UInt8(64))
|
|
self.connectionType = UInt8()
|
|
self.pad1octet = UInt8()
|
|
self.serverSelectedProtocol = UInt32Le()
|
|
|
|
class ServerCoreData(CompositeType):
|
|
"""
|
|
@summary: Server side core settings structure
|
|
@see: http://msdn.microsoft.com/en-us/library/cc240517.aspx
|
|
"""
|
|
_TYPE_ = MessageType.SC_CORE
|
|
|
|
def __init__(self, readLen = None):
|
|
CompositeType.__init__(self, readLen = readLen)
|
|
self.rdpVersion = UInt32Le(Version.RDP_VERSION_5_PLUS)
|
|
self.clientRequestedProtocol = UInt32Le()
|
|
|
|
class ClientSecurityData(CompositeType):
|
|
"""
|
|
@summary: Client security setting
|
|
@see: http://msdn.microsoft.com/en-us/library/cc240511.aspx
|
|
"""
|
|
_TYPE_ = MessageType.CS_SECURITY
|
|
|
|
def __init__(self, readLen = None):
|
|
CompositeType.__init__(self, readLen = readLen)
|
|
self.encryptionMethods = UInt32Le(EncryptionMethod.ENCRYPTION_FLAG_40BIT | EncryptionMethod.ENCRYPTION_FLAG_56BIT | EncryptionMethod.ENCRYPTION_FLAG_128BIT)
|
|
self.extEncryptionMethods = UInt32Le()
|
|
|
|
class ServerSecurityData(CompositeType):
|
|
"""
|
|
@summary: Server security settings
|
|
@see: http://msdn.microsoft.com/en-us/library/cc240518.aspx
|
|
"""
|
|
_TYPE_ = MessageType.SC_SECURITY
|
|
|
|
def __init__(self, readLen = None):
|
|
CompositeType.__init__(self, readLen = readLen)
|
|
self.encryptionMethod = UInt32Le()
|
|
self.encryptionLevel = UInt32Le()
|
|
self.serverRandomLen = UInt32Le(0x00000020, constant = True, conditional = lambda:not(self.encryptionMethod.value == 0 and self.encryptionLevel == 0))
|
|
self.serverCertLen = UInt32Le(lambda:sizeof(self.serverCertificate), conditional = lambda:not(self.encryptionMethod.value == 0 and self.encryptionLevel == 0))
|
|
self.serverRandom = String(readLen = self.serverRandomLen, conditional = lambda:not(self.encryptionMethod.value == 0 and self.encryptionLevel == 0))
|
|
self.serverCertificate = ServerCertificate(readLen = self.serverCertLen, conditional = lambda:not(self.encryptionMethod.value == 0 and self.encryptionLevel == 0))
|
|
|
|
class ServerCertificate(CompositeType):
|
|
"""
|
|
@summary: Server certificate structure
|
|
@see: http://msdn.microsoft.com/en-us/library/cc240521.aspx
|
|
"""
|
|
def __init__(self, certData = None, readLen = None, conditional = lambda:True):
|
|
CompositeType.__init__(self, readLen = readLen, conditional = conditional)
|
|
self.dwVersion = UInt32Le(lambda:(self.certData.__class__._TYPE_))
|
|
|
|
def CertificateFactory():
|
|
"""
|
|
Closure for capability factory
|
|
"""
|
|
for c in [ProprietaryServerCertificate, X509CertificateChain]:
|
|
if self.dwVersion.value & 0x7fffffff == c._TYPE_:
|
|
return c()
|
|
raise InvalidExpectedDataException("unknown certificate type : %s "%hex(self.dwVersion.value))
|
|
|
|
if certData is None:
|
|
certData = FactoryType(CertificateFactory)
|
|
elif not "_TYPE_" in certData.__class__.__dict__:
|
|
raise InvalidExpectedDataException("Try to send an invalid Certificate")
|
|
|
|
self.certData = certData
|
|
|
|
class ProprietaryServerCertificate(CompositeType):
|
|
"""
|
|
@summary: microsoft proprietary certificate
|
|
@see: http://msdn.microsoft.com/en-us/library/cc240519.aspx
|
|
"""
|
|
_TYPE_ = CertificateType.CERT_CHAIN_VERSION_1
|
|
|
|
#http://msdn.microsoft.com/en-us/library/cc240776.aspx
|
|
_TERMINAL_SERVICES_MODULUS_ = "\x3d\x3a\x5e\xbd\x72\x43\x3e\xc9\x4d\xbb\xc1\x1e\x4a\xba\x5f\xcb\x3e\x88\x20\x87\xef\xf5\xc1\xe2\xd7\xb7\x6b\x9a\xf2\x52\x45\x95\xce\x63\x65\x6b\x58\x3a\xfe\xef\x7c\xe7\xbf\xfe\x3d\xf6\x5c\x7d\x6c\x5e\x06\x09\x1a\xf5\x61\xbb\x20\x93\x09\x5f\x05\x6d\xea\x87"
|
|
_TERMINAL_SERVICES_PRIVATE_EXPONENT_ = "\x87\xa7\x19\x32\xda\x11\x87\x55\x58\x00\x16\x16\x25\x65\x68\xf8\x24\x3e\xe6\xfa\xe9\x67\x49\x94\xcf\x92\xcc\x33\x99\xe8\x08\x60\x17\x9a\x12\x9f\x24\xdd\xb1\x24\x99\xc7\x3a\xb8\x0a\x7b\x0d\xdd\x35\x07\x79\x17\x0b\x51\x9b\xb3\xc7\x10\x01\x13\xe7\x3f\xf3\x5f"
|
|
_TERMINAL_SERVICES_PUBLIC_EXPONENT_ = "\x5b\x7b\x88\xc0"
|
|
|
|
def __init__(self):
|
|
CompositeType.__init__(self)
|
|
self.dwSigAlgId = UInt32Le(0x00000001, constant = True)
|
|
self.dwKeyAlgId = UInt32Le(0x00000001, constant = True)
|
|
self.wPublicKeyBlobType = UInt16Le(0x0006, constant = True)
|
|
self.wPublicKeyBlobLen = UInt16Le(lambda:sizeof(self.PublicKeyBlob))
|
|
self.PublicKeyBlob = RSAPublicKey(readLen = self.wPublicKeyBlobLen)
|
|
self.wSignatureBlobType = UInt16Le(0x0008, constant = True)
|
|
self.wSignatureBlobLen = UInt16Le(lambda:(sizeof(self.SignatureBlob) - 8))
|
|
self.SignatureBlob = String(readLen = self.wSignatureBlobLen)
|
|
self.padding = String(b"\x00" * 8, readLen = UInt8(8))
|
|
|
|
def getPublicKey(self):
|
|
"""
|
|
@return: {Tuple} (modulus, publicExponent)
|
|
"""
|
|
log.debug("read RSA public key from proprietary certificate")
|
|
#reverse because bignum in little endian
|
|
return rsa.PublicKey(self.PublicKeyBlob.pubExp.value, self.PublicKeyBlob.modulus.value[::-1])
|
|
|
|
def computeSignatureHash(self):
|
|
"""
|
|
@summary: compute hash
|
|
"""
|
|
s = Stream()
|
|
s.writeType(UInt32Le(self.__class__._TYPE_))
|
|
s.writeType(self.dwSigAlgId)
|
|
s.writeType(self.dwKeyAlgId)
|
|
s.writeType(self.wPublicKeyBlobType)
|
|
s.writeType(self.wPublicKeyBlobLen)
|
|
s.writeType(self.PublicKeyBlob)
|
|
|
|
md5Digest = md5.new()
|
|
md5Digest.update(s.getvalue())
|
|
|
|
return md5Digest.digest() + "\x00" + "\xff" * 46 + "\x01"
|
|
|
|
def sign(self):
|
|
"""
|
|
@summary: sign proprietary certificate
|
|
@see: http://msdn.microsoft.com/en-us/library/cc240778.aspx
|
|
"""
|
|
self.SignatureBlob.value = rsa.sign(self.computeSignatureHash()[::-1], rsa.PrivateKey(d = ProprietaryServerCertificate._TERMINAL_SERVICES_PRIVATE_EXPONENT_[::-1], n = ProprietaryServerCertificate._TERMINAL_SERVICES_MODULUS_[::-1]))[::-1]
|
|
|
|
def verify(self):
|
|
"""
|
|
@summary: verify certificate signature
|
|
"""
|
|
return rsa.verify(self.SignatureBlob.value[::-1], rsa.PublicKey(e = ProprietaryServerCertificate._TERMINAL_SERVICES_PUBLIC_EXPONENT_[::-1], n = ProprietaryServerCertificate._TERMINAL_SERVICES_MODULUS_[::-1]))[::-1] == self.computeSignatureHash()
|
|
|
|
|
|
class CertBlob(CompositeType):
|
|
"""
|
|
@summary: certificate blob, contain x509 data
|
|
@see: http://msdn.microsoft.com/en-us/library/cc241911.aspx
|
|
"""
|
|
def __init__(self):
|
|
CompositeType.__init__(self)
|
|
self.cbCert = UInt32Le(lambda:sizeof(self.abCert))
|
|
self.abCert = String(readLen = self.cbCert)
|
|
|
|
class X509CertificateChain(CompositeType):
|
|
"""
|
|
@summary: X509 certificate chain
|
|
@see: http://msdn.microsoft.com/en-us/library/cc241910.aspx
|
|
"""
|
|
_TYPE_ = CertificateType.CERT_CHAIN_VERSION_2
|
|
|
|
def __init__(self):
|
|
CompositeType.__init__(self)
|
|
self.NumCertBlobs = UInt32Le()
|
|
self.CertBlobArray = ArrayType(CertBlob, readLen = self.NumCertBlobs)
|
|
self.padding = String(readLen = UInt8(lambda:(8 + 4 * self.NumCertBlobs.value)))
|
|
|
|
def getPublicKey(self):
|
|
"""
|
|
@return: {Tuple} (modulus, publicExponent)
|
|
"""
|
|
log.debug("read RSA public key from x509 certificate")
|
|
#last certifcate contain public key
|
|
n, e = x509.extractRSAKey(x509.load(self.CertBlobArray[-1].abCert.value))
|
|
return rsa.PublicKey(e, n)
|
|
|
|
def verify(self):
|
|
"""
|
|
@todo: verify x509 signature
|
|
"""
|
|
return True
|
|
|
|
class RSAPublicKey(CompositeType):
|
|
"""
|
|
@see: http://msdn.microsoft.com/en-us/library/cc240520.aspx
|
|
"""
|
|
def __init__(self, readLen):
|
|
CompositeType.__init__(self, readLen = readLen)
|
|
#magic is RSA1(0x31415352)
|
|
self.magic = UInt32Le(0x31415352, constant = True)
|
|
self.keylen = UInt32Le(lambda:(sizeof(self.modulus) + sizeof(self.padding)))
|
|
self.bitlen = UInt32Le(lambda:((self.keylen.value - 8) * 8))
|
|
self.datalen = UInt32Le(lambda:((self.bitlen.value / 8) - 1))
|
|
self.pubExp = UInt32Le()
|
|
self.modulus = String(readLen = UInt16Le(lambda:(self.keylen.value - 8)))
|
|
self.padding = String("\x00" * 8, readLen = UInt8(8))
|
|
|
|
class ChannelDef(CompositeType):
|
|
"""
|
|
Channels structure share between client and server
|
|
@see: http://msdn.microsoft.com/en-us/library/cc240513.aspx
|
|
"""
|
|
def __init__(self, name = "", options = 0):
|
|
CompositeType.__init__(self)
|
|
#name of channel
|
|
self.name = String(name[0:8] + "\x00" * (8 - len(name)), readLen = UInt8(8))
|
|
#unknown
|
|
self.options = UInt32Le()
|
|
|
|
class ClientNetworkData(CompositeType):
|
|
"""
|
|
GCC client network block
|
|
All channels asked by client are listed here
|
|
@see: http://msdn.microsoft.com/en-us/library/cc240512.aspx
|
|
"""
|
|
_TYPE_ = MessageType.CS_NET
|
|
|
|
def __init__(self, readLen = None):
|
|
CompositeType.__init__(self, readLen = readLen)
|
|
self.channelCount = UInt32Le(lambda:len(self.channelDefArray._array))
|
|
self.channelDefArray = ArrayType(ChannelDef, readLen = self.channelCount)
|
|
|
|
class ServerNetworkData(CompositeType):
|
|
"""
|
|
GCC server network block
|
|
All channels asked by client are listed here
|
|
@see: All channels asked by client are listed here
|
|
"""
|
|
_TYPE_ = MessageType.SC_NET
|
|
|
|
def __init__(self, readLen = None):
|
|
CompositeType.__init__(self, readLen = readLen)
|
|
self.MCSChannelId = UInt16Le(mcs.Channel.MCS_GLOBAL_CHANNEL)
|
|
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))
|
|
|
|
class Settings(CompositeType):
|
|
"""
|
|
Class which group all clients settings supported by RDPY
|
|
"""
|
|
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):
|
|
"""
|
|
@param messageType: type of block
|
|
@return: specific block of type messageType
|
|
"""
|
|
for i in self.settings._array:
|
|
if i.type.value == messageType:
|
|
return i.dataBlock
|
|
return None
|
|
|
|
def __getattr__(self, name):
|
|
"""
|
|
@summary: Magic function for better access
|
|
@return: _value parameter
|
|
"""
|
|
if not name in MessageType.__dict__:
|
|
return None
|
|
return self.getBlock(MessageType.__dict__[name])
|
|
|
|
def clientSettings():
|
|
"""
|
|
Build settings for client
|
|
@return: Settings
|
|
"""
|
|
return Settings([ClientCoreData(), ClientNetworkData(), ClientSecurityData()])
|
|
|
|
def serverSettings():
|
|
"""
|
|
Build settings for server
|
|
@return Settings
|
|
"""
|
|
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)
|
|
per.readLength(s)
|
|
per.readChoice(s)
|
|
per.readSelection(s)
|
|
per.readNumericString(s, 1)
|
|
per.readPadding(s, 1)
|
|
|
|
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)
|
|
length = per.readLength(s)
|
|
clientSettings = Settings(readLen = UInt32Le(length))
|
|
s.readType(clientSettings)
|
|
return clientSettings
|
|
|
|
def readConferenceCreateResponse(s):
|
|
"""
|
|
Read response from server
|
|
and return server settings read from this response
|
|
@param s: Stream
|
|
@return: ServerSettings
|
|
"""
|
|
per.readChoice(s)
|
|
per.readObjectIdentifier(s, t124_02_98_oid)
|
|
per.readLength(s)
|
|
per.readChoice(s)
|
|
per.readInteger16(s, 1001)
|
|
per.readInteger(s)
|
|
per.readEnumerates(s)
|
|
per.readNumberOfSet(s)
|
|
per.readChoice(s)
|
|
if not per.readOctetStream(s, h221_sc_key, 4):
|
|
raise InvalidExpectedDataException("cannot read h221_sc_key")
|
|
|
|
length = per.readLength(s)
|
|
serverSettings = Settings(readLen = UInt32Le(length))
|
|
s.readType(serverSettings)
|
|
return serverSettings
|
|
|
|
def writeConferenceCreateRequest(userData):
|
|
"""
|
|
Write conference create request structure
|
|
@param userData: Settings for client
|
|
@return: GCC packet
|
|
"""
|
|
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 writeConferenceCreateResponse(serverData):
|
|
"""
|
|
Write a conference create response packet
|
|
@param serverData: Settings for server
|
|
@return: gcc packet
|
|
"""
|
|
serverDataStream = Stream()
|
|
serverDataStream.writeType(serverData)
|
|
|
|
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())) |