From 7277860f2111942a867828e317a409b7705fe242 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Thu, 25 Jan 2024 15:22:45 +0000 Subject: [PATCH] Don't pass drdynvc to neutrinoRDP Since v0.9.9, xrdp has assumed that the "drdynvc" static virtual channel is available for its exclusive use. With GFX support, it is necessary to codify this to prevent this sequence of operations:- - NeutrinoRDP target sends DVC Capabilities Request PDU - target responds wih DVC Capabilities Response PDU - xrdp processes this, starting the GFX virtual channel again In the future, if NeutrinoRDP requires access to virtual channels, data may somehow need to be passed through to the target while being parsed and handled appropriately within xrdp. --- common/ms-rdpbcgr.h | 6 +++++- libxrdp/xrdp_sec.c | 4 ++-- neutrinordp/xrdp-neutrinordp.c | 37 +++++++++++++++++++++++----------- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/common/ms-rdpbcgr.h b/common/ms-rdpbcgr.h index 6e39053543..11d50bdde6 100644 --- a/common/ms-rdpbcgr.h +++ b/common/ms-rdpbcgr.h @@ -85,11 +85,15 @@ #define CONNECTION_TYPE_LAN 0x06 #define CONNECTION_TYPE_AUTODETECT 0x07 -/* Channel definition structure CHANNEL_DEF (2.2.1.3.4.1) */ +/* TS_UD_CS_NET (2.2.1.3.4) */ /* This isn't explicitly named in MS-RDPBCGR */ +#define MAX_STATIC_CHANNELS 31 + +/* Channel definition structure CHANNEL_DEF (2.2.1.3.4.1) */ #define CHANNEL_NAME_LEN 7 /* These names are also not explicitly defined in MS-RDPBCGR */ #define CLIPRDR_SVC_CHANNEL_NAME "cliprdr" +#define DRDYNVC_SVC_CHANNEL_NAME "drdynvc" #define RAIL_SVC_CHANNEL_NAME "rail" #define RDPSND_SVC_CHANNEL_NAME "rdpsnd" #define RDPDR_SVC_CHANNEL_NAME "rdpdr" diff --git a/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c index bc3551fd5d..f2d1a4d4ee 100644 --- a/libxrdp/xrdp_sec.c +++ b/libxrdp/xrdp_sec.c @@ -2388,10 +2388,10 @@ xrdp_sec_process_mcs_data_channels(struct xrdp_sec *self, struct stream *s) in_uint32_le(s, num_channels); LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPBCGR] TS_UD_CS_NET " "channelCount %d", num_channels); - if (num_channels > 31) + if (num_channels > MAX_STATIC_CHANNELS) { LOG(LOG_LEVEL_ERROR, "[MS-RDPBCGR] Protocol error: too many channels requested. " - "max 31, received %d", num_channels); + "max %d, received %d", MAX_STATIC_CHANNELS, num_channels); return 1; } diff --git a/neutrinordp/xrdp-neutrinordp.c b/neutrinordp/xrdp-neutrinordp.c index 859b29b586..1d8ad8bbd0 100644 --- a/neutrinordp/xrdp-neutrinordp.c +++ b/neutrinordp/xrdp-neutrinordp.c @@ -1779,8 +1779,10 @@ lfreerdp_pre_connect(freerdp *instance) int index; int error; int num_chans; + int target_chan; int ch_flags; char ch_name[256]; + const char *ch_names[MAX_STATIC_CHANNELS]; char *dst_ch_name; LOG_DEVEL(LOG_LEVEL_INFO, "lfreerdp_pre_connect:"); @@ -1794,6 +1796,7 @@ lfreerdp_pre_connect(freerdp *instance) num_chans = 0; } + target_chan = 0; for (index = 0 ; index < num_chans; ++index) { error = mod->server_query_channel(mod, index, ch_name, &ch_flags); @@ -1802,21 +1805,31 @@ lfreerdp_pre_connect(freerdp *instance) LOG_DEVEL(LOG_LEVEL_DEBUG, "lfreerdp_pre_connect: " "got channel [%s], id [%d], flags [0x%8.8x]", ch_name, index, ch_flags); - dst_ch_name = instance->settings->channels[index].name; - g_memset(dst_ch_name, 0, 8); - g_snprintf(dst_ch_name, 8, "%s", ch_name); - instance->settings->channels[index].options = ch_flags; - } - else - { - LOG(LOG_LEVEL_ERROR, "lfreerdp_pre_connect: " - "Expected %d channels, got %d", - num_chans, index); - num_chans = index; + + if (g_strcmp(ch_name, DRDYNVC_SVC_CHANNEL_NAME) == 0) + { + /* xrdp currently reserves dynamic channels for its + * exclusive use (e.g. for GFX support) */ + LOG(LOG_LEVEL_INFO, "Channel '%s' not passed to module", + ch_name); + } + else if (target_chan < MAX_STATIC_CHANNELS) + { + dst_ch_name = instance->settings->channels[target_chan].name; + ch_names[target_chan] = dst_ch_name; + g_memset(dst_ch_name, 0, CHANNEL_NAME_LEN + 1); + g_snprintf(dst_ch_name, CHANNEL_NAME_LEN + 1, "%s", ch_name); + instance->settings->channels[target_chan].options = ch_flags; + ++target_chan; + } } } - instance->settings->num_channels = num_chans; + g_strnjoin(ch_name, sizeof(ch_name), ",", ch_names, target_chan); + LOG(LOG_LEVEL_INFO, "Static channels (from %d) passed to module : %s", + num_chans, ch_name); + + instance->settings->num_channels = target_chan; instance->settings->offscreen_bitmap_cache = 0; instance->settings->draw_nine_grid = 0;