From 4a0db63be7b42c887379c3ef574e71112c8fd427 Mon Sep 17 00:00:00 2001 From: Christopher Pitstick Date: Tue, 25 May 2021 00:05:54 -0400 Subject: [PATCH 1/2] Unify monitor processing logic. There are two places where monitor descriptions are passed through the RDP protocol: - TS_UD_CS_MONITOR ([MS-RDPBCGR] 2.2.1.3.6 Client Monitor Data) - DISPLAYCONTROL_PDU_TYPE_MONITOR_LAYOUT ([MS-RDPEDISP] 2.2.2.2) The processing logic for both of them is similar enough that they should be unified. Also update to define the constants for the maximum and minimum desktop width/height for monitors and total area. Also a large number of clarifications for the constants and protocol requirements. Note that this is also the first step to making resizing work with the extension GFX channel as well as an important foundational step to enable HiDPI compatibility. Also some misc logging updates. --- common/ms-rdpbcgr.h | 18 +- common/ms-rdpedisp.h | 16 +- common/xrdp_client_info.h | 25 ++ libxrdp/libxrdp.c | 324 +++++++++++++++++++++++- libxrdp/libxrdp.h | 12 + libxrdp/libxrdpinc.h | 20 ++ libxrdp/xrdp_sec.c | 156 +++--------- tests/libxrdp/test_monitor_processing.c | 15 +- xrdp/xrdp_mm.c | 236 +++++++++++------ 9 files changed, 606 insertions(+), 216 deletions(-) diff --git a/common/ms-rdpbcgr.h b/common/ms-rdpbcgr.h index 813dc4dba3..e993c27077 100644 --- a/common/ms-rdpbcgr.h +++ b/common/ms-rdpbcgr.h @@ -83,10 +83,24 @@ #define RDPSND_SVC_CHANNEL_NAME "rdpsnd" #define RDPDR_SVC_CHANNEL_NAME "rdpdr" -/* 2.2.1.3.6 Client Monitor Data - */ +/* 2.2.1.3.6 Client Monitor Data */ /* monitorCount (4 bytes): A 32-bit, unsigned integer. The number of display */ /* monitor definitions in the monitorDefArray field (the maximum allowed is 16). */ -#define CLIENT_MONITOR_DATA_MAXIMUM_MONITORS 16 +#define CLIENT_MONITOR_DATA_MAXIMUM_MONITORS 16 + +/* 2.2.1.3.6 Client Monitor Data */ +/* The maximum width of the virtual desktop resulting from the union of the monitors */ +/* contained in the monitorDefArray field MUST NOT exceed 32,766 pixels. Similarly, */ +/* the maximum height of the virtual desktop resulting from the union of the monitors */ +/* contained in the monitorDefArray field MUST NOT exceed 32,766 pixels. */ +/* The minimum permitted size of the virtual desktop is 200 x 200 pixels. */ +#define CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_WIDTH 0xC8 +#define CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_HEIGHT 0xC8 +#define CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_WIDTH 0x7FFE +#define CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_HEIGHT 0x7FFE + +/* 2.2.1.3.6.1 Monitor Definition (TS_MONITOR_DEF) */ +#define TS_MONITOR_PRIMARY 0x00000001 /* Options field */ /* NOTE: XR_ prefixed to avoid conflict with FreeRDP */ diff --git a/common/ms-rdpedisp.h b/common/ms-rdpedisp.h index dd3d51e77e..2e45b945e7 100644 --- a/common/ms-rdpedisp.h +++ b/common/ms-rdpedisp.h @@ -23,7 +23,19 @@ #define MS_RDPEDISP_H /* Display Control Messages: Display Virtual Channel Extension (2.2.2) */ -#define DISPLAYCONTROL_PDU_TYPE_MONITOR_LAYOUT 0x00000002 -#define DISPLAYCONTROL_PDU_TYPE_CAPS 0x00000005 +#define DISPLAYCONTROL_PDU_TYPE_MONITOR_LAYOUT 0x00000002 +#define DISPLAYCONTROL_PDU_TYPE_CAPS 0x00000005 + +/* Display Control Monitor Layout (2.2.2.2.1) */ +#define DISPLAYCONTROL_MONITOR_PRIMARY 0x00000001 +#define CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_MONITOR_WIDTH 0xC8 +#define CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_MONITOR_HEIGHT 0xC8 +#define CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_MONITOR_WIDTH 0x2000 +#define CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_MONITOR_HEIGHT 0x2000 + +#define ORIENTATION_LANDSCAPE 0 +#define ORIENTATION_PORTRAIT 90 +#define ORIENTATION_LANDSCAPE_FLIPPED 180 +#define ORIENTATION_PORTRAIT_FLIPPED 270 #endif /* MS_RDPEDISP_H */ diff --git a/common/xrdp_client_info.h b/common/xrdp_client_info.h index f45195e89f..106e47a7e3 100644 --- a/common/xrdp_client_info.h +++ b/common/xrdp_client_info.h @@ -24,12 +24,28 @@ #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) + * 2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT + */ struct monitor_info { + /* From 2.2.1.3.6.1 Monitor Definition (TS_MONITOR_DEF) */ int left; int top; int right; int bottom; + int flags; + + /* From 2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT */ + int physical_width; + int physical_height; + int orientation; + int desktop_scale_factor; + int device_scale_factor; + + /* Derived setting */ int is_primary; }; @@ -41,6 +57,15 @@ struct xrdp_keyboard_overrides int layout; }; +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; +}; + /** * Information about the xrdp client * diff --git a/libxrdp/libxrdp.c b/libxrdp/libxrdp.c index 637dff021a..f25b18c288 100644 --- a/libxrdp/libxrdp.c +++ b/libxrdp/libxrdp.c @@ -25,11 +25,9 @@ #include "libxrdp.h" #include "string_calls.h" #include "xrdp_orders_rail.h" - +#include "ms-rdpedisp.h" #include "ms-rdpbcgr.h" - - #define MAX_BITMAP_BUF_SIZE (16 * 1024) /* 16K */ /******************************************************************************/ @@ -1766,3 +1764,323 @@ libxrdp_send_session_info(struct xrdp_session *session, const char *data, return xrdp_rdp_send_session_info(rdp, data, data_bytes); } +/*****************************************************************************/ +/* + Process a [MS-RDPBCGR] TS_UD_CS_MONITOR message. + reads the client monitors data +*/ +int +libxrdp_process_monitor_stream(struct stream *s, + struct display_size_description *description, + int full_parameters) +{ + uint32_t num_monitor; + uint32_t monitor_index; + struct monitor_info *monitor_layout; + struct xrdp_rect all_monitors_encompassing_bounds = {0}; + int got_primary = 0; + int monitor_struct_stream_check_bytes; + const char *monitor_struct_stream_check_message; + + LOG_DEVEL(LOG_LEVEL_TRACE, "libxrdp_process_monitor_stream:"); + if (description == NULL) + { + LOG_DEVEL(LOG_LEVEL_ERROR, "libxrdp_process_monitor_stream: description was" + " null. Valid pointer to allocated description expected."); + return SEC_PROCESS_MONITORS_ERR; + } + + if (!s_check_rem_and_log(s, 4, + "libxrdp_process_monitor_stream:" + " Parsing [MS-RDPBCGR] TS_UD_CS_MONITOR")) + { + return SEC_PROCESS_MONITORS_ERR; + } + + in_uint32_le(s, num_monitor); + LOG(LOG_LEVEL_DEBUG, "libxrdp_process_monitor_stream:" + " The number of monitors received is: %d", + num_monitor); + + if (num_monitor >= CLIENT_MONITOR_DATA_MAXIMUM_MONITORS) + { + LOG(LOG_LEVEL_ERROR, + "libxrdp_process_monitor_stream: [MS-RDPBCGR] Protocol" + " error: TS_UD_CS_MONITOR monitorCount" + " MUST be less than %d, received: %d", + CLIENT_MONITOR_DATA_MAXIMUM_MONITORS, num_monitor); + return SEC_PROCESS_MONITORS_ERR_TOO_MANY_MONITORS; + } + + /* + * Unfortunately the structure length values aren't directly defined in the + * Microsoft specifications. They are derived from the lengths of the + * specific structures referenced below. + */ + if (full_parameters == 0) + { + monitor_struct_stream_check_bytes = 20; + monitor_struct_stream_check_message = + "libxrdp_process_monitor_stream: Parsing monitor definitions" + " from [MS-RDPBCGR] 2.2.1.3.6.1 Monitor Definition" + " (TS_MONITOR_DEF)."; + } + else + { + monitor_struct_stream_check_bytes = 40; + monitor_struct_stream_check_message = + "libxrdp_process_monitor_stream: Parsing monitor definitions" + " from [MS-RDPEDISP] 2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT."; + } + + description->monitorCount = num_monitor; + + for (monitor_index = 0; monitor_index < num_monitor; ++monitor_index) + { + if (!s_check_rem_and_log( + s, + monitor_struct_stream_check_bytes, + monitor_struct_stream_check_message)) + { + return SEC_PROCESS_MONITORS_ERR; + } + + 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); + + if (full_parameters == 0) + { + in_uint32_le(s, monitor_layout->right); + in_uint32_le(s, monitor_layout->bottom); + in_uint32_le(s, monitor_layout->is_primary); + + /* + * 2.2.1.3.6.1 Monitor Definition (TS_MONITOR_DEF) + */ + LOG_DEVEL(LOG_LEVEL_TRACE, "libxrdp_process_monitor_stream:" + " Received [MS-RDPBCGR] 2.2.1.3.6.1" + " TS_UD_CS_MONITOR.TS_MONITOR_DEF" + " Index: %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); + } + else + { + /* Per spec (2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT), + * this is the width. + * 200 <= width <= 8192 and must not be odd. + * Ex: in_uint32_le(s, monitor_layout->width); + */ + in_uint32_le(s, monitor_layout->right); + if (monitor_layout->right + > CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_MONITOR_WIDTH + || monitor_layout->right + < CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_MONITOR_WIDTH + || monitor_layout->right % 2 != 0) + { + return SEC_PROCESS_MONITORS_ERR_INVALID_MONITOR; + } + + /* Per spec (2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT), + * this is the height. + * 200 <= height <= 8192 + * Ex: in_uint32_le(s, monitor_layout->height); + */ + in_uint32_le(s, monitor_layout->bottom); + if (monitor_layout->bottom + > CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_MONITOR_HEIGHT + || monitor_layout->bottom + < CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_MONITOR_HEIGHT) + { + return SEC_PROCESS_MONITORS_ERR_INVALID_MONITOR; + } + + in_uint32_le(s, monitor_layout->physical_width); + in_uint32_le(s, monitor_layout->physical_height); + + in_uint32_le(s, monitor_layout->orientation); + switch (monitor_layout->orientation) { + case ORIENTATION_LANDSCAPE: + case ORIENTATION_PORTRAIT: + case ORIENTATION_LANDSCAPE_FLIPPED: + case ORIENTATION_PORTRAIT_FLIPPED: + break; + default: + LOG(LOG_LEVEL_WARNING, "libxrdp_process_monitor_stream:" + " Orientation is not one of %d, %d, %d, or %d." + " Value was %d and ignored.", + ORIENTATION_LANDSCAPE, + ORIENTATION_PORTRAIT, + ORIENTATION_LANDSCAPE_FLIPPED, + ORIENTATION_PORTRAIT_FLIPPED, + monitor_layout->orientation); + } + + in_uint32_le(s, monitor_layout->desktop_scale_factor); + in_uint32_le(s, monitor_layout->device_scale_factor); + + /* + * 2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT + */ + LOG_DEVEL(LOG_LEVEL_TRACE, "libxrdp_process_monitor_stream:" + " Received [MS-RDPEDISP] 2.2.2.2.1" + " DISPLAYCONTROL_MONITOR_LAYOUT_PDU" + ".DISPLAYCONTROL_MONITOR_LAYOUT" + " 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->right, + monitor_layout->bottom, + monitor_layout->physical_width, + monitor_layout->physical_height, + monitor_layout->orientation, + monitor_layout->desktop_scale_factor, + monitor_layout->device_scale_factor); + + monitor_layout->right = + monitor_layout->left + monitor_layout->right; + monitor_layout->bottom = + monitor_layout->top + monitor_layout->bottom; + + if (monitor_layout->flags == DISPLAYCONTROL_MONITOR_PRIMARY) + { + monitor_layout->is_primary = TS_MONITOR_PRIMARY; + } + } + + if (monitor_index == 0) + { + all_monitors_encompassing_bounds.left = monitor_layout->left; + all_monitors_encompassing_bounds.top = monitor_layout->top; + all_monitors_encompassing_bounds.right = monitor_layout->right; + all_monitors_encompassing_bounds.bottom = monitor_layout->bottom; + } + else + { + all_monitors_encompassing_bounds.left = + MIN(monitor_layout->left, + all_monitors_encompassing_bounds.left); + all_monitors_encompassing_bounds.top = + MIN(monitor_layout->top, + all_monitors_encompassing_bounds.top); + all_monitors_encompassing_bounds.right = + MAX(all_monitors_encompassing_bounds.right, + monitor_layout->right); + all_monitors_encompassing_bounds.bottom = + MAX(all_monitors_encompassing_bounds.bottom, + monitor_layout->bottom); + } + + if (monitor_layout->is_primary == TS_MONITOR_PRIMARY) + { + got_primary = 1; + } + } + + if (!got_primary) + { + /* no primary monitor was set, + * choose the leftmost monitor as primary. + */ + for (monitor_index = 0; monitor_index < num_monitor; ++monitor_index) + { + monitor_layout = description->minfo + monitor_index; + if (monitor_layout->left + == all_monitors_encompassing_bounds.left + && monitor_layout->top + == all_monitors_encompassing_bounds.top) + { + monitor_layout->is_primary = TS_MONITOR_PRIMARY; + break; + } + } + } + + /* set wm geometry if the encompassing area is well formed. Otherwise, log and return an error.*/ + if (all_monitors_encompassing_bounds.right + > all_monitors_encompassing_bounds.left + && all_monitors_encompassing_bounds.bottom + > all_monitors_encompassing_bounds.top) + { + description->session_width = + all_monitors_encompassing_bounds.right + - all_monitors_encompassing_bounds.left + 1; + description->session_height = + all_monitors_encompassing_bounds.bottom + - all_monitors_encompassing_bounds.top + 1; + } + else + { + LOG(LOG_LEVEL_ERROR, "libxrdp_process_monitor_stream:" + " The area encompassing the monitors is not a" + " well-formed rectangle. Received" + " (top: %d, left: %d, right: %d, bottom: %d)." + " This will prevent initialization.", + all_monitors_encompassing_bounds.top, + all_monitors_encompassing_bounds.left, + all_monitors_encompassing_bounds.right, + all_monitors_encompassing_bounds.bottom); + return SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP; + } + + /* Make sure virtual desktop size is OK + * 2.2.1.3.6 Client Monitor Data (TS_UD_CS_MONITOR) + */ + if (description->session_width + > CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_WIDTH + || description->session_width + < CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_WIDTH + || description->session_height + > CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_HEIGHT + || description->session_height + < CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_HEIGHT) + { + LOG(LOG_LEVEL_ERROR, + "libxrdp_process_monitor_stream: 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", + CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_WIDTH, + CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_WIDTH, + description->session_width, + CLIENT_MONITOR_DATA_MINIMUM_VIRTUAL_DESKTOP_HEIGHT, + CLIENT_MONITOR_DATA_MAXIMUM_VIRTUAL_DESKTOP_HEIGHT, + description->session_width); + return SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP; + } + + /* keep a copy of non negative monitor info values for xrdp_wm usage */ + for (monitor_index = 0; monitor_index < num_monitor; ++monitor_index) + { + 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 - all_monitors_encompassing_bounds.left; + monitor_layout->top = + monitor_layout->top - all_monitors_encompassing_bounds.top; + monitor_layout->right = + monitor_layout->right - all_monitors_encompassing_bounds.left; + monitor_layout->bottom = + monitor_layout->bottom - all_monitors_encompassing_bounds.top; + } + return 0; +} diff --git a/libxrdp/libxrdp.h b/libxrdp/libxrdp.h index b0eae8c61a..fb931bf3d0 100644 --- a/libxrdp/libxrdp.h +++ b/libxrdp/libxrdp.h @@ -359,6 +359,16 @@ int xrdp_mcs_disconnect(struct xrdp_mcs *self); /* xrdp_sec.c */ + +/* + These are return values for xrdp_sec_process_mcs_data_monitors + to clarify any reason for a non-zero response code. +*/ +#define SEC_PROCESS_MONITORS_ERR 1 +#define SEC_PROCESS_MONITORS_ERR_TOO_MANY_MONITORS 2 +#define SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP 3 +#define SEC_PROCESS_MONITORS_ERR_INVALID_MONITOR 4 + struct xrdp_sec * xrdp_sec_create(struct xrdp_rdp *owner, struct trans *trans); void @@ -383,6 +393,8 @@ int xrdp_sec_incoming(struct xrdp_sec *self); int xrdp_sec_disconnect(struct xrdp_sec *self); +int +xrdp_sec_process_mcs_data_monitors(struct xrdp_sec *self, struct stream *s); /* xrdp_rdp.c */ struct xrdp_rdp * diff --git a/libxrdp/libxrdpinc.h b/libxrdp/libxrdpinc.h index 7ec669c42f..91a18ec3ae 100644 --- a/libxrdp/libxrdpinc.h +++ b/libxrdp/libxrdpinc.h @@ -86,6 +86,9 @@ struct xrdp_drdynvc_procs int (*data)(intptr_t id, int chan_id, char *data, int bytes); }; +/* Defined in xrdp_client_info.h */ +struct display_size_description; + /*** * Initialise the XRDP library * @@ -304,4 +307,21 @@ int EXPORT_CC libxrdp_send_session_info(struct xrdp_session *session, const char *data, int data_bytes); +/** + * Processes a stream that is based on either + * 2.2.1.3.6 Client Monitor Data (TS_UD_CS_MONITOR) or 2.2.2.2 DISPLAYCONTROL_MONITOR_LAYOUT_PDU + * and then stores the processed monitor data into the description parameter. + * @param s + * The stream to process. + * @param description + * Must be pre-allocated. Monitor data is filled in as part of processing the stream. + * @param full_parameters + * 0 if the monitor stream is from 2.2.1.3.6 Client Monitor Data (TS_UD_CS_MONITOR) + * 1 if the monitor stream is from 2.2.2.2 DISPLAYCONTROL_MONITOR_LAYOUT_PDU + * @return 0 if the data is processed, non-zero if there is an error. + */ +int EXPORT_CC +libxrdp_process_monitor_stream(struct stream *s, struct display_size_description *description, + int full_parameters); + #endif diff --git a/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c index 8fa34aea79..ba3ad70c61 100644 --- a/libxrdp/xrdp_sec.c +++ b/libxrdp/xrdp_sec.c @@ -27,8 +27,6 @@ #include "log.h" #include "string_calls.h" - - /* some compilers need unsigned char to avoid warnings */ static tui8 g_pad_54[40] = { @@ -2333,155 +2331,61 @@ xrdp_sec_process_mcs_data_channels(struct xrdp_sec *self, struct stream *s) 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; + int error = 0; + struct xrdp_client_info *client_info = &(self->rdp_layer->client_info); - client_info = &(self->rdp_layer->client_info); + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_sec_process_mcs_data_monitors:"); /* 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"); + LOG(LOG_LEVEL_INFO, + "xrdp_sec_process_mcs_data_monitors:" + " Multi-monitor is disabled by server config"); return 0; } - if (!s_check_rem_and_log(s, 8, "Parsing [MS-RDPBCGR] TS_UD_CS_MONITOR")) + if (!s_check_rem_and_log(s, 4, + "xrdp_sec_process_mcs_data_monitors:" + " Parsing [MS-RDPBCGR] TS_UD_CS_MONITOR")) { - return 1; + return SEC_PROCESS_MONITORS_ERR; } 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); //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) - { - LOG(LOG_LEVEL_ERROR, - "[MS-RDPBCGR] Protocol error: TS_UD_CS_MONITOR monitorCount " - "MUST be less than 16, received: %d", monitorCount); - return 2; + "xrdp_sec_process_mcs_data_monitors: [MS-RDPBCGR]" + " Protocol error: TS_UD_CS_MONITOR flags MUST be zero," + " received: 0x%8.8x", flags); + return SEC_PROCESS_MONITORS_ERR; } - client_info->monitorCount = monitorCount; + struct display_size_description *description = + (struct display_size_description *) + g_malloc(sizeof(struct display_size_description), 1); - 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++) + error = libxrdp_process_monitor_stream(s, description, 0); + if (error == 0) { - if (!s_check_rem_and_log(s, 20, "Parsing [MS-RDPBCGR] TS_UD_CS_MONITOR.TS_MONITOR_DEF")) - { - return 1; - } - 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; - } - 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); - } - - if (client_info->minfo[index].is_primary) - { - got_primary = 1; - } + client_info->monitorCount = description->monitorCount; - 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); - } + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_sec_process_mcs_data_monitors:" + " Received [MS-RDPBCGR] TS_UD_CS_MONITOR" + " flags 0x%8.8x, monitorCount %d", + flags, description->monitorCount); - if (!got_primary) - { - /* no primary monitor was set, choose the leftmost monitor as primary */ - for (index = 0; index < monitorCount; index++) - { - if (client_info->minfo[index].left == x1 && - client_info->minfo[index].top == y1) - { - client_info->minfo[index].is_primary = 1; - break; - } - } + 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); } - /* set wm geometry */ - if ((x2 > x1) && (y2 > y1)) - { - client_info->width = (x2 - x1) + 1; - client_info->height = (y2 - y1) + 1; - } - /* make sure virtual desktop size is ok */ - if (client_info->width > 0x7FFE || client_info->width < 0xC8 || - client_info->height > 0x7FFE || client_info->height < 0xC8) - { - LOG(LOG_LEVEL_ERROR, - "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 3; /* error */ - } + g_free(description); - /* keep a copy of non negative monitor info values for xrdp_wm usage */ - for (index = 0; index < monitorCount; 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; - } - - return 0; + return error; } /*****************************************************************************/ diff --git a/tests/libxrdp/test_monitor_processing.c b/tests/libxrdp/test_monitor_processing.c index 951ffe686d..0314e7ddf6 100644 --- a/tests/libxrdp/test_monitor_processing.c +++ b/tests/libxrdp/test_monitor_processing.c @@ -11,9 +11,6 @@ struct xrdp_sec *sec_layer; struct xrdp_rdp *rdp_layer; struct xrdp_session *session; -int -xrdp_sec_process_mcs_data_monitors(struct xrdp_sec *self, struct stream *s); - void setup(void) { rdp_layer = (struct xrdp_rdp *)g_malloc(sizeof(struct xrdp_rdp), 1); @@ -45,7 +42,7 @@ START_TEST(test_process_monitors__when_flags_is_not_zero__fail) s->p = s->data; int error = xrdp_sec_process_mcs_data_monitors(sec_layer, s); - ck_assert_int_eq(error, 1); + ck_assert_int_eq(error, SEC_PROCESS_MONITORS_ERR); free_stream(s); } @@ -64,7 +61,7 @@ START_TEST(test_process_monitors__when_mounter_count_is_greater_than_sixteen__fa s->p = s->data; int error = xrdp_sec_process_mcs_data_monitors(sec_layer, s); - ck_assert_int_eq(error, 2); + ck_assert_int_eq(error, SEC_PROCESS_MONITORS_ERR_TOO_MANY_MONITORS); free_stream(s); } @@ -190,7 +187,7 @@ START_TEST(test_process_monitors__when_virtual_desktop_width_is_too_large) //Verify function call passed. int error = xrdp_sec_process_mcs_data_monitors(sec_layer, s); - ck_assert_int_eq(error, 3); + ck_assert_int_eq(error, SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP); free_stream(s); } @@ -218,7 +215,7 @@ START_TEST(test_process_monitors__when_virtual_desktop_width_is_too_small) //Verify function call passed. int error = xrdp_sec_process_mcs_data_monitors(sec_layer, s); - ck_assert_int_eq(error, 3); + ck_assert_int_eq(error, SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP); free_stream(s); } @@ -246,7 +243,7 @@ START_TEST(test_process_monitors__when_virtual_desktop_height_is_too_large) //Verify function call passed. int error = xrdp_sec_process_mcs_data_monitors(sec_layer, s); - ck_assert_int_eq(error, 3); + ck_assert_int_eq(error, SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP); free_stream(s); } @@ -274,7 +271,7 @@ START_TEST(test_process_monitors__when_virtual_desktop_height_is_too_small) //Verify function call passed. int error = xrdp_sec_process_mcs_data_monitors(sec_layer, s); - ck_assert_int_eq(error, 3); + ck_assert_int_eq(error, SEC_PROCESS_MONITORS_ERR_INVALID_DESKTOP); free_stream(s); } diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index b48e9f3bc0..c10f1b5d8c 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -1022,27 +1022,154 @@ 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; + + LOG_DEVEL(LOG_LEVEL_TRACE, "process_dynamic_monitor_description:"); + + if (wm->client_info->suppress_output == 1) + { + LOG(LOG_LEVEL_ERROR, + "process_dynamic_monitor_description:" + " Not allowing resize. Suppress output is active."); + return 0; + } + if (description == NULL) + { + LOG_DEVEL(LOG_LEVEL_ERROR, + "process_dynamic_monitor_description:" + " description is null."); + return 0; + } + if (description->session_width <= 0 || description->session_height <= 0) + { + LOG(LOG_LEVEL_ERROR, + "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_DEVEL(LOG_LEVEL_ERROR, + "process_dynamic_monitor_description:" + " libxrdp_reset failed %d", error); + return error; + } + /* reset cache */ + error = xrdp_cache_reset(wm->cache, wm->client_info); + if (error != 0) + { + LOG_DEVEL(LOG_LEVEL_ERROR, + "process_dynamic_monitor_description: xrdp_cache_reset" + " failed %d", error); + return error; + } + /* load some stuff */ + error = xrdp_wm_load_static_colors_plus(wm, 0); + if (error != 0) + { + LOG_DEVEL(LOG_LEVEL_ERROR, "process_dynamic_monitor_description:" + " xrdp_wm_load_static_colors_plus failed %d", error); + return error; + } + + error = xrdp_wm_load_static_pointers(wm); + if (error != 0) + { + LOG_DEVEL(LOG_LEVEL_ERROR, "process_dynamic_monitor_description:" + " 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_DEVEL(LOG_LEVEL_ERROR, "process_dynamic_monitor_description:" + " xrdp_bitmap_resize failed %d", error); + return error; + } + /* redraw */ + error = xrdp_bitmap_invalidate(wm->screen, 0); + if (error != 0) + { + LOG_DEVEL(LOG_LEVEL_ERROR, + "process_dynamic_monitor_description:" + " 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_ERROR, "process_dynamic_monitor_description:" + " 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_ERROR, "process_dynamic_monitor_description:" + "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_ERROR, "process_dynamic_monitor_description:" + "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; +} + /******************************************************************************/ 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; + int monitor_layout_size; LOG_DEVEL(LOG_LEVEL_TRACE, "dynamic_monitor_data:"); pro = (struct xrdp_process *) id; @@ -1058,70 +1185,31 @@ 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, monitor_layout_size); + if (monitor_layout_size != 40) + { + LOG(LOG_LEVEL_ERROR, "dynamic_monitor_data: monitor_layout_size" + " is %d. Per spec ([MS-RDPEDISP] 2.2.2.2" + " DISPLAYCONTROL_MONITOR_LAYOUT_PDU) it must be 40.", + monitor_layout_size); + return 1; + } + + struct display_size_description *description = + (struct display_size_description *) + g_malloc(sizeof(struct display_size_description), 1); + + error = libxrdp_process_monitor_stream(s, description, 1); + if (error == 0) + { + error = process_dynamic_monitor_description(wm, description); + } + g_free(description); + return error; } /******************************************************************************/ From bd9147d18f6bede787d6b9aafe7da8046d2c288a Mon Sep 17 00:00:00 2001 From: Christopher Pitstick Date: Sun, 20 Mar 2022 02:55:09 -0400 Subject: [PATCH 2/2] Updating to refactor xrdp_client_info - Eliminate duplicaiton for display_size_description - monitorCount needs to be uint32_t - width/height -> session_width/session_height - Update CLIENT_INFO_CURRENT_VERSION - Also some misc unit test updates. - Minor log updates. --- common/xrdp_client_info.h | 26 +- libxrdp/libxrdp.c | 77 +++- libxrdp/libxrdp.h | 6 +- libxrdp/libxrdpinc.h | 2 +- libxrdp/xrdp_caps.c | 29 +- libxrdp/xrdp_sec.c | 18 +- tests/libxrdp/Makefile.am | 3 +- tests/libxrdp/test_libxrdp.h | 1 + tests/libxrdp/test_libxrdp_main.c | 4 +- .../test_libxrdp_process_monitor_stream.c | 406 ++++++++++++++++++ ...test_xrdp_sec_process_mcs_data_monitors.c} | 88 ++-- vnc/vnc.c | 28 +- xrdp/xrdp_login_wnd.c | 16 +- xrdp/xrdp_mm.c | 20 +- xrdp/xrdp_wm.c | 16 +- 15 files changed, 603 insertions(+), 137 deletions(-) create mode 100644 tests/libxrdp/test_libxrdp_process_monitor_stream.c rename tests/libxrdp/{test_monitor_processing.c => test_xrdp_sec_process_mcs_data_monitors.c} (64%) diff --git a/common/xrdp_client_info.h b/common/xrdp_client_info.h index 106e47a7e3..0cd844d46b 100644 --- a/common/xrdp_client_info.h +++ b/common/xrdp_client_info.h @@ -39,14 +39,14 @@ struct monitor_info int flags; /* From 2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT */ - int physical_width; - int physical_height; - int orientation; - int desktop_scale_factor; - int device_scale_factor; + unsigned int physical_width; + unsigned int physical_height; + unsigned int orientation; + unsigned int desktop_scale_factor; + unsigned int device_scale_factor; /* Derived setting */ - int is_primary; + unsigned int is_primary; }; /* xrdp keyboard overrids */ @@ -59,11 +59,11 @@ struct xrdp_keyboard_overrides struct display_size_description { - int monitorCount; /* number of monitors detected (max = 16) */ + unsigned int monitorCount; /* 2.2.2.2 DISPLAYCONTROL_MONITOR_LAYOUT_PDU: 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; + unsigned int session_width; + unsigned int session_height; }; /** @@ -79,8 +79,6 @@ struct xrdp_client_info int size; /* bytes for this structure */ int version; /* Should be CLIENT_INFO_CURRENT_VERSION */ int bpp; - int width; - int height; /* bitmap cache info */ int cache1_entries; int cache1_size; @@ -153,9 +151,7 @@ struct xrdp_client_info int security_layer; /* 0 = rdp, 1 = tls , 2 = hybrid */ int multimon; /* 0 = deny , 1 = allow */ - 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 */ + struct display_size_description display_sizes; int keyboard_type; int keyboard_subtype; @@ -211,6 +207,6 @@ struct xrdp_client_info }; /* yyyymmdd of last incompatible change to xrdp_client_info */ -#define CLIENT_INFO_CURRENT_VERSION 20210723 +#define CLIENT_INFO_CURRENT_VERSION 20220320 #endif diff --git a/libxrdp/libxrdp.c b/libxrdp/libxrdp.c index f25b18c288..bba935b895 100644 --- a/libxrdp/libxrdp.c +++ b/libxrdp/libxrdp.c @@ -1134,7 +1134,7 @@ libxrdp_orders_send_font(struct xrdp_session *session, * to a single monitor */ int EXPORT_CC libxrdp_reset(struct xrdp_session *session, - int width, int height, int bpp) + unsigned int width, unsigned int height, int bpp) { if (session->client_info != 0) { @@ -1147,18 +1147,18 @@ libxrdp_reset(struct xrdp_session *session, } /* if same (and only one monitor on client) don't need to do anything */ - if (client_info->width == width && - client_info->height == height && + if (client_info->display_sizes.session_width == width && + client_info->display_sizes.session_height == height && client_info->bpp == bpp && - (client_info->monitorCount == 0 || client_info->multimon == 0)) + (client_info->display_sizes.monitorCount == 0 || client_info->multimon == 0)) { return 0; } - client_info->width = width; - client_info->height = height; + client_info->display_sizes.session_width = width; + client_info->display_sizes.session_height = height; + client_info->display_sizes.monitorCount = 0; client_info->bpp = bpp; - client_info->monitorCount = 0; client_info->multimon = 0; } else @@ -1908,8 +1908,39 @@ libxrdp_process_monitor_stream(struct stream *s, in_uint32_le(s, monitor_layout->physical_width); in_uint32_le(s, monitor_layout->physical_height); + /* Per spec (2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT), + * if EITHER physical_width or physical_height are + * out of range, BOTH must be ignored. + */ + if (monitor_layout->physical_width > 10000 + || monitor_layout->physical_width < 10) + { + LOG(LOG_LEVEL_WARNING, "libxrdp_process_monitor_stream:" + " physical_width is not within valid range." + " Setting physical_width to 0mm," + " Setting physical_height to 0mm," + " physical_width was: %d", + monitor_layout->physical_width); + monitor_layout->physical_width = 0; + monitor_layout->physical_height = 0; + } + + if (monitor_layout->physical_height > 10000 + || monitor_layout->physical_height < 10) + { + LOG(LOG_LEVEL_WARNING, "libxrdp_process_monitor_stream:" + " physical_height is not within valid range." + " Setting physical_width to 0mm," + " Setting physical_height to 0mm," + " physical_height was: %d", + monitor_layout->physical_height); + monitor_layout->physical_width = 0; + monitor_layout->physical_height = 0; + } + in_uint32_le(s, monitor_layout->orientation); - switch (monitor_layout->orientation) { + switch (monitor_layout->orientation) + { case ORIENTATION_LANDSCAPE: case ORIENTATION_PORTRAIT: case ORIENTATION_LANDSCAPE_FLIPPED: @@ -1918,21 +1949,47 @@ libxrdp_process_monitor_stream(struct stream *s, default: LOG(LOG_LEVEL_WARNING, "libxrdp_process_monitor_stream:" " Orientation is not one of %d, %d, %d, or %d." - " Value was %d and ignored.", + " Value was %d and ignored and set to default value of LANDSCAPE.", ORIENTATION_LANDSCAPE, ORIENTATION_PORTRAIT, ORIENTATION_LANDSCAPE_FLIPPED, ORIENTATION_PORTRAIT_FLIPPED, monitor_layout->orientation); + monitor_layout->orientation = ORIENTATION_LANDSCAPE; } in_uint32_le(s, monitor_layout->desktop_scale_factor); + if (monitor_layout->desktop_scale_factor < 100 + || monitor_layout->desktop_scale_factor > 500 + || (monitor_layout->desktop_scale_factor != 100 + && monitor_layout->desktop_scale_factor != 140 + && monitor_layout->desktop_scale_factor != 180)) + { + LOG(LOG_LEVEL_WARNING, "libxrdp_process_monitor_stream:" + " desktop_scale_factor is not within valid range. Assuming 100." + " Value was: %d", + monitor_layout->desktop_scale_factor); + monitor_layout->desktop_scale_factor = 100; + } + in_uint32_le(s, monitor_layout->device_scale_factor); + if (monitor_layout->device_scale_factor < 100 + || monitor_layout->device_scale_factor > 500 + || (monitor_layout->device_scale_factor != 100 + && monitor_layout->device_scale_factor != 140 + && monitor_layout->device_scale_factor != 180)) + { + LOG(LOG_LEVEL_WARNING, "libxrdp_process_monitor_stream:" + " device_scale_factor is not within valid range. Assuming 100." + " Value was: %d", + monitor_layout->device_scale_factor); + monitor_layout->device_scale_factor = 100; + } /* * 2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT */ - LOG_DEVEL(LOG_LEVEL_TRACE, "libxrdp_process_monitor_stream:" + LOG_DEVEL(LOG_LEVEL_INFO, "libxrdp_process_monitor_stream:" " Received [MS-RDPEDISP] 2.2.2.2.1" " DISPLAYCONTROL_MONITOR_LAYOUT_PDU" ".DISPLAYCONTROL_MONITOR_LAYOUT" diff --git a/libxrdp/libxrdp.h b/libxrdp/libxrdp.h index fb931bf3d0..b124a85bcc 100644 --- a/libxrdp/libxrdp.h +++ b/libxrdp/libxrdp.h @@ -361,8 +361,10 @@ xrdp_mcs_disconnect(struct xrdp_mcs *self); /* xrdp_sec.c */ /* - These are return values for xrdp_sec_process_mcs_data_monitors - to clarify any reason for a non-zero response code. + These are error return codes for both: + 1. xrdp_sec_process_mcs_data_monitors + 2. libxrdp_process_monitor_stream + To clarify any reason for a non-zero response code. */ #define SEC_PROCESS_MONITORS_ERR 1 #define SEC_PROCESS_MONITORS_ERR_TOO_MANY_MONITORS 2 diff --git a/libxrdp/libxrdpinc.h b/libxrdp/libxrdpinc.h index 91a18ec3ae..af00686837 100644 --- a/libxrdp/libxrdpinc.h +++ b/libxrdp/libxrdpinc.h @@ -193,7 +193,7 @@ libxrdp_orders_send_font(struct xrdp_session *session, int font_index, int char_index); int libxrdp_reset(struct xrdp_session *session, - int width, int height, int bpp); + unsigned int width, unsigned int height, int bpp); int libxrdp_orders_send_raw_bitmap2(struct xrdp_session *session, int width, int height, int bpp, char *data, diff --git a/libxrdp/xrdp_caps.c b/libxrdp/xrdp_caps.c index 5c5e74a579..c953205342 100644 --- a/libxrdp/xrdp_caps.c +++ b/libxrdp/xrdp_caps.c @@ -45,7 +45,8 @@ static int xrdp_caps_send_monitorlayout(struct xrdp_rdp *self) { struct stream *s; - int i; + uint32_t i; + struct display_size_description *description; make_stream(s); init_stream(s, 8192); @@ -56,16 +57,18 @@ xrdp_caps_send_monitorlayout(struct xrdp_rdp *self) return 1; } - out_uint32_le(s, self->client_info.monitorCount); /* monitorCount (4 bytes) */ + description = &self->client_info.display_sizes; + + out_uint32_le(s, description->monitorCount); /* monitorCount (4 bytes) */ /* TODO: validate for allowed monitors in terminal server (maybe by config?) */ - for (i = 0; i < self->client_info.monitorCount; i++) + for (i = 0; i < description->monitorCount; i++) { - out_uint32_le(s, self->client_info.minfo[i].left); - out_uint32_le(s, self->client_info.minfo[i].top); - out_uint32_le(s, self->client_info.minfo[i].right); - out_uint32_le(s, self->client_info.minfo[i].bottom); - out_uint32_le(s, self->client_info.minfo[i].is_primary); + out_uint32_le(s, description->minfo[i].left); + out_uint32_le(s, description->minfo[i].top); + out_uint32_le(s, description->minfo[i].right); + out_uint32_le(s, description->minfo[i].bottom); + out_uint32_le(s, description->minfo[i].is_primary); } s_mark_end(s); @@ -883,8 +886,8 @@ unsigned int calculate_multifragmentupdate_len(const struct xrdp_rdp *self) { unsigned int result = MAX_MULTIFRAGMENTUPDATE_SIZE; - unsigned int x_tiles = (self->client_info.width + 63) / 64; - unsigned int y_tiles = (self->client_info.height + 63) / 64; + unsigned int x_tiles = (self->client_info.display_sizes.session_width + 63) / 64; + unsigned int y_tiles = (self->client_info.display_sizes.session_height + 63) / 64; /* Check for overflow on calculation if bad parameters are supplied */ if ((x_tiles * y_tiles + 1) < (UINT_MAX / 16384)) @@ -979,8 +982,8 @@ xrdp_caps_send_demand_active(struct xrdp_rdp *self) out_uint16_le(s, 1); /* Receive 1 BPP */ out_uint16_le(s, 1); /* Receive 4 BPP */ out_uint16_le(s, 1); /* Receive 8 BPP */ - out_uint16_le(s, self->client_info.width); /* width */ - out_uint16_le(s, self->client_info.height); /* height */ + out_uint16_le(s, self->client_info.display_sizes.session_width); /* width */ + out_uint16_le(s, self->client_info.display_sizes.session_height); /* height */ out_uint16_le(s, 0); /* Pad */ out_uint16_le(s, 1); /* Allow resize */ out_uint16_le(s, 1); /* bitmap compression */ @@ -1242,7 +1245,7 @@ xrdp_caps_send_demand_active(struct xrdp_rdp *self) } /* send Monitor Layout PDU for dual monitor */ - if (self->client_info.monitorCount > 0 && + if (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_sec.c b/libxrdp/xrdp_sec.c index ba3ad70c61..885b5a3d47 100644 --- a/libxrdp/xrdp_sec.c +++ b/libxrdp/xrdp_sec.c @@ -1953,8 +1953,8 @@ xrdp_sec_process_mcs_data_CS_CORE(struct xrdp_sec *self, struct stream *s) /* TS_UD_CS_CORE requiered fields */ in_uint8s(s, 4); /* version */ - in_uint16_le(s, self->rdp_layer->client_info.width); - in_uint16_le(s, self->rdp_layer->client_info.height); + in_uint16_le(s, self->rdp_layer->client_info.display_sizes.session_width); + in_uint16_le(s, self->rdp_layer->client_info.display_sizes.session_height); in_uint16_le(s, colorDepth); switch (colorDepth) { @@ -1981,8 +1981,8 @@ xrdp_sec_process_mcs_data_CS_CORE(struct xrdp_sec *self, struct stream *s) "clientName %s, keyboardType (ignored), " "keyboardSubType (ignored), keyboardFunctionKey (ignored), " "imeFileName (ignroed)", - self->rdp_layer->client_info.width, - self->rdp_layer->client_info.height, + self->rdp_layer->client_info.display_sizes.session_width, + self->rdp_layer->client_info.display_sizes.session_height, (colorDepth == 0xca00 ? "RNS_UD_COLOR_4BPP" : colorDepth == 0xca01 ? "RNS_UD_COLOR_8BPP" : "unknown"), clientName); @@ -2370,17 +2370,17 @@ xrdp_sec_process_mcs_data_monitors(struct xrdp_sec *self, struct stream *s) error = libxrdp_process_monitor_stream(s, description, 0); if (error == 0) { - client_info->monitorCount = description->monitorCount; + client_info->display_sizes.monitorCount = description->monitorCount; LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_sec_process_mcs_data_monitors:" " Received [MS-RDPBCGR] TS_UD_CS_MONITOR" " flags 0x%8.8x, monitorCount %d", flags, 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); + client_info->display_sizes.session_width = description->session_width; + client_info->display_sizes.session_height = description->session_height; + g_memcpy(client_info->display_sizes.minfo, description->minfo, sizeof(struct monitor_info) * CLIENT_MONITOR_DATA_MAXIMUM_MONITORS); + g_memcpy(client_info->display_sizes.minfo_wm, description->minfo_wm, sizeof(struct monitor_info) * CLIENT_MONITOR_DATA_MAXIMUM_MONITORS); } g_free(description); diff --git a/tests/libxrdp/Makefile.am b/tests/libxrdp/Makefile.am index 30138cbfe6..4fb019598c 100644 --- a/tests/libxrdp/Makefile.am +++ b/tests/libxrdp/Makefile.am @@ -14,7 +14,8 @@ check_PROGRAMS = test_libxrdp test_libxrdp_SOURCES = \ test_libxrdp.h \ test_libxrdp_main.c \ - test_monitor_processing.c + test_libxrdp_process_monitor_stream.c \ + test_xrdp_sec_process_mcs_data_monitors.c test_libxrdp_CFLAGS = \ @CHECK_CFLAGS@ diff --git a/tests/libxrdp/test_libxrdp.h b/tests/libxrdp/test_libxrdp.h index 444adf9eaa..a048e2bf36 100644 --- a/tests/libxrdp/test_libxrdp.h +++ b/tests/libxrdp/test_libxrdp.h @@ -3,6 +3,7 @@ #include +Suite *make_suite_test_xrdp_sec_process_mcs_data_monitors(void); Suite *make_suite_test_monitor_processing(void); #endif /* TEST_LIBXRDP_H */ \ No newline at end of file diff --git a/tests/libxrdp/test_libxrdp_main.c b/tests/libxrdp/test_libxrdp_main.c index 0bd15cadd5..370c092cca 100644 --- a/tests/libxrdp/test_libxrdp_main.c +++ b/tests/libxrdp/test_libxrdp_main.c @@ -11,8 +11,8 @@ int main (void) int number_failed; SRunner *sr; - sr = srunner_create (make_suite_test_monitor_processing()); - // srunner_add_suite(sr, make_list_suite()); + sr = srunner_create(make_suite_test_xrdp_sec_process_mcs_data_monitors()); + srunner_add_suite(sr, make_suite_test_monitor_processing()); srunner_set_tap(sr, "-"); srunner_run_all (sr, CK_ENV); diff --git a/tests/libxrdp/test_libxrdp_process_monitor_stream.c b/tests/libxrdp/test_libxrdp_process_monitor_stream.c new file mode 100644 index 0000000000..cc2b6ef907 --- /dev/null +++ b/tests/libxrdp/test_libxrdp_process_monitor_stream.c @@ -0,0 +1,406 @@ +#if defined(HAVE_CONFIG_H) +#include "config_ac.h" +#endif + +#include "libxrdp.h" +#include "os_calls.h" + +#include "test_libxrdp.h" + +START_TEST(test_libxrdp_process_monitor_stream__when_description_is_null__fail) +{ + struct stream *s = (struct stream *)NULL; + make_stream(s); + init_stream(s, 4); + + //Dummy data. + out_uint32_le(s, 0); + s_mark_end(s); + //Reset the read counter of the stream so the processing function handles it properly. + s->p = s->data; + + int error = libxrdp_process_monitor_stream(s, NULL, 1); + ck_assert_int_eq(error, SEC_PROCESS_MONITORS_ERR); + + free_stream(s); +} +END_TEST + +START_TEST(test_libxrdp_process_monitor_stream__when_stream_is_too_small__fail) +{ + struct stream *s = (struct stream *)NULL; + make_stream(s); + init_stream(s, 2); + + //Dummy data. + out_uint16_le(s, 0); + s_mark_end(s); + //Reset the read counter of the stream so the processing function handles it properly. + s->p = s->data; + + struct display_size_description *description = + (struct display_size_description *) + g_malloc(sizeof(struct display_size_description), 1); + + int error = libxrdp_process_monitor_stream(s, description, 1); + ck_assert_int_eq(error, SEC_PROCESS_MONITORS_ERR); + + free(description); + free_stream(s); +} +END_TEST + +START_TEST(test_libxrdp_process_monitor_stream__when_monitor_count_is_greater_than_sixteen__fail) +{ + struct stream *s = (struct stream *)NULL; + make_stream(s); + init_stream(s, 4); + + //Dummy data. + out_uint32_le(s, 17); + s_mark_end(s); + //Reset the read counter of the stream so the processing function handles it properly. + s->p = s->data; + + struct display_size_description *description = + (struct display_size_description *) + g_malloc(sizeof(struct display_size_description), 1); + + int error = libxrdp_process_monitor_stream(s, description, 1); + ck_assert_int_eq(error, SEC_PROCESS_MONITORS_ERR_TOO_MANY_MONITORS); + + free(description); + free_stream(s); +} +END_TEST + +START_TEST(test_libxrdp_process_monitor_stream__with_single_monitor_happy_path) +{ + struct stream *s = (struct stream *)NULL; + make_stream(s); + init_stream(s, 44); + + out_uint32_le(s, 1); //monitorCount + + // Pretend we have a 4k monitor + out_uint32_le(s, TS_MONITOR_PRIMARY); //flags + out_uint32_le(s, 0); //monitor left + out_uint32_le(s, 0); //monitor top + out_uint32_le(s, 3840); //monitor right + out_uint32_le(s, 2160); //monitor bottom + out_uint32_le(s, 2000); //physical width + out_uint32_le(s, 2000); //physical height + out_uint32_le(s, 0); //orientation + out_uint32_le(s, 100); //desktop scale factor + out_uint32_le(s, 100); //device scale factor + + s_mark_end(s); + //Reset the read counter of the stream so the processing function handles it properly. + s->p = s->data; + + struct display_size_description *description = + (struct display_size_description *) + g_malloc(sizeof(struct display_size_description), 1); + + int error = libxrdp_process_monitor_stream(s, description, 1); + + //Verify function call passed. + ck_assert_int_eq(error, 0); + + ck_assert_int_eq(description->monitorCount, 1); + + // Verify normal monitor + ck_assert_int_eq(description->minfo[0].left, 0); + ck_assert_int_eq(description->minfo[0].top, 0); + ck_assert_int_eq(description->minfo[0].right, 3840); + ck_assert_int_eq(description->minfo[0].bottom, 2160); + ck_assert_int_eq(description->minfo[0].physical_width, 2000); + ck_assert_int_eq(description->minfo[0].physical_height, 2000); + ck_assert_int_eq(description->minfo[0].orientation, 0); + ck_assert_int_eq(description->minfo[0].desktop_scale_factor, 100); + ck_assert_int_eq(description->minfo[0].device_scale_factor, 100); + ck_assert_int_eq(description->minfo[0].is_primary, 1); + + // Verify normalized monitor + ck_assert_int_eq(description->minfo_wm[0].left, 0); + ck_assert_int_eq(description->minfo_wm[0].top, 0); + ck_assert_int_eq(description->minfo_wm[0].right, 3840); + ck_assert_int_eq(description->minfo_wm[0].bottom, 2160); + ck_assert_int_eq(description->minfo_wm[0].physical_width, 2000); + ck_assert_int_eq(description->minfo_wm[0].physical_height, 2000); + ck_assert_int_eq(description->minfo_wm[0].orientation, 0); + ck_assert_int_eq(description->minfo_wm[0].desktop_scale_factor, 100); + ck_assert_int_eq(description->minfo_wm[0].device_scale_factor, 100); + ck_assert_int_eq(description->minfo_wm[0].is_primary, 1); + + // Verify geometry (+1 greater than ) + ck_assert_int_eq(description->session_width, 3841); + ck_assert_int_eq(description->session_height, 2161); + + free(description); + free_stream(s); +} +END_TEST + +START_TEST(test_libxrdp_process_monitor_stream__with_sextuple_monitor_happy_path) +{ + struct stream *s = (struct stream *)NULL; + make_stream(s); + init_stream(s, 233); + + out_uint32_le(s, 6); //monitorCount + + // 4k monitor at position (0, 0) + out_uint32_le(s, 0); //flags + out_uint32_le(s, 0); //monitor left + out_uint32_le(s, 0); //monitor top + out_uint32_le(s, 3840); //monitor width + out_uint32_le(s, 2160); //monitor height + out_uint32_le(s, 9); //physical width + out_uint32_le(s, 9); //physical height + out_uint32_le(s, -10); //orientation + out_uint32_le(s, -100); //desktop scale factor + out_uint32_le(s, 600); //device scale factor + + // 4k monitor at position (1, 0) + out_uint32_le(s, TS_MONITOR_PRIMARY); //flags + out_uint32_le(s, 3841); //monitor left + out_uint32_le(s, 0); //monitor top + out_uint32_le(s, 3840); //monitor right + out_uint32_le(s, 2160); //monitor bottom + out_uint32_le(s, 5); //physical width + out_uint32_le(s, 11000); //physical height + out_uint32_le(s, 10); //orientation (Expect to be reset to 0) + out_uint32_le(s, 360); //desktop scale factor + out_uint32_le(s, 720); //device scale factor + + // 4k monitor at position (2, 0) + out_uint32_le(s, 0); //flags + out_uint32_le(s, 7682); //monitor left + out_uint32_le(s, 0); //monitor top + out_uint32_le(s, 3840); //monitor width + out_uint32_le(s, 2160); //monitor height + out_uint32_le(s, 1000); //physical width + out_uint32_le(s, 1000); //physical height + out_uint32_le(s, 5000); //orientation + out_uint32_le(s, 80); //desktop scale factor + out_uint32_le(s, 140); //device scale factor + + // 4k monitor at position (0, 1) + out_uint32_le(s, 0); //flags + out_uint32_le(s, 0); //monitor left + out_uint32_le(s, 2161); //monitor top + out_uint32_le(s, 3840); //monitor width + out_uint32_le(s, 2160); //monitor height + out_uint32_le(s, 1000); //physical width + out_uint32_le(s, 1000); //physical height + out_uint32_le(s, 91); //orientation + out_uint32_le(s, 180); //desktop scale factor + out_uint32_le(s, 100); //device scale factor + + // 4k monitor at position (1, 1) + out_uint32_le(s, 0); //flags + out_uint32_le(s, 3841); //monitor left + out_uint32_le(s, 2161); //monitor top + out_uint32_le(s, 3840); //monitor width + out_uint32_le(s, 2160); //monitor height + out_uint32_le(s, 1000); //physical width + out_uint32_le(s, 1000); //physical height + out_uint32_le(s, 0); //orientation + out_uint32_le(s, 20); //desktop scale factor + out_uint32_le(s, 50); //device scale factor + + // 4k monitor at position (2, 1) + out_uint32_le(s, 0); //flags + out_uint32_le(s, 7682); //monitor left + out_uint32_le(s, 2161); //monitor top + out_uint32_le(s, 3840); //monitor width + out_uint32_le(s, 2160); //monitor height + out_uint32_le(s, 1000); //physical width + out_uint32_le(s, 1000); //physical height + out_uint32_le(s, 0); //orientation + out_uint32_le(s, 300); //desktop scale factor + out_uint32_le(s, 400); //device scale factor + + s_mark_end(s); + // Reset the read counter of the stream so the processing function handles it properly. + s->p = s->data; + + struct display_size_description *description = + (struct display_size_description *) + g_malloc(sizeof(struct display_size_description), 1); + + int error = libxrdp_process_monitor_stream(s, description, 1); + + //Verify function call passed. + ck_assert_int_eq(error, 0); + + ck_assert_int_eq(description->monitorCount, 6); + + /************************************************* + * Verify standard monitors + *************************************************/ + ck_assert_int_eq(description->minfo[0].left, 0); + ck_assert_int_eq(description->minfo[0].top, 0); + ck_assert_int_eq(description->minfo[0].right, 3840); + ck_assert_int_eq(description->minfo[0].bottom, 2160); + ck_assert_int_eq(description->minfo[0].physical_width, 0); + ck_assert_int_eq(description->minfo[0].physical_height, 0); + ck_assert_int_eq(description->minfo[0].orientation, 0); + ck_assert_int_eq(description->minfo[0].desktop_scale_factor, 100); + ck_assert_int_eq(description->minfo[0].device_scale_factor, 100); + ck_assert_int_eq(description->minfo[0].is_primary, 0); + + ck_assert_int_eq(description->minfo[1].left, 3841); + ck_assert_int_eq(description->minfo[1].top, 0); + ck_assert_int_eq(description->minfo[1].right, 7681); + ck_assert_int_eq(description->minfo[1].bottom, 2160); + ck_assert_int_eq(description->minfo[1].physical_width, 0); + ck_assert_int_eq(description->minfo[1].physical_height, 0); + ck_assert_int_eq(description->minfo[1].orientation, 0); + ck_assert_int_eq(description->minfo[1].desktop_scale_factor, 100); + ck_assert_int_eq(description->minfo[1].device_scale_factor, 100); + ck_assert_int_eq(description->minfo[1].is_primary, 1); + + ck_assert_int_eq(description->minfo[2].left, 7682); + ck_assert_int_eq(description->minfo[2].top, 0); + ck_assert_int_eq(description->minfo[2].right, 11522); + ck_assert_int_eq(description->minfo[2].bottom, 2160); + ck_assert_int_eq(description->minfo[2].physical_width, 1000); + ck_assert_int_eq(description->minfo[2].physical_height, 1000); + ck_assert_int_eq(description->minfo[2].orientation, 0); + ck_assert_int_eq(description->minfo[2].desktop_scale_factor, 100); + ck_assert_int_eq(description->minfo[2].device_scale_factor, 140); + ck_assert_int_eq(description->minfo[2].is_primary, 0); + + ck_assert_int_eq(description->minfo[3].left, 0); + ck_assert_int_eq(description->minfo[3].top, 2161); + ck_assert_int_eq(description->minfo[3].right, 3840); + ck_assert_int_eq(description->minfo[3].bottom, 4321); + ck_assert_int_eq(description->minfo[3].physical_width, 1000); + ck_assert_int_eq(description->minfo[3].physical_height, 1000); + ck_assert_int_eq(description->minfo[3].orientation, 0); + ck_assert_int_eq(description->minfo[3].desktop_scale_factor, 180); + ck_assert_int_eq(description->minfo[3].device_scale_factor, 100); + ck_assert_int_eq(description->minfo[3].is_primary, 0); + + ck_assert_int_eq(description->minfo[4].left, 3841); + ck_assert_int_eq(description->minfo[4].top, 2161); + ck_assert_int_eq(description->minfo[4].right, 7681); + ck_assert_int_eq(description->minfo[4].bottom, 4321); + ck_assert_int_eq(description->minfo[4].physical_width, 1000); + ck_assert_int_eq(description->minfo[4].physical_height, 1000); + ck_assert_int_eq(description->minfo[4].orientation, 0); + ck_assert_int_eq(description->minfo[4].desktop_scale_factor, 100); + ck_assert_int_eq(description->minfo[4].device_scale_factor, 100); + ck_assert_int_eq(description->minfo[4].is_primary, 0); + + ck_assert_int_eq(description->minfo[5].left, 7682); + ck_assert_int_eq(description->minfo[5].top, 2161); + ck_assert_int_eq(description->minfo[5].right, 11522); + ck_assert_int_eq(description->minfo[5].bottom, 4321); + ck_assert_int_eq(description->minfo[5].physical_width, 1000); + ck_assert_int_eq(description->minfo[5].physical_height, 1000); + ck_assert_int_eq(description->minfo[5].orientation, 0); + ck_assert_int_eq(description->minfo[5].desktop_scale_factor, 100); + ck_assert_int_eq(description->minfo[5].device_scale_factor, 100); + ck_assert_int_eq(description->minfo[5].is_primary, 0); + + /************************************************* + * Verify normalized monitors + *************************************************/ + ck_assert_int_eq(description->minfo_wm[0].left, 0); + ck_assert_int_eq(description->minfo_wm[0].top, 0); + ck_assert_int_eq(description->minfo_wm[0].right, 3840); + ck_assert_int_eq(description->minfo_wm[0].bottom, 2160); + ck_assert_int_eq(description->minfo_wm[0].physical_width, 0); + ck_assert_int_eq(description->minfo_wm[0].physical_height, 0); + ck_assert_int_eq(description->minfo_wm[0].orientation, 0); + ck_assert_int_eq(description->minfo_wm[0].desktop_scale_factor, 100); + ck_assert_int_eq(description->minfo_wm[0].device_scale_factor, 100); + ck_assert_int_eq(description->minfo_wm[0].is_primary, 0); + + ck_assert_int_eq(description->minfo_wm[1].left, 3841); + ck_assert_int_eq(description->minfo_wm[1].top, 0); + ck_assert_int_eq(description->minfo_wm[1].right, 7681); + ck_assert_int_eq(description->minfo_wm[1].bottom, 2160); + ck_assert_int_eq(description->minfo_wm[1].physical_width, 0); + ck_assert_int_eq(description->minfo_wm[1].physical_height, 0); + ck_assert_int_eq(description->minfo_wm[1].orientation, 0); + ck_assert_int_eq(description->minfo_wm[1].desktop_scale_factor, 100); + ck_assert_int_eq(description->minfo_wm[1].device_scale_factor, 100); + ck_assert_int_eq(description->minfo_wm[1].is_primary, 1); + + ck_assert_int_eq(description->minfo_wm[2].left, 7682); + ck_assert_int_eq(description->minfo_wm[2].top, 0); + ck_assert_int_eq(description->minfo_wm[2].right, 11522); + ck_assert_int_eq(description->minfo_wm[2].bottom, 2160); + ck_assert_int_eq(description->minfo_wm[2].physical_width, 1000); + ck_assert_int_eq(description->minfo_wm[2].physical_height, 1000); + ck_assert_int_eq(description->minfo_wm[2].orientation, 0); + ck_assert_int_eq(description->minfo_wm[2].desktop_scale_factor, 100); + ck_assert_int_eq(description->minfo_wm[2].device_scale_factor, 140); + ck_assert_int_eq(description->minfo_wm[2].is_primary, 0); + + ck_assert_int_eq(description->minfo_wm[3].left, 0); + ck_assert_int_eq(description->minfo_wm[3].top, 2161); + ck_assert_int_eq(description->minfo_wm[3].right, 3840); + ck_assert_int_eq(description->minfo_wm[3].bottom, 4321); + ck_assert_int_eq(description->minfo_wm[3].physical_width, 1000); + ck_assert_int_eq(description->minfo_wm[3].physical_height, 1000); + ck_assert_int_eq(description->minfo_wm[3].orientation, 0); + ck_assert_int_eq(description->minfo_wm[3].desktop_scale_factor, 180); + ck_assert_int_eq(description->minfo_wm[3].device_scale_factor, 100); + ck_assert_int_eq(description->minfo_wm[3].is_primary, 0); + + ck_assert_int_eq(description->minfo_wm[4].left, 3841); + ck_assert_int_eq(description->minfo_wm[4].top, 2161); + ck_assert_int_eq(description->minfo_wm[4].right, 7681); + ck_assert_int_eq(description->minfo_wm[4].bottom, 4321); + ck_assert_int_eq(description->minfo_wm[4].physical_width, 1000); + ck_assert_int_eq(description->minfo_wm[4].physical_height, 1000); + ck_assert_int_eq(description->minfo_wm[4].orientation, 0); + ck_assert_int_eq(description->minfo_wm[4].desktop_scale_factor, 100); + ck_assert_int_eq(description->minfo_wm[4].device_scale_factor, 100); + ck_assert_int_eq(description->minfo_wm[4].is_primary, 0); + + ck_assert_int_eq(description->minfo_wm[5].left, 7682); + ck_assert_int_eq(description->minfo_wm[5].top, 2161); + ck_assert_int_eq(description->minfo_wm[5].right, 11522); + ck_assert_int_eq(description->minfo_wm[5].bottom, 4321); + ck_assert_int_eq(description->minfo_wm[5].physical_width, 1000); + ck_assert_int_eq(description->minfo_wm[5].physical_height, 1000); + ck_assert_int_eq(description->minfo_wm[5].orientation, 0); + ck_assert_int_eq(description->minfo_wm[5].desktop_scale_factor, 100); + ck_assert_int_eq(description->minfo_wm[5].device_scale_factor, 100); + ck_assert_int_eq(description->minfo_wm[5].is_primary, 0); + + // Verify geometry + ck_assert_int_eq(description->session_width, 11523); + ck_assert_int_eq(description->session_height, 4322); + + free(description); + free_stream(s); +} +END_TEST + +/******************************************************************************/ +Suite * +make_suite_test_monitor_processing(void) +{ + Suite *s; + TCase *tc_process_monitors; + + s = suite_create("test_libxrdp_process_monitor_stream"); + + tc_process_monitors = tcase_create("libxrdp_process_monitor_stream"); + tcase_add_test(tc_process_monitors, test_libxrdp_process_monitor_stream__when_description_is_null__fail); + tcase_add_test(tc_process_monitors, test_libxrdp_process_monitor_stream__when_stream_is_too_small__fail); + tcase_add_test(tc_process_monitors, test_libxrdp_process_monitor_stream__when_monitor_count_is_greater_than_sixteen__fail); + tcase_add_test(tc_process_monitors, test_libxrdp_process_monitor_stream__with_single_monitor_happy_path); + tcase_add_test(tc_process_monitors, test_libxrdp_process_monitor_stream__with_sextuple_monitor_happy_path); + + suite_add_tcase(s, tc_process_monitors); + + return s; +} diff --git a/tests/libxrdp/test_monitor_processing.c b/tests/libxrdp/test_xrdp_sec_process_mcs_data_monitors.c similarity index 64% rename from tests/libxrdp/test_monitor_processing.c rename to tests/libxrdp/test_xrdp_sec_process_mcs_data_monitors.c index 0314e7ddf6..64cda1eb53 100644 --- a/tests/libxrdp/test_monitor_processing.c +++ b/tests/libxrdp/test_xrdp_sec_process_mcs_data_monitors.c @@ -29,7 +29,7 @@ void teardown(void) g_free(rdp_layer); } -START_TEST(test_process_monitors__when_flags_is_not_zero__fail) +START_TEST(test_xrdp_sec_process_mcs_data_monitors__when_flags_is_not_zero__fail) { struct stream *s = (struct stream *)NULL; make_stream(s); @@ -48,7 +48,7 @@ START_TEST(test_process_monitors__when_flags_is_not_zero__fail) } END_TEST -START_TEST(test_process_monitors__when_mounter_count_is_greater_than_sixteen__fail) +START_TEST(test_xrdp_sec_process_mcs_data_monitors__when_monitor_count_is_greater_than_sixteen__fail) { struct stream *s = (struct stream *)NULL; make_stream(s); @@ -67,7 +67,7 @@ START_TEST(test_process_monitors__when_mounter_count_is_greater_than_sixteen__fa } END_TEST -START_TEST(test_process_monitors__with_single_monitor_happy_path) +START_TEST(test_xrdp_sec_process_mcs_data_monitors__with_single_monitor_happy_path) { struct xrdp_client_info *client_info = &(rdp_layer->client_info); struct stream *s = (struct stream *)NULL; @@ -92,31 +92,31 @@ START_TEST(test_process_monitors__with_single_monitor_happy_path) int error = xrdp_sec_process_mcs_data_monitors(sec_layer, s); ck_assert_int_eq(error, 0); - ck_assert_int_eq(client_info->monitorCount, 1); + ck_assert_int_eq(client_info->display_sizes.monitorCount, 1); // Verify normal monitor - ck_assert_int_eq(client_info->minfo[0].left, 0); - ck_assert_int_eq(client_info->minfo[0].top, 0); - ck_assert_int_eq(client_info->minfo[0].right, 3840); - ck_assert_int_eq(client_info->minfo[0].bottom, 2160); - ck_assert_int_eq(client_info->minfo[0].is_primary, 1); + ck_assert_int_eq(client_info->display_sizes.minfo[0].left, 0); + ck_assert_int_eq(client_info->display_sizes.minfo[0].top, 0); + ck_assert_int_eq(client_info->display_sizes.minfo[0].right, 3840); + ck_assert_int_eq(client_info->display_sizes.minfo[0].bottom, 2160); + ck_assert_int_eq(client_info->display_sizes.minfo[0].is_primary, 1); // Verify normalized monitor - ck_assert_int_eq(client_info->minfo_wm[0].left, 0); - ck_assert_int_eq(client_info->minfo_wm[0].top, 0); - ck_assert_int_eq(client_info->minfo_wm[0].right, 3840); - ck_assert_int_eq(client_info->minfo_wm[0].bottom, 2160); - ck_assert_int_eq(client_info->minfo_wm[0].is_primary, 1); + ck_assert_int_eq(client_info->display_sizes.minfo_wm[0].left, 0); + ck_assert_int_eq(client_info->display_sizes.minfo_wm[0].top, 0); + ck_assert_int_eq(client_info->display_sizes.minfo_wm[0].right, 3840); + ck_assert_int_eq(client_info->display_sizes.minfo_wm[0].bottom, 2160); + ck_assert_int_eq(client_info->display_sizes.minfo_wm[0].is_primary, 1); // Verify geometry (+1 greater than ) - ck_assert_int_eq(client_info->width, 3841); - ck_assert_int_eq(client_info->height, 2161); + ck_assert_int_eq(client_info->display_sizes.session_width, 3841); + ck_assert_int_eq(client_info->display_sizes.session_height, 2161); free_stream(s); } END_TEST -START_TEST(test_process_monitors__when_no_primary_monitor_is_specified_one_is_selected) +START_TEST(test_xrdp_sec_process_mcs_data_monitors__when_no_primary_monitor_is_specified_one_is_selected) { struct xrdp_client_info *client_info = &(rdp_layer->client_info); struct stream *s = (struct stream *)NULL; @@ -141,31 +141,31 @@ START_TEST(test_process_monitors__when_no_primary_monitor_is_specified_one_is_se int error = xrdp_sec_process_mcs_data_monitors(sec_layer, s); ck_assert_int_eq(error, 0); - ck_assert_int_eq(client_info->monitorCount, 1); + ck_assert_int_eq(client_info->display_sizes.monitorCount, 1); // Verify normal monitor - ck_assert_int_eq(client_info->minfo[0].left, 0); - ck_assert_int_eq(client_info->minfo[0].top, 0); - ck_assert_int_eq(client_info->minfo[0].right, 3840); - ck_assert_int_eq(client_info->minfo[0].bottom, 2160); - ck_assert_int_eq(client_info->minfo[0].is_primary, 1); + ck_assert_int_eq(client_info->display_sizes.minfo[0].left, 0); + ck_assert_int_eq(client_info->display_sizes.minfo[0].top, 0); + ck_assert_int_eq(client_info->display_sizes.minfo[0].right, 3840); + ck_assert_int_eq(client_info->display_sizes.minfo[0].bottom, 2160); + ck_assert_int_eq(client_info->display_sizes.minfo[0].is_primary, 1); // Verify normalized monitor - ck_assert_int_eq(client_info->minfo_wm[0].left, 0); - ck_assert_int_eq(client_info->minfo_wm[0].top, 0); - ck_assert_int_eq(client_info->minfo_wm[0].right, 3840); - ck_assert_int_eq(client_info->minfo_wm[0].bottom, 2160); - ck_assert_int_eq(client_info->minfo_wm[0].is_primary, 1); + ck_assert_int_eq(client_info->display_sizes.minfo_wm[0].left, 0); + ck_assert_int_eq(client_info->display_sizes.minfo_wm[0].top, 0); + ck_assert_int_eq(client_info->display_sizes.minfo_wm[0].right, 3840); + ck_assert_int_eq(client_info->display_sizes.minfo_wm[0].bottom, 2160); + ck_assert_int_eq(client_info->display_sizes.minfo_wm[0].is_primary, 1); // Verify geometry (+1 greater than ) - ck_assert_int_eq(client_info->width, 3841); - ck_assert_int_eq(client_info->height, 2161); + ck_assert_int_eq(client_info->display_sizes.session_width, 3841); + ck_assert_int_eq(client_info->display_sizes.session_height, 2161); free_stream(s); } END_TEST -START_TEST(test_process_monitors__when_virtual_desktop_width_is_too_large) +START_TEST(test_xrdp_sec_process_mcs_data_monitors__when_virtual_desktop_width_is_too_large) { struct stream *s = (struct stream *)NULL; make_stream(s); @@ -193,7 +193,7 @@ START_TEST(test_process_monitors__when_virtual_desktop_width_is_too_large) } END_TEST -START_TEST(test_process_monitors__when_virtual_desktop_width_is_too_small) +START_TEST(test_xrdp_sec_process_mcs_data_monitors__when_virtual_desktop_width_is_too_small) { struct stream *s = (struct stream *)NULL; make_stream(s); @@ -221,7 +221,7 @@ START_TEST(test_process_monitors__when_virtual_desktop_width_is_too_small) } END_TEST -START_TEST(test_process_monitors__when_virtual_desktop_height_is_too_large) +START_TEST(test_xrdp_sec_process_mcs_data_monitors__when_virtual_desktop_height_is_too_large) { struct stream *s = (struct stream *)NULL; make_stream(s); @@ -249,7 +249,7 @@ START_TEST(test_process_monitors__when_virtual_desktop_height_is_too_large) } END_TEST -START_TEST(test_process_monitors__when_virtual_desktop_height_is_too_small) +START_TEST(test_xrdp_sec_process_mcs_data_monitors__when_virtual_desktop_height_is_too_small) { struct stream *s = (struct stream *)NULL; make_stream(s); @@ -279,23 +279,23 @@ END_TEST /******************************************************************************/ Suite * -make_suite_test_monitor_processing(void) +make_suite_test_xrdp_sec_process_mcs_data_monitors(void) { Suite *s; TCase *tc_process_monitors; - s = suite_create("Monitor_Processing"); + s = suite_create("test_xrdp_sec_process_mcs_data_monitors"); tc_process_monitors = tcase_create("xrdp_sec_process_mcs_data_monitors"); tcase_add_checked_fixture(tc_process_monitors, setup, teardown); - tcase_add_test(tc_process_monitors, test_process_monitors__when_flags_is_not_zero__fail); - tcase_add_test(tc_process_monitors, test_process_monitors__when_mounter_count_is_greater_than_sixteen__fail); - tcase_add_test(tc_process_monitors, test_process_monitors__with_single_monitor_happy_path); - tcase_add_test(tc_process_monitors, test_process_monitors__when_no_primary_monitor_is_specified_one_is_selected); - tcase_add_test(tc_process_monitors, test_process_monitors__when_virtual_desktop_width_is_too_large); - tcase_add_test(tc_process_monitors, test_process_monitors__when_virtual_desktop_width_is_too_small); - tcase_add_test(tc_process_monitors, test_process_monitors__when_virtual_desktop_height_is_too_large); - tcase_add_test(tc_process_monitors, test_process_monitors__when_virtual_desktop_height_is_too_small); + tcase_add_test(tc_process_monitors, test_xrdp_sec_process_mcs_data_monitors__when_flags_is_not_zero__fail); + tcase_add_test(tc_process_monitors, test_xrdp_sec_process_mcs_data_monitors__when_monitor_count_is_greater_than_sixteen__fail); + tcase_add_test(tc_process_monitors, test_xrdp_sec_process_mcs_data_monitors__with_single_monitor_happy_path); + tcase_add_test(tc_process_monitors, test_xrdp_sec_process_mcs_data_monitors__when_no_primary_monitor_is_specified_one_is_selected); + tcase_add_test(tc_process_monitors, test_xrdp_sec_process_mcs_data_monitors__when_virtual_desktop_width_is_too_large); + tcase_add_test(tc_process_monitors, test_xrdp_sec_process_mcs_data_monitors__when_virtual_desktop_width_is_too_small); + tcase_add_test(tc_process_monitors, test_xrdp_sec_process_mcs_data_monitors__when_virtual_desktop_height_is_too_large); + tcase_add_test(tc_process_monitors, test_xrdp_sec_process_mcs_data_monitors__when_virtual_desktop_height_is_too_small); suite_add_tcase(s, tc_process_monitors); diff --git a/vnc/vnc.c b/vnc/vnc.c index 7486132981..cf2c6e796d 100644 --- a/vnc/vnc.c +++ b/vnc/vnc.c @@ -2039,25 +2039,25 @@ static void init_client_layout(struct vnc_screen_layout *layout, const struct xrdp_client_info *client_info) { - int i; + uint32_t i; - layout->total_width = client_info->width; - layout->total_height = client_info->height; + layout->total_width = client_info->display_sizes.session_width; + layout->total_height = client_info->display_sizes.session_height; - layout->count = client_info->monitorCount; + layout->count = client_info->display_sizes.monitorCount; layout->s = g_new(struct vnc_screen, layout->count); - for (i = 0 ; i < client_info->monitorCount ; ++i) + for (i = 0 ; i < client_info->display_sizes.monitorCount ; ++i) { /* Use minfo_wm, as this is normalised for a top-left of (0,0) * as required by RFC6143 */ layout->s[i].id = i; - layout->s[i].x = client_info->minfo_wm[i].left; - layout->s[i].y = client_info->minfo_wm[i].top; - layout->s[i].width = client_info->minfo_wm[i].right - - client_info->minfo_wm[i].left + 1; - layout->s[i].height = client_info->minfo_wm[i].bottom - - client_info->minfo_wm[i].top + 1; + layout->s[i].x = client_info->display_sizes.minfo_wm[i].left; + layout->s[i].y = client_info->display_sizes.minfo_wm[i].top; + layout->s[i].width = client_info->display_sizes.minfo_wm[i].right - + client_info->display_sizes.minfo_wm[i].left + 1; + layout->s[i].height = client_info->display_sizes.minfo_wm[i].bottom - + client_info->display_sizes.minfo_wm[i].top + 1; layout->s[i].flags = 0; } } @@ -2106,11 +2106,11 @@ lib_mod_set_param(struct vnc *v, const char *name, const char *value) g_free(v->client_layout.s); /* Save monitor information from the client */ - if (!client_info->multimon || client_info->monitorCount < 1) + if (!client_info->multimon || client_info->display_sizes.monitorCount < 1) { set_single_screen_layout(&v->client_layout, - client_info->width, - client_info->height); + client_info->display_sizes.session_width, + client_info->display_sizes.session_height); } else { diff --git a/xrdp/xrdp_login_wnd.c b/xrdp/xrdp_login_wnd.c index da5917b232..28ab4f851d 100644 --- a/xrdp/xrdp_login_wnd.c +++ b/xrdp/xrdp_login_wnd.c @@ -652,7 +652,7 @@ xrdp_login_wnd_create(struct xrdp_wm *self) int primary_height; int primary_x_offset; /* Offset of centre of primary screen */ int primary_y_offset; - int index; + uint32_t index; int x; int y; int cx; @@ -684,16 +684,16 @@ xrdp_login_wnd_create(struct xrdp_wm *self) } /* multimon scenario, draw login window on primary monitor */ - if (self->client_info->monitorCount > 1) + if (self->client_info->display_sizes.monitorCount > 1) { - for (index = 0; index < self->client_info->monitorCount; index++) + for (index = 0; index < self->client_info->display_sizes.monitorCount; index++) { - if (self->client_info->minfo_wm[index].is_primary) + if (self->client_info->display_sizes.minfo_wm[index].is_primary) { - x = self->client_info->minfo_wm[index].left; - y = self->client_info->minfo_wm[index].top; - cx = self->client_info->minfo_wm[index].right; - cy = self->client_info->minfo_wm[index].bottom; + x = self->client_info->display_sizes.minfo_wm[index].left; + y = self->client_info->display_sizes.minfo_wm[index].top; + cx = self->client_info->display_sizes.minfo_wm[index].right; + cy = self->client_info->display_sizes.minfo_wm[index].bottom; primary_width = cx - x; primary_height = cy - y; diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index c10f1b5d8c..796d997f70 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -1144,14 +1144,14 @@ process_dynamic_monitor_description(struct xrdp_wm *wm, } } - 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, + wm->client_info->display_sizes.monitorCount = description->monitorCount; + wm->client_info->display_sizes.session_width = description->session_width; + wm->client_info->display_sizes.session_height = description->session_height; + g_memcpy(wm->client_info->display_sizes.minfo, description->minfo, sizeof(struct monitor_info) * CLIENT_MONITOR_DATA_MAXIMUM_MONITORS); - g_memcpy(wm->client_info->minfo_wm, + g_memcpy(wm->client_info->display_sizes.minfo_wm, description->minfo_wm, sizeof(struct monitor_info) * CLIENT_MONITOR_DATA_MAXIMUM_MONITORS); @@ -3603,10 +3603,10 @@ server_reset(struct xrdp_mod *mod, int width, int height, int bpp) } /* if same (and only one monitor on client) don't need to do anything */ - if (wm->client_info->width == width && - wm->client_info->height == height && + if (wm->client_info->display_sizes.session_width == (uint32_t)width && + wm->client_info->display_sizes.session_height == (uint32_t)height && wm->client_info->bpp == bpp && - (wm->client_info->monitorCount == 0 || wm->client_info->multimon == 0)) + (wm->client_info->display_sizes.monitorCount == 0 || wm->client_info->multimon == 0)) { return 0; } @@ -3620,8 +3620,8 @@ server_reset(struct xrdp_mod *mod, int width, int height, int bpp) /* reset cache */ xrdp_cache_reset(wm->cache, wm->client_info); /* resize the main window */ - xrdp_bitmap_resize(wm->screen, wm->client_info->width, - wm->client_info->height); + xrdp_bitmap_resize(wm->screen, wm->client_info->display_sizes.session_width, + wm->client_info->display_sizes.session_height); /* load some stuff */ xrdp_wm_load_static_colors_plus(wm, 0); xrdp_wm_load_static_pointers(wm); diff --git a/xrdp/xrdp_wm.c b/xrdp/xrdp_wm.c index 94691582d0..caa1160a0c 100644 --- a/xrdp/xrdp_wm.c +++ b/xrdp/xrdp_wm.c @@ -45,8 +45,8 @@ xrdp_wm_create(struct xrdp_process *owner, self = (struct xrdp_wm *)g_malloc(sizeof(struct xrdp_wm), 1); self->client_info = client_info; - self->screen = xrdp_bitmap_create(client_info->width, - client_info->height, + self->screen = xrdp_bitmap_create(client_info->display_sizes.session_width, + client_info->display_sizes.session_height, client_info->bpp, WND_TYPE_SCREEN, self); self->screen->wm = self; @@ -2088,7 +2088,7 @@ xrdp_wm_show_log(struct xrdp_wm *self) int h; int xoffset; int yoffset; - int index; + uint32_t index; int primary_x_offset; int primary_y_offset; @@ -2124,14 +2124,14 @@ xrdp_wm_show_log(struct xrdp_wm *self) primary_y_offset = 0; /* multimon scenario, draw log window on primary monitor */ - if (self->client_info->monitorCount > 1) + if (self->client_info->display_sizes.monitorCount > 1) { - for (index = 0; index < self->client_info->monitorCount; index++) + for (index = 0; index < self->client_info->display_sizes.monitorCount; index++) { - if (self->client_info->minfo_wm[index].is_primary) + if (self->client_info->display_sizes.minfo_wm[index].is_primary) { - primary_x_offset = self->client_info->minfo_wm[index].left; - primary_y_offset = self->client_info->minfo_wm[index].top; + primary_x_offset = self->client_info->display_sizes.minfo_wm[index].left; + primary_y_offset = self->client_info->display_sizes.minfo_wm[index].top; break; } }