diff --git a/common/ms-rdpbcgr.h b/common/ms-rdpbcgr.h index 813dc4db..e993c270 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 dd3d51e7..2e45b945 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 f45195e8..106e47a7 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 637dff02..f25b18c2 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 b0eae8c6..fb931bf3 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 7ec669c4..91a18ec3 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 8fa34aea..ba3ad70c 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; + "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; } - //verify monitorCount - max 16 - if (monitorCount > 16) + + struct display_size_description *description = + (struct display_size_description *) + g_malloc(sizeof(struct display_size_description), 1); + + error = libxrdp_process_monitor_stream(s, description, 0); + if (error == 0) { - LOG(LOG_LEVEL_ERROR, - "[MS-RDPBCGR] Protocol error: TS_UD_CS_MONITOR monitorCount " - "MUST be less than 16, received: %d", monitorCount); - return 2; + client_info->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->monitorCount = monitorCount; + g_free(description); - 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++) - { - 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; - } - - 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 (!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; - } - } - } - - /* 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 */ - } - - /* 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 951ffe68..0314e7dd 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 b48e9f3b..c10f1b5d 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) + 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); - } + return 0; } - session_width = rect.right - rect.left; - session_height = rect.bottom - rect.top; - if ((session_width > 0) && (session_height > 0)) + in_uint32_le(s, monitor_layout_size); + if (monitor_layout_size != 40) { - // 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); - } + 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; } - return 0; + + 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; } /******************************************************************************/