Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions

View File

@@ -0,0 +1,26 @@
set(MODULE_NAME "TestClient")
set(MODULE_PREFIX "TEST_CLIENT")
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
set(${MODULE_PREFIX}_TESTS TestClientRdpFile.c TestClientChannels.c TestClientCmdLine.c)
create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS})
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
target_compile_definitions(${MODULE_NAME} PRIVATE TEST_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client freerdp)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
foreach(test ${${MODULE_PREFIX}_TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/Client/Test")

View File

@@ -0,0 +1,87 @@
#include <stdio.h>
#include <winpr/crt.h>
#include <winpr/windows.h>
#include <freerdp/client/channels.h>
#include <freerdp/channels/rdpsnd.h>
int TestClientChannels(int argc, char* argv[])
{
DWORD dwFlags = 0;
FREERDP_ADDIN** ppAddins = nullptr;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
dwFlags = FREERDP_ADDIN_DYNAMIC;
printf("Enumerate all\n");
ppAddins = freerdp_channels_list_addins(nullptr, nullptr, nullptr, dwFlags);
for (size_t index = 0; ppAddins[index] != nullptr; index++)
{
FREERDP_ADDIN* pAddin = ppAddins[index];
printf("Addin: Name: %s Subsystem: %s Type: %s\n", pAddin->cName, pAddin->cSubsystem,
pAddin->cType);
}
freerdp_channels_addin_list_free(ppAddins);
printf("Enumerate rdpsnd\n");
ppAddins = freerdp_channels_list_addins(RDPSND_CHANNEL_NAME, nullptr, nullptr, dwFlags);
for (size_t index = 0; ppAddins[index] != nullptr; index++)
{
FREERDP_ADDIN* pAddin = ppAddins[index];
printf("Addin: Name: %s Subsystem: %s Type: %s\n", pAddin->cName, pAddin->cSubsystem,
pAddin->cType);
}
freerdp_channels_addin_list_free(ppAddins);
#if defined(CHANNEL_TSMF_CLIENT)
printf("Enumerate tsmf video\n");
ppAddins = freerdp_channels_list_addins("tsmf", nullptr, "video", dwFlags);
for (size_t index = 0; ppAddins[index] != nullptr; index++)
{
FREERDP_ADDIN* pAddin = ppAddins[index];
printf("Addin: Name: %s Subsystem: %s Type: %s\n", pAddin->cName, pAddin->cSubsystem,
pAddin->cType);
}
freerdp_channels_addin_list_free(ppAddins);
#endif
ppAddins = freerdp_channels_list_addins("unknown", nullptr, nullptr, dwFlags);
for (size_t index = 0; ppAddins[index] != nullptr; index++)
{
FREERDP_ADDIN* pAddin = ppAddins[index];
printf("Addin: Name: %s Subsystem: %s Type: %s\n", pAddin->cName, pAddin->cSubsystem,
pAddin->cType);
}
freerdp_channels_addin_list_free(ppAddins);
printf("Enumerate static addins\n");
dwFlags = FREERDP_ADDIN_STATIC;
ppAddins = freerdp_channels_list_addins(nullptr, nullptr, nullptr, dwFlags);
for (size_t index = 0; ppAddins[index] != nullptr; index++)
{
FREERDP_ADDIN* pAddin = ppAddins[index];
printf("Addin: Name: %s Subsystem: %s Type: %s\n", pAddin->cName, pAddin->cSubsystem,
pAddin->cType);
}
freerdp_channels_addin_list_free(ppAddins);
return 0;
}

View File

@@ -0,0 +1,263 @@
#include <freerdp/client.h>
#include <freerdp/client/cmdline.h>
#include <freerdp/settings.h>
#include <winpr/cmdline.h>
#include <winpr/spec.h>
#include <winpr/strlst.h>
#include <winpr/collections.h>
typedef BOOL (*validate_settings_pr)(rdpSettings* settings);
#define printref() printf("%s:%d: in function %-40s:", __FILE__, __LINE__, __func__)
#define TEST_ERROR(format, ...) \
do \
{ \
(void)fprintf(stderr, format, ##__VA_ARGS__); \
printref(); \
(void)printf(format, ##__VA_ARGS__); \
(void)fflush(stdout); \
} while (0)
#define TEST_FAILURE(format, ...) \
do \
{ \
printref(); \
(void)printf(" FAILURE "); \
(void)printf(format, ##__VA_ARGS__); \
(void)fflush(stdout); \
} while (0)
static void print_test_title(int argc, char** argv)
{
printf("Running test:");
for (int i = 0; i < argc; i++)
{
printf(" %s", argv[i]);
}
printf("\n");
}
static inline BOOL testcase(const char* name, char** argv, size_t argc, int expected_return,
validate_settings_pr validate_settings)
{
int status = 0;
BOOL valid_settings = TRUE;
rdpSettings* settings = freerdp_settings_new(0);
WINPR_ASSERT(argc <= INT_MAX);
print_test_title((int)argc, argv);
if (!settings)
{
TEST_ERROR("Test %s could not allocate settings!\n", name);
return FALSE;
}
status = freerdp_client_settings_parse_command_line(settings, (int)argc, argv, FALSE);
if (validate_settings)
{
valid_settings = validate_settings(settings);
}
freerdp_settings_free(settings);
if (status == expected_return)
{
if (!valid_settings)
{
return FALSE;
}
}
else
{
TEST_FAILURE("Expected status %d, got status %d\n", expected_return, status);
return FALSE;
}
return TRUE;
}
#if defined(_WIN32)
#define DRIVE_REDIRECT_PATH "c:\\Windows"
#else
#define DRIVE_REDIRECT_PATH "/tmp"
#endif
static BOOL check_settings_smartcard_no_redirection(rdpSettings* settings)
{
BOOL result = TRUE;
if (freerdp_settings_get_bool(settings, FreeRDP_RedirectSmartCards))
{
TEST_FAILURE("Expected RedirectSmartCards = FALSE, but RedirectSmartCards = TRUE!\n");
result = FALSE;
}
if (freerdp_device_collection_find_type(settings, RDPDR_DTYP_SMARTCARD))
{
TEST_FAILURE("Expected no SMARTCARD device, but found at least one!\n");
result = FALSE;
}
return result;
}
typedef struct
{
int expected_status;
validate_settings_pr validate_settings;
const char* command_line[128];
struct
{
int index;
const char* expected_value;
} modified_arguments[8];
} test;
// NOLINTBEGIN(bugprone-suspicious-missing-comma)
static const test tests[] = {
{ COMMAND_LINE_STATUS_PRINT_HELP,
check_settings_smartcard_no_redirection,
{ "testfreerdp", "--help", nullptr },
{ { 0 } } },
{ COMMAND_LINE_STATUS_PRINT_HELP,
check_settings_smartcard_no_redirection,
{ "testfreerdp", "/help", nullptr },
{ { 0 } } },
{ COMMAND_LINE_STATUS_PRINT_HELP,
check_settings_smartcard_no_redirection,
{ "testfreerdp", "-help", nullptr },
{ { 0 } } },
{ COMMAND_LINE_STATUS_PRINT_VERSION,
check_settings_smartcard_no_redirection,
{ "testfreerdp", "--version", nullptr },
{ { 0 } } },
{ COMMAND_LINE_STATUS_PRINT_VERSION,
check_settings_smartcard_no_redirection,
{ "testfreerdp", "/version", nullptr },
{ { 0 } } },
{ COMMAND_LINE_STATUS_PRINT_VERSION,
check_settings_smartcard_no_redirection,
{ "testfreerdp", "-version", nullptr },
{ { 0 } } },
{ 0,
check_settings_smartcard_no_redirection,
{ "testfreerdp", "-v", "test.freerdp.com", nullptr },
{ { 0 } } },
{ 0,
check_settings_smartcard_no_redirection,
{ "testfreerdp", "--v", "test.freerdp.com", nullptr },
{ { 0 } } },
{ 0,
check_settings_smartcard_no_redirection,
{ "testfreerdp", "/v:test.freerdp.com", nullptr },
{ { 0 } } },
{ 0,
check_settings_smartcard_no_redirection,
{ "testfreerdp", "/sound", "/drive:media," DRIVE_REDIRECT_PATH, "/v:test.freerdp.com",
nullptr },
{ { 0 } } },
{ 0,
check_settings_smartcard_no_redirection,
{ "testfreerdp", "-u", "test", "-p", "test", "-v", "test.freerdp.com", nullptr },
{ { 4, "****" }, { 0 } } },
{ 0,
check_settings_smartcard_no_redirection,
{ "testfreerdp", "/u:test", "/p:test", "/v:test.freerdp.com", nullptr },
{ { 2, "/p:****" }, { 0 } } },
{ COMMAND_LINE_ERROR_NO_KEYWORD,
check_settings_smartcard_no_redirection,
{ "testfreerdp", "-invalid", nullptr },
{ { 0 } } },
{ COMMAND_LINE_ERROR_NO_KEYWORD,
check_settings_smartcard_no_redirection,
{ "testfreerdp", "--invalid", nullptr },
{ { 0 } } },
#if defined(WITH_FREERDP_DEPRECATED_CMDLINE)
{ COMMAND_LINE_STATUS_PRINT,
check_settings_smartcard_no_redirection,
{ "testfreerdp", "/kbd-list", 0 },
{ { 0 } } },
{ COMMAND_LINE_STATUS_PRINT,
check_settings_smartcard_no_redirection,
{ "testfreerdp", "/monitor-list", 0 },
{ { 0 } } },
#endif
{ COMMAND_LINE_STATUS_PRINT,
check_settings_smartcard_no_redirection,
{ "testfreerdp", "/list:kbd", nullptr },
{ { 0 } } },
{ COMMAND_LINE_STATUS_PRINT,
check_settings_smartcard_no_redirection,
{ "testfreerdp", "/list:monitor", nullptr },
{ { 0 } } },
{ 0,
check_settings_smartcard_no_redirection,
{ "testfreerdp", "/sound", "/drive:media:" DRIVE_REDIRECT_PATH, "/v:test.freerdp.com",
nullptr },
{ { 0 } } },
{ 0,
check_settings_smartcard_no_redirection,
{ "testfreerdp", "/sound", "/drive:media,/foo/bar/blabla", "/v:test.freerdp.com", nullptr },
{ { 0 } } },
};
// NOLINTEND(bugprone-suspicious-missing-comma)
static void check_modified_arguments(const test* test, char** command_line, int* rc)
{
const char* expected_argument = nullptr;
for (int k = 0; (expected_argument = test->modified_arguments[k].expected_value); k++)
{
int index = test->modified_arguments[k].index;
char* actual_argument = command_line[index];
if (0 != strcmp(actual_argument, expected_argument))
{
printref();
printf("Failure: overridden argument %d is %s but it should be %s\n", index,
actual_argument, expected_argument);
(void)fflush(stdout);
*rc = -1;
}
}
}
int TestClientCmdLine(int argc, char* argv[])
{
int rc = 0;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
for (size_t i = 0; i < ARRAYSIZE(tests); i++)
{
const test* current = &tests[i];
int failure = 0;
char** command_line = string_list_copy(current->command_line);
const int len = string_list_length((const char* const*)command_line);
if (!testcase(__func__, command_line, WINPR_ASSERTING_INT_CAST(size_t, len),
current->expected_status, current->validate_settings))
{
TEST_FAILURE("parsing arguments.\n");
failure = 1;
}
check_modified_arguments(current, command_line, &failure);
if (failure)
{
string_list_print(stdout, (const char* const*)command_line);
rc = -1;
}
string_list_free(command_line);
}
return rc;
}

View File

@@ -0,0 +1,838 @@
#include <freerdp/config.h>
#include <stdio.h>
#include <errno.h>
#include <winpr/crt.h>
#include <winpr/windows.h>
#include <winpr/path.h>
#include <winpr/crypto.h>
#include <freerdp/client/file.h>
#include <freerdp/channels/rdpecam.h>
static const BYTE testRdpFileUTF16[] = {
0xff, 0xfe, 0x73, 0x00, 0x63, 0x00, 0x72, 0x00, 0x65, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x20, 0x00,
0x6d, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00, 0x20, 0x00, 0x69, 0x00, 0x64, 0x00, 0x3a, 0x00,
0x69, 0x00, 0x3a, 0x00, 0x32, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x75, 0x00, 0x73, 0x00, 0x65, 0x00,
0x20, 0x00, 0x6d, 0x00, 0x75, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x6f, 0x00,
0x6e, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x30, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x64, 0x00,
0x65, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x70, 0x00, 0x77, 0x00, 0x69, 0x00,
0x64, 0x00, 0x74, 0x00, 0x68, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x39, 0x00,
0x32, 0x00, 0x30, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x64, 0x00, 0x65, 0x00, 0x73, 0x00, 0x6b, 0x00,
0x74, 0x00, 0x6f, 0x00, 0x70, 0x00, 0x68, 0x00, 0x65, 0x00, 0x69, 0x00, 0x67, 0x00, 0x68, 0x00,
0x74, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x30, 0x00, 0x38, 0x00, 0x30, 0x00,
0x0d, 0x00, 0x0a, 0x00, 0x73, 0x00, 0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00,
0x6e, 0x00, 0x20, 0x00, 0x62, 0x00, 0x70, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00,
0x33, 0x00, 0x32, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x77, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x70, 0x00,
0x6f, 0x00, 0x73, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x3a, 0x00, 0x73, 0x00, 0x3a, 0x00,
0x30, 0x00, 0x2c, 0x00, 0x31, 0x00, 0x2c, 0x00, 0x35, 0x00, 0x35, 0x00, 0x33, 0x00, 0x2c, 0x00,
0x32, 0x00, 0x31, 0x00, 0x31, 0x00, 0x2c, 0x00, 0x31, 0x00, 0x33, 0x00, 0x35, 0x00, 0x33, 0x00,
0x2c, 0x00, 0x38, 0x00, 0x31, 0x00, 0x31, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x63, 0x00, 0x6f, 0x00,
0x6d, 0x00, 0x70, 0x00, 0x72, 0x00, 0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00,
0x6e, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x6b, 0x00,
0x65, 0x00, 0x79, 0x00, 0x62, 0x00, 0x6f, 0x00, 0x61, 0x00, 0x72, 0x00, 0x64, 0x00, 0x68, 0x00,
0x6f, 0x00, 0x6f, 0x00, 0x6b, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x32, 0x00, 0x0d, 0x00,
0x0a, 0x00, 0x61, 0x00, 0x75, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x61, 0x00,
0x70, 0x00, 0x74, 0x00, 0x75, 0x00, 0x72, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x64, 0x00,
0x65, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x30, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x76, 0x00,
0x69, 0x00, 0x64, 0x00, 0x65, 0x00, 0x6f, 0x00, 0x70, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00,
0x62, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00,
0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x63, 0x00, 0x6f, 0x00,
0x6e, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00,
0x20, 0x00, 0x74, 0x00, 0x79, 0x00, 0x70, 0x00, 0x65, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00,
0x37, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x74, 0x00, 0x77, 0x00, 0x6f, 0x00,
0x72, 0x00, 0x6b, 0x00, 0x61, 0x00, 0x75, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00,
0x74, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x31, 0x00,
0x0d, 0x00, 0x0a, 0x00, 0x62, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x77, 0x00, 0x69, 0x00,
0x64, 0x00, 0x74, 0x00, 0x68, 0x00, 0x61, 0x00, 0x75, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x64, 0x00,
0x65, 0x00, 0x74, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00,
0x31, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x64, 0x00, 0x69, 0x00, 0x73, 0x00, 0x70, 0x00, 0x6c, 0x00,
0x61, 0x00, 0x79, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x63, 0x00,
0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x72, 0x00, 0x3a, 0x00,
0x69, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x61, 0x00,
0x62, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x77, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x6b, 0x00, 0x73, 0x00,
0x70, 0x00, 0x61, 0x00, 0x63, 0x00, 0x65, 0x00, 0x72, 0x00, 0x65, 0x00, 0x63, 0x00, 0x6f, 0x00,
0x6e, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00,
0x30, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x64, 0x00, 0x69, 0x00, 0x73, 0x00, 0x61, 0x00, 0x62, 0x00,
0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, 0x77, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x70, 0x00,
0x61, 0x00, 0x70, 0x00, 0x65, 0x00, 0x72, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x30, 0x00,
0x0d, 0x00, 0x0a, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x20, 0x00,
0x66, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x20, 0x00, 0x73, 0x00, 0x6d, 0x00, 0x6f, 0x00,
0x6f, 0x00, 0x74, 0x00, 0x68, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x3a, 0x00, 0x69, 0x00,
0x3a, 0x00, 0x30, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x6f, 0x00,
0x77, 0x00, 0x20, 0x00, 0x64, 0x00, 0x65, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x74, 0x00, 0x6f, 0x00,
0x70, 0x00, 0x20, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x73, 0x00,
0x69, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00,
0x30, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x64, 0x00, 0x69, 0x00, 0x73, 0x00, 0x61, 0x00, 0x62, 0x00,
0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, 0x66, 0x00, 0x75, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x20, 0x00,
0x77, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x20, 0x00, 0x64, 0x00,
0x72, 0x00, 0x61, 0x00, 0x67, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x0d, 0x00,
0x0a, 0x00, 0x64, 0x00, 0x69, 0x00, 0x73, 0x00, 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00,
0x20, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x75, 0x00, 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00,
0x69, 0x00, 0x6d, 0x00, 0x73, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x0d, 0x00,
0x0a, 0x00, 0x64, 0x00, 0x69, 0x00, 0x73, 0x00, 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00,
0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x73, 0x00, 0x3a, 0x00,
0x69, 0x00, 0x3a, 0x00, 0x30, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x64, 0x00, 0x69, 0x00, 0x73, 0x00,
0x61, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, 0x63, 0x00, 0x75, 0x00, 0x72, 0x00,
0x73, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x20, 0x00, 0x73, 0x00, 0x65, 0x00, 0x74, 0x00, 0x74, 0x00,
0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x30, 0x00, 0x0d, 0x00,
0x0a, 0x00, 0x62, 0x00, 0x69, 0x00, 0x74, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x70, 0x00, 0x63, 0x00,
0x61, 0x00, 0x63, 0x00, 0x68, 0x00, 0x65, 0x00, 0x70, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00,
0x69, 0x00, 0x73, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00,
0x65, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x66, 0x00,
0x75, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x61, 0x00, 0x64, 0x00, 0x64, 0x00, 0x72, 0x00,
0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 0x3a, 0x00, 0x73, 0x00, 0x3a, 0x00, 0x4c, 0x00, 0x41, 0x00,
0x42, 0x00, 0x31, 0x00, 0x2d, 0x00, 0x57, 0x00, 0x37, 0x00, 0x2d, 0x00, 0x44, 0x00, 0x4d, 0x00,
0x2d, 0x00, 0x30, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x62, 0x00, 0x31, 0x00,
0x2e, 0x00, 0x61, 0x00, 0x77, 0x00, 0x61, 0x00, 0x6b, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x6c, 0x00,
0x6f, 0x00, 0x63, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x61, 0x00, 0x75, 0x00,
0x64, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00, 0x3a, 0x00,
0x69, 0x00, 0x3a, 0x00, 0x30, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00,
0x69, 0x00, 0x72, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x70, 0x00, 0x72, 0x00, 0x69, 0x00,
0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00,
0x31, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x69, 0x00, 0x72, 0x00,
0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x70, 0x00, 0x6f, 0x00,
0x72, 0x00, 0x74, 0x00, 0x73, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x30, 0x00, 0x0d, 0x00,
0x0a, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x69, 0x00, 0x72, 0x00, 0x65, 0x00, 0x63, 0x00,
0x74, 0x00, 0x73, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x72, 0x00, 0x74, 0x00, 0x63, 0x00, 0x61, 0x00,
0x72, 0x00, 0x64, 0x00, 0x73, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x0d, 0x00,
0x0a, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x69, 0x00, 0x72, 0x00, 0x65, 0x00, 0x63, 0x00,
0x74, 0x00, 0x63, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x70, 0x00, 0x62, 0x00, 0x6f, 0x00, 0x61, 0x00,
0x72, 0x00, 0x64, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x0d, 0x00, 0x0a, 0x00,
0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x69, 0x00, 0x72, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00,
0x70, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x64, 0x00, 0x65, 0x00, 0x76, 0x00, 0x69, 0x00, 0x63, 0x00,
0x65, 0x00, 0x73, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x30, 0x00, 0x0d, 0x00, 0x0a, 0x00,
0x61, 0x00, 0x75, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x63, 0x00, 0x6f, 0x00,
0x6e, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00,
0x20, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x64, 0x00,
0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x61, 0x00, 0x75, 0x00,
0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00,
0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x76, 0x00,
0x65, 0x00, 0x6c, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x32, 0x00, 0x0d, 0x00, 0x0a, 0x00,
0x70, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x70, 0x00, 0x74, 0x00, 0x20, 0x00, 0x66, 0x00,
0x6f, 0x00, 0x72, 0x00, 0x20, 0x00, 0x63, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x65, 0x00,
0x6e, 0x00, 0x74, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x73, 0x00, 0x3a, 0x00, 0x69, 0x00,
0x3a, 0x00, 0x30, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x67, 0x00, 0x6f, 0x00,
0x74, 0x00, 0x69, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x73, 0x00, 0x65, 0x00,
0x63, 0x00, 0x75, 0x00, 0x72, 0x00, 0x69, 0x00, 0x74, 0x00, 0x79, 0x00, 0x20, 0x00, 0x6c, 0x00,
0x61, 0x00, 0x79, 0x00, 0x65, 0x00, 0x72, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x31, 0x00,
0x0d, 0x00, 0x0a, 0x00, 0x72, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x65, 0x00,
0x61, 0x00, 0x70, 0x00, 0x70, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x74, 0x00,
0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x65, 0x00, 0x3a, 0x00,
0x69, 0x00, 0x3a, 0x00, 0x30, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x74, 0x00,
0x65, 0x00, 0x72, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x73, 0x00,
0x68, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x3a, 0x00, 0x73, 0x00, 0x3a, 0x00, 0x0d, 0x00,
0x0a, 0x00, 0x73, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x77, 0x00,
0x6f, 0x00, 0x72, 0x00, 0x6b, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x20, 0x00, 0x64, 0x00,
0x69, 0x00, 0x72, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x79, 0x00,
0x3a, 0x00, 0x73, 0x00, 0x3a, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x67, 0x00, 0x61, 0x00, 0x74, 0x00,
0x65, 0x00, 0x77, 0x00, 0x61, 0x00, 0x79, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x74, 0x00,
0x6e, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x3a, 0x00, 0x73, 0x00, 0x3a, 0x00, 0x4c, 0x00,
0x41, 0x00, 0x42, 0x00, 0x31, 0x00, 0x2d, 0x00, 0x57, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x38, 0x00,
0x52, 0x00, 0x32, 0x00, 0x2d, 0x00, 0x47, 0x00, 0x57, 0x00, 0x2e, 0x00, 0x6c, 0x00, 0x61, 0x00,
0x62, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x77, 0x00, 0x61, 0x00, 0x6b, 0x00, 0x65, 0x00,
0x2e, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x0d, 0x00, 0x0a, 0x00,
0x67, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x77, 0x00, 0x61, 0x00, 0x79, 0x00, 0x75, 0x00,
0x73, 0x00, 0x61, 0x00, 0x67, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x74, 0x00, 0x68, 0x00,
0x6f, 0x00, 0x64, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x0d, 0x00, 0x0a, 0x00,
0x67, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x77, 0x00, 0x61, 0x00, 0x79, 0x00, 0x63, 0x00,
0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x69, 0x00, 0x61, 0x00,
0x6c, 0x00, 0x73, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x72, 0x00, 0x63, 0x00, 0x65, 0x00,
0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x30, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x67, 0x00, 0x61, 0x00,
0x74, 0x00, 0x65, 0x00, 0x77, 0x00, 0x61, 0x00, 0x79, 0x00, 0x70, 0x00, 0x72, 0x00, 0x6f, 0x00,
0x66, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x75, 0x00, 0x73, 0x00, 0x61, 0x00, 0x67, 0x00,
0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x74, 0x00, 0x68, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x3a, 0x00,
0x69, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x72, 0x00, 0x6f, 0x00,
0x6d, 0x00, 0x70, 0x00, 0x74, 0x00, 0x63, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x65, 0x00,
0x6e, 0x00, 0x74, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x63, 0x00,
0x65, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x31, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x75, 0x00,
0x73, 0x00, 0x65, 0x00, 0x20, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x69, 0x00, 0x72, 0x00,
0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x73, 0x00,
0x65, 0x00, 0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x6e, 0x00, 0x61, 0x00,
0x6d, 0x00, 0x65, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00, 0x30, 0x00, 0x0d, 0x00, 0x0a, 0x00,
0x72, 0x00, 0x64, 0x00, 0x67, 0x00, 0x69, 0x00, 0x73, 0x00, 0x6b, 0x00, 0x64, 0x00, 0x63, 0x00,
0x70, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x78, 0x00, 0x79, 0x00, 0x3a, 0x00, 0x69, 0x00, 0x3a, 0x00,
0x30, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x6b, 0x00, 0x64, 0x00, 0x63, 0x00, 0x70, 0x00, 0x72, 0x00,
0x6f, 0x00, 0x78, 0x00, 0x79, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x3a, 0x00,
0x73, 0x00, 0x3a, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x64, 0x00, 0x72, 0x00, 0x69, 0x00, 0x76, 0x00,
0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x64, 0x00, 0x69, 0x00,
0x72, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x3a, 0x00, 0x73, 0x00, 0x3a, 0x00, 0x2a, 0x00,
0x0d, 0x00, 0x0a, 0x00, 0x75, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6e, 0x00, 0x61, 0x00,
0x6d, 0x00, 0x65, 0x00, 0x3a, 0x00, 0x73, 0x00, 0x3a, 0x00, 0x4c, 0x00, 0x41, 0x00, 0x42, 0x00,
0x31, 0x00, 0x5c, 0x00, 0x4a, 0x00, 0x6f, 0x00, 0x68, 0x00, 0x6e, 0x00, 0x44, 0x00, 0x6f, 0x00,
0x65, 0x00, 0x0d, 0x00, 0x0a, 0x00
};
#if defined(CHANNEL_RDPECAM_CLIENT)
static const char* camera_args[] = { RDPECAM_DVC_CHANNEL_NAME,
"device:*",
"device:\\?\\usb#vid_0bda&pid_58b0&mi",
"device:-\\?\\usb#vid_0bdc&pid_58b1&mi",
"encode:1",
"quality:2" };
#endif
#if defined(CHANNEL_URBDRC_CLIENT)
static const char* urbdrc_args[] = { "urbdrc", "device:*", "device:USBInstanceID:someid",
"device:{72631e54-78a4-11d0-bcf7-00aa00b7b32a}" };
#endif
static char testRdpFileUTF8[] =
"screen mode id:i:2\n"
"use multimon:i:0\n"
"desktopwidth:i:1920\n"
"desktopheight:i:1080\n"
"dynamic resolution:i:1080\n"
"desktopscalefactor:i:1080\n"
"redirected video capture encoding quality:i:2\n"
"encode redirected video capture:i:1\n"
"camerastoredirect:s:*,\\?\\usb#vid_0bda&pid_58b0&mi,-\\?\\usb#vid_0bdc&pid_58b1&mi\n"
"usbdevicestoredirect:s:*,USBInstanceID:someid,{72631e54-78a4-11d0-bcf7-00aa00b7b32a}\n"
"selectedmonitors:s:3,2,42,23"
"session bpp:i:32\n"
"winposstr:s:0,1,553,211,1353,811\n"
"compression:i:1\n"
"keyboardhook:i:2\n"
"audiocapturemode:i:0\n"
"videoplaybackmode:i:2\n"
"connection type:i:7\n"
"networkautodetect:i:1\n"
"bandwidthautodetect:i:1\n"
"displayconnectionbar:i:1\n"
"enableworkspacereconnect:i:0\n"
"disable wallpaper:i:0\n"
"allow font smoothing:i:0\n"
"allow desktop composition:i:0\n"
"disable full window drag:i:1\n"
"disable menu anims:i:1\n"
"disable themes:i:0\n"
"disable cursor setting:i:0\n"
"bitmapcachepersistenable:i:1\n"
"full address:s:LAB1-W7-DM-01.lab1.awake.local\n"
"alternate full address:s:LAB1-W7-DM-01.lab1.awake.global\n"
"audiomode:i:0\n"
"redirectprinters:i:1\n"
"redirectcomports:i:0\n"
"redirectsmartcards:i:1\n"
"redirectclipboard:i:1\n"
"redirectposdevices:i:0\n"
"autoreconnection enabled:i:1\n"
"authentication level:i:2\n"
"prompt for credentials:i:0\n"
"negotiate security layer:i:1\n"
"remoteapplicationmode:i:0\n"
"alternate shell:s:\n"
"shell working directory:s:\n"
"gatewayhostname:s:LAB1-W2K8R2-GW.lab1.awake.local\n"
"gatewayusagemethod:i:1\n"
"gatewaycredentialssource:i:0\n"
"gatewayprofileusagemethod:i:1\n"
"promptcredentialonce:i:1\n"
"use redirection server name:i:0\n"
"rdgiskdcproxy:i:0\n"
"kdcproxyname:s:\n"
"drivestoredirect:s:*\n"
"username:s:LAB1\\JohnDoe\n"
"vendor integer:i:123\n"
"vendor string:s:microsoft\n";
static char* append(const char* fmt, ...)
{
int rc = 0;
char* dst = nullptr;
va_list ap = WINPR_C_ARRAY_INIT;
va_start(ap, fmt);
rc = vsnprintf(nullptr, 0, fmt, ap);
va_end(ap);
if (rc < 0)
return nullptr;
dst = malloc((size_t)rc + 1);
if (!dst)
return nullptr;
va_start(ap, fmt);
rc = vsnprintf(dst, (size_t)rc + 1, fmt, ap);
va_end(ap);
if (rc < 0)
{
free(dst);
return nullptr;
}
return dst;
}
static FILE* test_fopen(const char* name, const char* mode)
{
#ifndef TEST_SOURCE_DIR
#error "TEST_SOURCE_DIR must be defined to the test source directory"
#endif
char* path = GetCombinedPath(TEST_SOURCE_DIR, name);
FILE* fp = winpr_fopen(path, mode);
free(path);
return fp;
}
static void* read_rdp_data(const char* name, size_t* plen)
{
BOOL success = FALSE;
char* json = nullptr;
FILE* fp = test_fopen(name, "r");
if (!fp)
goto fail;
if (fseek(fp, 0, SEEK_END) != 0)
goto fail;
const INT64 pos = _ftelli64(fp);
if (pos < 0)
goto fail;
if (fseek(fp, 0, SEEK_SET) != 0)
goto fail;
const size_t upos = WINPR_CXX_COMPAT_CAST(size_t, pos);
json = calloc(1ULL + upos, sizeof(char));
if (!json)
goto fail;
if (fread(json, 1, pos, fp) != pos)
goto fail;
*plen = upos;
success = TRUE;
fail:
if (!success)
{
char buffer[128] = WINPR_C_ARRAY_INIT;
WLog_ERR(__func__, "failed to read data from '%s': %s", name,
winpr_strerror(errno, buffer, sizeof(buffer)));
free(json);
json = nullptr;
}
if (fp)
(void)fclose(fp);
return json;
}
static bool save_settings(const rdpSettings* settings, const char* name)
{
bool rc = false;
size_t datalen = 0;
char* data = freerdp_settings_serialize(settings, TRUE, &datalen);
if (!data)
return false;
FILE* fp = test_fopen(name, "w");
if (fp)
{
const size_t res = fwrite(data, 1, datalen, fp);
(void)fclose(fp);
rc = res == datalen;
}
free(data);
return rc;
}
static char* get_json_name(const char* base, bool unchecked)
{
size_t namelen = 0;
char* name = nullptr;
winpr_asprintf(&name, &namelen, "%s%s.json", base, unchecked ? ".unchecked" : "");
return name;
}
static rdpSettings* read_json(const char* name)
{
size_t datalen = 0;
void* data = read_rdp_data(name, &datalen);
rdpSettings* settings = freerdp_settings_deserialize(data, datalen);
fail:
free(data);
return settings;
}
static rdpSettings* load_from(const void* data, size_t len, bool unchecked)
{
BOOL rc = false;
rdpFile* file = freerdp_client_rdp_file_new();
rdpSettings* settings = read_json("default-settings.json");
if (!settings)
{
settings = freerdp_settings_new(0);
if (settings)
{
save_settings(settings, "default-settings.json");
}
}
if (!file || !settings)
goto fail;
if (!freerdp_client_parse_rdp_file_buffer(file, data, len))
goto fail;
if (unchecked)
{
if (!freerdp_client_populate_settings_from_rdp_file_unchecked(file, settings))
goto fail;
}
else
{
if (!freerdp_client_populate_settings_from_rdp_file(file, settings))
goto fail;
}
rc = true;
fail:
freerdp_client_rdp_file_free(file);
if (!rc)
{
freerdp_settings_free(settings);
return nullptr;
}
return settings;
}
static rdpSettings* load_from_file(const char* name, bool unchecked)
{
size_t datalen = 0;
void* data = read_rdp_data(name, &datalen);
if (!data)
return nullptr;
rdpSettings* settings = load_from(data, datalen, unchecked);
free(data);
return settings;
}
static bool test_data(const char* json, const void* data, size_t len, bool unchecked)
{
bool rc = false;
rdpSettings* settings = load_from(data, len, unchecked);
rdpSettings* expect = read_json(json);
if (!settings || !expect)
goto fail;
#ifndef WITH_GFX_H264
if (!freerdp_settings_set_bool(expect, FreeRDP_GfxH264, FALSE) ||
!freerdp_settings_set_bool(expect, FreeRDP_GfxAVC444, FALSE) ||
!freerdp_settings_set_bool(expect, FreeRDP_GfxAVC444v2, FALSE))
goto fail;
#endif
wLog* log = WLog_Get(__func__);
WLog_Print(log, WLOG_INFO, "Test cast '%s'", json);
if (freerdp_settings_print_diff(log, WLOG_ERROR, expect, settings))
goto fail;
rc = true;
fail:
freerdp_settings_free(settings);
freerdp_settings_free(expect);
return rc;
}
static HANDLE FindFirstFileUTF8(LPCSTR pszSearchPath, WIN32_FIND_DATAW* FindData)
{
HANDLE hdl = INVALID_HANDLE_VALUE;
if (!pszSearchPath)
return hdl;
WCHAR* wpath = ConvertUtf8ToWCharAlloc(pszSearchPath, nullptr);
if (!wpath)
return hdl;
hdl = FindFirstFileW(wpath, FindData);
free(wpath);
return hdl;
}
static bool test_rdp_file(const char* base, bool allowCreate, bool unchecked)
{
bool rc = false;
size_t rdplen = 0;
char* rdp = nullptr;
winpr_asprintf(&rdp, &rdplen, "%s.rdp", base);
char* json = get_json_name(base, unchecked);
size_t datalen = 0;
void* data = read_rdp_data(rdp, &datalen);
if (!data)
goto fail;
rc = test_data(json, data, datalen, unchecked);
if (!rc && allowCreate)
{
rdpSettings* expect = read_json(json);
if (expect)
{
freerdp_settings_free(expect);
goto fail;
}
rdpSettings* settings = load_from_file(rdp, unchecked);
if (!settings)
goto fail;
rc = save_settings(settings, json);
}
fail:
free(data);
free(json);
free(rdp);
return rc;
}
static bool test_rdp_files(bool allowCreate)
{
bool rc = false;
/* Load RDP files from directory, compare to JSON in same directory.
* If JSON does not exist, create it.
*/
#ifndef TEST_SOURCE_DIR
#error "TEST_SOURCE_DIR must be defined to the test source directory"
#endif
HANDLE hdl = INVALID_HANDLE_VALUE;
char* path = GetCombinedPath(TEST_SOURCE_DIR, "rdp-testcases/*.rdp");
if (!path)
goto fail;
WIN32_FIND_DATAW FindData = WINPR_C_ARRAY_INIT;
hdl = FindFirstFileUTF8(path, &FindData);
if (hdl == INVALID_HANDLE_VALUE)
{
WLog_INFO(
__func__,
"no RDP files found in %s. Add RDP files to generate settings JSON for comparison.",
path);
rc = true;
goto fail;
}
do
{
if ((FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
{
char cFileName[6 * MAX_PATH] = WINPR_C_ARRAY_INIT;
char rdp[6 * MAX_PATH] = WINPR_C_ARRAY_INIT;
ConvertWCharToUtf8(FindData.cFileName, cFileName, sizeof(cFileName));
const size_t len = strnlen(cFileName, sizeof(cFileName));
if (len < 4)
continue;
strcpy(rdp, "rdp-testcases/");
strncpy(&rdp[14], cFileName, len - 4);
if (!test_rdp_file(rdp, allowCreate, false))
goto fail;
if (!test_rdp_file(rdp, allowCreate, true))
goto fail;
}
} while (FindNextFileW(hdl, &FindData));
rc = true;
fail:
FindClose(hdl);
free(path);
return rc;
}
int TestClientRdpFile(int argc, char* argv[])
{
int rc = -1;
int iValue = 0;
UINT32 uValue = 0;
const UINT32* puValue = nullptr;
const char* sValue = nullptr;
char* utfname = nullptr;
char* uniname = nullptr;
char* base = nullptr;
char* tmp = nullptr;
UINT64 id = 0;
rdpFile* file = nullptr;
rdpSettings* settings = nullptr;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
if (winpr_RAND(&id, sizeof(id)) < 0)
return -1;
/* UTF8 */
#if defined(CHANNEL_URBDRC_CLIENT) && defined(CHANNEL_RDPECAM_CLIENT)
if (!test_data("testRdpFileUTF8.json", testRdpFileUTF8, sizeof(testRdpFileUTF8), false))
return -1;
if (!test_data("testRdpFileUTF8.unchecked.json", testRdpFileUTF8, sizeof(testRdpFileUTF8),
true))
return -1;
#endif
/* Unicode */
#if defined(CHANNEL_URBDRC_CLIENT)
if (!test_data("testRdpFileUTF16.json", testRdpFileUTF16, sizeof(testRdpFileUTF16), false))
return -1;
if (!test_data("testRdpFileUTF16.unchecked.json", testRdpFileUTF16, sizeof(testRdpFileUTF16),
true))
return -1;
#endif
#if defined(CHANNEL_URBDRC_CLIENT) && defined(CHANNEL_RDPECAM_CLIENT)
if (!test_rdp_files(argc > 1))
return -1;
#endif
/* Ascii */
file = freerdp_client_rdp_file_new();
settings = freerdp_settings_new(0);
if (!file || !settings)
{
printf("rdp_file_new failed\n");
goto fail;
}
if (!freerdp_client_parse_rdp_file_buffer(file, (BYTE*)testRdpFileUTF8,
sizeof(testRdpFileUTF8)))
goto fail;
if (!freerdp_client_populate_settings_from_rdp_file(file, settings))
goto fail;
if (freerdp_settings_get_bool(settings, FreeRDP_UseMultimon))
{
printf("UseMultiMon mismatch: Actual: %" PRIu32 ", Expected: 0\n",
freerdp_settings_get_bool(settings, FreeRDP_UseMultimon));
return -1;
}
if (!freerdp_settings_get_bool(settings, FreeRDP_Fullscreen))
{
printf("ScreenModeId mismatch: Actual: %" PRIu32 ", Expected: TRUE\n",
freerdp_settings_get_bool(settings, FreeRDP_Fullscreen));
return -1;
}
if (strcmp(freerdp_settings_get_string(settings, FreeRDP_ServerHostname),
"LAB1-W7-DM-01.lab1.awake.global") != 0)
{
printf("ServerHostname mismatch: Actual: %s, Expected: %s\n",
freerdp_settings_get_string(settings, FreeRDP_ServerHostname),
"LAB1-W7-DM-01.lab1.awake.global");
goto fail;
}
if (strcmp(freerdp_settings_get_string(settings, FreeRDP_GatewayHostname),
"LAB1-W2K8R2-GW.lab1.awake.local") != 0)
{
printf("GatewayHostname mismatch: Actual: %s, Expected: %s\n",
freerdp_settings_get_string(settings, FreeRDP_GatewayHostname),
"LAB1-W2K8R2-GW.lab1.awake.local");
goto fail;
}
iValue = freerdp_client_rdp_file_get_integer_option(file, "dynamic resolution");
if (iValue != 1080)
{
printf("dynamic resolution uses invalid default value %d", iValue);
goto fail;
}
if (!freerdp_settings_get_bool(settings, FreeRDP_DynamicResolutionUpdate))
{
printf("FreeRDP_DynamicResolutionUpdate has invalid value");
goto fail;
}
iValue = freerdp_client_rdp_file_get_integer_option(file, "desktopscalefactor");
if (iValue != 1080)
{
printf("desktopscalefactor uses invalid default value %d", iValue);
goto fail;
}
if ((INT64)freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor) != iValue)
{
printf("FreeRDP_DesktopScaleFactor has invalid value");
goto fail;
}
/* Check [MS-RDPECAM] related options */
#if defined(CHANNEL_RDPECAM_CLIENT)
{
ADDIN_ARGV* args = nullptr;
iValue =
freerdp_client_rdp_file_get_integer_option(file, "encode redirected video capture");
if (iValue != 1)
{
printf("encode redirected video capture uses invalid default value %d", iValue);
goto fail;
}
iValue = freerdp_client_rdp_file_get_integer_option(
file, "redirected video capture encoding quality");
if (iValue != 2)
{
printf("redirected video capture encoding quality uses invalid default value %d",
iValue);
goto fail;
}
args = freerdp_dynamic_channel_collection_find(settings, RDPECAM_DVC_CHANNEL_NAME);
if (!args)
{
printf("rdpecam channel was not loaded");
goto fail;
}
if (args->argc != 6)
{
printf("rdpecam channel was not loaded");
goto fail;
}
for (int x = 0; x < args->argc; x++)
{
if (strcmp(args->argv[x], camera_args[x]) != 0)
{
printf("rdpecam invalid argument argv[%d]: %s", x, args->argv[x]);
goto fail;
}
}
}
#endif
/* Check [URBDRC] related options */
#if defined(CHANNEL_URBDRC_CLIENT)
{
ADDIN_ARGV* args = freerdp_dynamic_channel_collection_find(settings, "urbdrc");
if (!args)
{
printf("urbdrc channel was not loaded");
goto fail;
}
if (args->argc != 4)
{
printf("urbdrc channel was not loaded");
goto fail;
}
for (int x = 0; x < args->argc; x++)
{
if (strcmp(args->argv[x], urbdrc_args[x]) != 0)
{
printf("urbdrc invalid argument argv[%d]: %s", x, args->argv[x]);
goto fail;
}
}
}
#endif
/* Validate selectedmonitors:s:3,2,42,23 */
uValue = freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds);
if (uValue != 4)
{
printf("FreeRDP_NumMonitorIds has invalid value %" PRIu32, uValue);
goto fail;
}
puValue = (const UINT32*)freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorIds, 0);
if (!puValue)
{
printf("FreeRDP_MonitorIds has invalid value %p", (const void*)puValue);
goto fail;
}
if ((puValue[0] != 3) || (puValue[1] != 2) || (puValue[2] != 42) || (puValue[3] != 23))
{
printf("FreeRDP_MonitorIds has invalid values: [%" PRIu32 ",%" PRIu32 ",%" PRIu32
",%" PRIu32 "]",
puValue[0], puValue[1], puValue[2], puValue[3]);
goto fail;
}
iValue = freerdp_client_rdp_file_get_integer_option(file, "videoplaybackmode");
if (iValue != 2)
{
printf("videoplaybackmode uses invalid default value %d", iValue);
goto fail;
}
if (!freerdp_settings_get_bool(settings, FreeRDP_SupportVideoOptimized))
{
printf("FreeRDP_SupportVideoOptimized has invalid value");
goto fail;
}
if (!freerdp_settings_get_bool(settings, FreeRDP_SupportGeometryTracking))
{
printf("FreeRDP_SupportGeometryTracking has invalid value");
goto fail;
}
iValue = freerdp_client_rdp_file_get_integer_option(file, "vendor integer");
if (iValue != 123)
goto fail;
if (freerdp_client_rdp_file_set_integer_option(file, "vendor integer", 456) == -1)
{
printf("failed to set integer: vendor integer");
goto fail;
}
iValue = freerdp_client_rdp_file_get_integer_option(file, "vendor integer");
if (iValue != 456)
return -1;
const char microsoft[] = "microsoft";
sValue = freerdp_client_rdp_file_get_string_option(file, "vendor string");
if (strncmp(sValue, microsoft, sizeof(microsoft)) != 0)
goto fail;
const char apple[] = "apple";
freerdp_client_rdp_file_set_string_option(file, "vendor string", "apple");
sValue = freerdp_client_rdp_file_get_string_option(file, "vendor string");
if (strncmp(sValue, apple, sizeof(apple)) != 0)
goto fail;
freerdp_client_rdp_file_set_string_option(file, "fruits", "banana,oranges");
if (freerdp_client_rdp_file_set_integer_option(file, "numbers", 123456789) == -1)
{
printf("failed to set integer: numbers");
return -1;
}
freerdp_client_rdp_file_free(file);
tmp = GetKnownPath(KNOWN_PATH_TEMP);
if (!tmp)
goto fail;
base = append("%s/rdp-file-test-%" PRIx64, tmp, id);
if (!base)
goto fail;
if (!CreateDirectoryA(base, nullptr))
goto fail;
utfname = append("%s/utfname", base);
uniname = append("%s/uniname", base);
file = freerdp_client_rdp_file_new();
if (!file || !utfname || !uniname)
goto fail;
if (!freerdp_client_populate_rdp_file_from_settings(file, settings))
goto fail;
if (!freerdp_client_write_rdp_file(file, utfname, FALSE))
goto fail;
if (!freerdp_client_write_rdp_file(file, uniname, TRUE))
goto fail;
rc = 0;
fail:
if (utfname)
winpr_DeleteFile(utfname);
if (uniname)
winpr_DeleteFile(uniname);
if (base)
winpr_RemoveDirectory(base);
free(utfname);
free(uniname);
free(base);
free(tmp);
freerdp_client_rdp_file_free(file);
freerdp_settings_free(settings);
return rc;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
This directory should contain RDP files that are checked by TestClientRdpFile
Adding new test works like this:
1. place a .rdp file in this folder
2. run TestClient TestClientRdpFile generate to generate a settings JSON from the RDP file
3. git add .rdp .json && git commit .
4. now the unit test is run and the result is compared

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
gatewayusagemethod:i:1
gatewayprofileusagemethod:i:1
authentication level:i:1
gatewaybrokeringtype:i:1
wvd endpoint pool:s:11112222-0815-1234-abcd-123456789abc
geo:s:EU
armpath:s:/subscriptions/584e4430-82fd-41aa-b87a-efc8b62f890c/resourcegroups/f6cfbbf2-efed-4756-a9c8-3c547bc4eb50/providers/Microsoft.DesktopVirtualization/hostpools/3367af18e772425b82d958c4f06d8023
aadtenantid:s:77064fd5-2634-4a0d-b310-2fa3c1d0472d
full address:s:rdgateway-r1.wvd.microsoft.com
alternate full address:s:rdgateway-r1.wvd.microsoft.com
diagnosticserviceurl:s:https://rdweb-g-eu-r1.wvd.microsoft.com/api/arm/DiagnosticEvents/v1
hubdiscoverygeourl:s:https://rdweb-g-eu-r1.wvd.microsoft.com/api/arm/hubdiscovery?resourceId=16e1fb18-0f41-4e0c-acf8-5046124affe9
resourceprovider:s:arm
gatewayhostname:s:afdfp-rdgateway-r1.wvd.microsoft.com:443
loadbalanceinfo:s:mth://localhost/b47b47c1-b81e-4dfa-ac1b-a8a195d43f26/16e1fb18-0f41-4e0c-acf8-5046124affe9
workspace id:s:cd2471f8-135b-405b-ac04-c2e1564ef354
activityhint:s:ms-wvd-ep:16e1fb18-0f41-4e0c-acf8-5046124affe9?ScaleUnitPath={"Geo"%3a"EU"%2c"Ring"%3a1%2c"Region"%3a"westeurope"%2c"ScaleUnit"%3a100}
promptcredentialonce:i:1
gatewaycredentialssource:i:0
remoteapplicationprogram:s:||40d51148-8d2c-4222-aeb3-7ad10be11650
remotedesktopname:s:Cloud PC Enterprise 8vCPU/32GB/512GB
remoteapplicationmode:i:0
audiomode:i:0
redirectclipboard:i:1
redirectprinters:i:1
redirectsmartcards:i:1
dynamic resolution:i:1
audiocapturemode:i:1
camerastoredirect:s:*
devicestoredirect:s:*
redirectcomports:i:1
drivestoredirect:s:*
usbdevicestoredirect:s:*
singlemoninwindowedmode:i:1
redirectlocation:i:1
targetisaadjoined:i:1
enablerdsaadauth:i:0
clientrejectinjectedinput:i:0

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,39 @@
gatewayusagemethod:i:1
gatewayprofileusagemethod:i:1
authentication level:i:1
gatewaybrokeringtype:i:1
wvd endpoint pool:s:11112222-0815-1234-abcd-123456789abc
geo:s:EU
armpath:s:/subscriptions/584e4430-82fd-41aa-b87a-efc8b62f890c/resourcegroups/f6cfbbf2-efed-4756-a9c8-3c547bc4eb50/providers/Microsoft.DesktopVirtualization/hostpools/3367af18e772425b82d958c4f06d8023
aadtenantid:s:77064fd5-2634-4a0d-b310-2fa3c1d0472d
full address:s:rdgateway-r1.wvd.microsoft.com
rdgiskdcproxy:i:1
alternate full address:s:rdgateway-r1.wvd.microsoft.com
diagnosticserviceurl:s:https://rdweb-g-eu-r1.wvd.microsoft.com/api/arm/DiagnosticEvents/v1
hubdiscoverygeourl:s:https://rdweb-g-eu-r1.wvd.microsoft.com/api/arm/hubdiscovery?resourceId=16e1fb18-0f41-4e0c-acf8-5046124affe9
resourceprovider:s:arm
gatewayhostname:s:afdfp-rdgateway-r1.wvd.microsoft.com:443
loadbalanceinfo:s:mth://localhost/b47b47c1-b81e-4dfa-ac1b-a8a195d43f26/16e1fb18-0f41-4e0c-acf8-5046124affe9
workspace id:s:cd2471f8-135b-405b-ac04-c2e1564ef354
activityhint:s:ms-wvd-ep:16e1fb18-0f41-4e0c-acf8-5046124affe9?ScaleUnitPath={"Geo"%3a"EU"%2c"Ring"%3a1%2c"Region"%3a"westeurope"%2c"ScaleUnit"%3a100}
promptcredentialonce:i:1
gatewaycredentialssource:i:0
remoteapplicationprogram:s:||40d51148-8d2c-4222-aeb3-7ad10be11650
remotedesktopname:s:Cloud PC Enterprise 8vCPU/32GB/512GB
remoteapplicationmode:i:0
audiomode:i:0
redirectclipboard:i:1
redirectprinters:i:1
redirectsmartcards:i:1
dynamic resolution:i:1
audiocapturemode:i:1
camerastoredirect:s:*
devicestoredirect:s:*
redirectcomports:i:1
drivestoredirect:s:*
usbdevicestoredirect:s:*
singlemoninwindowedmode:i:1
redirectlocation:i:1
targetisaadjoined:i:1
enablerdsaadauth:i:0
clientrejectinjectedinput:i:0

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,39 @@
gatewayusagemethod:i:1
gatewayprofileusagemethod:i:1
authentication level:i:1
gatewaybrokeringtype:i:1
wvd endpoint pool:s:11112222-0815-1234-abcd-123456789abc
geo:s:EU
armpath:s:/subscriptions/584e4430-82fd-41aa-b87a-efc8b62f890c/resourcegroups/f6cfbbf2-efed-4756-a9c8-3c547bc4eb50/providers/Microsoft.DesktopVirtualization/hostpools/3367af18e772425b82d958c4f06d8023
aadtenantid:s:77064fd5-2634-4a0d-b310-2fa3c1d0472d
full address:s:rdgateway-r1.wvd.microsoft.com
rdgiskdcproxy:i:0
alternate full address:s:rdgateway-r1.wvd.microsoft.com
diagnosticserviceurl:s:https://rdweb-g-eu-r1.wvd.microsoft.com/api/arm/DiagnosticEvents/v1
hubdiscoverygeourl:s:https://rdweb-g-eu-r1.wvd.microsoft.com/api/arm/hubdiscovery?resourceId=16e1fb18-0f41-4e0c-acf8-5046124affe9
resourceprovider:s:arm
gatewayhostname:s:afdfp-rdgateway-r1.wvd.microsoft.com:443
loadbalanceinfo:s:mth://localhost/b47b47c1-b81e-4dfa-ac1b-a8a195d43f26/16e1fb18-0f41-4e0c-acf8-5046124affe9
workspace id:s:cd2471f8-135b-405b-ac04-c2e1564ef354
activityhint:s:ms-wvd-ep:16e1fb18-0f41-4e0c-acf8-5046124affe9?ScaleUnitPath={"Geo"%3a"EU"%2c"Ring"%3a1%2c"Region"%3a"westeurope"%2c"ScaleUnit"%3a100}
promptcredentialonce:i:1
gatewaycredentialssource:i:0
remoteapplicationprogram:s:||40d51148-8d2c-4222-aeb3-7ad10be11650
remotedesktopname:s:Cloud PC Enterprise 8vCPU/32GB/512GB
remoteapplicationmode:i:0
audiomode:i:0
redirectclipboard:i:1
redirectprinters:i:1
redirectsmartcards:i:1
dynamic resolution:i:1
audiocapturemode:i:1
camerastoredirect:s:*
devicestoredirect:s:*
redirectcomports:i:1
drivestoredirect:s:*
usbdevicestoredirect:s:*
singlemoninwindowedmode:i:1
redirectlocation:i:1
targetisaadjoined:i:1
enablerdsaadauth:i:0
clientrejectinjectedinput:i:0

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff