diff --git a/configure.ac b/configure.ac index 932a39ac..d373e94b 100644 --- a/configure.ac +++ b/configure.ac @@ -493,6 +493,7 @@ AC_CONFIG_FILES([ sesman/tools/Makefile tests/Makefile tests/common/Makefile + tests/libxrdp/Makefile tests/memtest/Makefile tests/xrdp/Makefile tools/Makefile diff --git a/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c index c5b34272..8fa34aea 100644 --- a/libxrdp/xrdp_sec.c +++ b/libxrdp/xrdp_sec.c @@ -2330,7 +2330,7 @@ xrdp_sec_process_mcs_data_channels(struct xrdp_sec *self, struct stream *s) /*****************************************************************************/ /* Process a [MS-RDPBCGR] TS_UD_CS_MONITOR message. reads the client monitors data */ -static int +int xrdp_sec_process_mcs_data_monitors(struct xrdp_sec *self, struct stream *s) { int index; @@ -2374,7 +2374,7 @@ xrdp_sec_process_mcs_data_monitors(struct xrdp_sec *self, struct stream *s) LOG(LOG_LEVEL_ERROR, "[MS-RDPBCGR] Protocol error: TS_UD_CS_MONITOR monitorCount " "MUST be less than 16, received: %d", monitorCount); - return 1; + return 2; } client_info->monitorCount = monitorCount; @@ -2468,7 +2468,7 @@ xrdp_sec_process_mcs_data_monitors(struct xrdp_sec *self, struct stream *s) "Allowed height range: min %d, max %d. Height received: %d", 0xC8, 0x7FFE, client_info->width, 0xC8, 0x7FFE, client_info->height); - return 1; /* error */ + return 3; /* error */ } /* keep a copy of non negative monitor info values for xrdp_wm usage */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 42b0df1c..01ed83f2 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -4,5 +4,6 @@ EXTRA_DIST = \ SUBDIRS = \ common \ + libxrdp \ memtest \ xrdp diff --git a/tests/libxrdp/Makefile.am b/tests/libxrdp/Makefile.am new file mode 100644 index 00000000..e98e8d9c --- /dev/null +++ b/tests/libxrdp/Makefile.am @@ -0,0 +1,23 @@ +AM_CPPFLAGS = \ + -I$(top_builddir) \ + -I$(top_srcdir)/libxrdp \ + -I$(top_srcdir)/common + +LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \ + $(top_srcdir)/tap-driver.sh + +TESTS = test_libxrdp +check_PROGRAMS = test_libxrdp + +test_libxrdp_SOURCES = \ + test_libxrdp.h \ + test_libxrdp_main.c \ + test_monitor_processing.c + +test_libxrdp_CFLAGS = \ + @CHECK_CFLAGS@ + +test_libxrdp_LDADD = \ + $(top_builddir)/common/libcommon.la \ + $(top_builddir)/libxrdp/libxrdp.la \ + @CHECK_LIBS@ diff --git a/tests/libxrdp/test_libxrdp.h b/tests/libxrdp/test_libxrdp.h new file mode 100644 index 00000000..444adf9e --- /dev/null +++ b/tests/libxrdp/test_libxrdp.h @@ -0,0 +1,8 @@ +#ifndef TEST_LIBXRDP_H +#define TEST_LIBXRDP_H + +#include + +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 new file mode 100644 index 00000000..0bd15cad --- /dev/null +++ b/tests/libxrdp/test_libxrdp_main.c @@ -0,0 +1,22 @@ +#if defined(HAVE_CONFIG_H) +#include "config_ac.h" +#endif + +#include +#include +#include "test_libxrdp.h" + +int main (void) +{ + int number_failed; + SRunner *sr; + + sr = srunner_create (make_suite_test_monitor_processing()); + // srunner_add_suite(sr, make_list_suite()); + + srunner_set_tap(sr, "-"); + srunner_run_all (sr, CK_ENV); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/tests/libxrdp/test_monitor_processing.c b/tests/libxrdp/test_monitor_processing.c new file mode 100644 index 00000000..969da780 --- /dev/null +++ b/tests/libxrdp/test_monitor_processing.c @@ -0,0 +1,305 @@ +#if defined(HAVE_CONFIG_H) +#include "config_ac.h" +#endif + +#include "test_libxrdp.h" +#include "libxrdp.h" +#include "os_calls.h" + +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); + session = (struct xrdp_session *)g_malloc(sizeof(struct xrdp_session), 1); + session->rdp = rdp_layer; + session->client_info = &(((struct xrdp_rdp *)session->rdp)->client_info); + session->client_info->multimon = 1; + sec_layer = (struct xrdp_sec *) g_malloc(sizeof(struct xrdp_sec), 1); + sec_layer->rdp_layer = rdp_layer; +} + +void teardown(void) +{ + g_free(sec_layer); + g_free(session); + g_free(rdp_layer); +} + +START_TEST(test_process_monitors__when_flags_is_not_zero__fail) +{ + struct stream *s = (struct stream *)NULL; + make_stream(s); + init_stream(s, 8); + + out_uint32_le(s, 1); + 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 = xrdp_sec_process_mcs_data_monitors(sec_layer, s); + ck_assert_int_eq(error, 1); + + free_stream(s); +} +END_TEST + +START_TEST(test_process_monitors__when_mounter_count_is_greater_than_sixteen__fail) +{ + struct stream *s = (struct stream *)NULL; + make_stream(s); + init_stream(s, 8); + + out_uint32_le(s, 0); + 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; + + int error = xrdp_sec_process_mcs_data_monitors(sec_layer, s); + ck_assert_int_eq(error, 2); + + free_stream(s); +} +END_TEST + +START_TEST(test_process_monitors__with_single_monitor_happy_path) +{ + struct xrdp_client_info *client_info = &(rdp_layer->client_info); + struct stream *s = (struct stream *)NULL; + make_stream(s); + init_stream(s, 28); + + out_uint32_le(s, 0); //flags + out_uint32_le(s, 1); //monitorCount + + // Pretend we have a 4k monitor + 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, 1); //is primary + + s_mark_end(s); + //Reset the read counter of the stream so the processing function handles it properly. + s->p = s->data; + + //Verify function call passed. + 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); + + // 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); + + // 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); + + // Verify geometry (+1 greater than ) + ck_assert_int_eq(client_info->width, 3841); + ck_assert_int_eq(client_info->height, 2161); + + free_stream(s); +} +END_TEST + +START_TEST(test_process_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; + make_stream(s); + init_stream(s, 28); + + out_uint32_le(s, 0); //flags + out_uint32_le(s, 1); //monitorCount + + // Pretend we have a 4k monitor + 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, 0); //is primary + + s_mark_end(s); + //Reset the read counter of the stream so the processing function handles it properly. + s->p = s->data; + + //Verify function call passed. + 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); + + // 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); + + // 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); + + // Verify geometry (+1 greater than ) + ck_assert_int_eq(client_info->width, 3841); + ck_assert_int_eq(client_info->height, 2161); + + free_stream(s); +} +END_TEST + +START_TEST(test_process_monitors__when_virtual_desktop_width_is_too_large) +{ + struct stream *s = (struct stream *)NULL; + make_stream(s); + init_stream(s, 28); + + out_uint32_le(s, 0); //flags + out_uint32_le(s, 1); //monitorCount + + // Pretend we have a 4k monitor + out_uint32_le(s, 0); //monitor left + out_uint32_le(s, 0); //monitor top + out_uint32_le(s, 33000); //monitor right + out_uint32_le(s, 2160); //monitor bottom + out_uint32_le(s, 1); //is primary + + s_mark_end(s); + //Reset the read counter of the stream so the processing function handles it properly. + s->p = s->data; + + //Verify function call passed. + int error = xrdp_sec_process_mcs_data_monitors(sec_layer, s); + ck_assert_int_eq(error, 3); + + free_stream(s); +} +END_TEST + +START_TEST(test_process_monitors__when_virtual_desktop_width_is_too_small) +{ + struct stream *s = (struct stream *)NULL; + make_stream(s); + init_stream(s, 28); + + out_uint32_le(s, 0); //flags + out_uint32_le(s, 1); //monitorCount + + // Pretend we have a 4k monitor + out_uint32_le(s, 0); //monitor left + out_uint32_le(s, 0); //monitor top + out_uint32_le(s, 100); //monitor right + out_uint32_le(s, 2160); //monitor bottom + out_uint32_le(s, 1); //is primary + + s_mark_end(s); + //Reset the read counter of the stream so the processing function handles it properly. + s->p = s->data; + + //Verify function call passed. + int error = xrdp_sec_process_mcs_data_monitors(sec_layer, s); + ck_assert_int_eq(error, 3); + + free_stream(s); +} +END_TEST + +START_TEST(test_process_monitors__when_virtual_desktop_height_is_too_large) +{ + struct stream *s = (struct stream *)NULL; + make_stream(s); + init_stream(s, 28); + + out_uint32_le(s, 0); //flags + out_uint32_le(s, 1); //monitorCount + + // Pretend we have a 4k monitor + 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, 33000); //monitor bottom + out_uint32_le(s, 1); //is primary + + s_mark_end(s); + //Reset the read counter of the stream so the processing function handles it properly. + s->p = s->data; + + //Verify function call passed. + int error = xrdp_sec_process_mcs_data_monitors(sec_layer, s); + ck_assert_int_eq(error, 3); + + free_stream(s); +} +END_TEST + +START_TEST(test_process_monitors__when_virtual_desktop_height_is_too_small) +{ + struct stream *s = (struct stream *)NULL; + make_stream(s); + init_stream(s, 28); + + out_uint32_le(s, 0); //flags + out_uint32_le(s, 1); //monitorCount + + // Pretend we have a 4k monitor + 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, 100); //monitor bottom + out_uint32_le(s, 1); //is primary + + s_mark_end(s); + //Reset the read counter of the stream so the processing function handles it properly. + s->p = s->data; + + //Verify function call passed. + int error = xrdp_sec_process_mcs_data_monitors(sec_layer, s); + ck_assert_int_eq(error, 3); + + free_stream(s); +} +END_TEST + +/******************************************************************************/ +Suite * +make_suite_test_monitor_processing(void) +{ + Suite *s; + TCase *tc_process_monitors; + + s = suite_create("Monitor_Processing"); + + 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); + + suite_add_tcase(s, tc_process_monitors); + + return s; +}