xrdp/libxrdp/xrdp_mcs.c
matt335672 8fdc1ba216 Relaxed Channel Join PDU requirements for non-TLS
Windows 10 RDS is quite relaxed about missing channel join PDUs,
whereas we have to adhere quite tightly to the specification to
make sure we get a TLS "Client hello" where appropriate. This makes
us incompatible with older RDP clients. For example, the Wyse sx0
thin client does not send a channel join PDU for the user channel.
Older, non-TLS versions of xrdp supported these devices.

This commit re-implements the xrdp v0.6.1 behaviour for non-TLS
connections only, allowing system administrators to use these devices
on trusted networks. These devices are in any case too old to
establish a modern TLS connection.
2022-05-18 12:18:23 +01:00

1546 lines
50 KiB
C

/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Jay Sorg 2004-2014
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* mcs layer which implements the Multipoint Communication Service protocol as
* specified in [ITU-T T.125]
*/
#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif
#include "libxrdp.h"
#include "ms-rdpbcgr.h"
#include "log.h"
/* Forward references */
static int
handle_non_tls_client_channel_join_requests(struct xrdp_mcs *self,
struct stream *s, int *appid);
/*****************************************************************************/
struct xrdp_mcs *
xrdp_mcs_create(struct xrdp_sec *owner, struct trans *trans,
struct stream *client_mcs_data,
struct stream *server_mcs_data)
{
struct xrdp_mcs *self;
self = (struct xrdp_mcs *)g_malloc(sizeof(struct xrdp_mcs), 1);
self->sec_layer = owner;
self->userid = 1;
self->chanid = 1001;
self->client_mcs_data = client_mcs_data;
self->server_mcs_data = server_mcs_data;
self->iso_layer = xrdp_iso_create(self, trans);
self->channel_list = list_create();
return self;
}
/*****************************************************************************/
void
xrdp_mcs_delete(struct xrdp_mcs *self)
{
struct mcs_channel_item *channel_item;
int index;
int count;
if (self == 0)
{
return;
}
/* here we have to free the channel items and anything in them */
count = self->channel_list->count;
for (index = count - 1; index >= 0; index--)
{
channel_item = (struct mcs_channel_item *)
list_get_item(self->channel_list, index);
g_free(channel_item);
}
list_delete(self->channel_list);
xrdp_iso_delete(self->iso_layer);
/* make sure we get null pointer exception if struct is used again. */
LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mcs_delete processed");
g_memset(self, 0, sizeof(struct xrdp_mcs)) ;
g_free(self);
}
/*****************************************************************************/
/* Send an [ITU-T T.125] DomainMCSPDU message with type ChannelJoinConfirm */
/* returns error = 1 ok = 0 */
static int
xrdp_mcs_send_cjcf(struct xrdp_mcs *self, int userid, int chanid)
{
struct stream *s;
make_stream(s);
init_stream(s, 8192);
if (xrdp_iso_init(self->iso_layer, s) != 0)
{
free_stream(s);
LOG(LOG_LEVEL_ERROR, "xrdp_mcs_send_cjcf: xrdp_iso_init failed");
return 1;
}
/* The DomainMCSPDU choice index is a 6-bit int with the next bit as the
bit field of the two optional fields in the struct (channelId, nonStandard)
*/
out_uint8(s, (MCS_CJCF << 2) | 0x02); /* DomainMCSPDU choice index,
channelId field is present,
nonStandard field is not present */
out_uint8(s, 0); /* result choice index 0 = rt-successful */
out_uint16_be(s, userid); /* initiator */
out_uint16_be(s, chanid); /* requested */
out_uint16_be(s, chanid); /* channelId (OPTIONAL) */
s_mark_end(s);
LOG_DEVEL(LOG_LEVEL_TRACE, "Sending [ITU-T T.125] ChannelJoinConfirm "
"result SUCCESS, initiator %d, requested %d, "
"channelId %d", userid, chanid, chanid);
if (xrdp_iso_send(self->iso_layer, s) != 0)
{
free_stream(s);
LOG(LOG_LEVEL_ERROR, "Sening [ITU-T T.125] ChannelJoinConfirm failed");
return 1;
}
free_stream(s);
return 0;
}
/*****************************************************************************/
/* Reads the header of a DomainMCSPDU and gets the appid
*
* @return 0 for success */
static int
get_domain_mcs_pdu_header(struct xrdp_mcs *self, struct stream *s, int *appid)
{
int opcode;
if (xrdp_iso_recv(self->iso_layer, s) != 0)
{
LOG(LOG_LEVEL_ERROR, "xrdp_mcs_recv: xrdp_iso_recv failed");
return 1;
}
if (!s_check_rem_and_log(s, 1, "Parsing [ITU-T T.125] DomainMCSPDU"))
{
return 1;
}
/* The DomainMCSPDU choice index is a 6-bit int with the 2 least
significant bits of the byte as padding */
in_uint8(s, opcode);
*appid = opcode >> 2; /* 2-bit padding */
LOG_DEVEL(LOG_LEVEL_TRACE,
"Received [ITU-T T.125] DomainMCSPDU choice index %d", *appid);
return 0;
}
/*****************************************************************************/
/*
* Processes an [ITU-T T.125] DomainMCSPDU message.
*
* Note: DomainMCSPDU messages use the ALIGNED BASIC-PER (Packed Encoding Rules)
* from [ITU-T X.691].
*
* returns error
*/
int
xrdp_mcs_recv(struct xrdp_mcs *self, struct stream *s, int *chan)
{
int appid;
int len;
if (get_domain_mcs_pdu_header(self, s, &appid) != 0)
{
return 1;
}
if (self->expecting_channel_join_requests)
{
if (handle_non_tls_client_channel_join_requests(self, s, &appid) != 0)
{
return 1;
}
LOG(LOG_LEVEL_DEBUG, "[MCS Connection Sequence] completed");
self->expecting_channel_join_requests = 0;
}
if (appid == MCS_DPUM) /* Disconnect Provider Ultimatum */
{
LOG_DEVEL(LOG_LEVEL_TRACE,
"Received [ITU-T T.125] DisconnectProviderUltimatum");
LOG(LOG_LEVEL_DEBUG, "Recieved disconnection request");
return 1;
}
if (appid != MCS_SDRQ)
{
LOG(LOG_LEVEL_ERROR, "Received [ITU-T T.125] DomainMCSPDU "
"choice index %d is unknown. Expected the DomainMCSPDU to "
"contain the type SendDataRequest with index %d",
appid, MCS_SDRQ);
return 1;
}
if (!s_check_rem_and_log(s, 6, "Parsing [ITU-T T.125] SendDataRequest"))
{
return 1;
}
in_uint8s(s, 2); /* initiator */
in_uint16_be(s, *chan); /* channelId */
in_uint8s(s, 1); /* dataPriority (4-bits), segmentation (2-bits), padding (2-bits) */
in_uint8(s, len); /* userData Length (byte 1) */
if ((len & 0xC0) == 0x80)
{
/* From [ITU-T X.691] 11.9.3.7
encoding a length determinant if "n" is greater than 127 and
less than 16K, then n is encoded using 2 bytes.
The first byte will have the two highest order bits set to 1 and 0
(ie. len & 0xC0 == 0x80) and the length is encoded as remaining 14 bits of
the two bytes (ie. len & 0x3fff). */
if (!s_check_rem_and_log(s, 1, "Parsing [ITU-T T.125] SendDataRequest userData Length"))
{
return 1;
}
in_uint8s(s, 1); /* userData Length (byte 2) */
}
else if ((len & 0xC0) == 0xC0)
{
/* From [ITU-T X.691] 11.9.3.8
encoding a length determinant if "n" is greater than 16K,
then the list of items is fragmented with the length of the first
fragment encoded using 1 byte. The two highest order bits are set
to 1 and 1 (ie. len & 0xC0 == 0xC0) and the remaining 6 bits contain
a multiplyer for 16K (ie. n = (len & 0x3f) * 0x3f)
*/
LOG(LOG_LEVEL_ERROR, "[ITU-T T.125] SendDataRequest with length greater "
"than 16K is not supported. len 0x%2.2x", len);
return 1;
}
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [ITU-T T.125] SendDataRequest "
"initiator (ignored), channelId %d, dataPriority (ignored), "
"segmentation (ignored), userData Length (ignored)", *chan);
return 0;
}
/*****************************************************************************/
/**
* Parse the identifier and length of a [ITU-T X.690] BER (Basic Encoding Rules)
* structure header.
*
* @param self
* @param s [in] - the stream to read from
* @param tag_val [in] - the expected tag value
* @param len [out] - the length of the structure
* @returns error
*/
static int
xrdp_mcs_ber_parse_header(struct xrdp_mcs *self, struct stream *s,
int tag_val, int *len)
{
int tag;
int l;
int i;
if (tag_val > 0xff)
{
if (!s_check_rem_and_log(s, 2, "Parsing [ITU-T X.690] Identifier"))
{
return 1;
}
in_uint16_be(s, tag);
}
else
{
if (!s_check_rem_and_log(s, 1, "Parsing [ITU-T X.690] Identifier"))
{
return 1;
}
in_uint8(s, tag);
}
if (tag != tag_val)
{
LOG(LOG_LEVEL_ERROR, "Parsed [ITU-T X.690] Identifier: "
"expected 0x%4.4x, actual 0x%4.4x", tag_val, tag);
return 1;
}
if (!s_check_rem_and_log(s, 1, "Parsing [ITU-T X.690] Length"))
{
return 1;
}
in_uint8(s, l);
if (l & 0x80)
{
l = l & ~0x80;
*len = 0;
while (l > 0)
{
if (!s_check_rem_and_log(s, 1, "Parsing [ITU-T X.690] Length"))
{
return 1;
}
in_uint8(s, i);
*len = (*len << 8) | i;
l--;
}
}
else
{
*len = l;
}
LOG_DEVEL(LOG_LEVEL_TRACE, "Parsed BER header [ITU-T X.690] "
"Identifier 0x%4.4x, Length %d", tag, *len);
return 0;
}
/*****************************************************************************/
/* Parses a [ITU-T T.125] DomainParameters structure encoded using BER */
/* returns error */
static int
xrdp_mcs_parse_domain_params(struct xrdp_mcs *self, struct stream *s)
{
int len;
if (xrdp_mcs_ber_parse_header(self, s, MCS_TAG_DOMAIN_PARAMS, &len) != 0)
{
LOG(LOG_LEVEL_ERROR,
"Parsing [ITU-T T.125] DomainParameters failed");
return 1;
}
if (len < 0)
{
LOG(LOG_LEVEL_ERROR,
"Parsing [ITU-T T.125] DomainParameters length field is "
"invalid. Expected >= 0, actual %d", len);
return 1;
}
if (!s_check_rem_and_log(s, len, "Parsing [ITU-T T.125] DomainParameters"))
{
return 1;
}
in_uint8s(s, len); /* skip all fields */
return !s_check_rem_and_log(s, 0, "Parsing [ITU-T T.125] DomainParameters");
}
/*****************************************************************************/
/* Process a [ITU-T T.125] Connect-Initial message encoded using BER */
/* returns error */
static int
xrdp_mcs_recv_connect_initial(struct xrdp_mcs *self)
{
int len;
struct stream *s;
s = libxrdp_force_read(self->iso_layer->trans);
if (s == 0)
{
LOG(LOG_LEVEL_ERROR, "Processing [ITU-T T.125] Connect-Initial failed");
return 1;
}
if (xrdp_iso_recv(self->iso_layer, s) != 0)
{
LOG(LOG_LEVEL_ERROR, "Processing [ITU-T T.125] Connect-Initial failed");
return 1;
}
if (xrdp_mcs_ber_parse_header(self, s, MCS_CONNECT_INITIAL, &len) != 0)
{
LOG(LOG_LEVEL_ERROR,
"Parsing [ITU-T T.125] Connect-Initial failed");
return 1;
}
if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len) != 0)
{
LOG(LOG_LEVEL_ERROR,
"Parsing [ITU-T T.125] Connect-Initial callingDomainSelector failed");
return 1;
}
if (len < 0)
{
LOG(LOG_LEVEL_ERROR,
"Parsing [ITU-T T.125] Connect-Initial callingDomainSelector length field is "
"invalid. Expected >= 0, actual %d", len);
return 1;
}
if (!s_check_rem_and_log(s, len, "Parsing [ITU-T T.125] Connect-Initial callingDomainSelector"))
{
return 1;
}
in_uint8s(s, len); /* [ITU-T T.125] Connect-Initial callingDomainSelector */
if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len) != 0)
{
LOG(LOG_LEVEL_ERROR,
"Parsing [ITU-T T.125] Connect-Initial calledDomainSelector failed");
return 1;
}
if (len < 0)
{
LOG(LOG_LEVEL_ERROR,
"Parsing [ITU-T T.125] Connect-Initial calledDomainSelector length field is "
"invalid. Expected >= 0, actual %d", len);
return 1;
}
if (!s_check_rem_and_log(s, len, "Parsing [ITU-T T.125] Connect-Initial calledDomainSelector"))
{
return 1;
}
in_uint8s(s, len); /* [ITU-T T.125] Connect-Initial calledDomainSelector */
if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_BOOLEAN, &len) != 0)
{
LOG(LOG_LEVEL_ERROR,
"Parsing [ITU-T T.125] Connect-Initial upwardFlag failed");
return 1;
}
if (len < 0)
{
LOG(LOG_LEVEL_ERROR,
"Parsing [ITU-T T.125] Connect-Initial upwardFlag length field is "
"invalid. Expected >= 0, actual %d", len);
return 1;
}
if (!s_check_rem_and_log(s, len, "Parsing [ITU-T T.125] Connect-Initial upwardFlag"))
{
return 1;
}
in_uint8s(s, len); /* [ITU-T T.125] Connect-Initial upwardFlag */
/* [ITU-T T.125] Connect-Initial targetParameters */
if (xrdp_mcs_parse_domain_params(self, s) != 0)
{
LOG(LOG_LEVEL_ERROR,
"Parsing [ITU-T T.125] Connect-Initial targetParameters failed");
return 1;
}
/* [ITU-T T.125] Connect-Initial minimumParameters */
if (xrdp_mcs_parse_domain_params(self, s) != 0)
{
LOG(LOG_LEVEL_ERROR,
"Parsing [ITU-T T.125] Connect-Initial minimumParameters failed");
return 1;
}
/* [ITU-T T.125] Connect-Initial maximumParameters */
if (xrdp_mcs_parse_domain_params(self, s) != 0)
{
LOG(LOG_LEVEL_ERROR,
"Parsing [ITU-T T.125] Connect-Initial maximumParameters failed");
return 1;
}
if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len) != 0)
{
LOG(LOG_LEVEL_ERROR,
"Parsing [ITU-T T.125] Connect-Initial userData failed");
return 1;
}
/* mcs userData can not be zero length */
if ((len <= 0) || (len > 16 * 1024))
{
LOG(LOG_LEVEL_ERROR,
"Parsing [ITU-T T.125] Connect-Initial userData: invalid length. "
"Expected min 1, max %d; Actual %d", 16 * 1024, len);
return 1;
}
if (!s_check_rem_and_log(s, len, "Parsing [ITU-T T.125] Connect-Initial userData"))
{
return 1;
}
LOG_DEVEL(LOG_LEVEL_TRACE, "Received header [ITU-T T.125] Connect-Initial "
"callingDomainSelector (ignored), calledDomainSelector (ignored), "
"upwardFlag (ignored), targetParameters (ignored), "
"minimumParameters (ignored), maximumParameters (ignored), "
"userData (copied to client_mcs_data)");
/* make a copy of client mcs data */
init_stream(self->client_mcs_data, len);
out_uint8a(self->client_mcs_data, s->p, len); /* [ITU-T T.125] Connect-Initial userData */
in_uint8s(s, len);
s_mark_end(self->client_mcs_data);
if (!s_check_end_and_log(s, "MCS protocol error [ITU-T T.125] Connect-Initial"))
{
return 1;
}
return 0;
}
/*****************************************************************************/
/* Processes a [ITU-T T.25] DomainMCSPDU with type ErectDomainRequest
*
* Note: a parsing example can be found in [MS-RDPBCGR] 4.1.5
*
* returns error */
static int
xrdp_mcs_recv_edrq(struct xrdp_mcs *self)
{
int opcode;
struct stream *s;
s = libxrdp_force_read(self->iso_layer->trans);
if (s == 0)
{
LOG(LOG_LEVEL_ERROR, "Processing [ITU-T T.125] ErectDomainRequest failed");
return 1;
}
if (xrdp_iso_recv(self->iso_layer, s) != 0)
{
LOG(LOG_LEVEL_ERROR, "Processing [ITU-T T.125] ErectDomainRequest failed");
return 1;
}
if (!s_check_rem_and_log(s, 1, "Parsing [ITU-T T.125] DomainMCSPDU"))
{
return 1;
}
/* The DomainMCSPDU choice index is a 6-bit int with the next bit as the
bit field of the optional field in the struct
*/
in_uint8(s, opcode);
if ((opcode >> 2) != MCS_EDRQ)
{
LOG(LOG_LEVEL_ERROR, "Parsed [ITU-T T.125] DomainMCSPDU choice index "
"expected %d, received %d", MCS_EDRQ, (opcode >> 2));
return 1;
}
if (!s_check_rem_and_log(s, 4, "Parsing [ITU-T T.125] ErectDomainRequest"))
{
return 1;
}
in_uint8s(s, 2); /* subHeight */
in_uint8s(s, 2); /* subInterval */
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [ITU-T T.125] DomainMCSPDU "
"choice index %d (ErectDomainRequest)", (opcode >> 2));
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [ITU-T T.125] ErectDomainRequest "
"subHeight (ignored), subInterval (ignored), "
"nonStandard (%s)",
(opcode & 2) ? "present" : "not present");
/*
* [MS-RDPBCGR] 2.2.1.5 says that the mcsEDrq field is 5 bytes (which have
* already been read into the opcode and previous fields), so the
* nonStandard field should never be present.
*/
if (opcode & 2) /* ErectDomainRequest v3 nonStandard optional field is present? */
{
if (!s_check_rem_and_log(s, 2, "Parsing [ITU-T T.125] ErectDomainRequest nonStandard"))
{
return 1;
}
in_uint16_be(s, self->userid); /* NonStandardParameter.key
NonStandardParameter.data */
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [ITU-T T.125] DomainMCSPDU "
"choice index %d (ErectDomainRequest)", (opcode >> 2));
}
if (!s_check_end_and_log(s, "MCS protocol error [ITU-T T.125] ErectDomainRequest"))
{
return 1;
}
return 0;
}
/*****************************************************************************/
/* Processes a [ITU-T T.25] DomainMCSPDU with type AttachUserRequest
*
* Note: a parsing example can be found in [MS-RDPBCGR] 4.1.6
*
* returns error */
static int
xrdp_mcs_recv_aurq(struct xrdp_mcs *self)
{
int opcode;
struct stream *s;
s = libxrdp_force_read(self->iso_layer->trans);
if (s == 0)
{
LOG(LOG_LEVEL_ERROR, "Processing [ITU-T T.125] AttachUserRequest failed");
return 1;
}
if (xrdp_iso_recv(self->iso_layer, s) != 0)
{
LOG(LOG_LEVEL_ERROR, "Processing [ITU-T T.125] AttachUserRequest failed");
return 1;
}
if (!s_check_rem_and_log(s, 1, "Parsing [ITU-T T.125] DomainMCSPDU"))
{
return 1;
}
/* The DomainMCSPDU choice index is a 6-bit int with the next bit as the
bit field of the optional field in the struct
*/
in_uint8(s, opcode);
if ((opcode >> 2) != MCS_AURQ)
{
LOG(LOG_LEVEL_ERROR, "Parsed [ITU-T T.125] DomainMCSPDU choice index "
"expected %d, received %d", MCS_AURQ, (opcode >> 2));
return 1;
}
/*
* [MS-RDPBCGR] 2.2.1.6 says that the mcsAUrq field is 1 bytes (which have
* already been read into the opcode), so the nonStandard field should
* never be present.
*/
if (opcode & 2)
{
if (!s_check_rem_and_log(s, 2, "Parsing [ITU-T T.125] AttachUserRequest nonStandard"))
{
return 1;
}
in_uint16_be(s, self->userid); /* NonStandardParameter.key
NonStandardParameter.data */
}
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [ITU-T T.125] DomainMCSPDU "
"choice index %d (AttachUserRequest)", (opcode >> 2));
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [ITU-T T.125] AttachUserRequest "
"nonStandard (%s)",
(opcode & 2) ? "present" : "not present");
if (!s_check_end_and_log(s, "MCS protocol error [ITU-T T.125] AttachUserRequest"))
{
return 1;
}
return 0;
}
/*****************************************************************************/
/* Send a [ITU-T T.125] DomainMCSPDU with type AttachUserConfirm.
*
* Note: a parsing example can be found in [MS-RDPBCGR] 4.1.7
*
* returns error */
static int
xrdp_mcs_send_aucf(struct xrdp_mcs *self)
{
struct stream *s;
make_stream(s);
init_stream(s, 8192);
if (xrdp_iso_init(self->iso_layer, s) != 0)
{
free_stream(s);
LOG(LOG_LEVEL_ERROR, "xrdp_mcs_send_aucf: xrdp_iso_init failed");
return 1;
}
out_uint8(s, ((MCS_AUCF << 2) | 2)); /* AttachUserConfirm
optional field initiator is present */
out_uint8s(s, 1); /* result = 0 rt-successful */
out_uint16_be(s, self->userid); /* initiator */
s_mark_end(s);
LOG_DEVEL(LOG_LEVEL_TRACE, "Sending [ITU-T T.125] DomainMCSPDU "
"of type AttachUserConfirm: result SUCCESS, initiator %d",
self->userid);
if (xrdp_iso_send(self->iso_layer, s) != 0)
{
free_stream(s);
LOG(LOG_LEVEL_ERROR, "Sending [ITU-T T.125] AttachUserConfirm failed");
return 1;
}
free_stream(s);
return 0;
}
/*****************************************************************************/
/* Processes a [ITU-T T.25] DomainMCSPDU with type ChannelJoinRequest
*
* Note: a parsing example can be found in [MS-RDPBCGR] 4.1.8.1.1
*
* returns error */
static int
xrdp_mcs_recv_cjrq(struct xrdp_mcs *self, int *channel_id)
{
int opcode;
struct stream *s;
int initiator;
s = libxrdp_force_read(self->iso_layer->trans);
if (s == 0)
{
LOG(LOG_LEVEL_ERROR, "Processing [ITU-T T.25] ChannelJoinRequest failed");
return 1;
}
if (xrdp_iso_recv(self->iso_layer, s) != 0)
{
LOG(LOG_LEVEL_ERROR, "Processing [ITU-T T.25] ChannelJoinRequest failed");
return 1;
}
if (!s_check_rem_and_log(s, 1, "Parsing [ITU-T T.125] DomainMCSPDU"))
{
return 1;
}
in_uint8(s, opcode);
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [ITU-T T.125] DomainMCSPDU "
"choice index %d (ChannelJoinRequest)", (opcode >> 2));
if ((opcode >> 2) != MCS_CJRQ)
{
LOG(LOG_LEVEL_ERROR, "Parsed [ITU-T T.125] DomainMCSPDU choice index "
"expected %d, received %d", MCS_CJRQ, (opcode >> 2));
return 1;
}
if (!s_check_rem_and_log(s, 4, "Parsing [ITU-T T.125] ChannelJoinRequest"))
{
return 1;
}
in_uint16_be(s, initiator);
in_uint16_be(s, *channel_id);
/*
* [MS-RDPBCGR] 2.2.1.8 says that the mcsAUrq field is 5 bytes (which have
* already been read into the opcode and other fields), so the nonStandard
* field should never be present.
*/
if (opcode & 2)
{
if (!s_check_rem_and_log(s, 2, "Parsing [ITU-T T.125] ChannelJoinRequest nonStandard"))
{
return 1;
}
in_uint8s(s, 2); /* NonStandardParameter.key
NonStandardParameter.data */
}
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [ITU-T T.125] ChannelJoinRequest "
"initiator %d, channelId %d, "
"nonStandard (%s)",
initiator, *channel_id,
(opcode & 2) ? "present" : "not present");
if (!s_check_end_and_log(s, "MCS protocol error [ITU-T T.125] ChannelJoinRequest"))
{
return 1;
}
return 0;
}
/*****************************************************************************/
/* Write the identifier and length of a [ITU-T X.690] BER (Basic Encoding Rules)
* structure header.
* returns error */
static int
xrdp_mcs_ber_out_header(struct xrdp_mcs *self, struct stream *s,
int tag_val, int len)
{
if (tag_val > 0xff)
{
out_uint16_be(s, tag_val);
}
else
{
out_uint8(s, tag_val);
}
if (len >= 0x80)
{
out_uint8(s, 0x82);
out_uint16_be(s, len);
}
else
{
out_uint8(s, len);
}
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding header [ITU-T X.690] Identifier %d, Length %d",
tag_val, len);
return 0;
}
/*****************************************************************************/
/* returns error */
static int
xrdp_mcs_ber_out_int8(struct xrdp_mcs *self, struct stream *s, int value)
{
xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 1);
out_uint8(s, value);
return 0;
}
#if 0 /* not used */
/*****************************************************************************/
/* returns error */
static int
xrdp_mcs_ber_out_int16(struct xrdp_mcs *self, struct stream *s, int value)
{
xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 2);
out_uint8(s, (value >> 8));
out_uint8(s, value);
return 0;
}
#endif
/*****************************************************************************/
/* returns error */
static int
xrdp_mcs_ber_out_int24(struct xrdp_mcs *self, struct stream *s, int value)
{
xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 3);
out_uint8(s, (value >> 16));
out_uint8(s, (value >> 8));
out_uint8(s, value);
return 0;
}
/*****************************************************************************/
/* returns error */
static int
xrdp_mcs_out_domain_params(struct xrdp_mcs *self, struct stream *s,
int max_channels,
int max_users, int max_tokens,
int max_pdu_size)
{
xrdp_mcs_ber_out_header(self, s, MCS_TAG_DOMAIN_PARAMS, 26);
xrdp_mcs_ber_out_int8(self, s, max_channels);
xrdp_mcs_ber_out_int8(self, s, max_users);
xrdp_mcs_ber_out_int8(self, s, max_tokens);
xrdp_mcs_ber_out_int8(self, s, 1); /* numPriorities */
xrdp_mcs_ber_out_int8(self, s, 0); /* minThroughput */
xrdp_mcs_ber_out_int8(self, s, 1); /* maxHeight */
xrdp_mcs_ber_out_int24(self, s, max_pdu_size);
xrdp_mcs_ber_out_int8(self, s, 2); /* protocolVersion */
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding struct [ITU-T T.125] DomainParameters "
"maxChannelIds %d, maxUserIds %d, maxTokenIds %d, numPriorities 1, "
"minThroughput 0 B/s, maxHeight 1, maxMCSPDUsize %d, "
"protocolVersion 2",
max_channels, max_users, max_tokens, max_pdu_size);
return 0;
}
/*****************************************************************************/
/* Write an [ITU-T T.124] ConnectData (ALIGNED variant of BASIC-PER) message
* with ConnectGCCPDU, ConferenceCreateResponse,
* and [MS-RDPBCGR] Server Data Blocks as user data.
*/
int
xrdp_mcs_out_gcc_data(struct xrdp_sec *self)
{
struct stream *s;
int num_channels_even;
int num_channels;
int index;
int channel;
int gcc_size;
char *gcc_size_ptr;
char *ud_ptr;
int header_length = 0;
int server_cert_len = 0;
int public_key_blob_len = 0;
int key_len = 0;
int bit_len = 0;
int data_len = 0;
int modulus_len = 0;
num_channels = self->mcs_layer->channel_list->count;
num_channels_even = num_channels + (num_channels & 1);
s = &(self->server_mcs_data);
init_stream(s, 8192);
/* [ITU-T T.124] ConnectData (ALIGNED variant of BASIC-PER) */
out_uint16_be(s, 5); /* = 0x00 0x05 */
/* t124Identifier choice index = 0 (object) */
/* object length = 5 */
out_uint16_be(s, 0x14); /* t124Identifier.object = ??? (0x00 0x14 0x7c 0x00 0x01) */
out_uint8(s, 0x7c);
out_uint16_be(s, 1); /* -- */
out_uint8(s, 0x2a); /* connectPDU length = 42 */
/* connectPDU octet string of type ConnectGCCPDU
(unknown where this octet string is defined to be
of type ConnectGCCPDU) */
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding struct [ITU-T T.124] ConnectData "
"t124Identifier.object 0x00 0x14 0x7c 0x00 0x01, connectPDU length %d",
0x2a);
/* [ITU-T T.124] ConnectGCCPDU (ALIGNED variant of BASIC-PER) */
out_uint8(s, 0x14); /* ConnectGCCPDU choice index 1 = ConferenceCreateResponse with userData present */
/* [ITU-T T.124] ConferenceCreateResponse (ALIGNED variant of BASIC-PER) */
out_uint8(s, 0x76); /* nodeID = 31219 - 1001 (PER offset for min value)
= 30218 (big-endian 0x760a) */
out_uint8(s, 0x0a);
out_uint8(s, 1); /* tag length */
out_uint8(s, 1); /* tag */
out_uint8(s, 0); /* result = 0 (success) */
out_uint16_le(s, 0xc001); /* userData set count = 1 (0x01),
userData.isPresent = 0x80 (yes) | userData.key choice index = 0x40 (1 = h221NonStandard) */
out_uint8(s, 0); /* userData.key.h221NonStandard length
= 4 - 4 (PER offset for min value) (H221NonStandardIdentifier is an octet string SIZE (4..255))
= 0
*/
/* [ITU-T H.221] H221NonStandardIdentifier uses country codes and
manufactuer codes from [ITU-T T.35]. Unknown why these values are used,
maybe this is just copied from the [MS-RDPBCGR] 4.1.4 example which uses
the value "McDn" */
out_uint8(s, 0x4d); /* M */
out_uint8(s, 0x63); /* c */
out_uint8(s, 0x44); /* D */
out_uint8(s, 0x6e); /* n */
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding struct [ITU-T T.124] ConferenceCreateResponse "
"nodeID %d, result SUCCESS", 0x760a + 1001);
/* ConferenceCreateResponse.userData.key.value (octet string) */
/* GCC Response Total Length - 2 bytes , set later */
gcc_size_ptr = s->p; /* RDPGCCUserDataResponseLength */
out_uint8s(s, 2);
ud_ptr = s->p; /* User Data */
/* [MS-RDPBCGR] TS_UD_HEADER */
out_uint16_le(s, SEC_TAG_SRV_INFO); /* type */
if (self->mcs_layer->iso_layer->rdpNegData)
{
out_uint16_le(s, 12); /* length */
}
else
{
out_uint16_le(s, 8); /* length */
}
/* [MS-RDPBCGR] TS_UD_SC_CORE */
out_uint8(s, 4); /* version (0x00080004 = rdp5, 0x00080001 = rdp4) */
out_uint8(s, 0);
out_uint8(s, 8);
out_uint8(s, 0); /* version (last byte) */
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding struct header [MS-RDPBCGR] TS_UD_HEADER "
"type 0x%4.4x, length %d",
SEC_TAG_SRV_INFO,
self->mcs_layer->iso_layer->rdpNegData ? 12 : 8);
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding struct [MS-RDPBCGR] TS_UD_SC_CORE "
"<Requiered fields> version 0x%8.8x", 0x00080004);
if (self->mcs_layer->iso_layer->rdpNegData)
{
/* RequestedProtocol */
out_uint32_le(s, self->mcs_layer->iso_layer->requestedProtocol); /* clientRequestedProtocols */
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding struct [MS-RDPBCGR] TS_UD_SC_CORE "
"<Optional fields> clientRequestedProtocols 0x%8.8x",
self->mcs_layer->iso_layer->requestedProtocol);
}
/* [MS-RDPBCGR] TS_UD_HEADER */
out_uint16_le(s, SEC_TAG_SRV_CHANNELS); /* type */
out_uint16_le(s, 8 + (num_channels_even * 2)); /* length */
/* [MS-RDPBCGR] TS_UD_SC_NET */
out_uint16_le(s, MCS_GLOBAL_CHANNEL); /* 1003, 0x03eb main channel (MCSChannelId) */
out_uint16_le(s, num_channels); /* number of other channels (channelCount) */
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding struct header [MS-RDPBCGR] TS_UD_HEADER "
"type 0x%4.4x, length %d",
SEC_TAG_SRV_CHANNELS, 8 + (num_channels_even * 2));
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding struct [MS-RDPBCGR] TS_UD_SC_NET "
"MCSChannelId %d, channelCount %d",
MCS_GLOBAL_CHANNEL, num_channels);
for (index = 0; index < num_channels_even; index++)
{
if (index < num_channels)
{
channel = MCS_GLOBAL_CHANNEL + (index + 1);
out_uint16_le(s, channel); /* channelIdArray[index] (channel allocated) */
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding struct [MS-RDPBCGR] TS_UD_SC_NET channelIdArray[%d] "
"channelId %d", index, channel);
}
else
{
out_uint16_le(s, 0); /* padding or channelIdArray[index] (channel not allocated) */
}
}
if (self->rsa_key_bytes == 64 || self->rsa_key_bytes == 256)
{
if (self->rsa_key_bytes == 64)
{
header_length = 0x00ec; /* length = 236 */
server_cert_len = 0xb8; /* serverCertLen (184 bytes) */
public_key_blob_len = 0x005c; /* wPublicKeyBlobLen (92 bytes) */
key_len = 0x0048; /* keylen (72 bytes = (bitlen / 8) modulus + 8 padding) */
bit_len = 512; /* bitlen = 512 */
data_len = 63; /* datalen (63 = (bitlen / 8) - 1) */
modulus_len = 64;
}
else /* if (self->rsa_key_bytes == 256) */
{
header_length = 0x01ac; /* length = 428 */
server_cert_len = 0x178; /* serverCertLen (376 bytes) */
public_key_blob_len = 0x011c; /* wPublicKeyBlobLen (284 bytes) */
key_len = 0x0108; /* keylen (264 bytes = (bitlen / 8) modulus + 8 padding) */
bit_len = 2048; /* bitlen = 2048 */
data_len = 255; /* datalen (255 = (bitlen / 8) - 1) */
modulus_len = 256;
}
LOG(LOG_LEVEL_DEBUG, "using %d bit RSA key", bit_len);
/* [MS-RDPBCGR] TS_UD_HEADER */
out_uint16_le(s, SEC_TAG_SRV_CRYPT); /* type */
out_uint16_le(s, header_length); /* length */
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding struct header [MS-RDPBCGR] TS_UD_HEADER "
"type 0x%4.4x, length %d", SEC_TAG_SRV_CRYPT, header_length);
/* [MS-RDPBCGR] TS_UD_SC_SEC1 */
out_uint32_le(s, self->crypt_method); /* encryptionMethod */
out_uint32_le(s, self->crypt_level); /* encryptionLevel */
out_uint32_le(s, 32); /* serverRandomLen */
out_uint32_le(s, server_cert_len); /* serverCertLen */
out_uint8a(s, self->server_random, 32); /* serverRandom */
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding struct [MS-RDPBCGR] TS_UD_SC_SEC1 "
"encryptionMethod 0x%8.8x, encryptionLevel 0x%8.8x, "
"serverRandomLen 32, serverCertLen %d, serverRandom (omitted), ",
self->crypt_method, self->crypt_level, server_cert_len);
/* (field serverCertificate) [MS-RDPBCGR] SERVER_CERTIFICATE */
/* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ */
/* TermService\Parameters\Certificate */
out_uint32_le(s, 1); /* dwVersion (1 = PROPRIETARYSERVERCERTIFICATE) */
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding struct [MS-RDPBCGR] SERVER_CERTIFICATE "
"dwVersion.certChainVersion 1 (CERT_CHAIN_VERSION_1), "
"dwVersion.t 0 (permanent)");
/* [MS-RDPBCGR] PROPRIETARYSERVERCERTIFICATE */
out_uint32_le(s, 1); /* dwSigAlgId (1 = RSA) */
out_uint32_le(s, 1); /* dwKeyAlgId (1 = RSA) */
out_uint16_le(s, SEC_TAG_PUBKEY); /* wPublicKeyBlobType (BB_RSA_KEY_BLOB) */
out_uint16_le(s, public_key_blob_len); /* wPublicKeyBlobLen */
/* (field PublicKeyBlob) [MS-RDPBCGR] RSA_PUBLIC_KEY */
out_uint32_le(s, SEC_RSA_MAGIC); /* magic (0x31415352 'RSA1') */
out_uint32_le(s, key_len); /* keylen */
out_uint32_le(s, bit_len); /* bitlen */
out_uint32_le(s, data_len); /* datalen */
out_uint8a(s, self->pub_exp, 4); /* pubExp */
out_uint8a(s, self->pub_mod, modulus_len); /* modulus */
out_uint8s(s, 8); /* modulus zero padding */
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding struct [MS-RDPBCGR] RSA_PUBLIC_KEY "
"magic 0x%8.8x, keylen %d, bitlen %d, datalen %d, "
"pubExp <omitted>, modulus <omitted>, ",
SEC_RSA_MAGIC, key_len, bit_len, data_len);
out_uint16_le(s, SEC_TAG_KEYSIG); /* wSignatureBlobType (0x0008 RSA) */
out_uint16_le(s, 72); /* wSignatureBlobLen */
out_uint8a(s, self->pub_sig, 64); /* SignatureBlob */
out_uint8s(s, 8); /* modulus zero padding */
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding struct [MS-RDPBCGR] PROPRIETARYSERVERCERTIFICATE "
"dwKeyAlgId 1, "
"wPublicKeyBlobType 0x%4.4x, "
"wPublicKeyBlobLen %d, PublicKeyBlob <see RSA_PUBLIC_KEY above>"
"wSignatureBlobType 0x%4.4x, "
"wSignatureBlobLen %d, "
"SignatureBlob <omitted>",
SEC_TAG_PUBKEY, public_key_blob_len,
SEC_TAG_KEYSIG, 72);
}
else if (self->rsa_key_bytes == 0) /* no security */
{
LOG(LOG_LEVEL_DEBUG, "using no security");
/* [MS-RDPBCGR] TS_UD_HEADER */
out_uint16_le(s, SEC_TAG_SRV_CRYPT); /* type*/
out_uint16_le(s, 12); /* length */
/* [MS-RDPBCGR] TS_UD_SC_SEC1 */
out_uint32_le(s, self->crypt_method); /* encryptionMethod */
out_uint32_le(s, self->crypt_level); /* encryptionLevel */
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding struct header [MS-RDPBCGR] TS_UD_HEADER "
"type 0x%4.4x, length %d", SEC_TAG_SRV_CRYPT, 12);
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding struct [MS-RDPBCGR] TS_UD_SC_SEC1 "
"encryptionMethod 0x%8.8x, encryptionMethod 0x%8.8x",
self->crypt_method, self->crypt_level);
}
else
{
LOG(LOG_LEVEL_WARNING,
"Unsupported xrdp_sec.rsa_key_bytes value: %d, the client "
"will not be sent a [MS-RDPBCGR] TS_UD_SC_SEC1 message.",
self->rsa_key_bytes);
}
s_mark_end(s);
gcc_size = (int)(s->end - ud_ptr) | 0x8000;
gcc_size_ptr[0] = gcc_size >> 8;
gcc_size_ptr[1] = gcc_size;
return 0;
}
/*****************************************************************************/
/* Send an [ITU-T T.125] Connect-Response message.
*
* Note: the xrdp_mcs_out_gcc_data() function must be called (to populate the
* xrdp_mcs.server_mcs_data stream) before this method is called.
*
* returns error
*/
static int
xrdp_mcs_send_connect_response(struct xrdp_mcs *self)
{
int data_len;
struct stream *s;
make_stream(s);
init_stream(s, 8192);
data_len = (int) (self->server_mcs_data->end - self->server_mcs_data->data);
xrdp_iso_init(self->iso_layer, s);
//TODO: we should calculate the whole length include MCS_CONNECT_RESPONSE
xrdp_mcs_ber_out_header(self, s, MCS_CONNECT_RESPONSE,
data_len > 0x80 ? data_len + 38 : data_len + 36);
xrdp_mcs_ber_out_header(self, s, BER_TAG_RESULT, 1);
out_uint8(s, 0); /* result choice index 0 = rt-successful */
xrdp_mcs_ber_out_header(self, s, BER_TAG_INTEGER, 1);
out_uint8(s, 0); /* calledConnectId */
xrdp_mcs_out_domain_params(self, s, 22, 3, 0, 0xfff8);
xrdp_mcs_ber_out_header(self, s, BER_TAG_OCTET_STRING, data_len);
/* mcs data */
out_uint8a(s, self->server_mcs_data->data, data_len);
s_mark_end(s);
LOG_DEVEL(LOG_LEVEL_TRACE, "Sending [ITU-T T.125] Connect-Response "
"result SUCCESS, calledConnectId 0, "
"domainParameters (see xrdp_mcs_out_domain_params() trace logs), "
"userData (see xrdp_mcs_out_gcc_data() trace logs and "
"hex dump below)");
LOG_DEVEL_HEXDUMP(LOG_LEVEL_TRACE, "[ITU-T T.125] Connect-Response userData",
self->server_mcs_data->data, data_len);
if (xrdp_iso_send(self->iso_layer, s) != 0)
{
free_stream(s);
LOG(LOG_LEVEL_ERROR, "Sending [ITU-T T.125] Connect-Response failed");
return 1;
}
free_stream(s);
return 0;
}
/*****************************************************************************/
/* Handle all client channel join requests for a non-TLS connection
*
* @param self MCS structure
* @param s Input stream
* @param[in,out] appid Type of the MCS PDU whose header has just been read.
* @return 0 for success
*
* For non-TLS connections, the channel join MCS PDUs are followed by
* another MCS PDU. This not the case for TLS connections.
*
* Called when an MCS PDU header has been read, but the PDU has not
* been processed.
*
* If the PDU is a channel join request, it is processed, and the next
* PDU header is read. When we've exhausted all the channel join requests,
* the type of the next PDU is passed back to the caller for the caller
* to process.
*
* In order to cater for older clients which may not conform exactly to
* the specification, we simply take all the join requests which come in,
* and respond to them.
*
* See :-
* - https://github.com/neutrinolabs/xrdp/issues/2166
* - [MS-RDPBCGR] 3.2.5.3.8 and 3.2.5.3.8
*/
static int
handle_non_tls_client_channel_join_requests(struct xrdp_mcs *self,
struct stream *s, int *appid)
{
int rv = 0;
while (*appid == MCS_CJRQ)
{
int userid;
int chanid;
if (!s_check_rem_and_log(s, 4, "Parsing [ITU-T T.125] "
"ChannelJoinRequest"))
{
rv = 1;
break;
}
in_uint16_be(s, userid);
in_uint16_be(s, chanid);
LOG_DEVEL(LOG_LEVEL_TRACE,
"Received [ITU-T T.125] ChannelJoinRequest "
"initiator 0x%4.4x, channelId 0x%4.4x", userid, chanid);
if (xrdp_mcs_send_cjcf(self, userid, chanid) != 0)
{
LOG(LOG_LEVEL_WARNING,
"[ITU-T T.125] Channel join sequence: failed");
}
/* Get the next PDU header */
s = libxrdp_force_read(self->iso_layer->trans);
if (s == 0)
{
LOG(LOG_LEVEL_ERROR, "xrdp_mcs_recv: libxrdp_force_read failed");
rv = 1;
break;
}
if (get_domain_mcs_pdu_header(self, s, appid) != 0)
{
rv = 1;
break;
}
}
return rv;
}
/*****************************************************************************/
/* Handle all client channel join requests for a TLS connection
*
* @param self MCS structure
* @return 0 for success
*
* When were are about to negotiate a TLS connection, it is important that
* we agree on the exact number of client join request / client join confirm
* PDUs, so that we get the TLS 'client hello' message exactly when
* expected.
*
* See [MS-RDPBCGR] 3.2.5.3.8 and 3.2.5.3.8
*/
static int
handle_tls_client_channel_join_requests(struct xrdp_mcs *self)
{
int index;
int rv = 0;
static const char *tag = "[MCS Connection Sequence (TLS)]";
/*
* Expect a channel join request PDU for each of the static virtual
* channels, plus the user channel (self->chanid) and the I/O channel
* (MCS_GLOBAL_CHANNEL) */
for (index = 0; index < self->channel_list->count + 2; index++)
{
int channel_id;
LOG(LOG_LEVEL_DEBUG, "%s receive channel join request", tag);
if (xrdp_mcs_recv_cjrq(self, &channel_id) != 0)
{
LOG(LOG_LEVEL_ERROR, "%s receive channel join request failed", tag);
rv = 1;
break;
}
LOG(LOG_LEVEL_DEBUG, "%s send channel join confirm", tag);
if (xrdp_mcs_send_cjcf(self, self->userid, channel_id) != 0)
{
LOG(LOG_LEVEL_ERROR, "%s send channel join confirm failed", tag);
rv = 1;
break;
}
}
return rv;
}
/*****************************************************************************/
/* Process and send the MCS messages for the RDP Connection Sequence
* [MS-RDPBCGR] 1.3.1.1
*
* returns error
*/
int
xrdp_mcs_incoming(struct xrdp_mcs *self)
{
LOG(LOG_LEVEL_DEBUG, "[MCS Connection Sequence] receive connection request");
if (xrdp_mcs_recv_connect_initial(self) != 0)
{
LOG(LOG_LEVEL_ERROR, "[MCS Connection Sequence] receive connection request failed");
return 1;
}
/* in xrdp_sec.c */
if (xrdp_sec_process_mcs_data(self->sec_layer) != 0)
{
LOG(LOG_LEVEL_ERROR, "[MCS Connection Sequence] Connect Initial PDU with GCC Conference Create Request failed");
return 1;
}
LOG(LOG_LEVEL_DEBUG, "[MCS Connection Sequence] construct connection reponse");
if (xrdp_mcs_out_gcc_data(self->sec_layer) != 0)
{
LOG(LOG_LEVEL_ERROR, "[MCS Connection Sequence] construct connection reponse failed");
return 1;
}
LOG(LOG_LEVEL_DEBUG, "[MCS Connection Sequence] send connection reponse");
if (xrdp_mcs_send_connect_response(self) != 0)
{
LOG(LOG_LEVEL_ERROR, "[MCS Connection Sequence] send connection reponse failed");
return 1;
}
LOG(LOG_LEVEL_DEBUG, "[MCS Connection Sequence] receive erect domain request");
if (xrdp_mcs_recv_edrq(self) != 0)
{
LOG(LOG_LEVEL_ERROR, "[MCS Connection Sequence] receive erect domain request failed");
return 1;
}
LOG(LOG_LEVEL_DEBUG, "[MCS Connection Sequence] receive attach user request");
if (xrdp_mcs_recv_aurq(self) != 0)
{
LOG(LOG_LEVEL_ERROR, "[MCS Connection Sequence] receive attach user request failed");
return 1;
}
LOG(LOG_LEVEL_DEBUG, "[MCS Connection Sequence] send attach user confirm");
if (xrdp_mcs_send_aucf(self) != 0)
{
LOG(LOG_LEVEL_ERROR, "[MCS Connection Sequence] send attach user confirm failed");
return 1;
}
if (self->iso_layer->selectedProtocol > PROTOCOL_RDP)
{
/* TLS connection. Client and server have to agree on MCS channel
* join messages, and these have to be processed before the TLS
* client hello */
if (handle_tls_client_channel_join_requests(self) != 0)
{
return 1;
}
LOG(LOG_LEVEL_DEBUG, "[MCS Connection Sequence (TLS)] completed");
}
else
{
/* Non-TLS connection - channel joins handled in MCS PDU
* processing loop */
self->expecting_channel_join_requests = 1;
}
return 0;
}
/*****************************************************************************/
/* returns error */
int
xrdp_mcs_init(struct xrdp_mcs *self, struct stream *s)
{
xrdp_iso_init(self->iso_layer, s);
s_push_layer(s, mcs_hdr, 8);
return 0;
}
/*****************************************************************************/
/* returns error */
/* Inform the callback that an mcs packet has been sent. This is needed so
the module can send any high priority mcs packets like audio. */
static int
xrdp_mcs_call_callback(struct xrdp_mcs *self)
{
int rv;
struct xrdp_session *session;
rv = 0;
/* if there is a callback, call it here */
session = self->sec_layer->rdp_layer->session;
if (session != 0)
{
if (session->callback != 0)
{
if (session->check_for_app_input)
{
/* in xrdp_wm.c */
rv = session->callback(session->id, 0x5556, 0, 0, 0, 0);
}
}
else
{
LOG_DEVEL(LOG_LEVEL_WARNING, "session->callback is NULL");
}
}
else
{
LOG_DEVEL(LOG_LEVEL_WARNING, "session is NULL");
}
return rv;
}
/*****************************************************************************/
/* Send a [ITU-T T.125] SendDataIndication message
* returns error */
int
xrdp_mcs_send(struct xrdp_mcs *self, struct stream *s, int chan)
{
int len;
char *lp;
//static int max_len = 0;
s_pop_layer(s, mcs_hdr);
len = (s->end - s->p) - 8;
if (len > 8192 * 2)
{
LOG(LOG_LEVEL_WARNING, "xrdp_mcs_send: stream size too big: %d bytes", len);
}
/* The DomainMCSPDU choice index is a 6-bit int with the 2 least
significant bits of the byte as padding */
out_uint8(s, MCS_SDIN << 2); /* DomainMCSPDU choice index */
out_uint16_be(s, self->userid); /* initiator */
out_uint16_be(s, chan); /* channelId */
out_uint8(s, 0x70); /* dataPriority (upper 2 bits),
segmentation (next 2 bits),
padding (4 bits) */
if (len >= 128)
{
len = len | 0x8000;
out_uint16_be(s, len); /* userData length */
}
else
{
out_uint8(s, len); /* userData length */
/* move everything up one byte */
lp = s->p;
while (lp < s->end)
{
lp[0] = lp[1];
lp++;
}
s->end--;
}
LOG_DEVEL(LOG_LEVEL_TRACE, "Adding header [ITU-T T.125] SendDataIndication "
"initiator %d, channelId %d, dataPriority %d, segmentation 0x0, "
"userData length %d",
self->userid, chan, 0x70 >> 6, (0x70 >> 4) & 0x03);
if (xrdp_iso_send(self->iso_layer, s) != 0)
{
LOG(LOG_LEVEL_ERROR, "xrdp_mcs_send: xrdp_iso_send failed");
return 1;
}
/* todo, do we need to call this for every mcs packet,
maybe every 5 or so */
if (chan == MCS_GLOBAL_CHANNEL)
{
xrdp_mcs_call_callback(self);
}
return 0;
}
/**
* Internal help function to close the socket
* @param self
*/
void
close_rdp_socket(struct xrdp_mcs *self)
{
if (self->iso_layer != 0)
{
if (self->iso_layer->trans != 0)
{
trans_shutdown_tls_mode(self->iso_layer->trans);
g_tcp_close(self->iso_layer->trans->sck);
self->iso_layer->trans->sck = -1;
LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_mcs_disconnect - socket closed");
return;
}
}
LOG_DEVEL(LOG_LEVEL_WARNING, "Failed to close socket");
}
/*****************************************************************************/
/* returns error */
int
xrdp_mcs_disconnect(struct xrdp_mcs *self)
{
struct stream *s;
make_stream(s);
init_stream(s, 8192);
if (xrdp_iso_init(self->iso_layer, s) != 0)
{
free_stream(s);
close_rdp_socket(self);
LOG(LOG_LEVEL_ERROR, "xrdp_mcs_disconnect: xrdp_iso_init failed");
return 1;
}
out_uint8(s, (MCS_DPUM << 2) | 1);
out_uint8(s, 0x80); /* reason (upper 3 bits) (4 = rn-channel-purged)*/
s_mark_end(s);
LOG_DEVEL(LOG_LEVEL_TRACE, "Sending [ITU T.125] DisconnectProviderUltimatum "
"reason %d", 0x80 >> 5);
if (xrdp_iso_send(self->iso_layer, s) != 0)
{
free_stream(s);
close_rdp_socket(self);
LOG(LOG_LEVEL_ERROR, "Sending [ITU T.125] DisconnectProviderUltimatum failed");
return 1;
}
free_stream(s);
close_rdp_socket(self);
return 0;
}