Blame libfreerdp/core/gcc.c

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