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.
This commit is contained in:
matt335672 2024-02-14 12:14:10 +00:00
parent 689269dcde
commit 74598d1cc3
4 changed files with 43 additions and 17 deletions

View File

@ -74,6 +74,7 @@
/* Client Core Data: earlyCapabilityFlags (2.2.1.3.2) */ /* Client Core Data: earlyCapabilityFlags (2.2.1.3.2) */
#define RNS_UD_CS_WANT_32BPP_SESSION 0x0002 #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 #define RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL 0x0100
/* Client Core Data: connectionType (2.2.1.3.2) */ /* Client Core Data: connectionType (2.2.1.3.2) */
@ -448,6 +449,7 @@
#define RDP_DATA_PDU_LOGON 38 #define RDP_DATA_PDU_LOGON 38
#define RDP_DATA_PDU_FONT2 39 #define RDP_DATA_PDU_FONT2 39
#define RDP_DATA_PDU_DISCONNECT 47 #define RDP_DATA_PDU_DISCONNECT 47
#define PDUTYPE2_MONITOR_LAYOUT_PDU 55
/* TS_SECURITY_HEADER: flags (2.2.8.1.1.2.1) */ /* TS_SECURITY_HEADER: flags (2.2.8.1.1.2.1) */
/* TODO: to be renamed */ /* TODO: to be renamed */

View File

@ -437,6 +437,10 @@ int
xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s, xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
int data_pdu_type); int data_pdu_type);
int 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, xrdp_rdp_send_fastpath(struct xrdp_rdp *self, struct stream *s,
int data_pdu_type); int data_pdu_type);
int int

View File

@ -48,6 +48,7 @@ xrdp_caps_send_monitorlayout(struct xrdp_rdp *self)
struct stream *s; struct stream *s;
uint32_t i; uint32_t i;
struct display_size_description *description; struct display_size_description *description;
int rv = 0;
make_stream(s); make_stream(s);
init_stream(s, 8192); init_stream(s, 8192);
@ -74,14 +75,13 @@ xrdp_caps_send_monitorlayout(struct xrdp_rdp *self)
s_mark_end(s); s_mark_end(s);
if (xrdp_rdp_send_data(self, s, 0x37) != 0) // [MS-RDPBCGR]
{ // - 2.2.12.1 - ...the pduSource field MUST be set to zero.
free_stream(s); // - 3.3.5.12.1 - The contents of this PDU SHOULD NOT be compressed
return 1; rv = xrdp_rdp_send_data_from_channel(self, s,
} PDUTYPE2_MONITOR_LAYOUT_PDU, 0, 0);
free_stream(s); free_stream(s);
return 0; return rv;
} }
/*****************************************************************************/ /*****************************************************************************/
@ -1337,8 +1337,11 @@ xrdp_caps_send_demand_active(struct xrdp_rdp *self)
return 1; return 1;
} }
/* send Monitor Layout PDU for dual monitor */ /* send Monitor Layout PDU for multi-monitor */
if (self->client_info.display_sizes.monitorCount > 0 && 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) self->client_info.multimon == 1)
{ {
LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_caps_send_demand_active: sending monitor layout pdu"); LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_caps_send_demand_active: sending monitor layout pdu");

View File

@ -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 */ added and data compressed */
int int
xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s, xrdp_rdp_send_data_from_channel(struct xrdp_rdp *self, struct stream *s,
int data_pdu_type) int data_pdu_type, int channel_id,
int compress)
{ {
int len; int len;
int ctype; int ctype;
@ -614,7 +616,8 @@ xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
clen = len; clen = len;
tocomplen = pdulen - 18; 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; mppc_enc = self->mppc_enc;
if (compress_rdp(mppc_enc, (tui8 *)(s->p + 18), tocomplen)) 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 else
{ {
LOG_DEVEL(LOG_LEVEL_TRACE, 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", "uncompressed data. type %d, flags %d",
mppc_enc->protocol_type, mppc_enc->flags); mppc_enc->protocol_type, mppc_enc->flags);
} }
@ -652,11 +656,11 @@ xrdp_rdp_send_data(struct xrdp_rdp *self, struct stream *s,
/* TS_SHARECONTROLHEADER */ /* TS_SHARECONTROLHEADER */
out_uint16_le(s, pdulen); /* totalLength */ out_uint16_le(s, pdulen); /* totalLength */
out_uint16_le(s, pdutype); /* pduType */ 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 " LOG_DEVEL(LOG_LEVEL_TRACE, "Adding header [MS-RDPBCGR] TS_SHARECONTROLHEADER "
"totalLength %d, pduType.type %s (%d), pduType.PDUVersion %d, " "totalLength %d, pduType.type %s (%d), pduType.PDUVersion %d, "
"pduSource %d", pdulen, PDUTYPE_TO_STR(pdutype & 0xf), "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 */ /* TS_SHAREDATAHEADER */
out_uint32_le(s, self->share_id); 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) 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 1;
} }
return 0; 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 */ /* returns the fastpath rdp byte count */
int int