Blame libfreerdp/core/gcc.c

Packit Service fa4841
/**
Packit Service fa4841
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service fa4841
 * T.124 Generic Conference Control (GCC)
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit Service fa4841
 * Copyright 2014 Norbert Federa <norbert.federa@thincast.com>
Packit Service fa4841
 * Copyright 2014 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
Packit Service fa4841
 *
Packit Service fa4841
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service fa4841
 * you may not use this file except in compliance with the License.
Packit Service fa4841
 * You may obtain a copy of the License at
Packit Service fa4841
 *
Packit Service fa4841
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit Service fa4841
 *
Packit Service fa4841
 * Unless required by applicable law or agreed to in writing, software
Packit Service fa4841
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service fa4841
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service fa4841
 * See the License for the specific language governing permissions and
Packit Service fa4841
 * limitations under the License.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_CONFIG_H
Packit Service fa4841
#include "config.h"
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include <winpr/crt.h>
Packit Service fa4841
#include <winpr/crypto.h>
Packit Service fa4841
Packit Service fa4841
#include <freerdp/log.h>
Packit Service fa4841
Packit Service fa4841
#include "gcc.h"
Packit Service fa4841
#include "certificate.h"
Packit Service fa4841
Packit Service fa4841
#define TAG FREERDP_TAG("core.gcc")
Packit Service fa4841
Packit Service fa4841
static BOOL gcc_read_client_cluster_data(wStream* s, rdpMcs* mcs, UINT16 blockLength);
Packit Service fa4841
static BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs, UINT16 blockLength);
Packit Service fa4841
static BOOL gcc_read_client_data_blocks(wStream* s, rdpMcs* mcs, int length);
Packit Service fa4841
static BOOL gcc_read_server_data_blocks(wStream* s, rdpMcs* mcs, int length);
Packit Service fa4841
static BOOL gcc_read_user_data_header(wStream* s, UINT16* type, UINT16* length);
Packit Service fa4841
static void gcc_write_user_data_header(wStream* s, UINT16 type, UINT16 length);
Packit Service fa4841
Packit Service fa4841
static void gcc_write_client_core_data(wStream* s, rdpMcs* mcs);
Packit Service fa4841
static BOOL gcc_read_server_core_data(wStream* s, rdpMcs* mcs);
Packit Service fa4841
static BOOL gcc_write_server_core_data(wStream* s, rdpMcs* mcs);
Packit Service fa4841
static BOOL gcc_read_client_security_data(wStream* s, rdpMcs* mcs, UINT16 blockLength);
Packit Service fa4841
static void gcc_write_client_security_data(wStream* s, rdpMcs* mcs);
Packit Service fa4841
static BOOL gcc_read_server_security_data(wStream* s, rdpMcs* mcs);
Packit Service fa4841
static BOOL gcc_write_server_security_data(wStream* s, rdpMcs* mcs);
Packit Service fa4841
static BOOL gcc_read_client_network_data(wStream* s, rdpMcs* mcs, UINT16 blockLength);
Packit Service fa4841
static void gcc_write_client_network_data(wStream* s, rdpMcs* mcs);
Packit Service fa4841
static BOOL gcc_read_server_network_data(wStream* s, rdpMcs* mcs);
Packit Service fa4841
static BOOL gcc_write_server_network_data(wStream* s, rdpMcs* mcs);
Packit Service fa4841
static void gcc_write_client_cluster_data(wStream* s, rdpMcs* mcs);
Packit Service fa4841
static BOOL gcc_read_client_monitor_data(wStream* s, rdpMcs* mcs, UINT16 blockLength);
Packit Service fa4841
static void gcc_write_client_monitor_data(wStream* s, rdpMcs* mcs);
Packit Service fa4841
static BOOL gcc_read_client_monitor_extended_data(wStream* s, rdpMcs* mcs, UINT16 blockLength);
Packit Service fa4841
static void gcc_write_client_monitor_extended_data(wStream* s, rdpMcs* mcs);
Packit Service fa4841
static BOOL gcc_read_client_message_channel_data(wStream* s, rdpMcs* mcs, UINT16 blockLength);
Packit Service fa4841
static void gcc_write_client_message_channel_data(wStream* s, rdpMcs* mcs);
Packit Service fa4841
static BOOL gcc_read_server_message_channel_data(wStream* s, rdpMcs* mcs);
Packit Service fa4841
static BOOL gcc_write_server_message_channel_data(wStream* s, rdpMcs* mcs);
Packit Service fa4841
static BOOL gcc_read_client_multitransport_channel_data(wStream* s, rdpMcs* mcs,
Packit Service fa4841
                                                        UINT16 blockLength);
Packit Service fa4841
static void gcc_write_client_multitransport_channel_data(wStream* s, rdpMcs* mcs);
Packit Service fa4841
static BOOL gcc_read_server_multitransport_channel_data(wStream* s, rdpMcs* mcs);
Packit Service fa4841
static void gcc_write_server_multitransport_channel_data(wStream* s, rdpMcs* mcs);
Packit Service fa4841
Packit Service fa4841
static DWORD rdp_version_common(DWORD serverVersion, DWORD clientVersion)
Packit Service fa4841
{
Packit Service fa4841
	DWORD version = MIN(serverVersion, clientVersion);
Packit Service fa4841
Packit Service fa4841
	switch (version)
Packit Service fa4841
	{
Packit Service fa4841
		case RDP_VERSION_4:
Packit Service fa4841
		case RDP_VERSION_5_PLUS:
Packit Service fa4841
		case RDP_VERSION_10_0:
Packit Service fa4841
		case RDP_VERSION_10_1:
Packit Service fa4841
		case RDP_VERSION_10_2:
Packit Service fa4841
		case RDP_VERSION_10_3:
Packit Service fa4841
		case RDP_VERSION_10_4:
Packit Service fa4841
		case RDP_VERSION_10_5:
Packit Service fa4841
		case RDP_VERSION_10_6:
Packit Service fa4841
		case RDP_VERSION_10_7:
Packit Service fa4841
			return version;
Packit Service fa4841
Packit Service fa4841
		default:
Packit Service fa4841
			WLog_ERR(TAG, "Invalid client [%" PRId32 "] and server [%" PRId32 "] versions",
Packit Service fa4841
			         serverVersion, clientVersion);
Packit Service fa4841
			return version;
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * T.124 GCC is defined in:
Packit Service fa4841
 *
Packit Service fa4841
 * http://www.itu.int/rec/T-REC-T.124-199802-S/en
Packit Service fa4841
 * ITU-T T.124 (02/98): Generic Conference Control
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * ConnectData ::= SEQUENCE
Packit Service fa4841
 * {
Packit Service fa4841
 * 	t124Identifier	Key,
Packit Service fa4841
 * 	connectPDU	OCTET_STRING
Packit Service fa4841
 * }
Packit Service fa4841
 *
Packit Service fa4841
 * Key ::= CHOICE
Packit Service fa4841
 * {
Packit Service fa4841
 * 	object				OBJECT_IDENTIFIER,
Packit Service fa4841
 * 	h221NonStandard			H221NonStandardIdentifier
Packit Service fa4841
 * }
Packit Service fa4841
 *
Packit Service fa4841
 * ConnectGCCPDU ::= CHOICE
Packit Service fa4841
 * {
Packit Service fa4841
 * 	conferenceCreateRequest		ConferenceCreateRequest,
Packit Service fa4841
 * 	conferenceCreateResponse	ConferenceCreateResponse,
Packit Service fa4841
 * 	conferenceQueryRequest		ConferenceQueryRequest,
Packit Service fa4841
 * 	conferenceQueryResponse		ConferenceQueryResponse,
Packit Service fa4841
 * 	conferenceJoinRequest		ConferenceJoinRequest,
Packit Service fa4841
 *	conferenceJoinResponse		ConferenceJoinResponse,
Packit Service fa4841
 *	conferenceInviteRequest		ConferenceInviteRequest,
Packit Service fa4841
 *	conferenceInviteResponse	ConferenceInviteResponse,
Packit Service fa4841
 *	...
Packit Service fa4841
 * }
Packit Service fa4841
 *
Packit Service fa4841
 * ConferenceCreateRequest ::= SEQUENCE
Packit Service fa4841
 * {
Packit Service fa4841
 * 	conferenceName			ConferenceName,
Packit Service fa4841
 * 	convenerPassword		Password OPTIONAL,
Packit Service fa4841
 * 	password			Password OPTIONAL,
Packit Service fa4841
 * 	lockedConference		BOOLEAN,
Packit Service fa4841
 * 	listedConference		BOOLEAN,
Packit Service fa4841
 * 	conductibleConference		BOOLEAN,
Packit Service fa4841
 * 	terminationMethod		TerminationMethod,
Packit Service fa4841
 * 	conductorPrivileges		SET OF Privilege OPTIONAL,
Packit Service fa4841
 * 	conductedPrivileges		SET OF Privilege OPTIONAL,
Packit Service fa4841
 * 	nonConductedPrivileges		SET OF Privilege OPTIONAL,
Packit Service fa4841
 * 	conferenceDescription		TextString OPTIONAL,
Packit Service fa4841
 * 	callerIdentifier		TextString OPTIONAL,
Packit Service fa4841
 * 	userData			UserData OPTIONAL,
Packit Service fa4841
 * 	...,
Packit Service fa4841
 * 	conferencePriority		ConferencePriority OPTIONAL,
Packit Service fa4841
 * 	conferenceMode			ConferenceMode OPTIONAL
Packit Service fa4841
 * }
Packit Service fa4841
 *
Packit Service fa4841
 * ConferenceCreateResponse ::= SEQUENCE
Packit Service fa4841
 * {
Packit Service fa4841
 * 	nodeID				UserID,
Packit Service fa4841
 * 	tag				INTEGER,
Packit Service fa4841
 * 	result				ENUMERATED
Packit Service fa4841
 * 	{
Packit Service fa4841
 * 		success				(0),
Packit Service fa4841
 * 		userRejected			(1),
Packit Service fa4841
 * 		resourcesNotAvailable		(2),
Packit Service fa4841
 * 		rejectedForSymmetryBreaking	(3),
Packit Service fa4841
 * 		lockedConferenceNotSupported	(4)
Packit Service fa4841
 * 	},
Packit Service fa4841
 * 	userData			UserData OPTIONAL,
Packit Service fa4841
 * 	...
Packit Service fa4841
 * }
Packit Service fa4841
 *
Packit Service fa4841
 * ConferenceName ::= SEQUENCE
Packit Service fa4841
 * {
Packit Service fa4841
 * 	numeric				SimpleNumericString
Packit Service fa4841
 * 	text				SimpleTextString OPTIONAL,
Packit Service fa4841
 * 	...
Packit Service fa4841
 * }
Packit Service fa4841
 *
Packit Service fa4841
 * SimpleNumericString ::= NumericString (SIZE (1..255)) (FROM ("0123456789"))
Packit Service fa4841
 *
Packit Service fa4841
 * UserData ::= SET OF SEQUENCE
Packit Service fa4841
 * {
Packit Service fa4841
 * 	key				Key,
Packit Service fa4841
 * 	value				OCTET_STRING OPTIONAL
Packit Service fa4841
 * }
Packit Service fa4841
 *
Packit Service fa4841
 * H221NonStandardIdentifier ::= OCTET STRING (SIZE (4..255))
Packit Service fa4841
 *
Packit Service fa4841
 * UserID ::= DynamicChannelID
Packit Service fa4841
 *
Packit Service fa4841
 * ChannelID ::= INTEGER (1..65535)
Packit Service fa4841
 * StaticChannelID ::= INTEGER (1..1000)
Packit Service fa4841
 * DynamicChannelID ::= INTEGER (1001..65535)
Packit Service fa4841
 *
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
/*
Packit Service fa4841
 * OID = 0.0.20.124.0.1
Packit Service fa4841
 * { itu-t(0) recommendation(0) t(20) t124(124) version(0) 1 }
Packit Service fa4841
 * v.1 of ITU-T Recommendation T.124 (Feb 1998): "Generic Conference Control"
Packit Service fa4841
 */
Packit Service fa4841
BYTE t124_02_98_oid[6] = { 0, 0, 20, 124, 0, 1 };
Packit Service fa4841
Packit Service fa4841
BYTE h221_cs_key[4] = "Duca";
Packit Service fa4841
BYTE h221_sc_key[4] = "McDn";
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Read a GCC Conference Create Request.\n
Packit Service fa4841
 * @msdn{cc240836}
Packit Service fa4841
 * @param s stream
Packit Service fa4841
 * @param settings rdp settings
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
BOOL gcc_read_conference_create_request(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	UINT16 length;
Packit Service fa4841
	BYTE choice;
Packit Service fa4841
	BYTE number;
Packit Service fa4841
	BYTE selection;
Packit Service fa4841
Packit Service fa4841
	/* ConnectData */
Packit Service fa4841
	if (!per_read_choice(s, &choice))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!per_read_object_identifier(s, t124_02_98_oid))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* ConnectData::connectPDU (OCTET_STRING) */
Packit Service fa4841
	if (!per_read_length(s, &length))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* ConnectGCCPDU */
Packit Service fa4841
	if (!per_read_choice(s, &choice))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!per_read_selection(s, &selection))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* ConferenceCreateRequest::conferenceName */
Packit Service fa4841
	if (!per_read_numeric_string(s, 1)) /* ConferenceName::numeric */
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!per_read_padding(s, 1)) /* padding */
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* UserData (SET OF SEQUENCE) */
Packit Service fa4841
	if (!per_read_number_of_sets(s, &number) || number != 1) /* one set of UserData */
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!per_read_choice(s, &choice) ||
Packit Service fa4841
	    choice != 0xC0) /* UserData::value present + select h221NonStandard (1) */
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* h221NonStandard */
Packit Service fa4841
	if (!per_read_octet_string(s, h221_cs_key, 4,
Packit Service fa4841
	                           4)) /* h221NonStandard, client-to-server H.221 key, "Duca" */
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* userData::value (OCTET_STRING) */
Packit Service fa4841
	if (!per_read_length(s, &length))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < length)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!gcc_read_client_data_blocks(s, mcs, length))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Write a GCC Conference Create Request.\n
Packit Service fa4841
 * @msdn{cc240836}
Packit Service fa4841
 * @param s stream
Packit Service fa4841
 * @param user_data client data blocks
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void gcc_write_conference_create_request(wStream* s, wStream* userData)
Packit Service fa4841
{
Packit Service fa4841
	/* ConnectData */
Packit Service fa4841
	per_write_choice(s, 0); /* From Key select object (0) of type OBJECT_IDENTIFIER */
Packit Service fa4841
	per_write_object_identifier(s, t124_02_98_oid); /* ITU-T T.124 (02/98) OBJECT_IDENTIFIER */
Packit Service fa4841
	/* ConnectData::connectPDU (OCTET_STRING) */
Packit Service fa4841
	per_write_length(s, Stream_GetPosition(userData) + 14); /* connectPDU length */
Packit Service fa4841
	/* ConnectGCCPDU */
Packit Service fa4841
	per_write_choice(s, 0);       /* From ConnectGCCPDU select conferenceCreateRequest (0) of type
Packit Service fa4841
	                                 ConferenceCreateRequest */
Packit Service fa4841
	per_write_selection(s, 0x08); /* select optional userData from ConferenceCreateRequest */
Packit Service fa4841
	/* ConferenceCreateRequest::conferenceName */
Packit Service fa4841
	per_write_numeric_string(s, (BYTE*)"1", 1, 1); /* ConferenceName::numeric */
Packit Service fa4841
	per_write_padding(s, 1);                       /* padding */
Packit Service fa4841
	/* UserData (SET OF SEQUENCE) */
Packit Service fa4841
	per_write_number_of_sets(s, 1); /* one set of UserData */
Packit Service fa4841
	per_write_choice(s, 0xC0);      /* UserData::value present + select h221NonStandard (1) */
Packit Service fa4841
	/* h221NonStandard */
Packit Service fa4841
	per_write_octet_string(s, h221_cs_key, 4,
Packit Service fa4841
	                       4); /* h221NonStandard, client-to-server H.221 key, "Duca" */
Packit Service fa4841
	/* userData::value (OCTET_STRING) */
Packit Service fa4841
	per_write_octet_string(s, Stream_Buffer(userData), Stream_GetPosition(userData),
Packit Service fa4841
	                       0); /* array of client data blocks */
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL gcc_read_conference_create_response(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	UINT16 length;
Packit Service fa4841
	UINT32 tag;
Packit Service fa4841
	UINT16 nodeID;
Packit Service fa4841
	BYTE result;
Packit Service fa4841
	BYTE choice;
Packit Service fa4841
	BYTE number;
Packit Service fa4841
Packit Service fa4841
	/* ConnectData */
Packit Service fa4841
	if (!per_read_choice(s, &choice) || !per_read_object_identifier(s, t124_02_98_oid))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* ConnectData::connectPDU (OCTET_STRING) */
Packit Service fa4841
	if (!per_read_length(s, &length))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* ConnectGCCPDU */
Packit Service fa4841
	if (!per_read_choice(s, &choice))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* ConferenceCreateResponse::nodeID (UserID) */
Packit Service fa4841
	if (!per_read_integer16(s, &nodeID, 1001))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* ConferenceCreateResponse::tag (INTEGER) */
Packit Service fa4841
	if (!per_read_integer(s, &tag))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* ConferenceCreateResponse::result (ENUMERATED) */
Packit Service fa4841
	if (!per_read_enumerated(s, &result, MCS_Result_enum_length))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* number of UserData sets */
Packit Service fa4841
	if (!per_read_number_of_sets(s, &number))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* UserData::value present + select h221NonStandard (1) */
Packit Service fa4841
	if (!per_read_choice(s, &choice))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* h221NonStandard */
Packit Service fa4841
	if (!per_read_octet_string(s, h221_sc_key, 4,
Packit Service fa4841
	                           4)) /* h221NonStandard, server-to-client H.221 key, "McDn" */
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* userData (OCTET_STRING) */
Packit Service fa4841
	if (!per_read_length(s, &length))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!gcc_read_server_data_blocks(s, mcs, length))
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "gcc_read_conference_create_response: gcc_read_server_data_blocks failed");
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void gcc_write_conference_create_response(wStream* s, wStream* userData)
Packit Service fa4841
{
Packit Service fa4841
	/* ConnectData */
Packit Service fa4841
	per_write_choice(s, 0);
Packit Service fa4841
	per_write_object_identifier(s, t124_02_98_oid);
Packit Service fa4841
	/* ConnectData::connectPDU (OCTET_STRING) */
Packit Service fa4841
	/* This length MUST be ignored by the client according to [MS-RDPBCGR] */
Packit Service fa4841
	per_write_length(s, 0x2A);
Packit Service fa4841
	/* ConnectGCCPDU */
Packit Service fa4841
	per_write_choice(s, 0x14);
Packit Service fa4841
	/* ConferenceCreateResponse::nodeID (UserID) */
Packit Service fa4841
	per_write_integer16(s, 0x79F3, 1001);
Packit Service fa4841
	/* ConferenceCreateResponse::tag (INTEGER) */
Packit Service fa4841
	per_write_integer(s, 1);
Packit Service fa4841
	/* ConferenceCreateResponse::result (ENUMERATED) */
Packit Service fa4841
	per_write_enumerated(s, 0, MCS_Result_enum_length);
Packit Service fa4841
	/* number of UserData sets */
Packit Service fa4841
	per_write_number_of_sets(s, 1);
Packit Service fa4841
	/* UserData::value present + select h221NonStandard (1) */
Packit Service fa4841
	per_write_choice(s, 0xC0);
Packit Service fa4841
	/* h221NonStandard */
Packit Service fa4841
	per_write_octet_string(s, h221_sc_key, 4,
Packit Service fa4841
	                       4); /* h221NonStandard, server-to-client H.221 key, "McDn" */
Packit Service fa4841
	/* userData (OCTET_STRING) */
Packit Service fa4841
	per_write_octet_string(s, Stream_Buffer(userData), Stream_GetPosition(userData),
Packit Service fa4841
	                       0); /* array of server data blocks */
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL gcc_read_client_data_blocks(wStream* s, rdpMcs* mcs, int length)
Packit Service fa4841
{
Packit Service fa4841
	UINT16 type;
Packit Service fa4841
	UINT16 blockLength;
Packit Service fa4841
	size_t begPos, endPos;
Packit Service fa4841
Packit Service fa4841
	while (length > 0)
Packit Service fa4841
	{
Packit Service fa4841
		begPos = Stream_GetPosition(s);
Packit Service fa4841
Packit Service fa4841
		if (!gcc_read_user_data_header(s, &type, &blockLength))
Packit Service fa4841
			return FALSE;
Packit Service fa4841
Packit Service fa4841
		if (Stream_GetRemainingLength(s) < (size_t)(blockLength - 4))
Packit Service fa4841
			return FALSE;
Packit Service fa4841
Packit Service fa4841
		switch (type)
Packit Service fa4841
		{
Packit Service fa4841
			case CS_CORE:
Packit Service fa4841
				if (!gcc_read_client_core_data(s, mcs, blockLength - 4))
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case CS_SECURITY:
Packit Service fa4841
				if (!gcc_read_client_security_data(s, mcs, blockLength - 4))
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case CS_NET:
Packit Service fa4841
				if (!gcc_read_client_network_data(s, mcs, blockLength - 4))
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case CS_CLUSTER:
Packit Service fa4841
				if (!gcc_read_client_cluster_data(s, mcs, blockLength - 4))
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case CS_MONITOR:
Packit Service fa4841
				if (!gcc_read_client_monitor_data(s, mcs, blockLength - 4))
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case CS_MCS_MSGCHANNEL:
Packit Service fa4841
				if (!gcc_read_client_message_channel_data(s, mcs, blockLength - 4))
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case CS_MONITOR_EX:
Packit Service fa4841
				if (!gcc_read_client_monitor_extended_data(s, mcs, blockLength - 4))
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case 0xC009:
Packit Service fa4841
			case CS_MULTITRANSPORT:
Packit Service fa4841
				if (!gcc_read_client_multitransport_channel_data(s, mcs, blockLength - 4))
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			default:
Packit Service fa4841
				WLog_ERR(TAG, "Unknown GCC client data block: 0x%04" PRIX16 "", type);
Packit Service fa4841
				Stream_Seek(s, blockLength - 4);
Packit Service fa4841
				break;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		endPos = Stream_GetPosition(s);
Packit Service fa4841
Packit Service fa4841
		if (endPos != (begPos + blockLength))
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG,
Packit Service fa4841
			         "Error parsing GCC client data block 0x%04" PRIX16
Packit Service fa4841
			         ": Actual Offset: %d Expected Offset: %d",
Packit Service fa4841
			         type, endPos, begPos + blockLength);
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		length -= blockLength;
Packit Service fa4841
		Stream_SetPosition(s, begPos + blockLength);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void gcc_write_client_data_blocks(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	rdpSettings* settings = mcs->settings;
Packit Service fa4841
	gcc_write_client_core_data(s, mcs);
Packit Service fa4841
	gcc_write_client_cluster_data(s, mcs);
Packit Service fa4841
	gcc_write_client_security_data(s, mcs);
Packit Service fa4841
	gcc_write_client_network_data(s, mcs);
Packit Service fa4841
Packit Service fa4841
	/* extended client data supported */
Packit Service fa4841
Packit Service fa4841
	if (settings->NegotiationFlags & EXTENDED_CLIENT_DATA_SUPPORTED)
Packit Service fa4841
	{
Packit Service fa4841
		if (settings->UseMultimon && !settings->SpanMonitors)
Packit Service fa4841
		{
Packit Service fa4841
			gcc_write_client_monitor_data(s, mcs);
Packit Service fa4841
			gcc_write_client_monitor_extended_data(s, mcs);
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		gcc_write_client_message_channel_data(s, mcs);
Packit Service fa4841
		gcc_write_client_multitransport_channel_data(s, mcs);
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		if (settings->UseMultimon && !settings->SpanMonitors)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "WARNING: true multi monitor support was not advertised by server!");
Packit Service fa4841
Packit Service fa4841
			if (settings->ForceMultimon)
Packit Service fa4841
			{
Packit Service fa4841
				WLog_ERR(TAG, "Sending multi monitor information anyway (may break connectivity!)");
Packit Service fa4841
				gcc_write_client_monitor_data(s, mcs);
Packit Service fa4841
				gcc_write_client_monitor_extended_data(s, mcs);
Packit Service fa4841
			}
Packit Service fa4841
			else
Packit Service fa4841
			{
Packit Service fa4841
				WLog_ERR(TAG, "Use /multimon:force to force sending multi monitor information");
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL gcc_read_server_data_blocks(wStream* s, rdpMcs* mcs, int length)
Packit Service fa4841
{
Packit Service fa4841
	UINT16 type;
Packit Service fa4841
	UINT16 offset = 0;
Packit Service fa4841
	UINT16 blockLength;
Packit Service fa4841
	BYTE* holdp;
Packit Service fa4841
Packit Service fa4841
	while (offset < length)
Packit Service fa4841
	{
Packit Service fa4841
		size_t rest;
Packit Service fa4841
		wStream sub;
Packit Service fa4841
Packit Service fa4841
		if (!gcc_read_user_data_header(s, &type, &blockLength))
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "gcc_read_server_data_blocks: gcc_read_user_data_header failed");
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
		holdp = Stream_Pointer(s);
Packit Service fa4841
		Stream_StaticInit(&sub, holdp, blockLength - 4);
Packit Service fa4841
		if (!Stream_SafeSeek(s, blockLength - 4))
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "gcc_read_server_data_blocks: stream too short");
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
		offset += blockLength;
Packit Service fa4841
Packit Service fa4841
		switch (type)
Packit Service fa4841
		{
Packit Service fa4841
			case SC_CORE:
Packit Service fa4841
				if (!gcc_read_server_core_data(&sub, mcs))
Packit Service fa4841
				{
Packit Service fa4841
					WLog_ERR(TAG, "gcc_read_server_data_blocks: gcc_read_server_core_data failed");
Packit Service fa4841
					return FALSE;
Packit Service fa4841
				}
Packit Service fa4841
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case SC_SECURITY:
Packit Service fa4841
				if (!gcc_read_server_security_data(&sub, mcs))
Packit Service fa4841
				{
Packit Service fa4841
					WLog_ERR(TAG,
Packit Service fa4841
					         "gcc_read_server_data_blocks: gcc_read_server_security_data failed");
Packit Service fa4841
					return FALSE;
Packit Service fa4841
				}
Packit Service fa4841
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case SC_NET:
Packit Service fa4841
				if (!gcc_read_server_network_data(&sub, mcs))
Packit Service fa4841
				{
Packit Service fa4841
					WLog_ERR(TAG,
Packit Service fa4841
					         "gcc_read_server_data_blocks: gcc_read_server_network_data failed");
Packit Service fa4841
					return FALSE;
Packit Service fa4841
				}
Packit Service fa4841
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case SC_MCS_MSGCHANNEL:
Packit Service fa4841
				if (!gcc_read_server_message_channel_data(&sub, mcs))
Packit Service fa4841
				{
Packit Service fa4841
					WLog_ERR(
Packit Service fa4841
					    TAG,
Packit Service fa4841
					    "gcc_read_server_data_blocks: gcc_read_server_message_channel_data failed");
Packit Service fa4841
					return FALSE;
Packit Service fa4841
				}
Packit Service fa4841
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case SC_MULTITRANSPORT:
Packit Service fa4841
				if (!gcc_read_server_multitransport_channel_data(&sub, mcs))
Packit Service fa4841
				{
Packit Service fa4841
					WLog_ERR(TAG, "gcc_read_server_data_blocks: "
Packit Service fa4841
					              "gcc_read_server_multitransport_channel_data failed");
Packit Service fa4841
					return FALSE;
Packit Service fa4841
				}
Packit Service fa4841
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			default:
Packit Service fa4841
				WLog_ERR(TAG, "gcc_read_server_data_blocks: ignoring type=%" PRIu16 "", type);
Packit Service fa4841
				break;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		rest = Stream_GetRemainingLength(&sub);
Packit Service fa4841
		if (rest > 0)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_WARN(
Packit Service fa4841
			    TAG, "gcc_read_server_data_blocks: ignoring %" PRIuz " bytes with type=%" PRIu16 "",
Packit Service fa4841
			    rest, type);
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL gcc_write_server_data_blocks(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	return gcc_write_server_core_data(s, mcs) &&          /* serverCoreData */
Packit Service fa4841
	       gcc_write_server_network_data(s, mcs) &&       /* serverNetworkData */
Packit Service fa4841
	       gcc_write_server_security_data(s, mcs) &&      /* serverSecurityData */
Packit Service fa4841
	       gcc_write_server_message_channel_data(s, mcs); /* serverMessageChannelData */
Packit Service fa4841
	/* TODO: Send these GCC data blocks only when the client sent them */
Packit Service fa4841
	// gcc_write_server_multitransport_channel_data(s, settings); /* serverMultitransportChannelData
Packit Service fa4841
	// */
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL gcc_read_user_data_header(wStream* s, UINT16* type, UINT16* length)
Packit Service fa4841
{
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < 4)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	Stream_Read_UINT16(s, *type);   /* type */
Packit Service fa4841
	Stream_Read_UINT16(s, *length); /* length */
Packit Service fa4841
Packit Service fa4841
	if ((*length < 4) || (Stream_GetRemainingLength(s) < (size_t)(*length - 4)))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Write a user data header (TS_UD_HEADER).\n
Packit Service fa4841
 * @msdn{cc240509}
Packit Service fa4841
 * @param s stream
Packit Service fa4841
 * @param type data block type
Packit Service fa4841
 * @param length data block length
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void gcc_write_user_data_header(wStream* s, UINT16 type, UINT16 length)
Packit Service fa4841
{
Packit Service fa4841
	Stream_Write_UINT16(s, type);   /* type */
Packit Service fa4841
	Stream_Write_UINT16(s, length); /* length */
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Read a client core data block (TS_UD_CS_CORE).\n
Packit Service fa4841
 * @msdn{cc240510}
Packit Service fa4841
 * @param s stream
Packit Service fa4841
 * @param settings rdp settings
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs, UINT16 blockLength)
Packit Service fa4841
{
Packit Service fa4841
	char* str = NULL;
Packit Service fa4841
	UINT32 version;
Packit Service fa4841
	BYTE connectionType = 0;
Packit Service fa4841
	UINT32 clientColorDepth;
Packit Service fa4841
	UINT16 colorDepth = 0;
Packit Service fa4841
	UINT16 postBeta2ColorDepth = 0;
Packit Service fa4841
	UINT16 highColorDepth = 0;
Packit Service fa4841
	UINT16 supportedColorDepths = 0;
Packit Service fa4841
	UINT32 serverSelectedProtocol = 0;
Packit Service fa4841
	UINT16 earlyCapabilityFlags = 0;
Packit Service fa4841
	rdpSettings* settings = mcs->settings;
Packit Service fa4841
Packit Service fa4841
	/* Length of all required fields, until imeFileName */
Packit Service fa4841
	if (blockLength < 128)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	Stream_Read_UINT32(s, version); /* version (4 bytes) */
Packit Service fa4841
	settings->RdpVersion = rdp_version_common(version, settings->RdpVersion);
Packit Service fa4841
	Stream_Read_UINT16(s, settings->DesktopWidth);  /* DesktopWidth (2 bytes) */
Packit Service fa4841
	Stream_Read_UINT16(s, settings->DesktopHeight); /* DesktopHeight (2 bytes) */
Packit Service fa4841
	Stream_Read_UINT16(s, colorDepth);              /* ColorDepth (2 bytes) */
Packit Service fa4841
	Stream_Seek_UINT16(s); /* SASSequence (Secure Access Sequence) (2 bytes) */
Packit Service fa4841
	Stream_Read_UINT32(s, settings->KeyboardLayout); /* KeyboardLayout (4 bytes) */
Packit Service fa4841
	Stream_Read_UINT32(s, settings->ClientBuild);    /* ClientBuild (4 bytes) */
Packit Service fa4841
Packit Service fa4841
	/* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
Packit Service fa4841
	if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)Stream_Pointer(s), 32 / 2, &str, 0, NULL, NULL) < 1)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "failed to convert client host name");
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	Stream_Seek(s, 32);
Packit Service fa4841
	free(settings->ClientHostname);
Packit Service fa4841
	settings->ClientHostname = str;
Packit Service fa4841
	str = NULL;
Packit Service fa4841
	Stream_Read_UINT32(s, settings->KeyboardType);        /* KeyboardType (4 bytes) */
Packit Service fa4841
	Stream_Read_UINT32(s, settings->KeyboardSubType);     /* KeyboardSubType (4 bytes) */
Packit Service fa4841
	Stream_Read_UINT32(s, settings->KeyboardFunctionKey); /* KeyboardFunctionKey (4 bytes) */
Packit Service fa4841
	Stream_Seek(s, 64);                                   /* imeFileName (64 bytes) */
Packit Service fa4841
	blockLength -= 128;
Packit Service fa4841
Packit Service fa4841
	/**
Packit Service fa4841
	 * The following fields are all optional. If one field is present, all of the preceding
Packit Service fa4841
	 * fields MUST also be present. If one field is not present, all of the subsequent fields
Packit Service fa4841
	 * MUST NOT be present.
Packit Service fa4841
	 * We must check the bytes left before reading each field.
Packit Service fa4841
	 */
Packit Service fa4841
Packit Service fa4841
	do
Packit Service fa4841
	{
Packit Service fa4841
		if (blockLength < 2)
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		Stream_Read_UINT16(s, postBeta2ColorDepth); /* postBeta2ColorDepth (2 bytes) */
Packit Service fa4841
		blockLength -= 2;
Packit Service fa4841
Packit Service fa4841
		if (blockLength < 2)
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		Stream_Seek_UINT16(s); /* clientProductID (2 bytes) */
Packit Service fa4841
		blockLength -= 2;
Packit Service fa4841
Packit Service fa4841
		if (blockLength < 4)
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		Stream_Seek_UINT32(s); /* serialNumber (4 bytes) */
Packit Service fa4841
		blockLength -= 4;
Packit Service fa4841
Packit Service fa4841
		if (blockLength < 2)
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		Stream_Read_UINT16(s, highColorDepth); /* highColorDepth (2 bytes) */
Packit Service fa4841
		blockLength -= 2;
Packit Service fa4841
Packit Service fa4841
		if (blockLength < 2)
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		Stream_Read_UINT16(s, supportedColorDepths); /* supportedColorDepths (2 bytes) */
Packit Service fa4841
		blockLength -= 2;
Packit Service fa4841
Packit Service fa4841
		if (blockLength < 2)
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		Stream_Read_UINT16(s, earlyCapabilityFlags); /* earlyCapabilityFlags (2 bytes) */
Packit Service fa4841
		settings->EarlyCapabilityFlags = (UINT32)earlyCapabilityFlags;
Packit Service fa4841
		blockLength -= 2;
Packit Service fa4841
Packit Service fa4841
		/* clientDigProductId (64 bytes): Contains a value that uniquely identifies the client */
Packit Service fa4841
Packit Service fa4841
		if (blockLength < 64)
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)Stream_Pointer(s), 64 / 2, &str, 0, NULL, NULL) <
Packit Service fa4841
		    1)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "failed to convert the client product identifier");
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		Stream_Seek(s, 64); /* clientDigProductId (64 bytes) */
Packit Service fa4841
		free(settings->ClientProductId);
Packit Service fa4841
		settings->ClientProductId = str;
Packit Service fa4841
		blockLength -= 64;
Packit Service fa4841
Packit Service fa4841
		if (blockLength < 1)
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		Stream_Read_UINT8(s, connectionType); /* connectionType (1 byte) */
Packit Service fa4841
		blockLength -= 1;
Packit Service fa4841
Packit Service fa4841
		if (blockLength < 1)
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		Stream_Seek_UINT8(s); /* pad1octet (1 byte) */
Packit Service fa4841
		blockLength -= 1;
Packit Service fa4841
Packit Service fa4841
		if (blockLength < 4)
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		Stream_Read_UINT32(s, serverSelectedProtocol); /* serverSelectedProtocol (4 bytes) */
Packit Service fa4841
		blockLength -= 4;
Packit Service fa4841
Packit Service fa4841
		if (blockLength < 4)
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		Stream_Read_UINT32(s, settings->DesktopPhysicalWidth); /* desktopPhysicalWidth (4 bytes) */
Packit Service fa4841
		blockLength -= 4;
Packit Service fa4841
Packit Service fa4841
		if (blockLength < 4)
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		Stream_Read_UINT32(s,
Packit Service fa4841
		                   settings->DesktopPhysicalHeight); /* desktopPhysicalHeight (4 bytes) */
Packit Service fa4841
		blockLength -= 4;
Packit Service fa4841
Packit Service fa4841
		if (blockLength < 2)
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		Stream_Read_UINT16(s, settings->DesktopOrientation); /* desktopOrientation (2 bytes) */
Packit Service fa4841
		blockLength -= 2;
Packit Service fa4841
Packit Service fa4841
		if (blockLength < 4)
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		Stream_Read_UINT32(s, settings->DesktopScaleFactor); /* desktopScaleFactor (4 bytes) */
Packit Service fa4841
		blockLength -= 4;
Packit Service fa4841
Packit Service fa4841
		if (blockLength < 4)
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		Stream_Read_UINT32(s, settings->DeviceScaleFactor); /* deviceScaleFactor (4 bytes) */
Packit Service fa4841
Packit Service fa4841
		if (settings->SelectedProtocol != serverSelectedProtocol)
Packit Service fa4841
			return FALSE;
Packit Service fa4841
	} while (0);
Packit Service fa4841
Packit Service fa4841
	if (highColorDepth > 0)
Packit Service fa4841
	{
Packit Service fa4841
		if (earlyCapabilityFlags & RNS_UD_CS_WANT_32BPP_SESSION)
Packit Service fa4841
			clientColorDepth = 32;
Packit Service fa4841
		else
Packit Service fa4841
			clientColorDepth = highColorDepth;
Packit Service fa4841
	}
Packit Service fa4841
	else if (postBeta2ColorDepth > 0)
Packit Service fa4841
	{
Packit Service fa4841
		switch (postBeta2ColorDepth)
Packit Service fa4841
		{
Packit Service fa4841
			case RNS_UD_COLOR_4BPP:
Packit Service fa4841
				clientColorDepth = 4;
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case RNS_UD_COLOR_8BPP:
Packit Service fa4841
				clientColorDepth = 8;
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case RNS_UD_COLOR_16BPP_555:
Packit Service fa4841
				clientColorDepth = 15;
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case RNS_UD_COLOR_16BPP_565:
Packit Service fa4841
				clientColorDepth = 16;
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case RNS_UD_COLOR_24BPP:
Packit Service fa4841
				clientColorDepth = 24;
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			default:
Packit Service fa4841
				return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		switch (colorDepth)
Packit Service fa4841
		{
Packit Service fa4841
			case RNS_UD_COLOR_4BPP:
Packit Service fa4841
				clientColorDepth = 4;
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case RNS_UD_COLOR_8BPP:
Packit Service fa4841
				clientColorDepth = 8;
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			default:
Packit Service fa4841
				return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/*
Packit Service fa4841
	 * If we are in server mode, accept client's color depth only if
Packit Service fa4841
	 * it is smaller than ours. This is what Windows server does.
Packit Service fa4841
	 */
Packit Service fa4841
	if ((clientColorDepth < settings->ColorDepth) || !settings->ServerMode)
Packit Service fa4841
		settings->ColorDepth = clientColorDepth;
Packit Service fa4841
Packit Service fa4841
	if (settings->NetworkAutoDetect)
Packit Service fa4841
		settings->NetworkAutoDetect =
Packit Service fa4841
		    (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_NETWORK_AUTODETECT) ? TRUE : FALSE;
Packit Service fa4841
Packit Service fa4841
	if (settings->SupportHeartbeatPdu)
Packit Service fa4841
		settings->SupportHeartbeatPdu =
Packit Service fa4841
		    (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_HEARTBEAT_PDU) ? TRUE : FALSE;
Packit Service fa4841
Packit Service fa4841
	if (settings->SupportGraphicsPipeline)
Packit Service fa4841
		settings->SupportGraphicsPipeline =
Packit Service fa4841
		    (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL) ? TRUE : FALSE;
Packit Service fa4841
Packit Service fa4841
	if (settings->SupportDynamicTimeZone)
Packit Service fa4841
		settings->SupportDynamicTimeZone =
Packit Service fa4841
		    (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE) ? TRUE : FALSE;
Packit Service fa4841
Packit Service fa4841
	if (settings->SupportMonitorLayoutPdu)
Packit Service fa4841
		settings->SupportMonitorLayoutPdu =
Packit Service fa4841
		    (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU) ? TRUE : FALSE;
Packit Service fa4841
Packit Service fa4841
	if (settings->SupportStatusInfoPdu)
Packit Service fa4841
		settings->SupportStatusInfoPdu =
Packit Service fa4841
		    (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_STATUSINFO_PDU) ? TRUE : FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!(earlyCapabilityFlags & RNS_UD_CS_VALID_CONNECTION_TYPE))
Packit Service fa4841
		connectionType = 0;
Packit Service fa4841
Packit Service fa4841
	settings->SupportErrorInfoPdu = earlyCapabilityFlags & RNS_UD_CS_SUPPORT_ERRINFO_PDU;
Packit Service fa4841
	settings->ConnectionType = connectionType;
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Write a client core data block (TS_UD_CS_CORE).\n
Packit Service fa4841
 * @msdn{cc240510}
Packit Service fa4841
 * @param s stream
Packit Service fa4841
 * @param settings rdp settings
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void gcc_write_client_core_data(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	WCHAR* clientName = NULL;
Packit Service fa4841
	int clientNameLength;
Packit Service fa4841
	BYTE connectionType;
Packit Service fa4841
	UINT16 highColorDepth;
Packit Service fa4841
	UINT16 supportedColorDepths;
Packit Service fa4841
	UINT16 earlyCapabilityFlags;
Packit Service fa4841
	WCHAR* clientDigProductId = NULL;
Packit Service fa4841
	int clientDigProductIdLength;
Packit Service fa4841
	rdpSettings* settings = mcs->settings;
Packit Service fa4841
	gcc_write_user_data_header(s, CS_CORE, 234);
Packit Service fa4841
	clientNameLength = ConvertToUnicode(CP_UTF8, 0, settings->ClientHostname, -1, &clientName, 0);
Packit Service fa4841
	clientDigProductIdLength =
Packit Service fa4841
	    ConvertToUnicode(CP_UTF8, 0, settings->ClientProductId, -1, &clientDigProductId, 0);
Packit Service fa4841
	Stream_Write_UINT32(s, settings->RdpVersion);    /* Version */
Packit Service fa4841
	Stream_Write_UINT16(s, settings->DesktopWidth);  /* DesktopWidth */
Packit Service fa4841
	Stream_Write_UINT16(s, settings->DesktopHeight); /* DesktopHeight */
Packit Service fa4841
	Stream_Write_UINT16(s,
Packit Service fa4841
	                    RNS_UD_COLOR_8BPP); /* ColorDepth, ignored because of postBeta2ColorDepth */
Packit Service fa4841
	Stream_Write_UINT16(s, RNS_UD_SAS_DEL); /* SASSequence (Secure Access Sequence) */
Packit Service fa4841
	Stream_Write_UINT32(s, settings->KeyboardLayout); /* KeyboardLayout */
Packit Service fa4841
	Stream_Write_UINT32(s, settings->ClientBuild);    /* ClientBuild */
Packit Service fa4841
Packit Service fa4841
	/* clientName (32 bytes, null-terminated unicode, truncated to 15 characters) */
Packit Service fa4841
Packit Service fa4841
	if (clientNameLength >= 16)
Packit Service fa4841
	{
Packit Service fa4841
		clientNameLength = 16;
Packit Service fa4841
		clientName[clientNameLength - 1] = 0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	Stream_Write(s, clientName, (clientNameLength * 2));
Packit Service fa4841
	Stream_Zero(s, 32 - (clientNameLength * 2));
Packit Service fa4841
	free(clientName);
Packit Service fa4841
	Stream_Write_UINT32(s, settings->KeyboardType);        /* KeyboardType */
Packit Service fa4841
	Stream_Write_UINT32(s, settings->KeyboardSubType);     /* KeyboardSubType */
Packit Service fa4841
	Stream_Write_UINT32(s, settings->KeyboardFunctionKey); /* KeyboardFunctionKey */
Packit Service fa4841
	Stream_Zero(s, 64);                                    /* imeFileName */
Packit Service fa4841
	Stream_Write_UINT16(s, RNS_UD_COLOR_8BPP);             /* postBeta2ColorDepth */
Packit Service fa4841
	Stream_Write_UINT16(s, 1);                             /* clientProductID */
Packit Service fa4841
	Stream_Write_UINT32(s, 0); /* serialNumber (should be initialized to 0) */
Packit Service fa4841
	highColorDepth = MIN(settings->ColorDepth, 24);
Packit Service fa4841
	supportedColorDepths = RNS_UD_24BPP_SUPPORT | RNS_UD_16BPP_SUPPORT | RNS_UD_15BPP_SUPPORT;
Packit Service fa4841
	earlyCapabilityFlags = RNS_UD_CS_SUPPORT_ERRINFO_PDU;
Packit Service fa4841
Packit Service fa4841
	if (settings->NetworkAutoDetect)
Packit Service fa4841
		settings->ConnectionType = CONNECTION_TYPE_AUTODETECT;
Packit Service fa4841
Packit Service fa4841
	if (settings->RemoteFxCodec && !settings->NetworkAutoDetect)
Packit Service fa4841
		settings->ConnectionType = CONNECTION_TYPE_LAN;
Packit Service fa4841
Packit Service fa4841
	connectionType = settings->ConnectionType;
Packit Service fa4841
Packit Service fa4841
	if (connectionType)
Packit Service fa4841
		earlyCapabilityFlags |= RNS_UD_CS_VALID_CONNECTION_TYPE;
Packit Service fa4841
Packit Service fa4841
	if (settings->ColorDepth == 32)
Packit Service fa4841
	{
Packit Service fa4841
		supportedColorDepths |= RNS_UD_32BPP_SUPPORT;
Packit Service fa4841
		earlyCapabilityFlags |= RNS_UD_CS_WANT_32BPP_SESSION;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (settings->NetworkAutoDetect)
Packit Service fa4841
		earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_NETWORK_AUTODETECT;
Packit Service fa4841
Packit Service fa4841
	if (settings->SupportHeartbeatPdu)
Packit Service fa4841
		earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_HEARTBEAT_PDU;
Packit Service fa4841
Packit Service fa4841
	if (settings->SupportGraphicsPipeline)
Packit Service fa4841
		earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL;
Packit Service fa4841
Packit Service fa4841
	if (settings->SupportDynamicTimeZone)
Packit Service fa4841
		earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE;
Packit Service fa4841
Packit Service fa4841
	if (settings->SupportMonitorLayoutPdu)
Packit Service fa4841
		earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU;
Packit Service fa4841
Packit Service fa4841
	if (settings->SupportStatusInfoPdu)
Packit Service fa4841
		earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_STATUSINFO_PDU;
Packit Service fa4841
Packit Service fa4841
	Stream_Write_UINT16(s, highColorDepth);       /* highColorDepth */
Packit Service fa4841
	Stream_Write_UINT16(s, supportedColorDepths); /* supportedColorDepths */
Packit Service fa4841
	Stream_Write_UINT16(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
Packit Service fa4841
Packit Service fa4841
	/* clientDigProductId (64 bytes, null-terminated unicode, truncated to 31 characters) */
Packit Service fa4841
	if (clientDigProductIdLength >= 32)
Packit Service fa4841
	{
Packit Service fa4841
		clientDigProductIdLength = 32;
Packit Service fa4841
		clientDigProductId[clientDigProductIdLength - 1] = 0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	Stream_Write(s, clientDigProductId, (clientDigProductIdLength * 2));
Packit Service fa4841
	Stream_Zero(s, 64 - (clientDigProductIdLength * 2));
Packit Service fa4841
	free(clientDigProductId);
Packit Service fa4841
	Stream_Write_UINT8(s, connectionType);                   /* connectionType */
Packit Service fa4841
	Stream_Write_UINT8(s, 0);                                /* pad1octet */
Packit Service fa4841
	Stream_Write_UINT32(s, settings->SelectedProtocol);      /* serverSelectedProtocol */
Packit Service fa4841
	Stream_Write_UINT32(s, settings->DesktopPhysicalWidth);  /* desktopPhysicalWidth */
Packit Service fa4841
	Stream_Write_UINT32(s, settings->DesktopPhysicalHeight); /* desktopPhysicalHeight */
Packit Service fa4841
	Stream_Write_UINT16(s, settings->DesktopOrientation);    /* desktopOrientation */
Packit Service fa4841
	Stream_Write_UINT32(s, settings->DesktopScaleFactor);    /* desktopScaleFactor */
Packit Service fa4841
	Stream_Write_UINT32(s, settings->DeviceScaleFactor);     /* deviceScaleFactor */
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL gcc_read_server_core_data(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 serverVersion;
Packit Service fa4841
	UINT32 clientRequestedProtocols;
Packit Service fa4841
	UINT32 earlyCapabilityFlags;
Packit Service fa4841
	rdpSettings* settings = mcs->settings;
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < 4)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	Stream_Read_UINT32(s, serverVersion); /* version */
Packit Service fa4841
	settings->RdpVersion = rdp_version_common(serverVersion, settings->RdpVersion);
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) >= 4)
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Read_UINT32(s, clientRequestedProtocols); /* clientRequestedProtocols */
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) >= 4)
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Read_UINT32(s, earlyCapabilityFlags); /* earlyCapabilityFlags */
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL gcc_write_server_core_data(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 earlyCapabilityFlags = 0;
Packit Service fa4841
	rdpSettings* settings = mcs->settings;
Packit Service fa4841
Packit Service fa4841
	if (!Stream_EnsureRemainingCapacity(s, 20))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	gcc_write_user_data_header(s, SC_CORE, 16);
Packit Service fa4841
Packit Service fa4841
	if (settings->SupportDynamicTimeZone)
Packit Service fa4841
		earlyCapabilityFlags |= RNS_UD_SC_DYNAMIC_DST_SUPPORTED;
Packit Service fa4841
Packit Service fa4841
	Stream_Write_UINT32(s, settings->RdpVersion);         /* version (4 bytes) */
Packit Service fa4841
	Stream_Write_UINT32(s, settings->RequestedProtocols); /* clientRequestedProtocols (4 bytes) */
Packit Service fa4841
	Stream_Write_UINT32(s, earlyCapabilityFlags);         /* earlyCapabilityFlags (4 bytes) */
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Read a client security data block (TS_UD_CS_SEC).\n
Packit Service fa4841
 * @msdn{cc240511}
Packit Service fa4841
 * @param s stream
Packit Service fa4841
 * @param settings rdp settings
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
BOOL gcc_read_client_security_data(wStream* s, rdpMcs* mcs, UINT16 blockLength)
Packit Service fa4841
{
Packit Service fa4841
	rdpSettings* settings = mcs->settings;
Packit Service fa4841
Packit Service fa4841
	if (blockLength < 8)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (settings->UseRdpSecurityLayer)
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Read_UINT32(s, settings->EncryptionMethods); /* encryptionMethods */
Packit Service fa4841
Packit Service fa4841
		if (settings->EncryptionMethods == 0)
Packit Service fa4841
			Stream_Read_UINT32(s, settings->EncryptionMethods); /* extEncryptionMethods */
Packit Service fa4841
		else
Packit Service fa4841
			Stream_Seek(s, 4);
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Seek(s, 8);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Write a client security data block (TS_UD_CS_SEC).\n
Packit Service fa4841
 * @msdn{cc240511}
Packit Service fa4841
 * @param s stream
Packit Service fa4841
 * @param settings rdp settings
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void gcc_write_client_security_data(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	rdpSettings* settings = mcs->settings;
Packit Service fa4841
	gcc_write_user_data_header(s, CS_SECURITY, 12);
Packit Service fa4841
Packit Service fa4841
	if (settings->UseRdpSecurityLayer)
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Write_UINT32(s, settings->EncryptionMethods); /* encryptionMethods */
Packit Service fa4841
		Stream_Write_UINT32(s, 0);                           /* extEncryptionMethods */
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		/* French locale, disable encryption */
Packit Service fa4841
		Stream_Write_UINT32(s, 0);                           /* encryptionMethods */
Packit Service fa4841
		Stream_Write_UINT32(s, settings->EncryptionMethods); /* extEncryptionMethods */
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL gcc_read_server_security_data(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	BYTE* data;
Packit Service fa4841
	UINT32 length;
Packit Service fa4841
	rdpSettings* settings = mcs->settings;
Packit Service fa4841
	BOOL validCryptoConfig = FALSE;
Packit Service fa4841
	UINT32 serverEncryptionMethod;
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < 8)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	Stream_Read_UINT32(s, serverEncryptionMethod);    /* encryptionMethod */
Packit Service fa4841
	Stream_Read_UINT32(s, settings->EncryptionLevel); /* encryptionLevel */
Packit Service fa4841
Packit Service fa4841
	/* Only accept valid/known encryption methods */
Packit Service fa4841
	switch (serverEncryptionMethod)
Packit Service fa4841
	{
Packit Service fa4841
		case ENCRYPTION_METHOD_NONE:
Packit Service fa4841
			WLog_DBG(TAG, "Server rdp encryption method: NONE");
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case ENCRYPTION_METHOD_40BIT:
Packit Service fa4841
			WLog_DBG(TAG, "Server rdp encryption method: 40BIT");
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case ENCRYPTION_METHOD_56BIT:
Packit Service fa4841
			WLog_DBG(TAG, "Server rdp encryption method: 56BIT");
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case ENCRYPTION_METHOD_128BIT:
Packit Service fa4841
			WLog_DBG(TAG, "Server rdp encryption method: 128BIT");
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case ENCRYPTION_METHOD_FIPS:
Packit Service fa4841
			WLog_DBG(TAG, "Server rdp encryption method: FIPS");
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		default:
Packit Service fa4841
			WLog_ERR(TAG, "Received unknown encryption method %08" PRIX32 "",
Packit Service fa4841
			         serverEncryptionMethod);
Packit Service fa4841
			return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (settings->UseRdpSecurityLayer && !(settings->EncryptionMethods & serverEncryptionMethod))
Packit Service fa4841
	{
Packit Service fa4841
		WLog_WARN(TAG, "Server uses non-advertised encryption method 0x%08" PRIX32 "",
Packit Service fa4841
		          serverEncryptionMethod);
Packit Service fa4841
		/* FIXME: Should we return FALSE; in this case ?? */
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	settings->EncryptionMethods = serverEncryptionMethod;
Packit Service fa4841
Packit Service fa4841
	/* Verify encryption level/method combinations according to MS-RDPBCGR Section 5.3.2 */
Packit Service fa4841
	switch (settings->EncryptionLevel)
Packit Service fa4841
	{
Packit Service fa4841
		case ENCRYPTION_LEVEL_NONE:
Packit Service fa4841
			if (settings->EncryptionMethods == ENCRYPTION_METHOD_NONE)
Packit Service fa4841
			{
Packit Service fa4841
				validCryptoConfig = TRUE;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case ENCRYPTION_LEVEL_FIPS:
Packit Service fa4841
			if (settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
Packit Service fa4841
			{
Packit Service fa4841
				validCryptoConfig = TRUE;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case ENCRYPTION_LEVEL_LOW:
Packit Service fa4841
		case ENCRYPTION_LEVEL_HIGH:
Packit Service fa4841
		case ENCRYPTION_LEVEL_CLIENT_COMPATIBLE:
Packit Service fa4841
			if (settings->EncryptionMethods == ENCRYPTION_METHOD_40BIT ||
Packit Service fa4841
			    settings->EncryptionMethods == ENCRYPTION_METHOD_56BIT ||
Packit Service fa4841
			    settings->EncryptionMethods == ENCRYPTION_METHOD_128BIT ||
Packit Service fa4841
			    settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
Packit Service fa4841
			{
Packit Service fa4841
				validCryptoConfig = TRUE;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		default:
Packit Service fa4841
			WLog_ERR(TAG, "Received unknown encryption level 0x%08" PRIX32 "",
Packit Service fa4841
			         settings->EncryptionLevel);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (!validCryptoConfig)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG,
Packit Service fa4841
		         "Received invalid cryptographic configuration (level=0x%08" PRIX32
Packit Service fa4841
		         " method=0x%08" PRIX32 ")",
Packit Service fa4841
		         settings->EncryptionLevel, settings->EncryptionMethods);
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (settings->EncryptionLevel == ENCRYPTION_LEVEL_NONE)
Packit Service fa4841
	{
Packit Service fa4841
		/* serverRandomLen and serverCertLen must not be present */
Packit Service fa4841
		settings->UseRdpSecurityLayer = FALSE;
Packit Service fa4841
		return TRUE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < 8)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	Stream_Read_UINT32(s, settings->ServerRandomLength);      /* serverRandomLen */
Packit Service fa4841
	Stream_Read_UINT32(s, settings->ServerCertificateLength); /* serverCertLen */
Packit Service fa4841
Packit Service fa4841
	if ((settings->ServerRandomLength == 0) || (settings->ServerCertificateLength == 0))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < settings->ServerRandomLength)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* serverRandom */
Packit Service fa4841
	settings->ServerRandom = (BYTE*)malloc(settings->ServerRandomLength);
Packit Service fa4841
Packit Service fa4841
	if (!settings->ServerRandom)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	Stream_Read(s, settings->ServerRandom, settings->ServerRandomLength);
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < settings->ServerCertificateLength)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	/* serverCertificate */
Packit Service fa4841
	settings->ServerCertificate = (BYTE*)malloc(settings->ServerCertificateLength);
Packit Service fa4841
Packit Service fa4841
	if (!settings->ServerCertificate)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	Stream_Read(s, settings->ServerCertificate, settings->ServerCertificateLength);
Packit Service fa4841
	certificate_free(settings->RdpServerCertificate);
Packit Service fa4841
	settings->RdpServerCertificate = certificate_new();
Packit Service fa4841
Packit Service fa4841
	if (!settings->RdpServerCertificate)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	data = settings->ServerCertificate;
Packit Service fa4841
	length = settings->ServerCertificateLength;
Packit Service fa4841
Packit Service fa4841
	if (!certificate_read_server_certificate(settings->RdpServerCertificate, data, length))
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
fail:
Packit Service fa4841
	free(settings->ServerRandom);
Packit Service fa4841
	free(settings->ServerCertificate);
Packit Service fa4841
	settings->ServerRandom = NULL;
Packit Service fa4841
	settings->ServerCertificate = NULL;
Packit Service fa4841
	return FALSE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static const BYTE initial_signature[] = {
Packit Service fa4841
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Packit Service fa4841
	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Packit Service fa4841
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Packit Service fa4841
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01
Packit Service fa4841
};
Packit Service fa4841
Packit Service fa4841
/*
Packit Service fa4841
 * Terminal Services Signing Keys.
Packit Service fa4841
 * Yes, Terminal Services Private Key is publicly available.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
const BYTE tssk_modulus[] = { 0x3d, 0x3a, 0x5e, 0xbd, 0x72, 0x43, 0x3e, 0xc9, 0x4d, 0xbb, 0xc1,
Packit Service fa4841
	                          0x1e, 0x4a, 0xba, 0x5f, 0xcb, 0x3e, 0x88, 0x20, 0x87, 0xef, 0xf5,
Packit Service fa4841
	                          0xc1, 0xe2, 0xd7, 0xb7, 0x6b, 0x9a, 0xf2, 0x52, 0x45, 0x95, 0xce,
Packit Service fa4841
	                          0x63, 0x65, 0x6b, 0x58, 0x3a, 0xfe, 0xef, 0x7c, 0xe7, 0xbf, 0xfe,
Packit Service fa4841
	                          0x3d, 0xf6, 0x5c, 0x7d, 0x6c, 0x5e, 0x06, 0x09, 0x1a, 0xf5, 0x61,
Packit Service fa4841
	                          0xbb, 0x20, 0x93, 0x09, 0x5f, 0x05, 0x6d, 0xea, 0x87 };
Packit Service fa4841
Packit Service fa4841
const BYTE tssk_privateExponent[] = {
Packit Service fa4841
	0x87, 0xa7, 0x19, 0x32, 0xda, 0x11, 0x87, 0x55, 0x58, 0x00, 0x16, 0x16, 0x25, 0x65, 0x68, 0xf8,
Packit Service fa4841
	0x24, 0x3e, 0xe6, 0xfa, 0xe9, 0x67, 0x49, 0x94, 0xcf, 0x92, 0xcc, 0x33, 0x99, 0xe8, 0x08, 0x60,
Packit Service fa4841
	0x17, 0x9a, 0x12, 0x9f, 0x24, 0xdd, 0xb1, 0x24, 0x99, 0xc7, 0x3a, 0xb8, 0x0a, 0x7b, 0x0d, 0xdd,
Packit Service fa4841
	0x35, 0x07, 0x79, 0x17, 0x0b, 0x51, 0x9b, 0xb3, 0xc7, 0x10, 0x01, 0x13, 0xe7, 0x3f, 0xf3, 0x5f
Packit Service fa4841
};
Packit Service fa4841
Packit Service fa4841
const BYTE tssk_exponent[] = { 0x5b, 0x7b, 0x88, 0xc0 };
Packit Service fa4841
Packit Service fa4841
BOOL gcc_write_server_security_data(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	BYTE* sigData;
Packit Service fa4841
	int expLen, keyLen, sigDataLen;
Packit Service fa4841
	BYTE encryptedSignature[TSSK_KEY_LENGTH];
Packit Service fa4841
	BYTE signature[sizeof(initial_signature)];
Packit Service fa4841
	UINT32 headerLen, serverRandomLen, serverCertLen, wPublicKeyBlobLen;
Packit Service fa4841
	rdpSettings* settings = mcs->settings;
Packit Service fa4841
Packit Service fa4841
	/**
Packit Service fa4841
	 * Re: settings->EncryptionLevel:
Packit Service fa4841
	 * This is configured/set by the server implementation and serves the same
Packit Service fa4841
	 * purpose as the "Encryption Level" setting in the RDP-Tcp configuration
Packit Service fa4841
	 * dialog of Microsoft's Remote Desktop Session Host Configuration.
Packit Service fa4841
	 * Re: settings->EncryptionMethods:
Packit Service fa4841
	 * at this point this setting contains the client's supported encryption
Packit Service fa4841
	 * methods we've received in gcc_read_client_security_data()
Packit Service fa4841
	 */
Packit Service fa4841
Packit Service fa4841
	if (!settings->UseRdpSecurityLayer)
Packit Service fa4841
	{
Packit Service fa4841
		/* TLS/NLA is used: disable rdp style encryption */
Packit Service fa4841
		settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/* verify server encryption level value */
Packit Service fa4841
	switch (settings->EncryptionLevel)
Packit Service fa4841
	{
Packit Service fa4841
		case ENCRYPTION_LEVEL_NONE:
Packit Service fa4841
			WLog_INFO(TAG, "Active rdp encryption level: NONE");
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case ENCRYPTION_LEVEL_FIPS:
Packit Service fa4841
			WLog_INFO(TAG, "Active rdp encryption level: FIPS Compliant");
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case ENCRYPTION_LEVEL_HIGH:
Packit Service fa4841
			WLog_INFO(TAG, "Active rdp encryption level: HIGH");
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case ENCRYPTION_LEVEL_LOW:
Packit Service fa4841
			WLog_INFO(TAG, "Active rdp encryption level: LOW");
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case ENCRYPTION_LEVEL_CLIENT_COMPATIBLE:
Packit Service fa4841
			WLog_INFO(TAG, "Active rdp encryption level: CLIENT-COMPATIBLE");
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		default:
Packit Service fa4841
			WLog_ERR(TAG, "Invalid server encryption level 0x%08" PRIX32 "",
Packit Service fa4841
			         settings->EncryptionLevel);
Packit Service fa4841
			WLog_ERR(TAG, "Switching to encryption level CLIENT-COMPATIBLE");
Packit Service fa4841
			settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/* choose rdp encryption method based on server level and client methods */
Packit Service fa4841
	switch (settings->EncryptionLevel)
Packit Service fa4841
	{
Packit Service fa4841
		case ENCRYPTION_LEVEL_NONE:
Packit Service fa4841
			/* The only valid method is NONE in this case */
Packit Service fa4841
			settings->EncryptionMethods = ENCRYPTION_METHOD_NONE;
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case ENCRYPTION_LEVEL_FIPS:
Packit Service fa4841
Packit Service fa4841
			/* The only valid method is FIPS in this case */
Packit Service fa4841
			if (!(settings->EncryptionMethods & ENCRYPTION_METHOD_FIPS))
Packit Service fa4841
			{
Packit Service fa4841
				WLog_WARN(TAG, "client does not support FIPS as required by server configuration");
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			settings->EncryptionMethods = ENCRYPTION_METHOD_FIPS;
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case ENCRYPTION_LEVEL_HIGH:
Packit Service fa4841
Packit Service fa4841
			/* Maximum key strength supported by the server must be used (128 bit)*/
Packit Service fa4841
			if (!(settings->EncryptionMethods & ENCRYPTION_METHOD_128BIT))
Packit Service fa4841
			{
Packit Service fa4841
				WLog_WARN(TAG, "client does not support 128 bit encryption method as required by "
Packit Service fa4841
				               "server configuration");
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			settings->EncryptionMethods = ENCRYPTION_METHOD_128BIT;
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case ENCRYPTION_LEVEL_LOW:
Packit Service fa4841
		case ENCRYPTION_LEVEL_CLIENT_COMPATIBLE:
Packit Service fa4841
Packit Service fa4841
			/* Maximum key strength supported by the client must be used */
Packit Service fa4841
			if (settings->EncryptionMethods & ENCRYPTION_METHOD_128BIT)
Packit Service fa4841
				settings->EncryptionMethods = ENCRYPTION_METHOD_128BIT;
Packit Service fa4841
			else if (settings->EncryptionMethods & ENCRYPTION_METHOD_56BIT)
Packit Service fa4841
				settings->EncryptionMethods = ENCRYPTION_METHOD_56BIT;
Packit Service fa4841
			else if (settings->EncryptionMethods & ENCRYPTION_METHOD_40BIT)
Packit Service fa4841
				settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT;
Packit Service fa4841
			else if (settings->EncryptionMethods & ENCRYPTION_METHOD_FIPS)
Packit Service fa4841
				settings->EncryptionMethods = ENCRYPTION_METHOD_FIPS;
Packit Service fa4841
			else
Packit Service fa4841
			{
Packit Service fa4841
				WLog_WARN(TAG, "client has not announced any supported encryption methods");
Packit Service fa4841
				settings->EncryptionMethods = ENCRYPTION_METHOD_128BIT;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		default:
Packit Service fa4841
			WLog_ERR(TAG, "internal error: unknown encryption level");
Packit Service fa4841
			return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/* log selected encryption method */
Packit Service fa4841
	switch (settings->EncryptionMethods)
Packit Service fa4841
	{
Packit Service fa4841
		case ENCRYPTION_METHOD_NONE:
Packit Service fa4841
			WLog_INFO(TAG, "Selected rdp encryption method: NONE");
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case ENCRYPTION_METHOD_40BIT:
Packit Service fa4841
			WLog_INFO(TAG, "Selected rdp encryption method: 40BIT");
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case ENCRYPTION_METHOD_56BIT:
Packit Service fa4841
			WLog_INFO(TAG, "Selected rdp encryption method: 56BIT");
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case ENCRYPTION_METHOD_128BIT:
Packit Service fa4841
			WLog_INFO(TAG, "Selected rdp encryption method: 128BIT");
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case ENCRYPTION_METHOD_FIPS:
Packit Service fa4841
			WLog_INFO(TAG, "Selected rdp encryption method: FIPS");
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		default:
Packit Service fa4841
			WLog_ERR(TAG, "internal error: unknown encryption method");
Packit Service fa4841
			return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	headerLen = 12;
Packit Service fa4841
	keyLen = 0;
Packit Service fa4841
	wPublicKeyBlobLen = 0;
Packit Service fa4841
	serverRandomLen = 0;
Packit Service fa4841
	serverCertLen = 0;
Packit Service fa4841
Packit Service fa4841
	if (settings->EncryptionMethods != ENCRYPTION_METHOD_NONE)
Packit Service fa4841
	{
Packit Service fa4841
		serverRandomLen = 32;
Packit Service fa4841
		keyLen = settings->RdpServerRsaKey->ModulusLength;
Packit Service fa4841
		expLen = sizeof(settings->RdpServerRsaKey->exponent);
Packit Service fa4841
		wPublicKeyBlobLen = 4;  /* magic (RSA1) */
Packit Service fa4841
		wPublicKeyBlobLen += 4; /* keylen */
Packit Service fa4841
		wPublicKeyBlobLen += 4; /* bitlen */
Packit Service fa4841
		wPublicKeyBlobLen += 4; /* datalen */
Packit Service fa4841
		wPublicKeyBlobLen += expLen;
Packit Service fa4841
		wPublicKeyBlobLen += keyLen;
Packit Service fa4841
		wPublicKeyBlobLen += 8; /* 8 bytes of zero padding */
Packit Service fa4841
		serverCertLen = 4;      /* dwVersion */
Packit Service fa4841
		serverCertLen += 4;     /* dwSigAlgId */
Packit Service fa4841
		serverCertLen += 4;     /* dwKeyAlgId */
Packit Service fa4841
		serverCertLen += 2;     /* wPublicKeyBlobType */
Packit Service fa4841
		serverCertLen += 2;     /* wPublicKeyBlobLen */
Packit Service fa4841
		serverCertLen += wPublicKeyBlobLen;
Packit Service fa4841
		serverCertLen += 2;                          /* wSignatureBlobType */
Packit Service fa4841
		serverCertLen += 2;                          /* wSignatureBlobLen */
Packit Service fa4841
		serverCertLen += sizeof(encryptedSignature); /* SignatureBlob */
Packit Service fa4841
		serverCertLen += 8;                          /* 8 bytes of zero padding */
Packit Service fa4841
		headerLen += sizeof(serverRandomLen);
Packit Service fa4841
		headerLen += sizeof(serverCertLen);
Packit Service fa4841
		headerLen += serverRandomLen;
Packit Service fa4841
		headerLen += serverCertLen;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (!Stream_EnsureRemainingCapacity(s, headerLen + 4))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	gcc_write_user_data_header(s, SC_SECURITY, headerLen);
Packit Service fa4841
	Stream_Write_UINT32(s, settings->EncryptionMethods); /* encryptionMethod */
Packit Service fa4841
	Stream_Write_UINT32(s, settings->EncryptionLevel);   /* encryptionLevel */
Packit Service fa4841
Packit Service fa4841
	if (settings->EncryptionMethods == ENCRYPTION_METHOD_NONE)
Packit Service fa4841
	{
Packit Service fa4841
		return TRUE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	Stream_Write_UINT32(s, serverRandomLen); /* serverRandomLen */
Packit Service fa4841
	Stream_Write_UINT32(s, serverCertLen);   /* serverCertLen */
Packit Service fa4841
	settings->ServerRandomLength = serverRandomLen;
Packit Service fa4841
	settings->ServerRandom = (BYTE*)malloc(serverRandomLen);
Packit Service fa4841
Packit Service fa4841
	if (!settings->ServerRandom)
Packit Service fa4841
	{
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	winpr_RAND(settings->ServerRandom, serverRandomLen);
Packit Service fa4841
	Stream_Write(s, settings->ServerRandom, serverRandomLen);
Packit Service fa4841
	sigData = Stream_Pointer(s);
Packit Service fa4841
	Stream_Write_UINT32(s, CERT_CHAIN_VERSION_1); /* dwVersion (4 bytes) */
Packit Service fa4841
	Stream_Write_UINT32(s, SIGNATURE_ALG_RSA);    /* dwSigAlgId */
Packit Service fa4841
	Stream_Write_UINT32(s, KEY_EXCHANGE_ALG_RSA); /* dwKeyAlgId */
Packit Service fa4841
	Stream_Write_UINT16(s, BB_RSA_KEY_BLOB);      /* wPublicKeyBlobType */
Packit Service fa4841
	Stream_Write_UINT16(s, wPublicKeyBlobLen);    /* wPublicKeyBlobLen */
Packit Service fa4841
	Stream_Write(s, "RSA1", 4);                   /* magic */
Packit Service fa4841
	Stream_Write_UINT32(s, keyLen + 8);           /* keylen */
Packit Service fa4841
	Stream_Write_UINT32(s, keyLen * 8);           /* bitlen */
Packit Service fa4841
	Stream_Write_UINT32(s, keyLen - 1);           /* datalen */
Packit Service fa4841
	Stream_Write(s, settings->RdpServerRsaKey->exponent, expLen);
Packit Service fa4841
	Stream_Write(s, settings->RdpServerRsaKey->Modulus, keyLen);
Packit Service fa4841
	Stream_Zero(s, 8);
Packit Service fa4841
	sigDataLen = Stream_Pointer(s) - sigData;
Packit Service fa4841
	Stream_Write_UINT16(s, BB_RSA_SIGNATURE_BLOB);          /* wSignatureBlobType */
Packit Service fa4841
	Stream_Write_UINT16(s, sizeof(encryptedSignature) + 8); /* wSignatureBlobLen */
Packit Service fa4841
	memcpy(signature, initial_signature, sizeof(initial_signature));
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Digest(WINPR_MD_MD5, sigData, sigDataLen, signature, sizeof(signature)))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	crypto_rsa_private_encrypt(signature, sizeof(signature), TSSK_KEY_LENGTH, tssk_modulus,
Packit Service fa4841
	                           tssk_privateExponent, encryptedSignature);
Packit Service fa4841
	Stream_Write(s, encryptedSignature, sizeof(encryptedSignature));
Packit Service fa4841
	Stream_Zero(s, 8);
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Read a client network data block (TS_UD_CS_NET).\n
Packit Service fa4841
 * @msdn{cc240512}
Packit Service fa4841
 * @param s stream
Packit Service fa4841
 * @param settings rdp settings
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
BOOL gcc_read_client_network_data(wStream* s, rdpMcs* mcs, UINT16 blockLength)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 i;
Packit Service fa4841
Packit Service fa4841
	if (blockLength < 4)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	Stream_Read_UINT32(s, mcs->channelCount); /* channelCount */
Packit Service fa4841
Packit Service fa4841
	if (blockLength < 4 + mcs->channelCount * 12)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (mcs->channelCount > CHANNEL_MAX_COUNT)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* channelDefArray */
Packit Service fa4841
	for (i = 0; i < mcs->channelCount; i++)
Packit Service fa4841
	{
Packit Service fa4841
		/**
Packit Service fa4841
		 * CHANNEL_DEF
Packit Service fa4841
		 * - name: an 8-byte array containing a null-terminated collection
Packit Service fa4841
		 *   of seven ANSI characters that uniquely identify the channel.
Packit Service fa4841
		 * - options: a 32-bit, unsigned integer. Channel option flags
Packit Service fa4841
		 */
Packit Service fa4841
		Stream_Read(s, mcs->channels[i].Name, 8); /* name (8 bytes) */
Packit Service fa4841
Packit Service fa4841
		if (!memchr(mcs->channels[i].Name, 0, 8))
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(
Packit Service fa4841
			    TAG,
Packit Service fa4841
			    "protocol violation: received a static channel name with missing null-termination");
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		Stream_Read_UINT32(s, mcs->channels[i].options); /* options (4 bytes) */
Packit Service fa4841
		mcs->channels[i].ChannelId = mcs->baseChannelId++;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Write a client network data block (TS_UD_CS_NET).\n
Packit Service fa4841
 * @msdn{cc240512}
Packit Service fa4841
 * @param s stream
Packit Service fa4841
 * @param settings rdp settings
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void gcc_write_client_network_data(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 i;
Packit Service fa4841
	UINT16 length;
Packit Service fa4841
Packit Service fa4841
	if (mcs->channelCount > 0)
Packit Service fa4841
	{
Packit Service fa4841
		length = mcs->channelCount * 12 + 8;
Packit Service fa4841
		gcc_write_user_data_header(s, CS_NET, length);
Packit Service fa4841
		Stream_Write_UINT32(s, mcs->channelCount); /* channelCount */
Packit Service fa4841
Packit Service fa4841
		/* channelDefArray */
Packit Service fa4841
		for (i = 0; i < mcs->channelCount; i++)
Packit Service fa4841
		{
Packit Service fa4841
			/* CHANNEL_DEF */
Packit Service fa4841
			Stream_Write(s, mcs->channels[i].Name, 8);        /* name (8 bytes) */
Packit Service fa4841
			Stream_Write_UINT32(s, mcs->channels[i].options); /* options (4 bytes) */
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL gcc_read_server_network_data(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	int i;
Packit Service fa4841
	UINT16 channelId;
Packit Service fa4841
	UINT16 MCSChannelId;
Packit Service fa4841
	UINT16 channelCount;
Packit Service fa4841
	UINT16 parsedChannelCount;
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < 4)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	Stream_Read_UINT16(s, MCSChannelId); /* MCSChannelId */
Packit Service fa4841
	Stream_Read_UINT16(s, channelCount); /* channelCount */
Packit Service fa4841
	parsedChannelCount = channelCount;
Packit Service fa4841
Packit Service fa4841
	if (channelCount != mcs->channelCount)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "requested %" PRIu32 " channels, got %" PRIu16 " instead", mcs->channelCount,
Packit Service fa4841
		         channelCount);
Packit Service fa4841
Packit Service fa4841
		/* we ensure that the response is not bigger than the request */
Packit Service fa4841
Packit Service fa4841
		if (channelCount > mcs->channelCount)
Packit Service fa4841
			parsedChannelCount = mcs->channelCount;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < (size_t)channelCount * 2)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	for (i = 0; i < parsedChannelCount; i++)
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Read_UINT16(s, channelId); /* channelId */
Packit Service fa4841
		mcs->channels[i].ChannelId = channelId;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (channelCount % 2 == 1)
Packit Service fa4841
		return Stream_SafeSeek(s, 2); /* padding */
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL gcc_write_server_network_data(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 i;
Packit Service fa4841
	int payloadLen = 8 + mcs->channelCount * 2 + (mcs->channelCount % 2 == 1 ? 2 : 0);
Packit Service fa4841
Packit Service fa4841
	if (!Stream_EnsureRemainingCapacity(s, payloadLen + 4))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	gcc_write_user_data_header(s, SC_NET, payloadLen);
Packit Service fa4841
	Stream_Write_UINT16(s, MCS_GLOBAL_CHANNEL_ID); /* MCSChannelId */
Packit Service fa4841
	Stream_Write_UINT16(s, mcs->channelCount);     /* channelCount */
Packit Service fa4841
Packit Service fa4841
	for (i = 0; i < mcs->channelCount; i++)
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Write_UINT16(s, mcs->channels[i].ChannelId);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (mcs->channelCount % 2 == 1)
Packit Service fa4841
		Stream_Write_UINT16(s, 0);
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Read a client cluster data block (TS_UD_CS_CLUSTER).\n
Packit Service fa4841
 * @msdn{cc240514}
Packit Service fa4841
 * @param s stream
Packit Service fa4841
 * @param settings rdp settings
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
BOOL gcc_read_client_cluster_data(wStream* s, rdpMcs* mcs, UINT16 blockLength)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 flags;
Packit Service fa4841
	UINT32 redirectedSessionId;
Packit Service fa4841
	rdpSettings* settings = mcs->settings;
Packit Service fa4841
Packit Service fa4841
	if (blockLength < 8)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	Stream_Read_UINT32(s, flags);               /* flags */
Packit Service fa4841
	Stream_Read_UINT32(s, redirectedSessionId); /* redirectedSessionId */
Packit Service fa4841
Packit Service fa4841
	if (flags & REDIRECTED_SESSIONID_FIELD_VALID)
Packit Service fa4841
		settings->RedirectedSessionId = redirectedSessionId;
Packit Service fa4841
Packit Service fa4841
	if (blockLength != 8)
Packit Service fa4841
	{
Packit Service fa4841
		if (Stream_GetRemainingLength(s) >= (size_t)(blockLength - 8))
Packit Service fa4841
		{
Packit Service fa4841
			/* The old Microsoft Mac RDP client can send a pad here */
Packit Service fa4841
			Stream_Seek(s, (blockLength - 8));
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Write a client cluster data block (TS_UD_CS_CLUSTER).\n
Packit Service fa4841
 * @msdn{cc240514}
Packit Service fa4841
 * @param s stream
Packit Service fa4841
 * @param settings rdp settings
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void gcc_write_client_cluster_data(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 flags;
Packit Service fa4841
	rdpSettings* settings = mcs->settings;
Packit Service fa4841
	gcc_write_user_data_header(s, CS_CLUSTER, 12);
Packit Service fa4841
	flags = REDIRECTION_SUPPORTED | (REDIRECTION_VERSION4 << 2);
Packit Service fa4841
Packit Service fa4841
	if (settings->ConsoleSession || settings->RedirectedSessionId)
Packit Service fa4841
		flags |= REDIRECTED_SESSIONID_FIELD_VALID;
Packit Service fa4841
Packit Service fa4841
	if (settings->RedirectSmartCards)
Packit Service fa4841
		flags |= REDIRECTED_SMARTCARD;
Packit Service fa4841
Packit Service fa4841
	Stream_Write_UINT32(s, flags);                         /* flags */
Packit Service fa4841
	Stream_Write_UINT32(s, settings->RedirectedSessionId); /* redirectedSessionID */
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Read a client monitor data block (TS_UD_CS_MONITOR).\n
Packit Service fa4841
 * @msdn{dd305336}
Packit Service fa4841
 * @param s stream
Packit Service fa4841
 * @param settings rdp settings
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
BOOL gcc_read_client_monitor_data(wStream* s, rdpMcs* mcs, UINT16 blockLength)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 index;
Packit Service fa4841
	UINT32 flags;
Packit Service fa4841
	UINT32 monitorCount;
Packit Service fa4841
	UINT32 left, top, right, bottom;
Packit Service fa4841
	rdpSettings* settings = mcs->settings;
Packit Service fa4841
Packit Service fa4841
	if (blockLength < 8)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	Stream_Read_UINT32(s, flags);        /* flags */
Packit Service fa4841
	Stream_Read_UINT32(s, monitorCount); /* monitorCount */
Packit Service fa4841
Packit Service fa4841
	/* 2.2.1.3.6 Client Monitor Data -
Packit Service fa4841
	 * monitorCount (4 bytes): A 32-bit, unsigned integer. The number of display
Packit Service fa4841
	 * monitor definitions in the monitorDefArray field (the maximum allowed is 16).
Packit Service fa4841
	 */
Packit Service fa4841
	if (monitorCount > 16)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "announced monitors(%" PRIu32 ") exceed the 16 limit", monitorCount);
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (monitorCount > settings->MonitorDefArraySize)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "too many announced monitors(%" PRIu32 "), clamping to %" PRIu32 "",
Packit Service fa4841
		         monitorCount, settings->MonitorDefArraySize);
Packit Service fa4841
		monitorCount = settings->MonitorDefArraySize;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if ((UINT32)((blockLength - 8) / 20) < monitorCount)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	settings->MonitorCount = monitorCount;
Packit Service fa4841
Packit Service fa4841
	for (index = 0; index < monitorCount; index++)
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Read_UINT32(s, left);   /* left */
Packit Service fa4841
		Stream_Read_UINT32(s, top);    /* top */
Packit Service fa4841
		Stream_Read_UINT32(s, right);  /* right */
Packit Service fa4841
		Stream_Read_UINT32(s, bottom); /* bottom */
Packit Service fa4841
		Stream_Read_UINT32(s, flags);  /* flags */
Packit Service fa4841
		settings->MonitorDefArray[index].x = left;
Packit Service fa4841
		settings->MonitorDefArray[index].y = top;
Packit Service fa4841
		settings->MonitorDefArray[index].width = right - left + 1;
Packit Service fa4841
		settings->MonitorDefArray[index].height = bottom - top + 1;
Packit Service fa4841
		settings->MonitorDefArray[index].is_primary = (flags & MONITOR_PRIMARY);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Write a client monitor data block (TS_UD_CS_MONITOR).\n
Packit Service fa4841
 * @msdn{dd305336}
Packit Service fa4841
 * @param s stream
Packit Service fa4841
 * @param settings rdp settings
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void gcc_write_client_monitor_data(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 i;
Packit Service fa4841
	UINT16 length;
Packit Service fa4841
	UINT32 left, top, right, bottom, flags;
Packit Service fa4841
	INT32 baseX = 0, baseY = 0;
Packit Service fa4841
	rdpSettings* settings = mcs->settings;
Packit Service fa4841
Packit Service fa4841
	if (settings->MonitorCount > 1)
Packit Service fa4841
	{
Packit Service fa4841
		length = (20 * settings->MonitorCount) + 12;
Packit Service fa4841
		gcc_write_user_data_header(s, CS_MONITOR, length);
Packit Service fa4841
		Stream_Write_UINT32(s, 0);                      /* flags */
Packit Service fa4841
		Stream_Write_UINT32(s, settings->MonitorCount); /* monitorCount */
Packit Service fa4841
Packit Service fa4841
		/* first pass to get the primary monitor coordinates (it is supposed to be
Packit Service fa4841
		 * in (0,0) */
Packit Service fa4841
		for (i = 0; i < settings->MonitorCount; i++)
Packit Service fa4841
		{
Packit Service fa4841
			if (settings->MonitorDefArray[i].is_primary)
Packit Service fa4841
			{
Packit Service fa4841
				baseX = settings->MonitorDefArray[i].x;
Packit Service fa4841
				baseY = settings->MonitorDefArray[i].y;
Packit Service fa4841
				break;
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		for (i = 0; i < settings->MonitorCount; i++)
Packit Service fa4841
		{
Packit Service fa4841
			left = settings->MonitorDefArray[i].x - baseX;
Packit Service fa4841
			top = settings->MonitorDefArray[i].y - baseY;
Packit Service fa4841
			right = left + settings->MonitorDefArray[i].width - 1;
Packit Service fa4841
			bottom = top + settings->MonitorDefArray[i].height - 1;
Packit Service fa4841
			flags = settings->MonitorDefArray[i].is_primary ? MONITOR_PRIMARY : 0;
Packit Service fa4841
			Stream_Write_UINT32(s, left);   /* left */
Packit Service fa4841
			Stream_Write_UINT32(s, top);    /* top */
Packit Service fa4841
			Stream_Write_UINT32(s, right);  /* right */
Packit Service fa4841
			Stream_Write_UINT32(s, bottom); /* bottom */
Packit Service fa4841
			Stream_Write_UINT32(s, flags);  /* flags */
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL gcc_read_client_monitor_extended_data(wStream* s, rdpMcs* mcs, UINT16 blockLength)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 index;
Packit Service fa4841
	UINT32 flags;
Packit Service fa4841
	UINT32 monitorCount;
Packit Service fa4841
	UINT32 monitorAttributeSize;
Packit Service fa4841
	rdpSettings* settings = mcs->settings;
Packit Service fa4841
Packit Service fa4841
	if (blockLength < 12)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	Stream_Read_UINT32(s, flags);                /* flags */
Packit Service fa4841
	Stream_Read_UINT32(s, monitorAttributeSize); /* monitorAttributeSize */
Packit Service fa4841
	Stream_Read_UINT32(s, monitorCount);         /* monitorCount */
Packit Service fa4841
Packit Service fa4841
	if (monitorAttributeSize != 20)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if ((blockLength - 12) / monitorAttributeSize < monitorCount)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (settings->MonitorCount != monitorCount)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	settings->HasMonitorAttributes = TRUE;
Packit Service fa4841
Packit Service fa4841
	for (index = 0; index < monitorCount; index++)
Packit Service fa4841
	{
Packit Service fa4841
		Stream_Read_UINT32(
Packit Service fa4841
		    s, settings->MonitorDefArray[index].attributes.physicalWidth); /* physicalWidth */
Packit Service fa4841
		Stream_Read_UINT32(
Packit Service fa4841
		    s, settings->MonitorDefArray[index].attributes.physicalHeight); /* physicalHeight */
Packit Service fa4841
		Stream_Read_UINT32(
Packit Service fa4841
		    s, settings->MonitorDefArray[index].attributes.orientation); /* orientation */
Packit Service fa4841
		Stream_Read_UINT32(s, settings->MonitorDefArray[index]
Packit Service fa4841
		                          .attributes.desktopScaleFactor); /* desktopScaleFactor */
Packit Service fa4841
		Stream_Read_UINT32(
Packit Service fa4841
		    s,
Packit Service fa4841
		    settings->MonitorDefArray[index].attributes.deviceScaleFactor); /* deviceScaleFactor */
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void gcc_write_client_monitor_extended_data(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 i;
Packit Service fa4841
	UINT16 length;
Packit Service fa4841
	rdpSettings* settings = mcs->settings;
Packit Service fa4841
Packit Service fa4841
	if (settings->HasMonitorAttributes)
Packit Service fa4841
	{
Packit Service fa4841
		length = (20 * settings->MonitorCount) + 16;
Packit Service fa4841
		gcc_write_user_data_header(s, CS_MONITOR_EX, length);
Packit Service fa4841
		Stream_Write_UINT32(s, 0);                      /* flags */
Packit Service fa4841
		Stream_Write_UINT32(s, 20);                     /* monitorAttributeSize */
Packit Service fa4841
		Stream_Write_UINT32(s, settings->MonitorCount); /* monitorCount */
Packit Service fa4841
Packit Service fa4841
		for (i = 0; i < settings->MonitorCount; i++)
Packit Service fa4841
		{
Packit Service fa4841
			Stream_Write_UINT32(
Packit Service fa4841
			    s, settings->MonitorDefArray[i].attributes.physicalWidth); /* physicalWidth */
Packit Service fa4841
			Stream_Write_UINT32(
Packit Service fa4841
			    s, settings->MonitorDefArray[i].attributes.physicalHeight); /* physicalHeight */
Packit Service fa4841
			Stream_Write_UINT32(
Packit Service fa4841
			    s, settings->MonitorDefArray[i].attributes.orientation); /* orientation */
Packit Service fa4841
			Stream_Write_UINT32(s, settings->MonitorDefArray[i]
Packit Service fa4841
			                           .attributes.desktopScaleFactor); /* desktopScaleFactor */
Packit Service fa4841
			Stream_Write_UINT32(
Packit Service fa4841
			    s,
Packit Service fa4841
			    settings->MonitorDefArray[i].attributes.deviceScaleFactor); /* deviceScaleFactor */
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Read a client message channel data block (TS_UD_CS_MCS_MSGCHANNEL).\n
Packit Service fa4841
 * @msdn{jj217627}
Packit Service fa4841
 * @param s stream
Packit Service fa4841
 * @param settings rdp settings
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
BOOL gcc_read_client_message_channel_data(wStream* s, rdpMcs* mcs, UINT16 blockLength)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 flags;
Packit Service fa4841
Packit Service fa4841
	if (blockLength < 4)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	Stream_Read_UINT32(s, flags);
Packit Service fa4841
	mcs->messageChannelId = mcs->baseChannelId++;
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Write a client message channel data block (TS_UD_CS_MCS_MSGCHANNEL).\n
Packit Service fa4841
 * @msdn{jj217627}
Packit Service fa4841
 * @param s stream
Packit Service fa4841
 * @param settings rdp settings
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void gcc_write_client_message_channel_data(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	rdpSettings* settings = mcs->settings;
Packit Service fa4841
Packit Service fa4841
	if (settings->NetworkAutoDetect || settings->SupportHeartbeatPdu ||
Packit Service fa4841
	    settings->SupportMultitransport)
Packit Service fa4841
	{
Packit Service fa4841
		gcc_write_user_data_header(s, CS_MCS_MSGCHANNEL, 8);
Packit Service fa4841
		Stream_Write_UINT32(s, 0); /* flags */
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL gcc_read_server_message_channel_data(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	UINT16 MCSChannelId;
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < 2)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	Stream_Read_UINT16(s, MCSChannelId); /* MCSChannelId */
Packit Service fa4841
	/* Save the MCS message channel id */
Packit Service fa4841
	mcs->messageChannelId = MCSChannelId;
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL gcc_write_server_message_channel_data(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	if (mcs->messageChannelId == 0)
Packit Service fa4841
		return TRUE;
Packit Service fa4841
Packit Service fa4841
	if (!Stream_EnsureRemainingCapacity(s, 2 + 4))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	gcc_write_user_data_header(s, SC_MCS_MSGCHANNEL, 6);
Packit Service fa4841
	Stream_Write_UINT16(s, mcs->messageChannelId); /* mcsChannelId (2 bytes) */
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Read a client multitransport channel data block (TS_UD_CS_MULTITRANSPORT).\n
Packit Service fa4841
 * @msdn{jj217498}
Packit Service fa4841
 * @param s stream
Packit Service fa4841
 * @param settings rdp settings
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
BOOL gcc_read_client_multitransport_channel_data(wStream* s, rdpMcs* mcs, UINT16 blockLength)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 flags;
Packit Service fa4841
Packit Service fa4841
	if (blockLength < 4)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	Stream_Read_UINT32(s, flags);
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Write a client multitransport channel data block (TS_UD_CS_MULTITRANSPORT).\n
Packit Service fa4841
 * @msdn{jj217498}
Packit Service fa4841
 * @param s stream
Packit Service fa4841
 * @param settings rdp settings
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void gcc_write_client_multitransport_channel_data(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	rdpSettings* settings = mcs->settings;
Packit Service fa4841
Packit Service fa4841
	gcc_write_user_data_header(s, CS_MULTITRANSPORT, 8);
Packit Service fa4841
	Stream_Write_UINT32(s, settings->MultitransportFlags); /* flags */
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL gcc_read_server_multitransport_channel_data(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 flags;
Packit Service fa4841
Packit Service fa4841
	if (Stream_GetRemainingLength(s) < 4)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	Stream_Read_UINT32(s, flags); /* flags */
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void gcc_write_server_multitransport_channel_data(wStream* s, rdpMcs* mcs)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 flags = 0;
Packit Service fa4841
	gcc_write_user_data_header(s, SC_MULTITRANSPORT, 8);
Packit Service fa4841
	Stream_Write_UINT32(s, flags); /* flags (4 bytes) */
Packit Service fa4841
}