From 78ed7572934bda7ab88275511d909644f04be907 Mon Sep 17 00:00:00 2001 From: Alexandre Quesnel <131881+aquesnel@users.noreply.github.com> Date: Mon, 17 Aug 2020 02:50:25 +0000 Subject: [PATCH] Adding logs to libxrdp/xrdp_mcs.c --- libxrdp/xrdp_mcs.c | 754 ++++++++++++++++++++++++++++++++------------- 1 file changed, 539 insertions(+), 215 deletions(-) diff --git a/libxrdp/xrdp_mcs.c b/libxrdp/xrdp_mcs.c index 8f75ceec..40bfbb12 100644 --- a/libxrdp/xrdp_mcs.c +++ b/libxrdp/xrdp_mcs.c @@ -15,7 +15,8 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * mcs layer + * mcs layer which implements the Multipoint Communication Service protocol as + * specified in [ITU-T T.125] */ #if defined(HAVE_CONFIG_H) @@ -80,45 +81,58 @@ xrdp_mcs_delete(struct xrdp_mcs *self) } /*****************************************************************************/ -/* This function sends channel join confirm */ +/* 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; - LOG_DEVEL(LOG_LEVEL_TRACE, " in xrdp_mcs_send_cjcf"); make_stream(s); init_stream(s, 8192); if (xrdp_iso_init(self->iso_layer, s) != 0) { free_stream(s); - LOG(LOG_LEVEL_ERROR, " out xrdp_mcs_send_cjcf error"); + LOG(LOG_LEVEL_ERROR, "xrdp_mcs_send_cjcf: xrdp_iso_init failed"); return 1; } - out_uint8(s, (MCS_CJCF << 2) | 2); - out_uint8(s, 0); - out_uint16_be(s, userid); - out_uint16_be(s, chanid); /* TODO Explain why we send this two times */ - out_uint16_be(s, chanid); + /* 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); if (xrdp_iso_send(self->iso_layer, s) != 0) { free_stream(s); - LOG(LOG_LEVEL_ERROR, " out xrdp_mcs_send_cjcf error"); + LOG(LOG_LEVEL_ERROR, "xrdp_mcs_send_cjcf: xrdp_iso_send failed"); return 1; } free_stream(s); - LOG_DEVEL(LOG_LEVEL_TRACE, " out xrdp_mcs_send_cjcf"); + LOG_DEVEL(LOG_LEVEL_TRACE, "Sent [ITU-T T.125] ChannelJoinConfirm " + "result SUCCESS, initiator %d, requested %d, " + "channelId %d", userid, chanid, chanid); return 0; } /*****************************************************************************/ -/* returns error */ +/* + * 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) { @@ -139,38 +153,43 @@ xrdp_mcs_recv(struct xrdp_mcs *self, struct stream *s, int *chan) if (!s_check_rem(s, 1)) { - LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv: error - not enough bytes in the stream"); + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream " + "len 1, remaining %d", s_rem(s)); return 1; } - in_uint8(s, opcode); - appid = opcode >> 2; + /* 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); if (appid == MCS_DPUM) /* Disconnect Provider Ultimatum */ { - LOG(LOG_LEVEL_INFO, "xrdp_mcs_recv: received Disconnect Provider Ultimatum"); + LOG_DEVEL(LOG_LEVEL_TRACE, "Received [ITU-T T.125] DisconnectProviderUltimatum"); return 1; } - /* this is channels getting added from the client */ + /* MCS_CJRQ: Channel Join ReQuest + this is channels getting added from the client */ if (appid == MCS_CJRQ) { - if (!s_check_rem(s, 4)) { - LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv: error - not enough bytes in the stream"); + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream " + "len 4, remaining %d", s_rem(s)); return 1; } in_uint16_be(s, userid); in_uint16_be(s, chanid); - LOG(LOG_LEVEL_DEBUG,"xrdp_mcs_recv: " - "MCS_CJRQ - channel join request received for user %4.4x channel %4.4x", - userid, 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,"xrdp_mcs_recv: xrdp_mcs_send_cjcf failed") ; + LOG(LOG_LEVEL_WARNING, "xrdp_mcs_recv: xrdp_mcs_send_cjcf failed"); } s = libxrdp_force_read(self->iso_layer->trans); @@ -182,52 +201,77 @@ xrdp_mcs_recv(struct xrdp_mcs *self, struct stream *s, int *chan) continue; } - - if (appid == MCS_SDRQ || appid == MCS_SDIN) - { - break; - } - else - { - LOG(LOG_LEVEL_DEBUG,"xrdp_mcs_recv: Received an unhandled appid: %d", appid); - } - break; } if (appid != MCS_SDRQ) { - LOG(LOG_LEVEL_ERROR, "xrdp_mcs_recv: error got appid 0x%x need MCS_SDRQ", appid); + 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(s, 6)) { - LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv: error - not enough bytes in the stream"); + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream " + "len 6, remaining %d", s_rem(s)); return 1; } - in_uint8s(s, 2); - in_uint16_be(s, *chan); - in_uint8s(s, 1); - in_uint8(s, len); + 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 & 0x80) + 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(s, 1)) { - LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv: error - not enough bytes in the stream"); + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream " + "len 1, remaining %d", s_rem(s)); return 1; } - in_uint8s(s, 1); + in_uint8s(s, 1); /* userData Length (byte 2) */ } - - LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mcs_recv: chan %d", *chan); + 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_DEVEL(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; } /*****************************************************************************/ -/* returns error */ +/** + * 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) @@ -240,6 +284,8 @@ xrdp_mcs_ber_parse_header(struct xrdp_mcs *self, struct stream *s, { if (!s_check_rem(s, 2)) { + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream " + "len 2, remaining %d", s_rem(s)); return 1; } in_uint16_be(s, tag); @@ -248,6 +294,8 @@ xrdp_mcs_ber_parse_header(struct xrdp_mcs *self, struct stream *s, { if (!s_check_rem(s, 1)) { + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream " + "len 1, remaining %d", s_rem(s)); return 1; } in_uint8(s, tag); @@ -255,11 +303,15 @@ xrdp_mcs_ber_parse_header(struct xrdp_mcs *self, struct stream *s, if (tag != tag_val) { + LOG_DEVEL(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(s, 1)) { + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream " + "len 1, remaining %d", s_rem(s)); return 1; } @@ -274,6 +326,8 @@ xrdp_mcs_ber_parse_header(struct xrdp_mcs *self, struct stream *s, { if (!s_check_rem(s, 1)) { + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream " + "len 1, remaining %d", s_rem(s)); return 1; } in_uint8(s, i); @@ -285,18 +339,23 @@ xrdp_mcs_ber_parse_header(struct xrdp_mcs *self, struct stream *s, { *len = l; } - + LOG_DEVEL(LOG_LEVEL_TRACE, "Parsed BER header [ITU-T X.690] " + "Identifier 0x%4.4x, Length %d", tag, *len); + if (s_check(s)) { return 0; } else { + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream " + "len 0, remaining %d", s_rem(s)); return 1; } } /*****************************************************************************/ +/* 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) @@ -305,27 +364,35 @@ xrdp_mcs_parse_domain_params(struct xrdp_mcs *self, struct stream *s) if (xrdp_mcs_ber_parse_header(self, s, MCS_TAG_DOMAIN_PARAMS, &len) != 0) { + LOG_DEVEL(LOG_LEVEL_ERROR, + "xrdp_mcs_parse_domain_params: xrdp_mcs_ber_parse_header " + "with MCS_TAG_DOMAIN_PARAMS failed"); return 1; } if ((len < 0) || !s_check_rem(s, len)) { + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream, " + "len %d, remaining %d", len, s_rem(s)); return 1; } - in_uint8s(s, len); - + in_uint8s(s, len); /* skip all fields */ + if (s_check(s)) { return 0; } else { + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream, " + "len 0, remaining %d", s_rem(s)); return 1; } } /*****************************************************************************/ +/* 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) @@ -336,7 +403,7 @@ xrdp_mcs_recv_connect_initial(struct xrdp_mcs *self) s = libxrdp_force_read(self->iso_layer->trans); if (s == 0) { - LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_connect_initial: ERROR stream is null"); + LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_connect_initial: libxrdp_force_read failed"); return 1; } @@ -348,67 +415,84 @@ xrdp_mcs_recv_connect_initial(struct xrdp_mcs *self) if (xrdp_mcs_ber_parse_header(self, s, MCS_CONNECT_INITIAL, &len) != 0) { - LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_connect_initial: xrdp_mcs_ber_parse_header with MCS_CONNECT_INITIAL failed"); + LOG_DEVEL(LOG_LEVEL_ERROR, + "xrdp_mcs_recv_connect_initial: xrdp_mcs_ber_parse_header " + "with MCS_CONNECT_INITIAL failed"); return 1; } if (xrdp_mcs_ber_parse_header(self, s, BER_TAG_OCTET_STRING, &len) != 0) { - LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_connect_initial: xrdp_mcs_ber_parse_header with BER_TAG_OCTET_STRING failed"); + LOG_DEVEL(LOG_LEVEL_ERROR, + "xrdp_mcs_recv_connect_initial: xrdp_mcs_ber_parse_header " + "with BER_TAG_OCTET_STRING failed"); return 1; } if ((len < 0) || !s_check_rem(s, len)) { - LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_connect_initial: ERROR not enough bytes in the stream"); + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream, " + "len %d, remaining %d", len, s_rem(s)); return 1; } - in_uint8s(s, len); + 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_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_connect_initial: xrdp_mcs_ber_parse_header with BER_TAG_OCTET_STRING failed"); + LOG_DEVEL(LOG_LEVEL_ERROR, + "xrdp_mcs_recv_connect_initial: xrdp_mcs_ber_parse_header " + "with BER_TAG_OCTET_STRING failed"); return 1; } if ((len < 0) || !s_check_rem(s, len)) { - LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_connect_initial: ERROR not enough bytes in the stream"); + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream, " + "len %d, remaining %d", len, s_rem(s)); return 1; } - in_uint8s(s, len); + 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_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_connect_initial: xrdp_mcs_ber_parse_header with BER_TAG_BOOLEAN failed"); + LOG_DEVEL(LOG_LEVEL_ERROR, + "xrdp_mcs_recv_connect_initial: xrdp_mcs_ber_parse_header " + "with BER_TAG_BOOLEAN failed"); return 1; } if ((len < 0) || !s_check_rem(s, len)) { - LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_connect_initial: ERROR not enough bytes in the stream"); + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream, " + "len %d, remaining %d", len, s_rem(s)); return 1; } - in_uint8s(s, len); + 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_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_connect_initial: xrdp_mcs_parse_domain_params failed"); + LOG_DEVEL(LOG_LEVEL_ERROR, + "xrdp_mcs_recv_connect_initial: xrdp_mcs_parse_domain_params failed"); return 1; } + /* [ITU-T T.125] Connect-Initial minimumParameters */ if (xrdp_mcs_parse_domain_params(self, s) != 0) { - LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_connect_initial: xrdp_mcs_parse_domain_params failed"); + LOG_DEVEL(LOG_LEVEL_ERROR, + "xrdp_mcs_recv_connect_initial: xrdp_mcs_parse_domain_params failed"); return 1; } + /* [ITU-T T.125] Connect-Initial maximumParameters */ if (xrdp_mcs_parse_domain_params(self, s) != 0) { - LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_connect_initial: xrdp_mcs_parse_domain_params failed"); + LOG_DEVEL(LOG_LEVEL_ERROR, + "xrdp_mcs_recv_connect_initial: xrdp_mcs_parse_domain_params failed"); return 1; } @@ -422,20 +506,26 @@ xrdp_mcs_recv_connect_initial(struct xrdp_mcs *self) /* mcs data can not be zero length */ if ((len <= 0) || (len > 16 * 1024)) { - LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_connect_initial: ERROR " - "nread request length too big. len %d", len); + LOG_DEVEL(LOG_LEVEL_ERROR, "MCS Protocol error: length too big. " + "max length %d, len %d", 16 * 1024, len); return 1; } if (!s_check_rem(s, len)) { - LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_connect_initial: ERROR not enough bytes in the stream"); + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream, " + "len %d, remaining %d", len, s_rem(s)); 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); + 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); @@ -445,159 +535,223 @@ xrdp_mcs_recv_connect_initial(struct xrdp_mcs *self) } else { - LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_connect_initial: ERROR " + LOG_DEVEL(LOG_LEVEL_ERROR, "MCS protocol error: " "the stream should be at the end but it is not"); return 1; } } /*****************************************************************************/ -/* returns error */ +/* 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; - LOG_DEVEL(LOG_LEVEL_TRACE, " in xrdp_mcs_recv_edrq"); - s = libxrdp_force_read(self->iso_layer->trans); if (s == 0) { + LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_edrq: libxrdp_force_read failed"); return 1; } if (xrdp_iso_recv(self->iso_layer, s) != 0) { + LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_edrq: xrdp_iso_recv failed"); return 1; } if (!s_check_rem(s, 1)) { + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream, " + "len 1, remaining %d", s_rem(s)); 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_DEVEL(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(s, 4)) { + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream, " + "len 4, remaining %d", s_rem(s)); return 1; } - in_uint8s(s, 2); - in_uint8s(s, 2); + in_uint8s(s, 2); /* subHeight */ + in_uint8s(s, 2); /* subInterval */ - if (opcode & 2) + 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), + (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(s, 2)) { + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream, " + "len 2, remaining %d", s_rem(s)); return 1; } - in_uint16_be(s, self->userid); + in_uint16_be(s, self->userid); /* NonStandardParameter.key + NonStandardParameter.data */ } if (!(s_check_end(s))) { + LOG_DEVEL(LOG_LEVEL_ERROR, "Expected to be at the end of the stream, " + "but there are %d bytes remaining", s_rem(s)); return 1; } - LOG_DEVEL(LOG_LEVEL_TRACE, " out xrdp_mcs_recv_edrq"); return 0; } /*****************************************************************************/ -/* returns error */ +/* 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; - LOG_DEVEL(LOG_LEVEL_TRACE, " in xrdp_mcs_recv_aurq"); - s = libxrdp_force_read(self->iso_layer->trans); if (s == 0) { + LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_aurq: libxrdp_force_read failed"); return 1; } if (xrdp_iso_recv(self->iso_layer, s) != 0) { + LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_aurq: xrdp_iso_recv failed"); return 1; } if (!s_check_rem(s, 1)) { + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream, " + "len 1, remaining %d", s_rem(s)); 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_DEVEL(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(s, 2)) { return 1; } - in_uint16_be(s, self->userid); + in_uint16_be(s, self->userid); /* NonStandardParameter.key + NonStandardParameter.data */ } if (!(s_check_end(s))) { + LOG_DEVEL(LOG_LEVEL_ERROR, "Expected to be at the end of the stream, " + "but there are %d bytes remaining", s_rem(s)); return 1; } - LOG_DEVEL(LOG_LEVEL_TRACE, " out xrdp_mcs_recv_aurq"); + 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), + (opcode & 2) ? "present" : "not present"); return 0; } /*****************************************************************************/ -/* returns error */ +/* 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; - LOG_DEVEL(LOG_LEVEL_TRACE, " in xrdp_mcs_send_aucf"); make_stream(s); init_stream(s, 8192); if (xrdp_iso_init(self->iso_layer, s) != 0) { free_stream(s); - LOG(LOG_LEVEL_ERROR, " out xrdp_mcs_send_aucf error"); + LOG(LOG_LEVEL_ERROR, "xrdp_mcs_send_aucf: xrdp_iso_init failed"); return 1; } - out_uint8(s, ((MCS_AUCF << 2) | 2)); - out_uint8s(s, 1); - out_uint16_be(s, self->userid); + 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, " out xrdp_mcs_send_aucf error"); + LOG(LOG_LEVEL_ERROR, "xrdp_mcs_send_aucf: xrdp_iso_send failed"); return 1; } free_stream(s); - LOG_DEVEL(LOG_LEVEL_TRACE, " out xrdp_mcs_send_aucf"); return 0; } /*****************************************************************************/ -/* returns error */ +/* 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) { @@ -607,16 +761,20 @@ xrdp_mcs_recv_cjrq(struct xrdp_mcs *self) s = libxrdp_force_read(self->iso_layer->trans); if (s == 0) { + LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_cjrq: libxrdp_force_read failed"); return 1; } if (xrdp_iso_recv(self->iso_layer, s) != 0) { + LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_recv_cjrq: xrdp_iso_recv failed"); return 1; } if (!s_check_rem(s, 1)) { + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream, " + "len 1, remaining %d", s_rem(s)); return 1; } @@ -624,35 +782,60 @@ xrdp_mcs_recv_cjrq(struct xrdp_mcs *self) if ((opcode >> 2) != MCS_CJRQ) { + LOG_DEVEL(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(s, 4)) { + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream, " + "len 4, remaining %d", s_rem(s)); return 1; } - in_uint8s(s, 4); + in_uint8s(s, 4); /* initiator (2 bytes) + channelId (2 bytes) */ + /* + * [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(s, 2)) { + LOG_DEVEL(LOG_LEVEL_ERROR, "Not enough bytes in the stream, " + "len 2, remaining %d", s_rem(s)); return 1; } - in_uint8s(s, 2); + in_uint8s(s, 2); /* NonStandardParameter.key + NonStandardParameter.data */ } if (!(s_check_end(s))) { + LOG_DEVEL(LOG_LEVEL_ERROR, "Expected to be at the end of the stream, " + "but there are %d bytes remaining", s_rem(s)); return 1; } + + 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] ChannelJoinRequest " + "initiator (ignored), channelId (ignored)" + "nonStandard (%s)", + (opcode >> 2), + (opcode & 2) ? "present" : "not present"); return 0; } /*****************************************************************************/ -/* returns error */ +/* 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) @@ -676,6 +859,8 @@ xrdp_mcs_ber_out_header(struct xrdp_mcs *self, struct stream *s, out_uint8(s, len); } + // LOG_DEVEL(LOG_LEVEL_TRACE, "Added header [ITU-T X.690] Identifier %d, Length %d", + // tag_val, len); return 0; } @@ -726,15 +911,24 @@ xrdp_mcs_out_domain_params(struct xrdp_mcs *self, struct stream *s, 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); - xrdp_mcs_ber_out_int8(self, s, 0); - xrdp_mcs_ber_out_int8(self, s, 1); + 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); + xrdp_mcs_ber_out_int8(self, s, 2); /* protocolVersion */ + + LOG_DEVEL(LOG_LEVEL_TRACE, "Write to stream [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; } /*****************************************************************************/ -/* prepare server gcc data to send in mcs response msg */ +/* 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) { @@ -751,137 +945,247 @@ xrdp_mcs_out_gcc_data(struct xrdp_sec *self) num_channels_even = num_channels + (num_channels & 1); s = &(self->server_mcs_data); init_stream(s, 8192); - out_uint16_be(s, 5); /* AsnBerObjectIdentifier */ - out_uint16_be(s, 0x14); - out_uint8(s, 0x7c); + + /* [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); /* ConnectPDULen */ - out_uint8(s, 0x14); - out_uint8(s, 0x76); + 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); - out_uint8(s, 1); - out_uint8(s, 0); - out_uint16_le(s, 0xc001); - out_uint8(s, 0); + 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 */ - out_uint16_le(s, SEC_TAG_SRV_INFO); + /* [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); /* len */ + out_uint16_le(s, 12); /* length */ } else { - out_uint16_le(s, 8); /* len */ + out_uint16_le(s, 8); /* length */ } - out_uint8(s, 4); /* 4 = rdp5 1 = rdp4 */ + /* [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); + 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 " + " version 0x%8.8x", 0x00080004); if (self->mcs_layer->iso_layer->rdpNegData) { - /* RequestedProtocol */ - out_uint32_le(s, self->mcs_layer->iso_layer->requestedProtocol); + /* 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 " + " clientRequestedProtocols 0x%8.8x", + self->mcs_layer->iso_layer->requestedProtocol); } - out_uint16_le(s, SEC_TAG_SRV_CHANNELS); - out_uint16_le(s, 8 + (num_channels_even * 2)); /* len */ - out_uint16_le(s, MCS_GLOBAL_CHANNEL); /* 1003, 0x03eb main channel */ - out_uint16_le(s, num_channels); /* number of other channels */ - + + + /* [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); + 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", channel); } else { - out_uint16_le(s, 0); + out_uint16_le(s, 0); /* padding or channelIdArray[index] (channel not allocated) */ } + } if (self->rsa_key_bytes == 64) { - LOG(LOG_LEVEL_DEBUG, "xrdp_sec_out_mcs_data: using 512 bit RSA key"); - out_uint16_le(s, SEC_TAG_SRV_CRYPT); - out_uint16_le(s, 0x00ec); /* len is 236 */ - out_uint32_le(s, self->crypt_method); - out_uint32_le(s, self->crypt_level); - out_uint32_le(s, 32); /* 32 bytes random len */ - out_uint32_le(s, 0xb8); /* 184 bytes rsa info(certificate) len */ - out_uint8a(s, self->server_random, 32); - /* here to end is certificate */ + LOG(LOG_LEVEL_DEBUG, "using 512 bit RSA key"); + /* [MS-RDPBCGR] TS_UD_HEADER */ + out_uint16_le(s, SEC_TAG_SRV_CRYPT); /* type */ + out_uint16_le(s, 0x00ec); /* length is 236 */ + /* [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, 0xb8); /* serverCertLen (184 bytes) */ + out_uint8a(s, self->server_random, 32); /* serverRandom */ + /* (field serverCertificate) [MS-RDPBCGR] SERVER_CERTIFICATE */ /* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ */ /* TermService\Parameters\Certificate */ - out_uint32_le(s, 1); - out_uint32_le(s, 1); - out_uint32_le(s, 1); - out_uint16_le(s, SEC_TAG_PUBKEY); /* 0x0006 */ - out_uint16_le(s, 0x005c); /* 92 bytes length of SEC_TAG_PUBKEY */ - out_uint32_le(s, SEC_RSA_MAGIC); /* 0x31415352 'RSA1' */ - out_uint32_le(s, 0x0048); /* 72 bytes modulus len */ - out_uint32_be(s, 0x00020000); /* bit len */ - out_uint32_be(s, 0x3f000000); /* data len */ - out_uint8a(s, self->pub_exp, 4); /* pub exp */ - out_uint8a(s, self->pub_mod, 64); /* pub mod */ - out_uint8s(s, 8); /* pad */ - out_uint16_le(s, SEC_TAG_KEYSIG); /* 0x0008 */ - out_uint16_le(s, 72); /* len */ - out_uint8a(s, self->pub_sig, 64); /* pub sig */ - out_uint8s(s, 8); /* pad */ + out_uint32_le(s, 1); /* dwVersion (1 = PROPRIETARYSERVERCERTIFICATE) */ + /* [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, 0x005c); /* wPublicKeyBlobLen (92 bytes) */ + /* (field PublicKeyBlob) [MS-RDPBCGR] RSA_PUBLIC_KEY */ + out_uint32_le(s, SEC_RSA_MAGIC); /* magic (0x31415352 'RSA1') */ + out_uint32_le(s, 0x0048); /* keylen (72 bytes = (bitlen / 8) modulus + 8 padding) */ + out_uint32_be(s, 0x00020000); /* bitlen = 512 */ + out_uint32_be(s, 0x3f000000); /* datalen (63 = (bitlen / 8) - 1) */ + out_uint8a(s, self->pub_exp, 4); /* pubExp */ + out_uint8a(s, self->pub_mod, 64); /* modulus */ + out_uint8s(s, 8); /* pad */ + 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); /* pad */ + LOG_DEVEL(LOG_LEVEL_TRACE, "Adding struct header [MS-RDPBCGR] TS_UD_HEADER " + "type 0x%4.4x, length %d", SEC_TAG_SRV_CRYPT, 0x00ec); + LOG_DEVEL(LOG_LEVEL_TRACE, "Adding struct [MS-RDPBCGR] TS_UD_SC_SEC1 " + "encryptionMethod 0x%8.8x, encryptionMethod 0x%8.8x, " + "serverRandomLen 32, serverCertLen 184, serverRandom (omitted), " + "serverCertificate.dwVersion 1, serverCertificate.dwSigAlgId 1, " + "serverCertificate.dwKeyAlgId 1, " + "serverCertificate.wPublicKeyBlobType 0x%4.4x, " + "serverCertificate.wPublicKeyBlobLen %d, " + "serverCertificate.PublicKeyBlob.magic 0x%8.8x, " + "serverCertificate.PublicKeyBlob.keylen %d, " + "serverCertificate.PublicKeyBlob.bitlen %d, " + "serverCertificate.PublicKeyBlob.datalen %d, " + "serverCertificate.PublicKeyBlob.pubExp (omitted), " + "serverCertificate.PublicKeyBlob.modulus (omitted), " + "serverCertificate.PublicKeyBlob.wSignatureBlobType 0x%4.4x, " + "serverCertificate.PublicKeyBlob.wSignatureBlobLen %d, " + "serverCertificate.PublicKeyBlob.SignatureBlob (omitted), ", + self->crypt_method, self->crypt_level, SEC_TAG_PUBKEY, + 00x005c, SEC_RSA_MAGIC, 0x0048, 0x00020000, 0x3f000000, + SEC_TAG_KEYSIG, 72); } else if (self->rsa_key_bytes == 256) { - LOG(LOG_LEVEL_DEBUG, "xrdp_sec_out_mcs_data: using 2048 bit RSA key"); - out_uint16_le(s, SEC_TAG_SRV_CRYPT); - out_uint16_le(s, 0x01ac); /* len is 428 */ - out_uint32_le(s, self->crypt_method); - out_uint32_le(s, self->crypt_level); - out_uint32_le(s, 32); /* 32 bytes random len */ - out_uint32_le(s, 0x178); /* 376 bytes rsa info(certificate) len */ - out_uint8a(s, self->server_random, 32); - /* here to end is certificate */ + LOG(LOG_LEVEL_DEBUG, "using 2048 bit RSA key"); + /* [MS-RDPBCGR] TS_UD_HEADER */ + out_uint16_le(s, SEC_TAG_SRV_CRYPT); /* type */ + out_uint16_le(s, 0x01ac); /* length is 428 */ + /* [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, 0x178); /* serverCertLen (376 bytes) */ + out_uint8a(s, self->server_random, 32); /* serverRandom */ + /* (field serverCertificate) [MS-RDPBCGR] SERVER_CERTIFICATE */ /* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ */ /* TermService\Parameters\Certificate */ - out_uint32_le(s, 1); - out_uint32_le(s, 1); - out_uint32_le(s, 1); - out_uint16_le(s, SEC_TAG_PUBKEY); /* 0x0006 */ - out_uint16_le(s, 0x011c); /* 284 bytes length of SEC_TAG_PUBKEY */ - out_uint32_le(s, SEC_RSA_MAGIC); /* 0x31415352 'RSA1' */ - out_uint32_le(s, 0x0108); /* 264 bytes modulus len */ - out_uint32_be(s, 0x00080000); /* bit len */ - out_uint32_be(s, 0xff000000); /* data len */ - out_uint8a(s, self->pub_exp, 4); /* pub exp */ - out_uint8a(s, self->pub_mod, 256); /* pub mod */ - out_uint8s(s, 8); /* pad */ - out_uint16_le(s, SEC_TAG_KEYSIG); /* 0x0008 */ - out_uint16_le(s, 72); /* len */ - out_uint8a(s, self->pub_sig, 64); /* pub sig */ - out_uint8s(s, 8); /* pad */ + out_uint32_le(s, 1); /* dwVersion (1 = PROPRIETARYSERVERCERTIFICATE) */ + /* [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, 0x011c); /* wPublicKeyBlobLen (284 bytes) */ + /* (field PublicKeyBlob) [MS-RDPBCGR] RSA_PUBLIC_KEY */ + out_uint32_le(s, SEC_RSA_MAGIC); /* magic (0x31415352 'RSA1') */ + out_uint32_le(s, 0x0108); /* keylen (264 bytes = (bitlen / 8) modulus + 8 padding) */ + out_uint32_be(s, 0x00080000); /* bitlen = 2048 */ + out_uint32_be(s, 0xff000000); /* datalen (255 = (bitlen / 8) - 1) */ + out_uint8a(s, self->pub_exp, 4); /* pubExp */ + out_uint8a(s, self->pub_mod, 256); /* modulus */ + out_uint8s(s, 8); /* pad */ + 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); /* pad */ + LOG_DEVEL(LOG_LEVEL_TRACE, "Adding struct header [MS-RDPBCGR] TS_UD_HEADER " + "type 0x%4.4x, length %d", SEC_TAG_SRV_CRYPT, 0x01ac); + LOG_DEVEL(LOG_LEVEL_TRACE, "Adding struct [MS-RDPBCGR] TS_UD_SC_SEC1 " + "encryptionMethod 0x%8.8x, encryptionMethod 0x%8.8x, " + "serverRandomLen 32, serverCertLen 376, serverRandom (omitted), " + "serverCertificate.dwVersion 1, serverCertificate.dwSigAlgId 1, " + "serverCertificate.dwKeyAlgId 1, " + "serverCertificate.wPublicKeyBlobType 0x%4.4x, " + "serverCertificate.wPublicKeyBlobLen %d, " + "serverCertificate.PublicKeyBlob.magic 0x%8.8x, " + "serverCertificate.PublicKeyBlob.keylen %d, " + "serverCertificate.PublicKeyBlob.bitlen %d, " + "serverCertificate.PublicKeyBlob.datalen %d, " + "serverCertificate.PublicKeyBlob.pubExp (omitted), " + "serverCertificate.PublicKeyBlob.modulus (omitted), " + "serverCertificate.PublicKeyBlob.wSignatureBlobType 0x%4.4x, " + "serverCertificate.PublicKeyBlob.wSignatureBlobLen %d, " + "serverCertificate.PublicKeyBlob.SignatureBlob (omitted), ", + self->crypt_method, self->crypt_level, SEC_TAG_PUBKEY, + 0x011c, SEC_RSA_MAGIC, 0x0108, 0x00080000, 0xff000000, + SEC_TAG_KEYSIG, 72); } else if (self->rsa_key_bytes == 0) /* no security */ { - LOG(LOG_LEVEL_DEBUG, "xrdp_sec_out_mcs_data: using no security"); - out_uint16_le(s, SEC_TAG_SRV_CRYPT); - out_uint16_le(s, 12); /* len is 12 */ - out_uint32_le(s, self->crypt_method); - out_uint32_le(s, self->crypt_level); + 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_ERROR, "xrdp_sec_out_mcs_data: error"); + 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); } - /* end certificate */ s_mark_end(s); gcc_size = (int)(s->end - ud_ptr) | 0x8000; @@ -891,14 +1195,19 @@ xrdp_mcs_out_gcc_data(struct xrdp_sec *self) return 0; } /*****************************************************************************/ -/* returns error */ +/* 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; - LOG_DEVEL(LOG_LEVEL_TRACE, " in xrdp_mcs_send_connect_response"); make_stream(s); init_stream(s, 8192); data_len = (int) (self->server_mcs_data->end - self->server_mcs_data->data); @@ -907,36 +1216,45 @@ xrdp_mcs_send_connect_response(struct xrdp_mcs *self) 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); + 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); + 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, "Sening [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, " out xrdp_mcs_send_connect_response error"); + LOG(LOG_LEVEL_ERROR, "xrdp_mcs_send_connect_response: xrdp_iso_send failed"); return 1; } free_stream(s); - LOG_DEVEL(LOG_LEVEL_TRACE, " out xrdp_mcs_send_connect_response"); return 0; } /*****************************************************************************/ -/* returns error */ +/* 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) { int index; - LOG_DEVEL(LOG_LEVEL_TRACE, " in xrdp_mcs_incoming"); - + LOG_DEVEL(LOG_LEVEL_DEBUG, "MCS Connection Sequence: receive connection request"); if (xrdp_mcs_recv_connect_initial(self) != 0) { LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_incoming: xrdp_mcs_recv_connect_initial failed"); @@ -956,24 +1274,28 @@ xrdp_mcs_incoming(struct xrdp_mcs *self) return 1; } + LOG_DEVEL(LOG_LEVEL_DEBUG, "MCS Connection Sequence: send connection reponse"); if (xrdp_mcs_send_connect_response(self) != 0) { LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_incoming: xrdp_mcs_send_connect_response failed"); return 1; } + LOG_DEVEL(LOG_LEVEL_DEBUG, "MCS Connection Sequence: receive erect domain request"); if (xrdp_mcs_recv_edrq(self) != 0) { LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_incoming: xrdp_mcs_recv_edrq failed"); return 1; } + LOG_DEVEL(LOG_LEVEL_DEBUG, "MCS Connection Sequence: receive attach user request"); if (xrdp_mcs_recv_aurq(self) != 0) { LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_incoming: xrdp_mcs_recv_aurq failed"); return 1; } + LOG_DEVEL(LOG_LEVEL_DEBUG, "MCS Connection Sequence: send attach user confirm"); if (xrdp_mcs_send_aucf(self) != 0) { LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_incoming: xrdp_mcs_send_aucf failed"); @@ -982,12 +1304,14 @@ xrdp_mcs_incoming(struct xrdp_mcs *self) for (index = 0; index < self->channel_list->count + 2; index++) { + LOG_DEVEL(LOG_LEVEL_DEBUG, "MCS Connection Sequence: receive channel join request"); if (xrdp_mcs_recv_cjrq(self) != 0) { LOG_DEVEL(LOG_LEVEL_ERROR, "xrdp_mcs_incoming: xrdp_mcs_recv_cjrq failed"); return 1; } + LOG_DEVEL(LOG_LEVEL_DEBUG, "MCS Connection Sequence: send channel join confirm"); if (xrdp_mcs_send_cjcf(self, self->userid, self->userid + MCS_USERCHANNEL_BASE + index) != 0) { @@ -996,7 +1320,7 @@ xrdp_mcs_incoming(struct xrdp_mcs *self) } } - LOG_DEVEL(LOG_LEVEL_TRACE, " out xrdp_mcs_incoming"); + LOG_DEVEL(LOG_LEVEL_DEBUG, "MCS Connection Sequence: completed"); return 0; } @@ -1036,19 +1360,20 @@ xrdp_mcs_call_callback(struct xrdp_mcs *self) } else { - LOG_DEVEL(LOG_LEVEL_TRACE, "in xrdp_mcs_send, session->callback is nil"); + LOG_DEVEL(LOG_LEVEL_WARNING, "session->callback is NULL"); } } else { - LOG_DEVEL(LOG_LEVEL_TRACE, "in xrdp_mcs_send, session is nil"); + LOG_DEVEL(LOG_LEVEL_WARNING, "session is NULL"); } return rv; } /*****************************************************************************/ -/* returns error */ +/* Send a [ITU-T T.125] SendDataIndication message + * returns error */ int xrdp_mcs_send(struct xrdp_mcs *self, struct stream *s, int chan) { @@ -1056,7 +1381,6 @@ xrdp_mcs_send(struct xrdp_mcs *self, struct stream *s, int chan) char *lp; //static int max_len = 0; - LOG_DEVEL(LOG_LEVEL_TRACE, " in xrdp_mcs_send"); s_pop_layer(s, mcs_hdr); len = (s->end - s->p) - 8; @@ -1065,26 +1389,23 @@ xrdp_mcs_send(struct xrdp_mcs *self, struct stream *s, int chan) LOG(LOG_LEVEL_WARNING, "xrdp_mcs_send: stream size too big: %d bytes", len); } - //if (len > max_len) - //{ - // max_len = len; - // g_printf("mcs max length is %d\r\n", max_len); - //} - //g_printf("mcs length %d max length is %d\r\n", len, max_len); - //g_printf("mcs length %d\r\n", len); - out_uint8(s, MCS_SDIN << 2); - out_uint16_be(s, self->userid); - out_uint16_be(s, chan); - out_uint8(s, 0x70); + /* 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); + out_uint16_be(s, len); /* userData length */ } else { - out_uint8(s, len); + out_uint8(s, len); /* userData length */ /* move everything up one byte */ lp = s->p; @@ -1097,6 +1418,10 @@ xrdp_mcs_send(struct xrdp_mcs *self, struct stream *s, int chan) 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"); @@ -1110,7 +1435,6 @@ xrdp_mcs_send(struct xrdp_mcs *self, struct stream *s, int chan) xrdp_mcs_call_callback(self); } - LOG_DEVEL(LOG_LEVEL_TRACE, " out xrdp_mcs_send"); return 0; } @@ -1128,11 +1452,11 @@ close_rdp_socket(struct xrdp_mcs *self) trans_shutdown_tls_mode(self->iso_layer->trans); g_tcp_close(self->iso_layer->trans->sck); self->iso_layer->trans->sck = 0 ; - LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mcs_disconnect - socket closed"); + LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_mcs_disconnect - socket closed"); return; } } - LOG_DEVEL(LOG_LEVEL_TRACE, "Failed to close socket"); + LOG_DEVEL(LOG_LEVEL_WARNING, "Failed to close socket"); } /*****************************************************************************/ @@ -1142,7 +1466,6 @@ xrdp_mcs_disconnect(struct xrdp_mcs *self) { struct stream *s; - LOG_DEVEL(LOG_LEVEL_TRACE, " in xrdp_mcs_disconnect"); make_stream(s); init_stream(s, 8192); @@ -1150,24 +1473,25 @@ xrdp_mcs_disconnect(struct xrdp_mcs *self) { free_stream(s); close_rdp_socket(self); - LOG(LOG_LEVEL_ERROR, " out xrdp_mcs_disconnect error - 1"); + LOG(LOG_LEVEL_ERROR, "xrdp_mcs_disconnect: xrdp_iso_init failed"); return 1; } out_uint8(s, (MCS_DPUM << 2) | 1); - out_uint8(s, 0x80); + 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, " out xrdp_mcs_disconnect error - 2"); + LOG(LOG_LEVEL_ERROR, "xrdp_mcs_disconnect: xrdp_iso_send failed"); return 1; } free_stream(s); close_rdp_socket(self); - LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mcs_disconnect - close sent"); return 0; }