diff --git a/constants.h b/constants.h index 267522b..512a35e 100644 --- a/constants.h +++ b/constants.h @@ -2,6 +2,7 @@ rdesktop: A Remote Desktop Protocol client. Miscellaneous protocol constants Copyright (C) Matthew Chapman 1999-2008 + Copyright 2017-2018 Henrik Andersson for Cendio AB This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -36,9 +37,6 @@ #define FASTPATH_OUTPUT_SECURE_CHECKSUM 0x1 #define FASTPATH_OUTPUT_ENCRYPTED 0x2 -#define IS_FASTPATH(hdr) ((hdr & 0x03) == FASTPATH_OUTPUT_ACTION_FASTPATH) -#define IS_SLOWPATH(hdr) ((hdr) == FASTPATH_OUTPUT_ACTION_X224) - /* [MS-RDPBCGR] 2.2.9.1.2.1 */ /* adjusted for position in updateHeader */ #define FASTPATH_UPDATETYPE_ORDERS 0x0 diff --git a/iso.c b/iso.c index eac4274..278f32a 100644 --- a/iso.c +++ b/iso.c @@ -3,7 +3,7 @@ Protocol services - ISO layer Copyright (C) Matthew Chapman 1999-2008 Copyright 2005-2011 Peter Astrand for Cendio AB - Copyright 2012-2017 Henrik Andersson for Cendio AB + Copyright 2012-2018 Henrik Andersson for Cendio AB This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -98,7 +98,7 @@ iso_send_connection_request(char *username, uint32 neg_proto) /* Receive a message on the ISO layer, return code */ static STREAM -iso_recv_msg(uint8 * code, uint8 * rdpver) +iso_recv_msg(uint8 * code, RD_BOOL *is_fastpath, uint8 *fastpath_hdr) { STREAM s; uint16 length; @@ -107,16 +107,23 @@ iso_recv_msg(uint8 * code, uint8 * rdpver) s = tcp_recv(NULL, 4); if (s == NULL) return NULL; - in_uint8(s, version); - if (rdpver != NULL) - *rdpver = version; - if (IS_SLOWPATH(version)) + + in_uint8(s, version); /* T.123 version or Fastpath output header */ + + /* detect if this is a slow or fast path PDU */ + *fastpath_hdr = 0x00; + *is_fastpath = False; + if (version == T123_HEADER_VERSION) { in_uint8s(s, 1); /* reserved */ in_uint16_be(s, length); /* length */ } else { + /* if version is not an expected T.123 version eg. 3, then this + stream is a fast path pdu */ + *is_fastpath = True; + *fastpath_hdr = version; in_uint8(s, length); /* length1 */ if (length & 0x80) { @@ -125,16 +132,20 @@ iso_recv_msg(uint8 * code, uint8 * rdpver) next_be(s, length); } } + if (length < 4) { logger(Protocol, Error, "iso_recv_msg(), bad packet header, length < 4"); return NULL; } + s = tcp_recv(s, length - 4); if (s == NULL) return NULL; - if (IS_FASTPATH(version)) + + if (*is_fastpath == True) return s; + in_uint8s(s, 1); /* hdrlen */ in_uint8(s, *code); if (*code == ISO_PDU_DT) @@ -180,17 +191,18 @@ iso_send(STREAM s) /* Receive ISO transport data packet */ STREAM -iso_recv(uint8 * rdpver) +iso_recv(RD_BOOL *is_fastpath, uint8 *fastpath_hdr) { STREAM s; uint8 code = 0; - s = iso_recv_msg(&code, rdpver); + s = iso_recv_msg(&code, is_fastpath, fastpath_hdr); if (s == NULL) return NULL; - if (rdpver != NULL) - if (IS_FASTPATH(*rdpver)) - return s; + + if (*is_fastpath == True) + return s; + if (code != ISO_PDU_DT) { logger(Protocol, Error, "iso_recv(), expected ISO_PDU_DT, got 0x%x", code); @@ -208,6 +220,8 @@ iso_connect(char *server, char *username, char *domain, char *password, STREAM s; uint8 code; uint32 neg_proto; + RD_BOOL is_fastpath; + uint8 fastpath_hdr; g_negotiate_rdp_protocol = True; @@ -236,7 +250,7 @@ iso_connect(char *server, char *username, char *domain, char *password, iso_send_connection_request(username, neg_proto); - s = iso_recv_msg(&code, NULL); + s = iso_recv_msg(&code, &is_fastpath, &fastpath_hdr); if (s == NULL) return False; diff --git a/mcs.c b/mcs.c index a68174c..f3a4c23 100644 --- a/mcs.c +++ b/mcs.c @@ -3,6 +3,7 @@ Protocol services - Multipoint Communications Service Copyright (C) Matthew Chapman 1999-2008 Copyright 2005-2011 Peter Astrand for Cendio AB + Copyright 2018 Henrik Andersson for Cendio AB This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -90,8 +91,12 @@ mcs_recv_connect_response(STREAM mcs_data) uint8 result; int length; STREAM s; + RD_BOOL is_fastpath; + uint8 fastpath_hdr; + logger(Protocol, Debug, "%s()", __func__); - s = iso_recv(NULL); + s = iso_recv(&is_fastpath, &fastpath_hdr); + if (s == NULL) return False; @@ -160,10 +165,14 @@ mcs_send_aurq(void) static RD_BOOL mcs_recv_aucf(uint16 * mcs_userid) { + RD_BOOL is_fastpath; + uint8 fastpath_hdr; uint8 opcode, result; STREAM s; + logger(Protocol, Debug, "%s()", __func__); - s = iso_recv(NULL); + s = iso_recv(&is_fastpath, &fastpath_hdr); + if (s == NULL) return False; @@ -209,10 +218,14 @@ mcs_send_cjrq(uint16 chanid) static RD_BOOL mcs_recv_cjcf(void) { + RD_BOOL is_fastpath; + uint8 fastpath_hdr; uint8 opcode, result; STREAM s; + logger(Protocol, Debug, "%s()", __func__); - s = iso_recv(NULL); + s = iso_recv(&is_fastpath, &fastpath_hdr); + if (s == NULL) return False; @@ -303,17 +316,18 @@ mcs_send(STREAM s) /* Receive an MCS transport data packet */ STREAM -mcs_recv(uint16 * channel, uint8 * rdpver) +mcs_recv(uint16 * channel, RD_BOOL *is_fastpath, uint8 *fastpath_hdr) { uint8 opcode, appid, length; STREAM s; - s = iso_recv(rdpver); + s = iso_recv(is_fastpath, fastpath_hdr); if (s == NULL) return NULL; - if (rdpver != NULL) - if (*rdpver != 3) - return s; + + if (*is_fastpath == True) + return s; + in_uint8(s, opcode); appid = opcode >> 2; if (appid != MCS_SDIN) diff --git a/proto.h b/proto.h index a5aa2f5..7ce19b4 100644 --- a/proto.h +++ b/proto.h @@ -82,7 +82,7 @@ void ewmh_init(void); /* iso.c */ STREAM iso_init(int length); void iso_send(STREAM s); -STREAM iso_recv(uint8 * rdpver); +STREAM iso_recv(RD_BOOL *is_fastpath, uint8 *fastpath_hdr); RD_BOOL iso_connect(char *server, char *username, char *domain, char *password, RD_BOOL reconnect, uint32 * selected_protocol); void iso_disconnect(void); @@ -95,7 +95,7 @@ void licence_process(STREAM s); STREAM mcs_init(int length); void mcs_send_to_channel(STREAM s, uint16 channel); void mcs_send(STREAM s); -STREAM mcs_recv(uint16 * channel, uint8 * rdpver); +STREAM mcs_recv(uint16 * channel, RD_BOOL *is_fastpath, uint8 *fastpath_hdr); RD_BOOL mcs_connect_start(char *server, char *username, char *domain, char *password, RD_BOOL reconnect, uint32 * selected_protocol); RD_BOOL mcs_connect_finalize(STREAM s); @@ -199,7 +199,7 @@ STREAM sec_init(uint32 flags, int maxlen); void sec_send_to_channel(STREAM s, uint32 flags, uint16 channel); void sec_send(STREAM s, uint32 flags); void sec_process_mcs_data(STREAM s); -STREAM sec_recv(uint8 * rdpver); +STREAM sec_recv(RD_BOOL * is_fastpath); RD_BOOL sec_connect(char *server, char *username, char *domain, char *password, RD_BOOL reconnect); void sec_disconnect(void); void sec_reset_state(void); diff --git a/rdp.c b/rdp.c index 749bf1b..1dbbc93 100644 --- a/rdp.c +++ b/rdp.c @@ -3,7 +3,7 @@ Protocol services - RDP layer Copyright (C) Matthew Chapman 1999-2008 Copyright 2003-2011 Peter Astrand for Cendio AB - Copyright 2011-2017 Henrik Andersson for Cendio AB + Copyright 2011-2018 Henrik Andersson for Cendio AB Copyright 2017 Karl Mikaelsson for Cendio AB This program is free software: you can redistribute it and/or modify @@ -92,51 +92,76 @@ uint16 g_session_height; static void rdp_out_unistr(STREAM s, char *string, int len); +/* reads a TS_SHARECONTROLHEADER from stream, returns True of there is + a PDU available otherwise False */ +static RD_BOOL +rdp_ts_in_share_control_header(STREAM s, uint8 *type, uint16 *length) +{ + uint16 pdu_type; + uint16 pdu_source; + + UNUSED(pdu_source); + + in_uint16_le(s, *length); /* totalLength */ + + /* If the totalLength field equals 0x8000, then the Share + Control Header and any data that follows MAY be interpreted + as a T.128 FlowPDU as described in [T128] section 8.5 (the + ASN.1 structure definition is detailed in [T128] section + 9.1) and MUST be ignored. + */ + if (*length == 0x8000) + { + /* skip over this message in stream */ + g_next_packet += 8; + return False; + } + + in_uint16_le(s, pdu_type); /* pduType */ + in_uint16(s, pdu_source); /* pduSource */ + + *type = pdu_type & 0xf; + + return True; +} + /* Receive an RDP packet */ static STREAM rdp_recv(uint8 * type) { + RD_BOOL is_fastpath; static STREAM rdp_s; - uint16 length, pdu_type; - uint8 rdpver; + uint16 length; - if ((rdp_s == NULL) || (g_next_packet >= rdp_s->end) || (g_next_packet == NULL)) + while (1) { - rdp_s = sec_recv(&rdpver); - if (rdp_s == NULL) - return NULL; - if (rdpver == 0xff) + /* fill stream with data if needed for parsing a new packet */ + if ((rdp_s == NULL) || (g_next_packet >= rdp_s->end) || (g_next_packet == NULL)) { - g_next_packet = rdp_s->end; - *type = 0; - return rdp_s; + rdp_s = sec_recv(&is_fastpath); + if (rdp_s == NULL) + return NULL; + + if (is_fastpath == True) + { + /* process_ts_fp_updates moves g_next_packet */ + process_ts_fp_updates(rdp_s); + continue; + } + + g_next_packet = rdp_s->p; } - else if (rdpver != 3) + else { - /* process_ts_fp_updates moves g_next_packet */ - process_ts_fp_updates(rdp_s); - *type = 0; - return rdp_s; + rdp_s->p = g_next_packet; } - g_next_packet = rdp_s->p; - } - else - { - rdp_s->p = g_next_packet; - } + /* parse a TS_SHARECONTROLHEADER */ + if (rdp_ts_in_share_control_header(rdp_s, type, &length) == False) + continue; - in_uint16_le(rdp_s, length); - /* 32k packets are really 8, keepalive fix */ - if (length == 0x8000) - { - g_next_packet += 8; - *type = 0; - return rdp_s; + break; } - in_uint16_le(rdp_s, pdu_type); - in_uint8s(rdp_s, 2); /* userid */ - *type = pdu_type & 0xf; logger(Protocol, Debug, "rdp_recv(), RDP packet #%d, type 0x%x", ++g_packetno, *type); @@ -1899,8 +1924,6 @@ rdp_loop(RD_BOOL * deactivated, uint32 * ext_disc_reason) process_data_pdu(s, ext_disc_reason); break; - case 0: - break; default: logger(Protocol, Warning, "rdp_loop(), unhandled PDU type %d received", type); diff --git a/secure.c b/secure.c index c093bcc..b829a02 100644 --- a/secure.c +++ b/secure.c @@ -3,7 +3,7 @@ Protocol services - RDP encryption and licensing Copyright (C) Matthew Chapman 1999-2008 Copyright 2005-2011 Peter Astrand for Cendio AB - Copyright 2017 Henrik Andersson for Cendio AB + Copyright 2017-2018 Henrik Andersson for Cendio AB This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -842,26 +842,27 @@ sec_process_mcs_data(STREAM s) /* Receive secure transport packet */ STREAM -sec_recv(uint8 * rdpver) +sec_recv(RD_BOOL *is_fastpath) { + uint8 fastpath_hdr; uint16 sec_flags; uint16 channel; STREAM s; - while ((s = mcs_recv(&channel, rdpver)) != NULL) + while ((s = mcs_recv(&channel, is_fastpath, &fastpath_hdr)) != NULL) { - if (rdpver != NULL) + if (*is_fastpath == True) { - if (*rdpver != 3) + /* If fastpath packet is encrypted, read data + signature and decrypt */ + if (fastpath_hdr & FASTPATH_OUTPUT_ENCRYPTED) { - if (*rdpver & 0x80) - { - in_uint8s(s, 8); /* signature */ - sec_decrypt(s->p, s->end - s->p); - } - return s; + in_uint8s(s, 8); /* signature */ + sec_decrypt(s->p, s->end - s->p); } + return s; } + if (g_encryption || (!g_licence_issued && !g_licence_error_result)) { /* TS_SECURITY_HEADER */ @@ -926,9 +927,7 @@ sec_recv(uint8 * rdpver) if (channel != MCS_GLOBAL_CHANNEL) { channel_process(s, channel); - if (rdpver != NULL) - *rdpver = 0xff; - return s; + continue; } return s;