21#include <freerdp/config.h>
26#include <winpr/assert.h>
29#include <winpr/path.h>
30#include <winpr/cmdline.h>
31#include <winpr/winsock.h>
33#include <freerdp/log.h>
34#include <freerdp/version.h>
36#include <winpr/tools/makecert.h>
39#include <sys/select.h>
44#include "shadow_cliprdr.h"
46#define TAG SERVER_TAG("shadow")
48static const char bind_address[] =
"bind-address,";
50#define fail_at(arg, rc) fail_at_((arg), (rc), __FILE__, __func__, __LINE__)
54 const DWORD level = WLOG_ERROR;
55 wLog* log = WLog_Get(TAG);
56 if (WLog_IsLevelActive(log, level))
57 WLog_PrintTextMessage(log, level, line, file, fkt,
58 "Command line parsing failed at '%s' value '%s' [%d]", arg->Name,
64static int command_line_compare(
const void* pa,
const void* pb)
76 return strcmp(a->Name, b->Name);
80static int shadow_server_print_command_line_help(
int argc,
char** argv,
83 if ((argc < 1) || !largs || !argv)
87 char* path = winpr_GetConfigFilePath(TRUE,
"SAM");
88 printf(
"Usage: %s [options]\n", argv[0]);
90 printf(
"Notes: By default NLA security is active.\n");
91 printf(
"\tIn this mode a SAM database is required.\n");
92 printf(
"\tProvide one with /sam-file:<file with path>\n");
93 printf(
"\telse the default path %s is used.\n", path);
94 printf(
"\tIf there is no existing SAM file authentication for all users will fail.\n");
95 printf(
"\n\tIf authentication against PAM is desired, start with -sec-nla (requires "
97 "support for PAM)\n\n");
99 printf(
" /flag (enables flag)\n");
100 printf(
" /option:<value> (specifies option with value)\n");
101 printf(
" +toggle -toggle (enables or disables toggle, where '/' is a synonym of '+')\n");
110 while (arg->Name !=
nullptr)
128 if (arg->Flags & COMMAND_LINE_VALUE_FLAG)
131 printf(
"%-20s\n", arg->Name);
132 printf(
"\t%s\n", arg->Text);
134 else if ((arg->Flags & COMMAND_LINE_VALUE_REQUIRED) ||
135 (arg->Flags & COMMAND_LINE_VALUE_OPTIONAL))
141 const size_t length = (strlen(arg->Name) + strlen(arg->Format) + 2);
142 char* str = (
char*)calloc(length + 1,
sizeof(
char));
147 (void)sprintf_s(str, length + 1,
"%s:%s", arg->Name, arg->Format);
148 (void)printf(
"%-20s\n", str);
153 printf(
"%-20s\n", arg->Name);
156 printf(
"\t%s\n", arg->Text);
158 else if (arg->Flags & COMMAND_LINE_VALUE_BOOL)
160 const size_t length = strlen(arg->Name) + 32;
161 char* str = calloc(length + 1,
sizeof(
char));
166 (void)sprintf_s(str, length + 1,
"%s (default:%s)", arg->Name,
167 arg->Default ?
"on" :
"off");
168 (void)printf(
" %s", arg->Default ?
"-" :
"+");
169 (void)printf(
"%-20s\n", str);
170 (void)printf(
"\t%s\n", arg->Text);
174 }
while ((arg = CommandLineFindNextArgumentA(arg)) !=
nullptr);
182int shadow_server_command_line_status_print(rdpShadowServer* server,
int argc,
char** argv,
185 WINPR_UNUSED(server);
187 if (status == COMMAND_LINE_STATUS_PRINT_VERSION)
189 printf(
"FreeRDP version %s (git %s)\n", FREERDP_VERSION_FULL, FREERDP_GIT_REVISION);
190 return COMMAND_LINE_STATUS_PRINT_VERSION;
192 else if (status == COMMAND_LINE_STATUS_PRINT_BUILDCONFIG)
194 printf(
"%s\n", freerdp_get_build_config());
195 return COMMAND_LINE_STATUS_PRINT_BUILDCONFIG;
197 else if (status == COMMAND_LINE_STATUS_PRINT)
199 return COMMAND_LINE_STATUS_PRINT;
203 if (shadow_server_print_command_line_help(argc, argv, cargs) < 0)
206 return COMMAND_LINE_STATUS_PRINT_HELP;
212int shadow_server_parse_command_line(rdpShadowServer* server,
int argc,
char** argv,
218 rdpSettings* settings = server->settings;
220 if ((argc < 2) || !argv || !cargs)
223 CommandLineClearArgumentsA(cargs);
224 flags = COMMAND_LINE_SEPARATOR_COLON;
225 flags |= COMMAND_LINE_SIGIL_SLASH | COMMAND_LINE_SIGIL_PLUS_MINUS;
226 status = CommandLineParseArgumentsA(argc, argv, cargs, flags, server,
nullptr,
nullptr);
236 if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT))
239 CommandLineSwitchStart(arg) CommandLineSwitchCase(arg,
"port")
241 long val = strtol(arg->Value,
nullptr, 0);
243 if ((errno != 0) || (val <= 0) || (val > UINT16_MAX))
244 return fail_at(arg, COMMAND_LINE_ERROR);
246 server->port = (DWORD)val;
248 CommandLineSwitchCase(arg,
"ipc-socket")
251 if (server->ipcSocket)
252 return fail_at(arg, COMMAND_LINE_ERROR);
253 server->ipcSocket = _strdup(arg->Value);
255 if (!server->ipcSocket)
256 return fail_at(arg, COMMAND_LINE_ERROR);
258 CommandLineSwitchCase(arg,
"bind-address")
261 size_t len = strlen(arg->Value) +
sizeof(bind_address);
263 if (server->ipcSocket)
264 return fail_at(arg, COMMAND_LINE_ERROR);
265 server->ipcSocket = calloc(len,
sizeof(CHAR));
267 if (!server->ipcSocket)
268 return fail_at(arg, COMMAND_LINE_ERROR);
270 rc = _snprintf(server->ipcSocket, len,
"%s%s", bind_address, arg->Value);
271 if ((rc < 0) || ((
size_t)rc != len - 1))
272 return fail_at(arg, COMMAND_LINE_ERROR);
274 CommandLineSwitchCase(arg,
"may-view")
276 server->mayView = arg->Value !=
nullptr;
278 CommandLineSwitchCase(arg,
"bitmap-compat")
280 server->SupportMultiRectBitmapUpdates = arg->Value ==
nullptr;
282 CommandLineSwitchCase(arg,
"may-interact")
284 server->mayInteract = arg->Value !=
nullptr;
286 CommandLineSwitchCase(arg,
"server-side-cursor")
288 server->ShowMouseCursor = arg->Value !=
nullptr;
290 CommandLineSwitchCase(arg,
"mouse-relative")
292 const BOOL val = arg->Value !=
nullptr;
295 return fail_at(arg, COMMAND_LINE_ERROR);
297 CommandLineSwitchCase(arg,
"max-connections")
300 unsigned long val = strtoul(arg->Value,
nullptr, 0);
302 if ((errno != 0) || (val > UINT32_MAX))
303 return fail_at(arg, COMMAND_LINE_ERROR);
304 server->maxClientsConnected = val;
306 CommandLineSwitchCase(arg,
"rect")
314 char* str = _strdup(arg->Value);
317 return fail_at(arg, COMMAND_LINE_ERROR);
320 p = strchr(p + 1,
',');
325 return fail_at(arg, COMMAND_LINE_ERROR);
330 p = strchr(p + 1,
',');
335 return fail_at(arg, COMMAND_LINE_ERROR);
340 p = strchr(p + 1,
',');
345 return fail_at(arg, COMMAND_LINE_ERROR);
350 x = strtol(tok[0],
nullptr, 0);
355 y = strtol(tok[1],
nullptr, 0);
360 w = strtol(tok[2],
nullptr, 0);
365 h = strtol(tok[3],
nullptr, 0);
373 if ((x < 0) || (y < 0) || (w < 1) || (h < 1) || (errno != 0))
374 return fail_at(arg, COMMAND_LINE_ERROR);
376 if ((x > UINT16_MAX) || (y > UINT16_MAX) || (x + w > UINT16_MAX) ||
377 (y + h > UINT16_MAX))
378 return fail_at(arg, COMMAND_LINE_ERROR);
379 server->subRect.left = (UINT16)x;
380 server->subRect.top = (UINT16)y;
381 server->subRect.right = (UINT16)(x + w);
382 server->subRect.bottom = (UINT16)(y + h);
383 server->shareSubRect = TRUE;
385 CommandLineSwitchCase(arg,
"auth")
387 server->authentication = arg->Value !=
nullptr;
389 CommandLineSwitchCase(arg,
"remote-guard")
392 arg->Value !=
nullptr))
393 return fail_at(arg, COMMAND_LINE_ERROR);
395 CommandLineSwitchCase(arg,
"restricted-admin")
398 arg->Value !=
nullptr))
399 return fail_at(arg, COMMAND_LINE_ERROR);
401 CommandLineSwitchCase(arg,
"vmconnect")
404 return fail_at(arg, COMMAND_LINE_ERROR);
406 CommandLineSwitchCase(arg,
"sec")
408 if (strcmp(
"rdp", arg->Value) == 0)
411 return fail_at(arg, COMMAND_LINE_ERROR);
413 return fail_at(arg, COMMAND_LINE_ERROR);
415 return fail_at(arg, COMMAND_LINE_ERROR);
417 return fail_at(arg, COMMAND_LINE_ERROR);
419 return fail_at(arg, COMMAND_LINE_ERROR);
421 else if (strcmp(
"tls", arg->Value) == 0)
424 return fail_at(arg, COMMAND_LINE_ERROR);
426 return fail_at(arg, COMMAND_LINE_ERROR);
428 return fail_at(arg, COMMAND_LINE_ERROR);
430 return fail_at(arg, COMMAND_LINE_ERROR);
432 else if (strcmp(
"nla", arg->Value) == 0)
435 return fail_at(arg, COMMAND_LINE_ERROR);
437 return fail_at(arg, COMMAND_LINE_ERROR);
439 return fail_at(arg, COMMAND_LINE_ERROR);
441 return fail_at(arg, COMMAND_LINE_ERROR);
443 else if (strcmp(
"ext", arg->Value) == 0)
446 return fail_at(arg, COMMAND_LINE_ERROR);
448 return fail_at(arg, COMMAND_LINE_ERROR);
450 return fail_at(arg, COMMAND_LINE_ERROR);
452 return fail_at(arg, COMMAND_LINE_ERROR);
456 WLog_ERR(TAG,
"unknown protocol security: %s", arg->Value);
457 return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
460 CommandLineSwitchCase(arg,
"sec-rdp")
463 return fail_at(arg, COMMAND_LINE_ERROR);
465 CommandLineSwitchCase(arg,
"sec-tls")
468 return fail_at(arg, COMMAND_LINE_ERROR);
470 CommandLineSwitchCase(arg,
"sec-nla")
473 return fail_at(arg, COMMAND_LINE_ERROR);
475 CommandLineSwitchCase(arg,
"sec-ext")
478 return fail_at(arg, COMMAND_LINE_ERROR);
480 CommandLineSwitchCase(arg,
"sam-file")
483 return fail_at(arg, COMMAND_LINE_ERROR);
485 CommandLineSwitchCase(arg,
"log-level")
487 wLog* root = WLog_GetRoot();
489 if (!WLog_SetStringLogLevel(root, arg->Value))
490 return fail_at(arg, COMMAND_LINE_ERROR);
492 CommandLineSwitchCase(arg,
"log-filters")
494 if (!WLog_AddStringLogFilters(arg->Value))
495 return fail_at(arg, COMMAND_LINE_ERROR);
497 CommandLineSwitchCase(arg,
"nsc")
500 return fail_at(arg, COMMAND_LINE_ERROR);
502 CommandLineSwitchCase(arg,
"rfx")
505 return fail_at(arg, COMMAND_LINE_ERROR);
507 CommandLineSwitchCase(arg,
"gfx")
510 arg->Value !=
nullptr))
511 return fail_at(arg, COMMAND_LINE_ERROR);
513 CommandLineSwitchCase(arg,
"gfx-progressive")
516 return fail_at(arg, COMMAND_LINE_ERROR);
518#if defined(WITH_GFX_AV1)
519 CommandLineSwitchCase(arg,
"gfx-av1")
521 BOOL parseFailed = FALSE;
527 char** args = CommandLineParseCommaSeparatedValues(arg->Value, &count);
528 WINPR_ASSERT(args || (count == 0));
529 for (
size_t x = 0; x < count; x++)
531 const char* cur = args[x];
532 if (strncmp(
"profile:", cur, 8) == 0)
534 const char* val = &cur[8];
535 if (strcmp(
"high", val) == 0)
537 else if (strcmp(
"low", val) == 0)
541 const unsigned long v = strtoul(val,
nullptr, 0);
542 if ((errno != 0) || (v >= UINT32_MAX))
548 profile = WINPR_ASSERTING_INT_CAST(UINT32, v);
551 else if (strcmp(
"off", cur) == 0)
561 CommandLineParserFree(args);
564 return fail_at(arg, COMMAND_LINE_ERROR);
566 return fail_at(arg, COMMAND_LINE_ERROR);
568 return fail_at(arg, COMMAND_LINE_ERROR);
571#if defined(WITH_GFX_AV2)
572 CommandLineSwitchCase(arg,
"gfx-av2")
574 BOOL parseFailed = FALSE;
580 char** args = CommandLineParseCommaSeparatedValues(arg->Value, &count);
581 WINPR_ASSERT(args || (count == 0));
582 for (
size_t x = 0; x < count; x++)
584 const char* cur = args[x];
585 if (strncmp(
"profile:", cur, 8) == 0)
587 const char* val = &cur[8];
588 if (strcmp(
"high", val) == 0)
590 else if (strcmp(
"low", val) == 0)
594 const unsigned long v = strtoul(val,
nullptr, 0);
595 if ((errno != 0) || (v >= UINT32_MAX))
601 profile = WINPR_ASSERTING_INT_CAST(UINT32, v);
604 else if (strcmp(
"off", cur) == 0)
614 CommandLineParserFree(args);
617 return fail_at(arg, COMMAND_LINE_ERROR);
619 return fail_at(arg, COMMAND_LINE_ERROR);
621 return fail_at(arg, COMMAND_LINE_ERROR);
624 CommandLineSwitchCase(arg,
"gfx-rfx")
627 return fail_at(arg, COMMAND_LINE_ERROR);
629 CommandLineSwitchCase(arg,
"gfx-planar")
632 return fail_at(arg, COMMAND_LINE_ERROR);
634 CommandLineSwitchCase(arg,
"gfx-avc420")
637 return fail_at(arg, COMMAND_LINE_ERROR);
639 CommandLineSwitchCase(arg,
"gfx-avc444")
642 return fail_at(arg, COMMAND_LINE_ERROR);
644 return fail_at(arg, COMMAND_LINE_ERROR);
646 CommandLineSwitchCase(arg,
"keytab")
649 return fail_at(arg, COMMAND_LINE_ERROR);
651 CommandLineSwitchCase(arg,
"ccache")
654 return fail_at(arg, COMMAND_LINE_ERROR);
656 CommandLineSwitchCase(arg,
"tls-secrets-file")
659 return fail_at(arg, COMMAND_LINE_ERROR);
661 CommandLineSwitchDefault(arg)
664 CommandLineSwitchEnd(arg)
665 }
while ((arg = CommandLineFindNextArgumentA(arg)) !=
nullptr);
668 arg = CommandLineFindArgumentA(cargs,
"subsystem");
670 if (arg && (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT))
672 if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
674 if (!shadow_subsystem_set_order(arg->Value))
675 return fail_at(arg, COMMAND_LINE_ERROR);
679 shadow_subsystem_list();
680 status = COMMAND_LINE_STATUS_PRINT;
684 arg = CommandLineFindArgumentA(cargs,
"monitors");
686 if (arg && (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT))
688 UINT32 numMonitors = 0;
690 numMonitors = shadow_enum_monitors(monitors, 16);
692 if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
697 long val = strtol(arg->Value,
nullptr, 0);
699 if ((val < 0) || (errno != 0) || ((UINT32)val >= numMonitors))
701 WLog_ERR(TAG,
"no monitor '%s': there are %" PRIu32
" (/monitors lists them)",
702 arg->Value, numMonitors);
703 status = COMMAND_LINE_STATUS_PRINT;
706 server->selectedMonitor = (UINT32)val;
712 for (UINT32 index = 0; index < numMonitors; index++)
715 const INT64 width = monitor->right - monitor->left + 1;
716 const INT64 height = monitor->bottom - monitor->top + 1;
718 TAG,
" %s [%" PRIu32
"] %" PRId64
"x%" PRId64
"\t+%" PRId32
"+%" PRId32
"",
719 (monitor->flags == 1) ?
"*" :
" ", index, width, height, monitor->left,
723 status = COMMAND_LINE_STATUS_PRINT;
733 return COMMAND_LINE_ERROR;
735 return COMMAND_LINE_ERROR;
741static DWORD WINAPI shadow_server_thread(LPVOID arg)
743 rdpShadowServer* server = (rdpShadowServer*)arg;
746 freerdp_listener* listener = server->listener;
747 if (shadow_subsystem_start(server->subsystem) < 0)
752 HANDLE events[MAXIMUM_WAIT_OBJECTS] = WINPR_C_ARRAY_INIT;
754 events[nCount++] = server->StopEvent;
755 nCount += listener->GetEventHandles(listener, &events[nCount], ARRAYSIZE(events) - nCount);
759 WLog_ERR(TAG,
"Failed to get FreeRDP file descriptor");
763 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
774 if (!listener->CheckFileDescriptor(listener))
776 WLog_ERR(TAG,
"Failed to check FreeRDP file descriptor");
790 listener->Close(listener);
791 shadow_subsystem_stop(server->subsystem);
795 if (shadow_client_boardcast_quit(server, 0))
797 while (ArrayList_Count(server->clients) > 0)
808static BOOL open_port(rdpShadowServer* server,
char* address)
811 char* modaddr = address;
815 if (modaddr[0] ==
'[')
817 char* end = strchr(address,
']');
820 WLog_ERR(TAG,
"Could not parse bind-address %s", address);
826 WLog_ERR(TAG,
"Excess data after IPv6 address: '%s'", end);
832 status = server->listener->Open(server->listener, modaddr, (UINT16)server->port);
837 "Problem creating TCP listener. (Port already used or insufficient permissions?)");
843int shadow_server_start(rdpShadowServer* server)
852 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
856 (void)signal(SIGPIPE, SIG_IGN);
858 server->screen = shadow_screen_new(server);
862 WLog_ERR(TAG,
"screen_new failed");
866 server->capture = shadow_capture_new(server);
868 if (!server->capture)
870 WLog_ERR(TAG,
"capture_new failed");
880 ipc = server->ipcSocket && (strncmp(bind_address, server->ipcSocket,
881 strnlen(bind_address,
sizeof(bind_address))) != 0);
886 char** ptr = CommandLineParseCommaSeparatedValuesEx(
nullptr, server->ipcSocket, &count);
887 if (!ptr || (count <= 1))
889 if (server->ipcSocket ==
nullptr)
891 if (!open_port(server,
nullptr))
893 CommandLineParserFree(ptr);
899 CommandLineParserFree(ptr);
904 WINPR_ASSERT(ptr || (count == 0));
905 for (
size_t x = 1; x < count; x++)
907 BOOL success = open_port(server, ptr[x]);
910 CommandLineParserFree(ptr);
914 CommandLineParserFree(ptr);
918 status = server->listener->OpenLocal(server->listener, server->ipcSocket);
922 WLog_ERR(TAG,
"Problem creating local socket listener. (Port already used or "
923 "insufficient permissions?)");
928 if (!(server->thread =
929 CreateThread(
nullptr, 0, shadow_server_thread, (
void*)server, 0,
nullptr)))
937int shadow_server_stop(rdpShadowServer* server)
944 (void)SetEvent(server->StopEvent);
945 (void)WaitForSingleObject(server->thread, INFINITE);
946 (void)CloseHandle(server->thread);
947 server->thread =
nullptr;
948 if (server->listener && server->listener->Close)
949 server->listener->Close(server->listener);
954 shadow_screen_free(server->screen);
955 server->screen =
nullptr;
960 shadow_capture_free(server->capture);
961 server->capture =
nullptr;
968static int shadow_server_init_config_path(rdpShadowServer* server)
970 if (!server->ConfigPath)
976 if (!winpr_PathFileExists(configHome) && !winpr_PathMakePath(configHome,
nullptr))
978 WLog_ERR(TAG,
"Failed to create directory '%s'", configHome);
983 server->ConfigPath = configHome;
987 if (!server->ConfigPath)
993#if defined(WITH_WINPR_TOOLS)
995static BOOL shadow_server_create_certificate(rdpShadowServer* server,
const char* filepath)
998 char* makecert_argv[6] = {
"makecert",
"-rdp",
"-live",
"-silent",
"-y",
"5" };
1000 WINPR_STATIC_ASSERT(ARRAYSIZE(makecert_argv) <= INT_MAX);
1001 const size_t makecert_argc = ARRAYSIZE(makecert_argv);
1003 MAKECERT_CONTEXT* makecert = makecert_context_new();
1008 if (makecert_context_process(makecert, (
int)makecert_argc, makecert_argv) < 0)
1011 if (makecert_context_set_output_file_name(makecert,
"shadow") != 1)
1014 WINPR_ASSERT(server);
1015 WINPR_ASSERT(filepath);
1016 if (!winpr_PathFileExists(server->CertificateFile))
1018 if (makecert_context_output_certificate_file(makecert, filepath) != 1)
1022 if (!winpr_PathFileExists(server->PrivateKeyFile))
1024 if (makecert_context_output_private_key_file(makecert, filepath) != 1)
1029 makecert_context_free(makecert);
1035static BOOL shadow_server_read_pem(rdpShadowServer* server)
1038 WINPR_ASSERT(server);
1040 rdpSettings* settings = server->settings;
1041 WINPR_ASSERT(settings);
1044 rdpPrivateKey* key = freerdp_key_new_from_file_enc(server->PrivateKeyFile,
nullptr);
1047 WLog_ERR(TAG,
"Private Key PEM %s invalid, aborting", server->PrivateKeyFile);
1053 WLog_ERR(TAG,
"Private Key PEM %s valid, but some properties failed to be extracted",
1054 server->PrivateKeyFile);
1059 rdpCertificate* cert = freerdp_certificate_new_from_file(server->CertificateFile);
1062 WLog_ERR(TAG,
"Certificate PEM %s invalid, aborting", server->CertificateFile);
1069 if (!freerdp_certificate_is_rdp_security_compatible(cert))
1080 WLog_ERR(TAG,
"Certificate PEM %s valid, but some properties failed to be extracted",
1081 server->CertificateFile);
1086static BOOL shadow_server_init_certificate(rdpShadowServer* server)
1088 char* filepath =
nullptr;
1091 WINPR_ASSERT(server);
1093 if (!winpr_PathFileExists(server->ConfigPath) &&
1094 !winpr_PathMakePath(server->ConfigPath,
nullptr))
1096 WLog_ERR(TAG,
"Failed to create directory '%s'", server->ConfigPath);
1100 if (!(filepath = GetCombinedPath(server->ConfigPath,
"shadow")))
1103 if (!winpr_PathFileExists(filepath) && !winpr_PathMakePath(filepath,
nullptr))
1105 if (!winpr_PathMakePath(filepath,
nullptr))
1107 WLog_ERR(TAG,
"Failed to create directory '%s'", filepath);
1112 server->CertificateFile = GetCombinedPath(filepath,
"shadow.crt");
1113 server->PrivateKeyFile = GetCombinedPath(filepath,
"shadow.key");
1115 if (!server->CertificateFile || !server->PrivateKeyFile)
1118 if ((!winpr_PathFileExists(server->CertificateFile)) ||
1119 (!winpr_PathFileExists(server->PrivateKeyFile)))
1121#if defined(WITH_WINPR_TOOLS)
1122 if (!shadow_server_create_certificate(server, filepath))
1124 const char* cexist = winpr_PathFileExists(server->CertificateFile) ?
"exists" :
"not found";
1125 const char* pexist = winpr_PathFileExists(server->PrivateKeyFile) ?
"exists" :
"not found";
1126 WLog_ERR(TAG,
"PEM files do not exist: cert: %s (%s), key: %s (%s)",
1127 server->CertificateFile, cexist, server->PrivateKeyFile, pexist);
1132 ret = shadow_server_read_pem(server);
1140static BOOL shadow_server_check_peer_restrictions(freerdp_listener* listener)
1142 WINPR_ASSERT(listener);
1144 rdpShadowServer* server = (rdpShadowServer*)listener->info;
1145 WINPR_ASSERT(server);
1147 if (server->maxClientsConnected > 0)
1149 const size_t count = ArrayList_Count(server->clients);
1150 if (count >= server->maxClientsConnected)
1152 WLog_WARN(TAG,
"connection limit [%" PRIuz
"] reached, discarding client",
1153 server->maxClientsConnected);
1160int shadow_server_init(rdpShadowServer* server)
1163 if (!winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT))
1165 if (!WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi()))
1168 if (!(server->clients = ArrayList_New(TRUE)))
1171 if (!(server->StopEvent = CreateEvent(
nullptr, TRUE, FALSE,
nullptr)))
1174 if (!InitializeCriticalSectionAndSpinCount(&(server->lock), 4000))
1177 status = shadow_server_init_config_path(server);
1182 if (!shadow_server_init_certificate(server))
1185 server->listener = freerdp_listener_new();
1187 if (!server->listener)
1190 server->listener->info = (
void*)server;
1191 server->listener->CheckPeerAcceptRestrictions = shadow_server_check_peer_restrictions;
1192 server->listener->PeerAccepted = shadow_client_accepted;
1193 server->clipboard = shadow_clipboard_new(server);
1195 server->subsystem = shadow_subsystem_new();
1197 if (!server->subsystem)
1200 status = shadow_subsystem_init(server->subsystem, server);
1207 shadow_server_uninit(server);
1208 WLog_ERR(TAG,
"Failed to initialize shadow server");
1212int shadow_server_uninit(rdpShadowServer* server)
1217 shadow_server_stop(server);
1218 shadow_subsystem_uninit(server->subsystem);
1219 shadow_subsystem_free(server->subsystem);
1220 server->subsystem =
nullptr;
1221 shadow_clipboard_free(server->clipboard);
1222 server->clipboard =
nullptr;
1223 freerdp_listener_free(server->listener);
1224 server->listener =
nullptr;
1225 free(server->CertificateFile);
1226 server->CertificateFile =
nullptr;
1227 free(server->PrivateKeyFile);
1228 server->PrivateKeyFile =
nullptr;
1229 free(server->ConfigPath);
1230 server->ConfigPath =
nullptr;
1231 DeleteCriticalSection(&(server->lock));
1232 (void)CloseHandle(server->StopEvent);
1233 server->StopEvent =
nullptr;
1234 ArrayList_Free(server->clients);
1235 server->clients =
nullptr;
1239rdpShadowServer* shadow_server_new(
void)
1241 rdpShadowServer* server =
nullptr;
1242 server = (rdpShadowServer*)calloc(1,
sizeof(rdpShadowServer));
1247 server->SupportMultiRectBitmapUpdates = TRUE;
1248 server->port = 3389;
1249 server->mayView = TRUE;
1250 server->mayInteract = TRUE;
1251 server->h264RateControlMode = H264_RATECONTROL_VBR;
1252 server->h264BitRate = 10000000;
1253 server->h264FrameRate = 30;
1255 server->h264HwAccel = FALSE;
1256 server->authentication = TRUE;
1257#if defined(WITH_GFX_AV1)
1258 server->AV1BitRate = 3000;
1259 server->AV1RateControlMode = FREERDP_AV1_VBR;
1261#if defined(WITH_GFX_AV2)
1262 server->AV2BitRate = 500;
1263 server->AV2RateControlMode = FREERDP_AV2_VBR;
1269void shadow_server_free(rdpShadowServer* server)
1274 free(server->ipcSocket);
1275 server->ipcSocket =
nullptr;
1277 server->settings =
nullptr;
FREERDP_API rdpSettings * freerdp_settings_new(DWORD flags)
creates a new setting struct
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.
WINPR_ATTR_NODISCARD FREERDP_API char * freerdp_settings_get_config_path(void)
return the configuration directory for the library
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_pointer_len(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id, const void *data, size_t len)
Set a pointer to value data.
FREERDP_API void freerdp_settings_free(rdpSettings *settings)
Free a settings struct with all data in it.
#define FREERDP_SETTINGS_SERVER_MODE
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *val)
Sets a string settings value. The param is copied.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.