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..0cd844d4 100644 --- a/common/xrdp_client_info.h +++ b/common/xrdp_client_info.h @@ -24,13 +24,29 @@ #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 is_primary; + int flags; + + /* From 2.2.2.2.1 DISPLAYCONTROL_MONITOR_LAYOUT */ + unsigned int physical_width; + unsigned int physical_height; + unsigned int orientation; + unsigned int desktop_scale_factor; + unsigned int device_scale_factor; + + /* Derived setting */ + unsigned int is_primary; }; /* xrdp keyboard overrids */ @@ -41,6 +57,15 @@ struct xrdp_keyboard_overrides int layout; }; +struct display_size_description +{ + 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 */ + unsigned int session_width; + unsigned int session_height; +}; + /** * Information about the xrdp client * @@ -54,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; @@ -128,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; @@ -186,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 637dff02..bba935b8 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 */ /******************************************************************************/ @@ -1136,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) { @@ -1149,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 @@ -1766,3 +1764,380 @@ 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); + + /* 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) + { + 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 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_INFO, "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..b124a85b 100644 --- a/libxrdp/libxrdp.h +++ b/libxrdp/libxrdp.h @@ -359,6 +359,18 @@ int xrdp_mcs_disconnect(struct xrdp_mcs *self); /* xrdp_sec.c */ + +/* + 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 +#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 +395,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..af006868 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 * @@ -190,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, @@ -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_caps.c b/libxrdp/xrdp_caps.c index 5c5e74a5..c9532053 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 8fa34aea..885b5a3d 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] = { @@ -1955,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) { @@ -1983,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); @@ -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->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->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); } - 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/Makefile.am b/tests/libxrdp/Makefile.am index 30138cbf..4fb01959 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 444adf9e..a048e2bf 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 0bd15cad..370c092c 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 00000000..cc2b6ef9 --- /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 60% rename from tests/libxrdp/test_monitor_processing.c rename to tests/libxrdp/test_xrdp_sec_process_mcs_data_monitors.c index 951ffe68..64cda1eb 100644 --- a/tests/libxrdp/test_monitor_processing.c +++ b/tests/libxrdp/test_xrdp_sec_process_mcs_data_monitors.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); @@ -32,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); @@ -45,13 +42,13 @@ 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); } 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); @@ -64,13 +61,13 @@ 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); } 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; @@ -95,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; @@ -144,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); @@ -190,13 +187,13 @@ 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); } 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); @@ -218,13 +215,13 @@ 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); } 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); @@ -246,13 +243,13 @@ 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); } 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); @@ -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); } @@ -282,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 74861329..cf2c6e79 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 da5917b2..28ab4f85 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 b48e9f3b..796d997f 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->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->display_sizes.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; } /******************************************************************************/ @@ -3515,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; } @@ -3532,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 94691582..caa1160a 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; } }