From 74598d1cc34639358497a39e332db0b4ba5303f7 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Wed, 14 Feb 2024 12:14:10 +0000 Subject: [PATCH] Fix sending of monitor layout PDU From [MS-RCPBCGR] 3.3.5.12.1:- > ...The contents of this PDU SHOULD NOT be compressed. > > This PDU MUST NOT be sent to a client that has not indicated support for > it by setting the RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU flag (0x0040) > in the earlyCapabilityFlags field of the Client Core Data (section > 2.2.1.3.2). Also, 2.2.12.1 specifies the source channel must be zero. In testing, a compressed monitor layout PDU causes mstsc.exe to exit with a protocol error. --- common/ms-rdpbcgr.h | 2 ++ libxrdp/libxrdp.h | 4 ++++ libxrdp/xrdp_caps.c | 21 ++++++++++++--------- libxrdp/xrdp_rdp.c | 33 +++++++++++++++++++++++++-------- 4 files changed, 43 insertions(+), 17 deletions(-) diff --git a/common/ms-rdpbcgr.h b/common/ms-rdpbcgr.h index 11d50bdd..45384832 100644 --- a/common/ms-rdpbcgr.h +++ b/common/ms-rdpbcgr.h @@ -74,6 +74,7 @@ /* Client Core Data: earlyCapabilityFlags (2.2.1.3.2) */ #define RNS_UD_CS_WANT_32BPP_SESSION 0x0002 +#define RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU 0x0040 #define RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL 0x0100 /* Client Core Data: connectionType (2.2.1.3.2) */ @@ -448,6 +449,7 @@ #define RDP_DATA_PDU_LOGON 38 #define RDP_DATA_PDU_FONT2 39 #define RDP_DATA_PDU_DISCONNECT 47 +#define PDUTYPE2_MONITOR_LAYOUT_PDU 55 /* TS_SECURITY_HEADER: flags (2.2.8.1.1.2.1) */ /* TODO: to be renamed */ diff --git a/libxrdp/libxrdp.h b/libxrdp/libxrdp.h index b9d1b8f9..9b289af9 100644 --- a/libxrdp/libxrdp.h +++ b/libxrdp/libxrdp.h @@ -437,6 +437,10 @@ int xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s, int data_pdu_type); int +xrdp_rdp_send_data_from_channel(struct xrdp_rdp *self, struct stream *s, + int data_pdu_type, int channel_id, + int compress); +int xrdp_rdp_send_fastpath(struct xrdp_rdp *self, struct stream *s, int data_pdu_type); int diff --git a/libxrdp/xrdp_caps.c b/libxrdp/xrdp_caps.c index 42eafb1f..524eff3a 100644 --- a/libxrdp/xrdp_caps.c +++ b/libxrdp/xrdp_caps.c @@ -48,6 +48,7 @@ xrdp_caps_send_monitorlayout(struct xrdp_rdp *self) struct stream *s; uint32_t i; struct display_size_description *description; + int rv = 0; make_stream(s); init_stream(s, 8192); @@ -74,14 +75,13 @@ xrdp_caps_send_monitorlayout(struct xrdp_rdp *self) s_mark_end(s); - if (xrdp_rdp_send_data(self, s, 0x37) != 0) - { - free_stream(s); - return 1; - } - + // [MS-RDPBCGR] + // - 2.2.12.1 - ...the pduSource field MUST be set to zero. + // - 3.3.5.12.1 - The contents of this PDU SHOULD NOT be compressed + rv = xrdp_rdp_send_data_from_channel(self, s, + PDUTYPE2_MONITOR_LAYOUT_PDU, 0, 0); free_stream(s); - return 0; + return rv; } /*****************************************************************************/ @@ -1337,8 +1337,11 @@ xrdp_caps_send_demand_active(struct xrdp_rdp *self) return 1; } - /* send Monitor Layout PDU for dual monitor */ - if (self->client_info.display_sizes.monitorCount > 0 && + /* send Monitor Layout PDU for multi-monitor */ + int early_cap_flags = self->client_info.mcs_early_capability_flags; + + if ((early_cap_flags & RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU) != 0 && + self->client_info.display_sizes.monitorCount > 0 && self->client_info.multimon == 1) { LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_caps_send_demand_active: sending monitor layout pdu"); diff --git a/libxrdp/xrdp_rdp.c b/libxrdp/xrdp_rdp.c index 29901db6..6be1ff6e 100644 --- a/libxrdp/xrdp_rdp.c +++ b/libxrdp/xrdp_rdp.c @@ -585,11 +585,13 @@ xrdp_rdp_send(struct xrdp_rdp *self, struct stream *s, int pdu_type) } /*****************************************************************************/ -/* Send a [MS-RDPBCGR] Data PDU with for the given pduType2 with the headers +/* Send a [MS-RDPBCGR] Data PDU for the given pduType2 from + * the specified source with the headers added and data compressed */ int -xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s, - int data_pdu_type) +xrdp_rdp_send_data_from_channel(struct xrdp_rdp *self, struct stream *s, + int data_pdu_type, int channel_id, + int compress) { int len; int ctype; @@ -614,7 +616,8 @@ xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s, clen = len; tocomplen = pdulen - 18; - if (self->client_info.rdp_compression && self->session->up_and_running) + if (compress && self->client_info.rdp_compression && + self->session->up_and_running) { mppc_enc = self->mppc_enc; if (compress_rdp(mppc_enc, (tui8 *)(s->p + 18), tocomplen)) @@ -643,7 +646,8 @@ xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s, else { LOG_DEVEL(LOG_LEVEL_TRACE, - "xrdp_rdp_send_data: compress_rdp failed, sending " + "xrdp_rdp_send_data_from_channel: " + "compress_rdp failed, sending " "uncompressed data. type %d, flags %d", mppc_enc->protocol_type, mppc_enc->flags); } @@ -652,11 +656,11 @@ xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s, /* TS_SHARECONTROLHEADER */ out_uint16_le(s, pdulen); /* totalLength */ out_uint16_le(s, pdutype); /* pduType */ - out_uint16_le(s, self->mcs_channel); /* pduSource */ + out_uint16_le(s, channel_id); /* pduSource */ LOG_DEVEL(LOG_LEVEL_TRACE, "Adding header [MS-RDPBCGR] TS_SHARECONTROLHEADER " "totalLength %d, pduType.type %s (%d), pduType.PDUVersion %d, " "pduSource %d", pdulen, PDUTYPE_TO_STR(pdutype & 0xf), - pdutype & 0xf, ((pdutype & 0xfff0) >> 4), self->mcs_channel); + pdutype & 0xf, ((pdutype & 0xfff0) >> 4), channel_id); /* TS_SHAREDATAHEADER */ out_uint32_le(s, self->share_id); @@ -673,13 +677,26 @@ xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s, if (xrdp_sec_send(self->sec_layer, s, MCS_GLOBAL_CHANNEL) != 0) { - LOG(LOG_LEVEL_ERROR, "xrdp_rdp_send_data: xrdp_sec_send failed"); + LOG(LOG_LEVEL_ERROR, "xrdp_rdp_send_data_from_channel: " + "xrdp_sec_send failed"); return 1; } return 0; } + +/*****************************************************************************/ +/* Send a [MS-RDPBCGR] Data PDU on the MCS channel for the given pduType2 + * with the headers added and data compressed */ +int +xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s, + int data_pdu_type) +{ + return xrdp_rdp_send_data_from_channel(self, s, data_pdu_type, + self->mcs_channel, 1); +} + /*****************************************************************************/ /* returns the fastpath rdp byte count */ int