From dfad088be552b61e244e6e9ae53e226a2c91c304 Mon Sep 17 00:00:00 2001 From: Christopher Pitstick Date: Tue, 25 May 2021 00:05:54 -0400 Subject: [PATCH] Unify monitor processing logic. There are two places where monitor descriptions are passed through the RDP protocol: - TS_UD_CS_MONITOR - DISPLAYCONTROL_PDU_TYPE_MONITOR_LAYOUT The processing logic for both of them is similar enough that they should be unified. Note that this is also the first step to making resizing work with the Extension GFX channel. --- common/xrdp_client_info.h | 21 ++++ libxrdp/xrdp_sec.c | 249 +++++++++++++++++++++----------------- xrdp/xrdp_mm.c | 179 ++++++++++++++++----------- 3 files changed, 268 insertions(+), 181 deletions(-) diff --git a/common/xrdp_client_info.h b/common/xrdp_client_info.h index 485221051e..4a1689453d 100644 --- a/common/xrdp_client_info.h +++ b/common/xrdp_client_info.h @@ -24,13 +24,34 @@ #if !defined(XRDP_CLIENT_INFO_H) #define XRDP_CLIENT_INFO_H +/* + * 2.2.1.3.6.1 Monitor Definition (TS_MONITOR_DEF) + * 2.2.1.3.9.1 Monitor Attributes (TS_MONITOR_ATTRIBUTES) + */ struct monitor_info { int left; int top; + int width; + int height; int right; int bottom; + int physical_width; + int physical_height; + int orientation; + int desktop_scale_factor; + int device_scale_factor; int is_primary; + int flags; +}; + +struct display_size_description +{ + int monitorCount; /* number of monitors detected (max = 16) */ + struct monitor_info minfo[CLIENT_MONITOR_DATA_MAXIMUM_MONITORS]; /* client monitor data */ + struct monitor_info minfo_wm[CLIENT_MONITOR_DATA_MAXIMUM_MONITORS]; /* client monitor data, non-negative values */ + int session_width; + int session_height; }; /** diff --git a/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c index 7fdf3fc8c3..31c2ada9fa 100644 --- a/libxrdp/xrdp_sec.c +++ b/libxrdp/xrdp_sec.c @@ -2298,159 +2298,190 @@ xrdp_sec_process_mcs_data_channels(struct xrdp_sec *self, struct stream *s) return 0; } -/*****************************************************************************/ -/* Process a [MS-RDPBCGR] TS_UD_CS_MONITOR message. - reads the client monitors data */ -static int -xrdp_sec_process_mcs_data_monitors(struct xrdp_sec *self, struct stream *s) -{ - int index; - int monitorCount; - int flags; - int x1; - int y1; - int x2; - int y2; - int got_primary; - struct xrdp_client_info *client_info = (struct xrdp_client_info *)NULL; +struct display_size_description* +process_monitor_stream(struct stream *s, int full_parameters) { + struct display_size_description *description = (struct display_size_description *) + g_malloc(sizeof(struct display_size_description), 1); - client_info = &(self->rdp_layer->client_info); + int NumMonitor; + struct monitor_info *monitor_layout; + struct xrdp_rect rect = {8192, 8192, -8192, -8192}; + int got_primary = 0; - /* this is an option set in xrdp.ini */ - if (client_info->multimon != 1) /* are multi-monitors allowed ? */ - { - LOG(LOG_LEVEL_INFO, "Multi-monitor is disabled by server config"); - return 0; - } - if (!s_check_rem_and_log(s, 8, "Parsing [MS-RDPBCGR] TS_UD_CS_MONITOR")) - { - return 1; - } - in_uint32_le(s, flags); /* flags */ - in_uint32_le(s, monitorCount); - LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPBCGR] TS_UD_CS_MONITOR " - "flags 0x%8.8x, monitorCount %d", flags, monitorCount); + in_uint32_le(s, NumMonitor); + LOG(LOG_LEVEL_DEBUG, " NumMonitor %d", NumMonitor); - //verify flags - must be 0x0 - if (flags != 0) - { - LOG(LOG_LEVEL_ERROR, - "[MS-RDPBCGR] Protocol error: TS_UD_CS_MONITOR flags MUST be zero, " - "received: 0x%8.8x", flags); - return 1; - } - //verify monitorCount - max 16 - if (monitorCount > 16) + if (NumMonitor >= CLIENT_MONITOR_DATA_MAXIMUM_MONITORS) { LOG(LOG_LEVEL_ERROR, "[MS-RDPBCGR] Protocol error: TS_UD_CS_MONITOR monitorCount " - "MUST be less than 16, received: %d", monitorCount); - return 1; + "MUST be less than 16, received: %d", NumMonitor); + goto exit_error; } - client_info->monitorCount = monitorCount; + description->monitorCount = NumMonitor; - x1 = 0; - y1 = 0; - x2 = 0; - y2 = 0; - got_primary = 0; - /* Add client_monitor_data to client_info struct, will later pass to X11rdp */ - for (index = 0; index < monitorCount; index++) + for (int monitor_index = 0; monitor_index < NumMonitor; ++monitor_index) { - if (!s_check_rem_and_log(s, 20, "Parsing [MS-RDPBCGR] TS_UD_CS_MONITOR.TS_MONITOR_DEF")) + if (!s_check_rem_and_log(s, full_parameters == 0 ? 20 : 40, "Parsing monitor definitions.")) { - return 1; + goto exit_error; } - in_uint32_le(s, client_info->minfo[index].left); - in_uint32_le(s, client_info->minfo[index].top); - in_uint32_le(s, client_info->minfo[index].right); - in_uint32_le(s, client_info->minfo[index].bottom); - in_uint32_le(s, client_info->minfo[index].is_primary); - - LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPBCGR] " - "TS_UD_CS_MONITOR.TS_MONITOR_DEF %d " - "left %d, top %d, right %d, bottom %d, flags 0x%8.8x", - index, - client_info->minfo[index].left, - client_info->minfo[index].top, - client_info->minfo[index].right, - client_info->minfo[index].bottom, - client_info->minfo[index].is_primary); - - if (index == 0) - { - x1 = client_info->minfo[index].left; - y1 = client_info->minfo[index].top; - x2 = client_info->minfo[index].right; - y2 = client_info->minfo[index].bottom; + + monitor_layout = description->minfo + monitor_index; + if (full_parameters != 0) { + in_uint32_le(s, monitor_layout->flags); + } + in_uint32_le(s, monitor_layout->left); + in_uint32_le(s, monitor_layout->top); + in_uint32_le(s, monitor_layout->width); + in_uint32_le(s, monitor_layout->height); + if (full_parameters != 0) { + in_uint32_le(s, monitor_layout->physical_width); + in_uint32_le(s, monitor_layout->physical_height); + in_uint32_le(s, monitor_layout->orientation); + in_uint32_le(s, monitor_layout->desktop_scale_factor); + in_uint32_le(s, monitor_layout->device_scale_factor); + } + + monitor_layout->right = monitor_layout->left + monitor_layout->width; + monitor_layout->bottom = monitor_layout->top + monitor_layout->height; + + if (full_parameters != 0) + { + LOG(LOG_LEVEL_INFO, " Index: %d, Flags 0x%8.8x Left %d Top %d " + "Width %d Height %d PhysicalWidth %d PhysicalHeight %d " + "Orientation %d DesktopScaleFactor %d DeviceScaleFactor %d", + monitor_index, monitor_layout->flags, monitor_layout->left, + monitor_layout->top, monitor_layout->width, monitor_layout->height, + monitor_layout->physical_width, monitor_layout->physical_height, + monitor_layout->orientation, monitor_layout->desktop_scale_factor, + monitor_layout->device_scale_factor); } else { - x1 = MIN(x1, client_info->minfo[index].left); - y1 = MIN(y1, client_info->minfo[index].top); - x2 = MAX(x2, client_info->minfo[index].right); - y2 = MAX(y2, client_info->minfo[index].bottom); + LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPBCGR] " + "TS_UD_CS_MONITOR.TS_MONITOR_DEF %d " + "left %d, top %d, right %d, bottom %d, flags 0x%8.8x", + monitor_index, + monitor_layout->left, + monitor_layout->top, + monitor_layout->right, + monitor_layout->bottom, + monitor_layout->is_primary); } - if (client_info->minfo[index].is_primary) + if (monitor_index == 0) { - got_primary = 1; + rect.left = monitor_layout->left; + rect.top = monitor_layout->top; + rect.right = monitor_layout->right; + rect.bottom = monitor_layout->bottom; + } + else + { + rect.left = MIN(monitor_layout->left, rect.left); + rect.top = MIN(monitor_layout->top, rect.top); + rect.right = MAX(rect.right, monitor_layout->right); + rect.bottom = MAX(rect.bottom, monitor_layout->bottom); } - LOG(LOG_LEVEL_DEBUG, - "Client monitor [%d]: left= %d, top= %d, right= %d, bottom= %d, " - "is_primary?= %d", - index, - client_info->minfo[index].left, - client_info->minfo[index].top, - client_info->minfo[index].right, - client_info->minfo[index].bottom, - client_info->minfo[index].is_primary); + if (monitor_layout->is_primary) + { + got_primary = 1; + } } if (!got_primary) { /* no primary monitor was set, choose the leftmost monitor as primary */ - for (index = 0; index < monitorCount; index++) + for (int monitor_index = 0; monitor_index < NumMonitor; ++monitor_index) { - if (client_info->minfo[index].left == x1 && - client_info->minfo[index].top == y1) + monitor_layout = description->minfo + monitor_index; + if (monitor_layout->left != rect.left || monitor_layout->top != rect.top) { - client_info->minfo[index].is_primary = 1; - break; + continue; } + monitor_layout->is_primary = 1; } } /* set wm geometry */ - if ((x2 > x1) && (y2 > y1)) + if ((rect.right > rect.left) && (rect.bottom > rect.top)) { - client_info->width = (x2 - x1) + 1; - client_info->height = (y2 - y1) + 1; + description->session_width = rect.right - rect.left; + description->session_height = rect.bottom - rect.top; } /* make sure virtual desktop size is ok */ - if (client_info->width > 0x7FFE || client_info->width < 0xC8 || - client_info->height > 0x7FFE || client_info->height < 0xC8) + if (description->session_width > 0x7FFE || description->session_width < 0xC8 || + description->session_height > 0x7FFE || description->session_height < 0xC8) { - LOG(LOG_LEVEL_ERROR, + LOG(LOG_LEVEL_INFO, "Client supplied virtual desktop width or height is invalid. " "Allowed width range: min %d, max %d. Width received: %d. " "Allowed height range: min %d, max %d. Height received: %d", - 0xC8, 0x7FFE, client_info->width, - 0xC8, 0x7FFE, client_info->height); - return 1; /* error */ + 0xC8, 0x7FFE, description->session_width, + 0xC8, 0x7FFE, description->session_width); + goto exit_error; } /* keep a copy of non negative monitor info values for xrdp_wm usage */ - for (index = 0; index < monitorCount; index++) + for (int monitor_index = 0; monitor_index < NumMonitor; ++monitor_index) { - client_info->minfo_wm[index].left = client_info->minfo[index].left - x1; - client_info->minfo_wm[index].top = client_info->minfo[index].top - y1; - client_info->minfo_wm[index].right = client_info->minfo[index].right - x1; - client_info->minfo_wm[index].bottom = client_info->minfo[index].bottom - y1; - client_info->minfo_wm[index].is_primary = client_info->minfo[index].is_primary; + monitor_layout = description->minfo_wm + monitor_index; + + g_memcpy(monitor_layout, description->minfo + monitor_index, sizeof(struct monitor_info)); + + monitor_layout->left = monitor_layout->left - rect.left; + monitor_layout->top = monitor_layout->top - rect.top; + monitor_layout->right = monitor_layout->right - rect.left; + monitor_layout->bottom = monitor_layout->bottom - rect.top; } + return description; +exit_error: + g_free(description); + return NULL; +} + +/*****************************************************************************/ +/* Process a [MS-RDPBCGR] TS_UD_CS_MONITOR message. + reads the client monitors data */ +static int +xrdp_sec_process_mcs_data_monitors(struct xrdp_sec *self, struct stream *s) +{ + int flags; + struct xrdp_client_info *client_info = &(self->rdp_layer->client_info); + + /* this is an option set in xrdp.ini */ + if (client_info->multimon != 1) /* are multi-monitors allowed ? */ + { + LOG(LOG_LEVEL_INFO, "Multi-monitor is disabled by server config"); + return 0; + } + if (!s_check_rem_and_log(s, 8, "Parsing [MS-RDPBCGR] TS_UD_CS_MONITOR")) + { + return 1; + } + in_uint32_le(s, flags); /* flags */ + + //verify flags - must be 0x0 + if (flags != 0) + { + LOG(LOG_LEVEL_ERROR, + "[MS-RDPBCGR] Protocol error: TS_UD_CS_MONITOR flags MUST be zero, " + "received: 0x%8.8x", flags); + return 1; + } + + struct display_size_description *description = process_monitor_stream(s, 0); + + client_info->monitorCount = description->monitorCount; + client_info->width = description->session_width; + client_info->height = description->session_height; + g_memcpy(client_info->minfo, description->minfo, sizeof(struct monitor_info) * CLIENT_MONITOR_DATA_MAXIMUM_MONITORS); + g_memcpy(client_info->minfo_wm, description->minfo_wm, sizeof(struct monitor_info) * CLIENT_MONITOR_DATA_MAXIMUM_MONITORS); + + g_free(description); return 0; } diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 6f501fd4aa..57f7c51407 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -1042,27 +1042,110 @@ dynamic_monitor_data_first(intptr_t id, int chan_id, char *data, int bytes, return 0; } +/******************************************************************************/ +static int +process_dynamic_monitor_description(struct xrdp_wm *wm, struct display_size_description *description) { + int error = 0; + struct xrdp_mm* mm = wm->mm; + struct xrdp_mod* module = mm->mod; + + if (wm->client_info->suppress_output == 1) { + LOG(LOG_LEVEL_INFO, "process_dynamic_monitor_description: Not allowing resize. Suppress output is active."); + return 0; + } + if (description->session_width <= 0 || description->session_height <= 0) { + LOG(LOG_LEVEL_INFO, "process_dynamic_monitor_description: Not allowing resize due to invalid dimensions (w: %d x h: %d)", description->session_width, description->session_height); + return 0; + } + + // TODO: Unify this logic with server_reset + error = libxrdp_reset(wm->session, description->session_width, description->session_height, wm->screen->bpp); + if (error != 0) + { + LOG(LOG_LEVEL_INFO, "dynamic_monitor_data: libxrdp_reset failed %d", error); + return error; + } + /* reset cache */ + error = xrdp_cache_reset(wm->cache, wm->client_info); + if (error != 0) + { + LOG(LOG_LEVEL_INFO, "dynamic_monitor_data: xrdp_cache_reset failed %d", error); + return error; + } + /* load some stuff */ + error = xrdp_wm_load_static_colors_plus(wm, 0); + if (error != 0) + { + LOG(LOG_LEVEL_INFO, "dynamic_monitor_data: xrdp_wm_load_static_colors_plus failed %d", error); + return error; + } + + error = xrdp_wm_load_static_pointers(wm); + if (error != 0) + { + LOG(LOG_LEVEL_INFO, "dynamic_monitor_data: xrdp_wm_load_static_pointers failed %d", error); + return error; + } + /* resize the main window */ + error = xrdp_bitmap_resize(wm->screen, description->session_width, description->session_height); + if (error != 0) + { + LOG(LOG_LEVEL_INFO, "dynamic_monitor_data: xrdp_bitmap_resize failed %d", error); + return error; + } + /* redraw */ + error = xrdp_bitmap_invalidate(wm->screen, 0); + if (error != 0) + { + LOG(LOG_LEVEL_INFO, "dynamic_monitor_data: xrdp_bitmap_invalidate failed %d", error); + return error; + } + + if (module != 0) { + error = module->mod_server_version_message(module); + if (error != 0) + { + LOG_DEVEL(LOG_LEVEL_INFO, "dynamic_monitor_data: mod_server_version_message failed %d", error); + return error; + } + error = module->mod_server_monitor_resize(module, description->session_width, description->session_height); + if (error != 0) + { + LOG_DEVEL(LOG_LEVEL_INFO, "dynamic_monitor_data: mod_server_monitor_resize failed %d", error); + return error; + } + error = module->mod_server_monitor_full_invalidate(module, description->session_width, description->session_height); + if (error != 0) + { + LOG_DEVEL(LOG_LEVEL_INFO, "dynamic_monitor_data: mod_server_monitor_full_invalidate failed %d", error); + return error; + } + } + + wm->client_info->monitorCount = description->monitorCount; + wm->client_info->width = description->session_width; + wm->client_info->height = description->session_height; + g_memcpy(wm->client_info->minfo, description->minfo, sizeof(struct monitor_info) * CLIENT_MONITOR_DATA_MAXIMUM_MONITORS); + g_memcpy(wm->client_info->minfo_wm, description->minfo_wm, sizeof(struct monitor_info) * CLIENT_MONITOR_DATA_MAXIMUM_MONITORS); + return 0; +} + +/******************************************************************************/ +struct display_size_description* +process_monitor_stream(struct stream *s, int full_parameters); + /******************************************************************************/ static int dynamic_monitor_data(intptr_t id, int chan_id, char *data, int bytes) { + int error = 0; struct stream ls; struct stream *s; int msg_type; int msg_length; - int monitor_index; struct xrdp_process *pro; struct xrdp_wm *wm; - int MonitorLayoutSize; - int NumMonitor; - - struct dynamic_monitor_layout monitor_layouts[CLIENT_MONITOR_DATA_MAXIMUM_MONITORS]; - struct dynamic_monitor_layout *monitor_layout; - - struct xrdp_rect rect; - int session_width; - int session_height; LOG_DEVEL(LOG_LEVEL_TRACE, "dynamic_monitor_data:"); pro = (struct xrdp_process *) id; @@ -1078,69 +1161,21 @@ dynamic_monitor_data(intptr_t id, int chan_id, char *data, int bytes) LOG(LOG_LEVEL_DEBUG, "dynamic_monitor_data: msg_type %d msg_length %d", msg_type, msg_length); - rect.left = 8192; - rect.top = 8192; - rect.right = -8192; - rect.bottom = -8192; - - if (msg_type == DISPLAYCONTROL_PDU_TYPE_MONITOR_LAYOUT) - { - in_uint32_le(s, MonitorLayoutSize); - in_uint32_le(s, NumMonitor); - LOG(LOG_LEVEL_DEBUG, " MonitorLayoutSize %d NumMonitor %d", - MonitorLayoutSize, NumMonitor); - for (monitor_index = 0; monitor_index < NumMonitor; monitor_index++) - { - monitor_layout = monitor_layouts + monitor_index; - in_uint32_le(s, monitor_layout->flags); - in_uint32_le(s, monitor_layout->left); - in_uint32_le(s, monitor_layout->top); - in_uint32_le(s, monitor_layout->width); - in_uint32_le(s, monitor_layout->height); - in_uint32_le(s, monitor_layout->physical_width); - in_uint32_le(s, monitor_layout->physical_height); - in_uint32_le(s, monitor_layout->orientation); - in_uint32_le(s, monitor_layout->desktop_scale_factor); - in_uint32_le(s, monitor_layout->device_scale_factor); - LOG_DEVEL(LOG_LEVEL_DEBUG, " Flags 0x%8.8x Left %d Top %d " - "Width %d Height %d PhysicalWidth %d PhysicalHeight %d " - "Orientation %d DesktopScaleFactor %d DeviceScaleFactor %d", - monitor_layout->flags, monitor_layout->left, monitor_layout->top, - monitor_layout->width, monitor_layout->height, - monitor_layout->physical_width, monitor_layout->physical_height, - monitor_layout->orientation, monitor_layout->desktop_scale_factor, - monitor_layout->device_scale_factor); - - rect.left = MIN(monitor_layout->left, rect.left); - rect.top = MIN(monitor_layout->top, rect.top); - rect.right = MAX(rect.right, monitor_layout->left + monitor_layout->width); - rect.bottom = MAX(rect.bottom, monitor_layout->top + monitor_layout->height); - } - } - session_width = rect.right - rect.left; - session_height = rect.bottom - rect.top; - if ((session_width > 0) && (session_height > 0)) - { - // TODO: Unify this logic with server_reset - libxrdp_reset(wm->session, session_width, session_height, wm->screen->bpp); - /* reset cache */ - xrdp_cache_reset(wm->cache, wm->client_info); - /* resize the main window */ - xrdp_bitmap_resize(wm->screen, session_width, session_height); - /* load some stuff */ - xrdp_wm_load_static_colors_plus(wm, 0); - xrdp_wm_load_static_pointers(wm); - /* redraw */ - xrdp_bitmap_invalidate(wm->screen, 0); - - struct xrdp_mod* v = wm->mm->mod; - if (v != 0) { - v->mod_server_version_message(v); - v->mod_server_monitor_resize(v, session_width, session_height); - v->mod_server_monitor_full_invalidate(v, session_width, session_height); - } + if (msg_type != DISPLAYCONTROL_PDU_TYPE_MONITOR_LAYOUT) + { + return 0; } - return 0; + in_uint32_le(s, MonitorLayoutSize); + if (MonitorLayoutSize != 40) + { + /* 2.2.2.2 DISPLAYCONTROL_MONITOR_LAYOUT_PDU */ + LOG(LOG_LEVEL_ERROR, "dynamic_monitor_data: MonitorLayoutSize is %d. Per spec it must be 40.", MonitorLayoutSize); + return 1; + } + struct display_size_description *description = process_monitor_stream(s, 1); + error = process_dynamic_monitor_description(wm, description); + g_free(description); + return error; } /******************************************************************************/