FreeRDP
client/common/cmdline.c
1 
22 #include <freerdp/config.h>
23 
24 #include <ctype.h>
25 #include <errno.h>
26 
27 #include <winpr/assert.h>
28 #include <winpr/string.h>
29 #include <winpr/crt.h>
30 #include <winpr/wlog.h>
31 #include <winpr/path.h>
32 #include <winpr/ncrypt.h>
33 #include <winpr/environment.h>
34 #include <winpr/timezone.h>
35 
36 #include <freerdp/freerdp.h>
37 #include <freerdp/addin.h>
38 #include <freerdp/settings.h>
39 #include <freerdp/client.h>
40 #include <freerdp/client/channels.h>
41 #include <freerdp/channels/drdynvc.h>
42 #include <freerdp/channels/cliprdr.h>
43 #include <freerdp/channels/encomsp.h>
44 #include <freerdp/channels/rdpear.h>
45 #include <freerdp/channels/rdp2tcp.h>
46 #include <freerdp/channels/remdesk.h>
47 #include <freerdp/channels/rdpsnd.h>
48 #include <freerdp/channels/disp.h>
49 #include <freerdp/crypto/crypto.h>
50 #include <freerdp/locale/keyboard.h>
51 #include <freerdp/utils/passphrase.h>
52 #include <freerdp/utils/proxy_utils.h>
53 #include <freerdp/utils/string.h>
54 #include <freerdp/channels/urbdrc.h>
55 #include <freerdp/channels/rdpdr.h>
56 #include <freerdp/locale/locale.h>
57 
58 #if defined(CHANNEL_AINPUT_CLIENT)
59 #include <freerdp/channels/ainput.h>
60 #endif
61 
62 #include <freerdp/channels/audin.h>
63 #include <freerdp/channels/echo.h>
64 
65 #include <freerdp/client/cmdline.h>
66 #include <freerdp/version.h>
67 #include <freerdp/client/utils/smartcard_cli.h>
68 
69 #include <openssl/tls1.h>
70 #include "cmdline.h"
71 
72 #include <freerdp/log.h>
73 #define TAG CLIENT_TAG("common.cmdline")
74 
75 static const char str_force[] = "force";
76 
77 static const char* option_starts_with(const char* what, const char* val);
78 static BOOL option_ends_with(const char* str, const char* ext);
79 static BOOL option_equals(const char* what, const char* val);
80 
81 static BOOL freerdp_client_print_codepages(const char* arg)
82 {
83  size_t count = 0;
84  DWORD column = 2;
85  const char* filter = NULL;
86  RDP_CODEPAGE* pages = NULL;
87 
88  if (arg)
89  {
90  filter = strchr(arg, ',');
91  if (!filter)
92  filter = arg;
93  else
94  filter++;
95  }
96  pages = freerdp_keyboard_get_matching_codepages(column, filter, &count);
97  if (!pages)
98  return TRUE;
99 
100  printf("%-10s %-8s %-60s %-36s %-48s\n", "<id>", "<locale>", "<win langid>", "<language>",
101  "<country>");
102  for (size_t x = 0; x < count; x++)
103  {
104  const RDP_CODEPAGE* page = &pages[x];
105  char buffer[2048] = { 0 };
106 
107  if (strnlen(page->subLanguageSymbol, ARRAYSIZE(page->subLanguageSymbol)) > 0)
108  (void)_snprintf(buffer, sizeof(buffer), "[%s|%s]", page->primaryLanguageSymbol,
109  page->subLanguageSymbol);
110  else
111  (void)_snprintf(buffer, sizeof(buffer), "[%s]", page->primaryLanguageSymbol);
112  printf("id=0x%04" PRIx16 ": [%-6s] %-60s %-36s %-48s\n", page->id, page->locale, buffer,
113  page->primaryLanguage, page->subLanguage);
114  }
115  freerdp_codepages_free(pages);
116  return TRUE;
117 }
118 
119 static BOOL freerdp_path_valid(const char* path, BOOL* special)
120 {
121  const char DynamicDrives[] = "DynamicDrives";
122  BOOL isPath = FALSE;
123  BOOL isSpecial = 0;
124  if (!path)
125  return FALSE;
126 
127  isSpecial =
128  (option_equals("*", path) || option_equals(DynamicDrives, path) || option_equals("%", path))
129  ? TRUE
130  : FALSE;
131  if (!isSpecial)
132  isPath = winpr_PathFileExists(path);
133 
134  if (special)
135  *special = isSpecial;
136 
137  return isSpecial || isPath;
138 }
139 
140 static BOOL freerdp_sanitize_drive_name(char* name, const char* invalid, const char* replacement)
141 {
142  if (!name || !invalid || !replacement)
143  return FALSE;
144  if (strlen(invalid) != strlen(replacement))
145  return FALSE;
146 
147  while (*invalid != '\0')
148  {
149  const char what = *invalid++;
150  const char with = *replacement++;
151 
152  char* cur = name;
153  while ((cur = strchr(cur, what)) != NULL)
154  *cur = with;
155  }
156  return TRUE;
157 }
158 
159 static char* name_from_path(const char* path)
160 {
161  const char* name = "NULL";
162  if (path)
163  {
164  if (option_equals("%", path))
165  name = "home";
166  else if (option_equals("*", path))
167  name = "hotplug-all";
168  else if (option_equals("DynamicDrives", path))
169  name = "hotplug";
170  else
171  name = path;
172  }
173  return _strdup(name);
174 }
175 
176 static BOOL freerdp_client_add_drive(rdpSettings* settings, const char* path, const char* name)
177 {
178  char* dname = NULL;
179  RDPDR_DEVICE* device = NULL;
180 
181  if (name)
182  {
183  BOOL skip = FALSE;
184  if (path)
185  {
186  switch (path[0])
187  {
188  case '*':
189  case '%':
190  skip = TRUE;
191  break;
192  default:
193  break;
194  }
195  }
196  /* Path was entered as secondary argument, swap */
197  if (!skip && winpr_PathFileExists(name))
198  {
199  if (!winpr_PathFileExists(path) || (!PathIsRelativeA(name) && PathIsRelativeA(path)))
200  {
201  const char* tmp = path;
202  path = name;
203  name = tmp;
204  }
205  }
206  }
207 
208  if (name)
209  dname = _strdup(name);
210  else /* We need a name to send to the server. */
211  dname = name_from_path(path);
212 
213  if (freerdp_sanitize_drive_name(dname, "\\/", "__"))
214  {
215  const char* args[] = { dname, path };
216  device = freerdp_device_new(RDPDR_DTYP_FILESYSTEM, ARRAYSIZE(args), args);
217  }
218  free(dname);
219  if (!device)
220  goto fail;
221 
222  if (!path)
223  goto fail;
224 
225  {
226  BOOL isSpecial = FALSE;
227  BOOL isPath = freerdp_path_valid(path, &isSpecial);
228 
229  if (!isPath && !isSpecial)
230  {
231  WLog_WARN(TAG, "Invalid drive to redirect: '%s' does not exist, skipping.", path);
232  freerdp_device_free(device);
233  }
234  else if (!freerdp_device_collection_add(settings, device))
235  goto fail;
236  }
237 
238  return TRUE;
239 
240 fail:
241  freerdp_device_free(device);
242  return FALSE;
243 }
244 
245 static BOOL value_to_int(const char* value, LONGLONG* result, LONGLONG min, LONGLONG max)
246 {
247  long long rc = 0;
248 
249  if (!value || !result)
250  return FALSE;
251 
252  errno = 0;
253  rc = _strtoi64(value, NULL, 0);
254 
255  if (errno != 0)
256  return FALSE;
257 
258  if ((rc < min) || (rc > max))
259  return FALSE;
260 
261  *result = rc;
262  return TRUE;
263 }
264 
265 static BOOL value_to_uint(const char* value, ULONGLONG* result, ULONGLONG min, ULONGLONG max)
266 {
267  unsigned long long rc = 0;
268 
269  if (!value || !result)
270  return FALSE;
271 
272  errno = 0;
273  rc = _strtoui64(value, NULL, 0);
274 
275  if (errno != 0)
276  return FALSE;
277 
278  if ((rc < min) || (rc > max))
279  return FALSE;
280 
281  *result = rc;
282  return TRUE;
283 }
284 
285 BOOL freerdp_client_print_version(void)
286 {
287  printf("This is FreeRDP version %s (%s)\n", FREERDP_VERSION_FULL, FREERDP_GIT_REVISION);
288  return TRUE;
289 }
290 
291 BOOL freerdp_client_print_version_ex(int argc, char** argv)
292 {
293  WINPR_ASSERT(argc >= 0);
294  WINPR_ASSERT(argv || (argc == 0));
295  const char* name = (argc > 0) ? argv[0] : "argc < 1";
296  printf("This is FreeRDP version [%s] %s (%s)\n", name, FREERDP_VERSION_FULL,
297  FREERDP_GIT_REVISION);
298  return TRUE;
299 }
300 
301 BOOL freerdp_client_print_buildconfig(void)
302 {
303  printf("%s", freerdp_get_build_config());
304  return TRUE;
305 }
306 
307 BOOL freerdp_client_print_buildconfig_ex(int argc, char** argv)
308 {
309  WINPR_ASSERT(argc >= 0);
310  WINPR_ASSERT(argv || (argc == 0));
311  const char* name = (argc > 0) ? argv[0] : "argc < 1";
312  printf("[%s] %s", name, freerdp_get_build_config());
313  return TRUE;
314 }
315 
316 static void freerdp_client_print_scancodes(void)
317 {
318  printf("RDP scancodes and their name for use with /kbd:remap\n");
319 
320  for (UINT32 x = 0; x < UINT16_MAX; x++)
321  {
322  const char* name = freerdp_keyboard_scancode_name(x);
323  if (name)
324  printf("0x%04" PRIx32 " --> %s\n", x, name);
325  }
326 }
327 
328 static BOOL is_delimiter(char c, const char* delimiters)
329 {
330  char d = 0;
331  while ((d = *delimiters++) != '\0')
332  {
333  if (c == d)
334  return TRUE;
335  }
336  return FALSE;
337 }
338 
339 static const char* get_last(const char* start, size_t len, const char* delimiters)
340 {
341  const char* last = NULL;
342  for (size_t x = 0; x < len; x++)
343  {
344  char c = start[x];
345  if (is_delimiter(c, delimiters))
346  last = &start[x];
347  }
348  return last;
349 }
350 
351 static SSIZE_T next_delimiter(const char* text, size_t len, size_t max, const char* delimiters)
352 {
353  if (len < max)
354  return -1;
355 
356  const char* last = get_last(text, max, delimiters);
357  if (!last)
358  return -1;
359 
360  return (SSIZE_T)(last - text);
361 }
362 
363 static SSIZE_T forced_newline_at(const char* text, size_t len, size_t limit,
364  const char* force_newline)
365 {
366  char d = 0;
367  while ((d = *force_newline++) != '\0')
368  {
369  const char* tok = strchr(text, d);
370  if (tok)
371  {
372  const size_t offset = WINPR_ASSERTING_INT_CAST(size_t, tok - text);
373  if ((offset > len) || (offset > limit))
374  continue;
375  return (SSIZE_T)(offset);
376  }
377  }
378  return -1;
379 }
380 
381 static BOOL print_align(size_t start_offset, size_t* current)
382 {
383  WINPR_ASSERT(current);
384  if (*current < start_offset)
385  {
386  const int rc = printf("%*c", (int)(start_offset - *current), ' ');
387  if (rc < 0)
388  return FALSE;
389  *current += (size_t)rc;
390  }
391  return TRUE;
392 }
393 
394 static char* print_token(char* text, size_t start_offset, size_t* current, size_t limit,
395  const char* delimiters, const char* force_newline)
396 {
397  int rc = 0;
398  const size_t tlen = strnlen(text, limit);
399  size_t len = tlen;
400  const SSIZE_T force_at = forced_newline_at(text, len, limit - *current, force_newline);
401  BOOL isForce = (force_at >= 0);
402 
403  if (isForce)
404  len = MIN(len, (size_t)force_at);
405 
406  if (!print_align(start_offset, current))
407  return NULL;
408 
409  const SSIZE_T delim = next_delimiter(text, len, limit - *current, delimiters);
410  const BOOL isDelim = delim > 0;
411  if (isDelim)
412  {
413  len = MIN(len, (size_t)delim + 1);
414  }
415 
416  rc = printf("%.*s", (int)len, text);
417  if (rc < 0)
418  return NULL;
419 
420  if (isForce || isDelim)
421  {
422  printf("\n");
423  *current = 0;
424 
425  const size_t offset = len + ((isForce && (force_at == 0)) ? 1 : 0);
426  return &text[offset];
427  }
428 
429  *current += (size_t)rc;
430 
431  if (tlen == (size_t)rc)
432  return NULL;
433  return &text[(size_t)rc];
434 }
435 
436 static size_t print_optionals(const char* text, size_t start_offset, size_t current)
437 {
438  const size_t limit = 80;
439  char* str = _strdup(text);
440  char* cur = str;
441 
442  do
443  {
444  cur = print_token(cur, start_offset + 1, &current, limit, "[], ", "\r\n");
445  } while (cur != NULL);
446 
447  free(str);
448  return current;
449 }
450 
451 static size_t print_description(const char* text, size_t start_offset, size_t current)
452 {
453  const size_t limit = 80;
454  char* str = _strdup(text);
455  char* cur = str;
456 
457  while (cur != NULL)
458  cur = print_token(cur, start_offset, &current, limit, " ", "\r\n");
459 
460  free(str);
461  const int rc = printf("\n");
462  if (rc >= 0)
463  {
464  const size_t src = WINPR_ASSERTING_INT_CAST(size_t, rc);
465  WINPR_ASSERT(SIZE_MAX - src > current);
466  current += src;
467  }
468  return current;
469 }
470 
471 static int cmp_cmdline_args(const void* pva, const void* pvb)
472 {
473  const COMMAND_LINE_ARGUMENT_A* a = (const COMMAND_LINE_ARGUMENT_A*)pva;
474  const COMMAND_LINE_ARGUMENT_A* b = (const COMMAND_LINE_ARGUMENT_A*)pvb;
475 
476  if (!a->Name && !b->Name)
477  return 0;
478  if (!a->Name)
479  return 1;
480  if (!b->Name)
481  return -1;
482  return strcmp(a->Name, b->Name);
483 }
484 
485 static void freerdp_client_print_command_line_args(COMMAND_LINE_ARGUMENT_A* parg, size_t count)
486 {
487  if (!parg)
488  return;
489 
490  qsort(parg, count, sizeof(COMMAND_LINE_ARGUMENT_A), cmp_cmdline_args);
491 
492  const COMMAND_LINE_ARGUMENT_A* arg = parg;
493  do
494  {
495  int rc = 0;
496  size_t pos = 0;
497  const size_t description_offset = 30 + 8;
498 
499  if (arg->Flags & (COMMAND_LINE_VALUE_BOOL | COMMAND_LINE_VALUE_FLAG))
500  {
501  if ((arg->Flags & (uint32_t)~COMMAND_LINE_VALUE_BOOL) == 0)
502  rc = printf(" %s%s", arg->Default ? "-" : "+", arg->Name);
503  else if ((arg->Flags & COMMAND_LINE_VALUE_OPTIONAL) != 0)
504  rc = printf(" [%s|/]%s", arg->Default ? "-" : "+", arg->Name);
505  else
506  {
507  rc = printf(" %s%s", arg->Default ? "-" : "+", arg->Name);
508  }
509  }
510  else
511  rc = printf(" /%s", arg->Name);
512 
513  if (rc < 0)
514  return;
515  pos += (size_t)rc;
516 
517  if ((arg->Flags & COMMAND_LINE_VALUE_REQUIRED) ||
518  (arg->Flags & COMMAND_LINE_VALUE_OPTIONAL))
519  {
520  if (arg->Format)
521  {
522  if (arg->Flags & COMMAND_LINE_VALUE_OPTIONAL)
523  {
524  rc = printf("[:");
525  if (rc < 0)
526  return;
527  pos += (size_t)rc;
528  pos = print_optionals(arg->Format, pos, pos);
529  rc = printf("]");
530  if (rc < 0)
531  return;
532  pos += (size_t)rc;
533  }
534  else
535  {
536  rc = printf(":");
537  if (rc < 0)
538  return;
539  pos += (size_t)rc;
540  pos = print_optionals(arg->Format, pos, pos);
541  }
542 
543  if (pos > description_offset)
544  {
545  printf("\n");
546  pos = 0;
547  }
548  }
549  }
550 
551  rc = printf("%*c", (int)(description_offset - pos), ' ');
552  if (rc < 0)
553  return;
554  pos += (size_t)rc;
555 
556  if (arg->Flags & COMMAND_LINE_VALUE_BOOL)
557  {
558  rc = printf("%s ", arg->Default ? "Disable" : "Enable");
559  if (rc < 0)
560  return;
561  pos += (size_t)rc;
562  }
563 
564  print_description(arg->Text, description_offset, pos);
565  } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
566 }
567 
568 BOOL freerdp_client_print_command_line_help(int argc, char** argv)
569 {
570  return freerdp_client_print_command_line_help_ex(argc, argv, NULL);
571 }
572 
573 static COMMAND_LINE_ARGUMENT_A* create_merged_args(const COMMAND_LINE_ARGUMENT_A* custom,
574  SSIZE_T count, size_t* pcount)
575 {
576  WINPR_ASSERT(pcount);
577  if (count < 0)
578  {
579  const COMMAND_LINE_ARGUMENT_A* cur = custom;
580  count = 0;
581  while (cur && cur->Name)
582  {
583  count++;
584  cur++;
585  }
586  }
587 
588  COMMAND_LINE_ARGUMENT_A* largs =
589  calloc((size_t)count + ARRAYSIZE(global_cmd_args), sizeof(COMMAND_LINE_ARGUMENT_A));
590  *pcount = 0;
591  if (!largs)
592  return NULL;
593 
594  size_t lcount = 0;
595  const COMMAND_LINE_ARGUMENT_A* cur = custom;
596  while (cur && cur->Name)
597  {
598  largs[lcount++] = *cur++;
599  }
600 
601  cur = global_cmd_args;
602  while (cur && cur->Name)
603  {
604  largs[lcount++] = *cur++;
605  }
606  *pcount = lcount;
607  return largs;
608 }
609 
610 BOOL freerdp_client_print_command_line_help_ex(int argc, char** argv,
611  const COMMAND_LINE_ARGUMENT_A* custom)
612 {
613  const char* name = "FreeRDP";
614 
615  /* allocate a merged copy of implementation defined and default arguments */
616  size_t lcount = 0;
617  COMMAND_LINE_ARGUMENT_A* largs = create_merged_args(custom, -1, &lcount);
618  if (!largs)
619  return FALSE;
620 
621  if (argc > 0)
622  name = argv[0];
623 
624  printf("\n");
625  printf("FreeRDP - A Free Remote Desktop Protocol Implementation\n");
626  printf("See www.freerdp.com for more information\n");
627  printf("\n");
628  printf("Usage: %s [file] [options] [/v:<server>[:port]]\n", argv[0]);
629  printf("\n");
630  printf("Syntax:\n");
631  printf(" /flag (enables flag)\n");
632  printf(" /option:<value> (specifies option with value)\n");
633  printf(" +toggle -toggle (enables or disables toggle, where '/' is a synonym of '+')\n");
634  printf("\n");
635 
636  freerdp_client_print_command_line_args(largs, lcount);
637  free(largs);
638 
639  printf("\n");
640  printf("Examples:\n");
641  printf(" %s connection.rdp /p:Pwd123! /f\n", name);
642  printf(" %s /u:CONTOSO\\JohnDoe /p:Pwd123! /v:rdp.contoso.com\n", name);
643  printf(" %s /u:JohnDoe /p:Pwd123! /w:1366 /h:768 /v:192.168.1.100:4489\n", name);
644  printf(" %s /u:JohnDoe /p:Pwd123! /vmconnect:C824F53E-95D2-46C6-9A18-23A5BB403532 "
645  "/v:192.168.1.100\n",
646  name);
647  printf(" %s /u:\\AzureAD\\user@corp.example /p:pwd /v:host\n", name);
648  printf("\n");
649  printf("Clipboard Redirection: +clipboard\n");
650  printf("\n");
651  printf("Drive Redirection: /drive:home,/home/user\n");
652  printf("Smartcard Redirection: /smartcard:<device>\n");
653  printf("Smartcard logon with Kerberos authentication: /smartcard-logon /sec:nla\n");
654 
655 #if defined(CHANNEL_SERIAL_CLIENT)
656  printf("Serial Port Redirection: /serial:<name>,<device>,[SerCx2|SerCx|Serial],[permissive]\n");
657  printf("Serial Port Redirection: /serial:COM1,/dev/ttyS0\n");
658 #endif
659 #if defined(CHANNEL_PARALLEL_CLIENT)
660  printf("Parallel Port Redirection: /parallel:<name>,<device>\n");
661 #endif
662  printf("Printer Redirection: /printer:<device>,<driver>,[default]\n");
663  printf("TCP redirection: /rdp2tcp:/usr/bin/rdp2tcp\n");
664  printf("\n");
665  printf("Audio Output Redirection: /sound:sys:oss,dev:1,format:1\n");
666  printf("Audio Output Redirection: /sound:sys:alsa\n");
667  printf("Audio Input Redirection: /microphone:sys:oss,dev:1,format:1\n");
668  printf("Audio Input Redirection: /microphone:sys:alsa\n");
669  printf("\n");
670  printf("Multimedia Redirection: /video\n");
671 #ifdef CHANNEL_URBDRC_CLIENT
672  printf("USB Device Redirection: /usb:id:054c:0268#4669:6e6b,addr:04:0c\n");
673 #endif
674  printf("\n");
675  printf("For Gateways, the https_proxy environment variable is respected:\n");
676 #ifdef _WIN32
677  printf(" set HTTPS_PROXY=http://proxy.contoso.com:3128/\n");
678 #else
679  printf(" export https_proxy=http://proxy.contoso.com:3128/\n");
680 #endif
681  printf(" %s /g:rdp.contoso.com ...\n", name);
682  printf("\n");
683  printf("More documentation is coming, in the meantime consult source files\n");
684  printf("\n");
685  return TRUE;
686 }
687 
688 static BOOL option_is_rdp_file(const char* option)
689 {
690  WINPR_ASSERT(option);
691 
692  if (option_ends_with(option, ".rdp"))
693  return TRUE;
694  if (option_ends_with(option, ".rdpw"))
695  return TRUE;
696  return FALSE;
697 }
698 
699 static BOOL option_is_incident_file(const char* option)
700 {
701  WINPR_ASSERT(option);
702 
703  if (option_ends_with(option, ".msrcIncident"))
704  return TRUE;
705  return FALSE;
706 }
707 
708 static int freerdp_client_command_line_pre_filter(void* context, int index, int argc, LPSTR* argv)
709 {
710  if (index == 1)
711  {
712  size_t length = 0;
713  rdpSettings* settings = NULL;
714 
715  if (argc <= index)
716  return -1;
717 
718  length = strlen(argv[index]);
719 
720  if (length > 4)
721  {
722  if (option_is_rdp_file(argv[index]))
723  {
724  settings = (rdpSettings*)context;
725 
726  if (!freerdp_settings_set_string(settings, FreeRDP_ConnectionFile, argv[index]))
727  return COMMAND_LINE_ERROR_MEMORY;
728 
729  return 1;
730  }
731  }
732 
733  if (length > 13)
734  {
735  if (option_is_incident_file(argv[index]))
736  {
737  settings = (rdpSettings*)context;
738 
739  if (!freerdp_settings_set_string(settings, FreeRDP_AssistanceFile, argv[index]))
740  return COMMAND_LINE_ERROR_MEMORY;
741 
742  return 1;
743  }
744  }
745  }
746 
747  return 0;
748 }
749 
750 BOOL freerdp_client_add_device_channel(rdpSettings* settings, size_t count,
751  const char* const* params)
752 {
753  WINPR_ASSERT(settings);
754  WINPR_ASSERT(params);
755  WINPR_ASSERT(count > 0);
756 
757  if (option_equals(params[0], "drive"))
758  {
759  BOOL rc = 0;
760  if (count < 2)
761  return FALSE;
762 
763  if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))
764  return FALSE;
765  if (count < 3)
766  rc = freerdp_client_add_drive(settings, params[1], NULL);
767  else
768  rc = freerdp_client_add_drive(settings, params[2], params[1]);
769 
770  return rc;
771  }
772  else if (option_equals(params[0], "printer"))
773  {
774  RDPDR_DEVICE* printer = NULL;
775 
776  if (count < 1)
777  return FALSE;
778 
779  if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectPrinters, TRUE))
780  return FALSE;
781  if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))
782  return FALSE;
783 
784  printer = freerdp_device_new(RDPDR_DTYP_PRINT, count - 1, &params[1]);
785  if (!printer)
786  return FALSE;
787 
788  if (!freerdp_device_collection_add(settings, printer))
789  {
790  freerdp_device_free(printer);
791  return FALSE;
792  }
793 
794  return TRUE;
795  }
796  else if (option_equals(params[0], "smartcard"))
797  {
798  RDPDR_DEVICE* smartcard = NULL;
799 
800  if (count < 1)
801  return FALSE;
802 
803  if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectSmartCards, TRUE))
804  return FALSE;
805  if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))
806  return FALSE;
807 
808  smartcard = freerdp_device_new(RDPDR_DTYP_SMARTCARD, count - 1, &params[1]);
809 
810  if (!smartcard)
811  return FALSE;
812 
813  if (!freerdp_device_collection_add(settings, smartcard))
814  {
815  freerdp_device_free(smartcard);
816  return FALSE;
817  }
818 
819  return TRUE;
820  }
821 #if defined(CHANNEL_SERIAL_CLIENT)
822  else if (option_equals(params[0], "serial"))
823  {
824  RDPDR_DEVICE* serial = NULL;
825 
826  if (count < 1)
827  return FALSE;
828 
829  if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectSerialPorts, TRUE))
830  return FALSE;
831  if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))
832  return FALSE;
833 
834  serial = freerdp_device_new(RDPDR_DTYP_SERIAL, count - 1, &params[1]);
835 
836  if (!serial)
837  return FALSE;
838 
839  if (!freerdp_device_collection_add(settings, serial))
840  {
841  freerdp_device_free(serial);
842  return FALSE;
843  }
844 
845  return TRUE;
846  }
847 #endif
848  else if (option_equals(params[0], "parallel"))
849  {
850  RDPDR_DEVICE* parallel = NULL;
851 
852  if (count < 1)
853  return FALSE;
854 
855  if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectParallelPorts, TRUE))
856  return FALSE;
857  if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))
858  return FALSE;
859 
860  parallel = freerdp_device_new(RDPDR_DTYP_PARALLEL, count - 1, &params[1]);
861 
862  if (!parallel)
863  return FALSE;
864 
865  if (!freerdp_device_collection_add(settings, parallel))
866  {
867  freerdp_device_free(parallel);
868  return FALSE;
869  }
870 
871  return TRUE;
872  }
873 
874  return FALSE;
875 }
876 
877 BOOL freerdp_client_del_static_channel(rdpSettings* settings, const char* name)
878 {
879  return freerdp_static_channel_collection_del(settings, name);
880 }
881 
882 BOOL freerdp_client_add_static_channel(rdpSettings* settings, size_t count,
883  const char* const* params)
884 {
885  ADDIN_ARGV* _args = NULL;
886 
887  if (!settings || !params || !params[0] || (count > INT_MAX))
888  return FALSE;
889 
890  if (freerdp_static_channel_collection_find(settings, params[0]))
891  return TRUE;
892 
893  _args = freerdp_addin_argv_new(count, params);
894 
895  if (!_args)
896  return FALSE;
897 
898  if (!freerdp_static_channel_collection_add(settings, _args))
899  goto fail;
900 
901  return TRUE;
902 fail:
903  freerdp_addin_argv_free(_args);
904  return FALSE;
905 }
906 
907 BOOL freerdp_client_del_dynamic_channel(rdpSettings* settings, const char* name)
908 {
909  return freerdp_dynamic_channel_collection_del(settings, name);
910 }
911 
912 BOOL freerdp_client_add_dynamic_channel(rdpSettings* settings, size_t count,
913  const char* const* params)
914 {
915  ADDIN_ARGV* _args = NULL;
916 
917  if (!settings || !params || !params[0] || (count > INT_MAX))
918  return FALSE;
919 
920  if (freerdp_dynamic_channel_collection_find(settings, params[0]))
921  return TRUE;
922 
923  _args = freerdp_addin_argv_new(count, params);
924 
925  if (!_args)
926  return FALSE;
927 
928  if (!freerdp_dynamic_channel_collection_add(settings, _args))
929  goto fail;
930 
931  return TRUE;
932 
933 fail:
934  freerdp_addin_argv_free(_args);
935  return FALSE;
936 }
937 
938 static BOOL read_pem_file(rdpSettings* settings, FreeRDP_Settings_Keys_String id, const char* file)
939 {
940  size_t length = 0;
941  char* pem = crypto_read_pem(file, &length);
942  if (!pem || (length == 0))
943  {
944  free(pem);
945  return FALSE;
946  }
947 
948  BOOL rc = freerdp_settings_set_string_len(settings, id, pem, length);
949  free(pem);
950  return rc;
951 }
952 
954 typedef enum
955 {
956  CMDLINE_SUBOPTION_STRING,
957  CMDLINE_SUBOPTION_FILE,
958 } CmdLineSubOptionType;
959 
960 typedef BOOL (*CmdLineSubOptionCb)(const char* value, rdpSettings* settings);
961 typedef struct
962 {
963  const char* optname;
964  FreeRDP_Settings_Keys_String id;
965  CmdLineSubOptionType opttype;
966  CmdLineSubOptionCb cb;
967 } CmdLineSubOptions;
968 
969 static BOOL parseSubOptions(rdpSettings* settings, const CmdLineSubOptions* opts, size_t count,
970  const char* arg)
971 {
972  BOOL found = FALSE;
973 
974  for (size_t xx = 0; xx < count; xx++)
975  {
976  const CmdLineSubOptions* opt = &opts[xx];
977 
978  if (option_starts_with(opt->optname, arg))
979  {
980  const size_t optlen = strlen(opt->optname);
981  const char* val = &arg[optlen];
982  BOOL status = 0;
983 
984  switch (opt->opttype)
985  {
986  case CMDLINE_SUBOPTION_STRING:
987  status = freerdp_settings_set_string(settings, opt->id, val);
988  break;
989  case CMDLINE_SUBOPTION_FILE:
990  status = read_pem_file(settings, opt->id, val);
991  break;
992  default:
993  WLog_ERR(TAG, "invalid subOption type");
994  return FALSE;
995  }
996 
997  if (!status)
998  return FALSE;
999 
1000  if (opt->cb && !opt->cb(val, settings))
1001  return FALSE;
1002 
1003  found = TRUE;
1004  break;
1005  }
1006  }
1007 
1008  if (!found)
1009  WLog_ERR(TAG, "option %s not handled", arg);
1010 
1011  return found;
1012 }
1013 
1014 #define fail_at(arg, rc) fail_at_((arg), (rc), __FILE__, __func__, __LINE__)
1015 static int fail_at_(const COMMAND_LINE_ARGUMENT_A* arg, int rc, const char* file, const char* fkt,
1016  size_t line)
1017 {
1018  const DWORD level = WLOG_ERROR;
1019  wLog* log = WLog_Get(TAG);
1020  if (WLog_IsLevelActive(log, level))
1021  WLog_PrintMessage(log, WLOG_MESSAGE_TEXT, level, line, file, fkt,
1022  "Command line parsing failed at '%s' value '%s' [%d]", arg->Name,
1023  arg->Value, rc);
1024  return rc;
1025 }
1026 
1027 static int freerdp_client_command_line_post_filter_int(void* context, COMMAND_LINE_ARGUMENT_A* arg)
1028 {
1029  rdpSettings* settings = (rdpSettings*)context;
1030  int status = CHANNEL_RC_OK;
1031  BOOL enable = arg->Value ? TRUE : FALSE;
1032 
1033  CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "a")
1034  {
1035  size_t count = 0;
1036  char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);
1037 
1038  if (!freerdp_client_add_device_channel(settings, count, (const char* const*)ptr))
1039  status = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
1040  if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))
1041  status = COMMAND_LINE_ERROR;
1042 
1043  CommandLineParserFree(ptr);
1044  if (status)
1045  return fail_at(arg, status);
1046  }
1047  CommandLineSwitchCase(arg, "kerberos")
1048  {
1049  size_t count = 0;
1050 
1051  char** ptr = CommandLineParseCommaSeparatedValuesEx("kerberos", arg->Value, &count);
1052  if (ptr)
1053  {
1054  const CmdLineSubOptions opts[] = {
1055  { "kdc-url:", FreeRDP_KerberosKdcUrl, CMDLINE_SUBOPTION_STRING, NULL },
1056  { "start-time:", FreeRDP_KerberosStartTime, CMDLINE_SUBOPTION_STRING, NULL },
1057  { "lifetime:", FreeRDP_KerberosLifeTime, CMDLINE_SUBOPTION_STRING, NULL },
1058  { "renewable-lifetime:", FreeRDP_KerberosRenewableLifeTime,
1059  CMDLINE_SUBOPTION_STRING, NULL },
1060  { "cache:", FreeRDP_KerberosCache, CMDLINE_SUBOPTION_STRING, NULL },
1061  { "armor:", FreeRDP_KerberosArmor, CMDLINE_SUBOPTION_STRING, NULL },
1062  { "pkinit-anchors:", FreeRDP_PkinitAnchors, CMDLINE_SUBOPTION_STRING, NULL },
1063  { "pkcs11-module:", FreeRDP_Pkcs11Module, CMDLINE_SUBOPTION_STRING, NULL }
1064  };
1065 
1066  for (size_t x = 1; x < count; x++)
1067  {
1068  const char* cur = ptr[x];
1069  if (!parseSubOptions(settings, opts, ARRAYSIZE(opts), cur))
1070  {
1071  CommandLineParserFree(ptr);
1072  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
1073  }
1074  }
1075  }
1076  CommandLineParserFree(ptr);
1077  }
1078 
1079  CommandLineSwitchCase(arg, "vc")
1080  {
1081  size_t count = 0;
1082  char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);
1083  if (!freerdp_client_add_static_channel(settings, count, (const char* const*)ptr))
1084  status = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
1085  CommandLineParserFree(ptr);
1086  if (status)
1087  return fail_at(arg, status);
1088  }
1089  CommandLineSwitchCase(arg, "dvc")
1090  {
1091  size_t count = 0;
1092  char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);
1093  if (!freerdp_client_add_dynamic_channel(settings, count, (const char* const*)ptr))
1094  status = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
1095  CommandLineParserFree(ptr);
1096  if (status)
1097  return fail_at(arg, status);
1098  }
1099  CommandLineSwitchCase(arg, "drive")
1100  {
1101  size_t count = 0;
1102  char** ptr = CommandLineParseCommaSeparatedValuesEx(arg->Name, arg->Value, &count);
1103  if (!freerdp_client_add_device_channel(settings, count, (const char* const*)ptr))
1104  status = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
1105  CommandLineParserFree(ptr);
1106  if (status)
1107  return fail_at(arg, status);
1108  }
1109 #if defined(CHANNEL_SERIAL_CLIENT)
1110  CommandLineSwitchCase(arg, "serial")
1111  {
1112  size_t count = 0;
1113  char** ptr = CommandLineParseCommaSeparatedValuesEx(arg->Name, arg->Value, &count);
1114  if (!freerdp_client_add_device_channel(settings, count, (const char* const*)ptr))
1115  status = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
1116  CommandLineParserFree(ptr);
1117  if (status)
1118  return fail_at(arg, status);
1119  }
1120 #endif
1121 #if defined(CHANNEL_PARALLEL_CLIENT)
1122  CommandLineSwitchCase(arg, "parallel")
1123  {
1124  size_t count = 0;
1125  char** ptr = CommandLineParseCommaSeparatedValuesEx(arg->Name, arg->Value, &count);
1126  if (!freerdp_client_add_device_channel(settings, count, (const char* const*)ptr))
1127  status = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
1128  CommandLineParserFree(ptr);
1129  if (status)
1130  return fail_at(arg, status);
1131  }
1132 #endif
1133  CommandLineSwitchCase(arg, "smartcard")
1134  {
1135  size_t count = 0;
1136  char** ptr = CommandLineParseCommaSeparatedValuesEx(arg->Name, arg->Value, &count);
1137  if (!freerdp_client_add_device_channel(settings, count, (const char* const*)ptr))
1138  status = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
1139  CommandLineParserFree(ptr);
1140  if (status)
1141  return fail_at(arg, status);
1142  }
1143  CommandLineSwitchCase(arg, "printer")
1144  {
1145  size_t count = 0;
1146  char** ptr = CommandLineParseCommaSeparatedValuesEx(arg->Name, arg->Value, &count);
1147  if (!freerdp_client_add_device_channel(settings, count, (const char* const*)ptr))
1148  status = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
1149  CommandLineParserFree(ptr);
1150  if (status)
1151  return fail_at(arg, status);
1152  }
1153  CommandLineSwitchCase(arg, "usb")
1154  {
1155  size_t count = 0;
1156  char** ptr =
1157  CommandLineParseCommaSeparatedValuesEx(URBDRC_CHANNEL_NAME, arg->Value, &count);
1158  if (!freerdp_client_add_dynamic_channel(settings, count, (const char* const*)ptr))
1159  status = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
1160  CommandLineParserFree(ptr);
1161  if (status)
1162  return fail_at(arg, status);
1163  }
1164  CommandLineSwitchCase(arg, "multitouch")
1165  {
1166  if (!freerdp_settings_set_bool(settings, FreeRDP_MultiTouchInput, enable))
1167  return fail_at(arg, COMMAND_LINE_ERROR);
1168  }
1169  CommandLineSwitchCase(arg, "gestures")
1170  {
1171  if (!freerdp_settings_set_bool(settings, FreeRDP_MultiTouchGestures, enable))
1172  return fail_at(arg, COMMAND_LINE_ERROR);
1173  }
1174  CommandLineSwitchCase(arg, "echo")
1175  {
1176  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportEchoChannel, enable))
1177  return fail_at(arg, COMMAND_LINE_ERROR);
1178  }
1179  CommandLineSwitchCase(arg, "ssh-agent")
1180  {
1181  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportSSHAgentChannel, enable))
1182  return fail_at(arg, COMMAND_LINE_ERROR);
1183  }
1184  CommandLineSwitchCase(arg, "disp")
1185  {
1186  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportDisplayControl, enable))
1187  return fail_at(arg, COMMAND_LINE_ERROR);
1188  }
1189  CommandLineSwitchCase(arg, "geometry")
1190  {
1191  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportGeometryTracking, enable))
1192  return fail_at(arg, COMMAND_LINE_ERROR);
1193  }
1194  CommandLineSwitchCase(arg, "video")
1195  {
1196  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportGeometryTracking,
1197  enable)) /* this requires geometry tracking */
1198  return fail_at(arg, COMMAND_LINE_ERROR);
1199  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportVideoOptimized, enable))
1200  return fail_at(arg, COMMAND_LINE_ERROR);
1201  }
1202  CommandLineSwitchCase(arg, "sound")
1203  {
1204  size_t count = 0;
1205  char** ptr =
1206  CommandLineParseCommaSeparatedValuesEx(RDPSND_CHANNEL_NAME, arg->Value, &count);
1207  if (!freerdp_client_add_static_channel(settings, count, (const char* const*)ptr))
1208  status = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
1209  if (!freerdp_client_add_dynamic_channel(settings, count, (const char* const*)ptr))
1210  status = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
1211 
1212  CommandLineParserFree(ptr);
1213  if (status)
1214  return fail_at(arg, status);
1215  }
1216  CommandLineSwitchCase(arg, "microphone")
1217  {
1218  size_t count = 0;
1219  char** ptr = CommandLineParseCommaSeparatedValuesEx(AUDIN_CHANNEL_NAME, arg->Value, &count);
1220  if (!freerdp_client_add_dynamic_channel(settings, count, (const char* const*)ptr))
1221  status = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
1222  CommandLineParserFree(ptr);
1223  if (status)
1224  return fail_at(arg, status);
1225  }
1226 #if defined(CHANNEL_TSMF_CLIENT)
1227  CommandLineSwitchCase(arg, "multimedia")
1228  {
1229  size_t count = 0;
1230  char** ptr = CommandLineParseCommaSeparatedValuesEx("tsmf", arg->Value, &count);
1231  if (!freerdp_client_add_dynamic_channel(settings, count, (const char* const*)ptr))
1232  status = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
1233  CommandLineParserFree(ptr);
1234  if (status)
1235  return fail_at(arg, status);
1236  }
1237 #endif
1238  CommandLineSwitchCase(arg, "heartbeat")
1239  {
1240  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportHeartbeatPdu, enable))
1241  return fail_at(arg, COMMAND_LINE_ERROR);
1242  }
1243  CommandLineSwitchCase(arg, "multitransport")
1244  {
1245  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportMultitransport, enable))
1246  return fail_at(arg, COMMAND_LINE_ERROR);
1247 
1248  UINT32 flags = 0;
1249  if (freerdp_settings_get_bool(settings, FreeRDP_SupportMultitransport))
1250  flags =
1251  (TRANSPORT_TYPE_UDP_FECR | TRANSPORT_TYPE_UDP_FECL | TRANSPORT_TYPE_UDP_PREFERRED);
1252 
1253  if (!freerdp_settings_set_uint32(settings, FreeRDP_MultitransportFlags, flags))
1254  return fail_at(arg, COMMAND_LINE_ERROR);
1255  }
1256  CommandLineSwitchEnd(arg)
1257 
1258  return status;
1259 }
1260 
1261 static int freerdp_client_command_line_post_filter(void* context, COMMAND_LINE_ARGUMENT_A* arg)
1262 {
1263  int status = freerdp_client_command_line_post_filter_int(context, arg);
1264  return status == CHANNEL_RC_OK ? 1 : -1;
1265 }
1266 
1267 static BOOL freerdp_parse_username_ptr(const char* username, const char** user, size_t* userlen,
1268  const char** domain, size_t* domainlen)
1269 {
1270  WINPR_ASSERT(user);
1271  WINPR_ASSERT(userlen);
1272  WINPR_ASSERT(domain);
1273  WINPR_ASSERT(domainlen);
1274 
1275  if (!username)
1276  return FALSE;
1277 
1278  const char* p = strchr(username, '\\');
1279 
1280  *user = NULL;
1281  *userlen = 0;
1282 
1283  *domain = NULL;
1284  *domainlen = 0;
1285 
1286  if (p)
1287  {
1288  const size_t length = (size_t)(p - username);
1289  *user = &p[1];
1290  *userlen = strlen(*user);
1291 
1292  *domain = username;
1293  *domainlen = length;
1294  }
1295  else
1296  {
1297  /* Do not break up the name for '@'; both credSSP and the
1298  * ClientInfo PDU expect 'user@corp.net' to be transmitted
1299  * as username 'user@corp.net', domain empty (not NULL!).
1300  */
1301  *user = username;
1302  *userlen = strlen(username);
1303  }
1304 
1305  return TRUE;
1306 }
1307 
1308 static BOOL freerdp_parse_username_settings(const char* username, rdpSettings* settings,
1309  FreeRDP_Settings_Keys_String userID,
1310  FreeRDP_Settings_Keys_String domainID)
1311 {
1312  const char* user = NULL;
1313  const char* domain = NULL;
1314  size_t userlen = 0;
1315  size_t domainlen = 0;
1316 
1317  const BOOL rc = freerdp_parse_username_ptr(username, &user, &userlen, &domain, &domainlen);
1318  if (!rc)
1319  return FALSE;
1320  if (!freerdp_settings_set_string_len(settings, userID, user, userlen))
1321  return FALSE;
1322  return freerdp_settings_set_string_len(settings, domainID, domain, domainlen);
1323 }
1324 
1325 BOOL freerdp_parse_username(const char* username, char** puser, char** pdomain)
1326 {
1327  const char* user = NULL;
1328  const char* domain = NULL;
1329  size_t userlen = 0;
1330  size_t domainlen = 0;
1331 
1332  *puser = NULL;
1333  *pdomain = NULL;
1334 
1335  const BOOL rc = freerdp_parse_username_ptr(username, &user, &userlen, &domain, &domainlen);
1336  if (!rc)
1337  return FALSE;
1338 
1339  if (userlen > 0)
1340  {
1341  *puser = strndup(user, userlen);
1342  if (!*puser)
1343  return FALSE;
1344  }
1345 
1346  if (domainlen > 0)
1347  {
1348  *pdomain = strndup(domain, domainlen);
1349  if (!*pdomain)
1350  {
1351  free(*puser);
1352  *puser = NULL;
1353  return FALSE;
1354  }
1355  }
1356 
1357  return TRUE;
1358 }
1359 
1360 BOOL freerdp_parse_hostname(const char* hostname, char** host, int* port)
1361 {
1362  char* p = NULL;
1363  p = strrchr(hostname, ':');
1364 
1365  if (p)
1366  {
1367  size_t length = (size_t)(p - hostname);
1368  LONGLONG val = 0;
1369 
1370  if (!value_to_int(p + 1, &val, 1, UINT16_MAX))
1371  return FALSE;
1372 
1373  *host = (char*)calloc(length + 1UL, sizeof(char));
1374 
1375  if (!(*host))
1376  return FALSE;
1377 
1378  CopyMemory(*host, hostname, length);
1379  (*host)[length] = '\0';
1380  *port = (UINT16)val;
1381  }
1382  else
1383  {
1384  *host = _strdup(hostname);
1385 
1386  if (!(*host))
1387  return FALSE;
1388 
1389  *port = -1;
1390  }
1391 
1392  return TRUE;
1393 }
1394 
1395 static BOOL freerdp_apply_connection_type(rdpSettings* settings, UINT32 type)
1396 {
1397  struct network_settings
1398  {
1399  FreeRDP_Settings_Keys_Bool id;
1400  BOOL value[7];
1401  };
1402  const struct network_settings config[] = {
1403  { FreeRDP_DisableWallpaper, { TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE } },
1404  { FreeRDP_AllowFontSmoothing, { FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE } },
1405  { FreeRDP_AllowDesktopComposition, { FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE } },
1406  { FreeRDP_DisableFullWindowDrag, { TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE } },
1407  { FreeRDP_DisableMenuAnims, { TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE } },
1408  { FreeRDP_DisableThemes, { TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE } }
1409  };
1410 
1411  switch (type)
1412  {
1413  case CONNECTION_TYPE_INVALID:
1414  return TRUE;
1415 
1416  case CONNECTION_TYPE_MODEM:
1417  case CONNECTION_TYPE_BROADBAND_LOW:
1418  case CONNECTION_TYPE_BROADBAND_HIGH:
1419  case CONNECTION_TYPE_SATELLITE:
1420  case CONNECTION_TYPE_WAN:
1421  case CONNECTION_TYPE_LAN:
1422  case CONNECTION_TYPE_AUTODETECT:
1423  break;
1424  default:
1425  WLog_WARN(TAG, "Unknown ConnectionType %" PRIu32 ", aborting", type);
1426  return FALSE;
1427  }
1428 
1429  for (size_t x = 0; x < ARRAYSIZE(config); x++)
1430  {
1431  const struct network_settings* cur = &config[x];
1432  if (!freerdp_settings_set_bool(settings, cur->id, cur->value[type - 1]))
1433  return FALSE;
1434  }
1435  return TRUE;
1436 }
1437 
1438 BOOL freerdp_set_connection_type(rdpSettings* settings, UINT32 type)
1439 {
1440 
1441  if (!freerdp_settings_set_uint32(settings, FreeRDP_ConnectionType, type))
1442  return FALSE;
1443 
1444  switch (type)
1445  {
1446  case CONNECTION_TYPE_INVALID:
1447  case CONNECTION_TYPE_MODEM:
1448  case CONNECTION_TYPE_BROADBAND_LOW:
1449  case CONNECTION_TYPE_SATELLITE:
1450  case CONNECTION_TYPE_BROADBAND_HIGH:
1451  case CONNECTION_TYPE_WAN:
1452  case CONNECTION_TYPE_LAN:
1453  if (!freerdp_apply_connection_type(settings, type))
1454  return FALSE;
1455  break;
1456  case CONNECTION_TYPE_AUTODETECT:
1457  if (!freerdp_apply_connection_type(settings, type))
1458  return FALSE;
1459  /* Automatically activate GFX and RFX codec support */
1460 #ifdef WITH_GFX_H264
1461  if (!freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444v2, TRUE) ||
1462  !freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444, TRUE) ||
1463  !freerdp_settings_set_bool(settings, FreeRDP_GfxH264, TRUE))
1464  return FALSE;
1465 #endif
1466  if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE) ||
1467  !freerdp_settings_set_bool(settings, FreeRDP_SupportGraphicsPipeline, TRUE))
1468  return FALSE;
1469  break;
1470  default:
1471  WLog_WARN(TAG, "Unknown ConnectionType %" PRIu32 ", aborting", type);
1472  return FALSE;
1473  }
1474 
1475  return TRUE;
1476 }
1477 
1478 static UINT32 freerdp_get_keyboard_layout_for_type(const char* name, DWORD type)
1479 {
1480  UINT32 res = 0;
1481  size_t count = 0;
1482  RDP_KEYBOARD_LAYOUT* layouts =
1483  freerdp_keyboard_get_layouts(RDP_KEYBOARD_LAYOUT_TYPE_STANDARD, &count);
1484 
1485  if (!layouts || (count == 0))
1486  goto fail;
1487 
1488  for (size_t x = 0; x < count; x++)
1489  {
1490  const RDP_KEYBOARD_LAYOUT* layout = &layouts[x];
1491  if (option_equals(layout->name, name))
1492  {
1493  res = layout->code;
1494  break;
1495  }
1496  }
1497 
1498 fail:
1499  freerdp_keyboard_layouts_free(layouts, count);
1500  return res;
1501 }
1502 
1503 static UINT32 freerdp_map_keyboard_layout_name_to_id(const char* name)
1504 {
1505  const UINT32 variants[] = { RDP_KEYBOARD_LAYOUT_TYPE_STANDARD, RDP_KEYBOARD_LAYOUT_TYPE_VARIANT,
1506  RDP_KEYBOARD_LAYOUT_TYPE_IME };
1507 
1508  for (size_t x = 0; x < ARRAYSIZE(variants); x++)
1509  {
1510  UINT32 rc = freerdp_get_keyboard_layout_for_type(name, variants[x]);
1511  if (rc > 0)
1512  return rc;
1513  }
1514 
1515  return 0;
1516 }
1517 
1518 static int freerdp_detect_command_line_pre_filter(void* context, int index, int argc, LPSTR* argv)
1519 {
1520  size_t length = 0;
1521  WINPR_UNUSED(context);
1522 
1523  if (index == 1)
1524  {
1525  if (argc < index)
1526  return -1;
1527 
1528  length = strlen(argv[index]);
1529 
1530  if (length > 4)
1531  {
1532  if (option_is_rdp_file(argv[index]))
1533  {
1534  return 1;
1535  }
1536  }
1537 
1538  if (length > 13)
1539  {
1540  if (option_is_incident_file(argv[index]))
1541  {
1542  return 1;
1543  }
1544  }
1545  }
1546 
1547  return 0;
1548 }
1549 
1550 static int freerdp_detect_windows_style_command_line_syntax(int argc, char** argv, size_t* count,
1551  BOOL ignoreUnknown)
1552 {
1553  int status = 0;
1554  DWORD flags = 0;
1555  int detect_status = 0;
1556  const COMMAND_LINE_ARGUMENT_A* arg = NULL;
1557  COMMAND_LINE_ARGUMENT_A largs[ARRAYSIZE(global_cmd_args)];
1558  memcpy(largs, global_cmd_args, sizeof(global_cmd_args));
1559 
1560  flags = COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_SILENCE_PARSER;
1561  flags |= COMMAND_LINE_SIGIL_SLASH | COMMAND_LINE_SIGIL_PLUS_MINUS;
1562 
1563  if (ignoreUnknown)
1564  {
1565  flags |= COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
1566  }
1567 
1568  *count = 0;
1569  detect_status = 0;
1570  CommandLineClearArgumentsA(largs);
1571  status = CommandLineParseArgumentsA(argc, argv, largs, flags, NULL,
1572  freerdp_detect_command_line_pre_filter, NULL);
1573 
1574  if (status < 0)
1575  return status;
1576 
1577  arg = largs;
1578 
1579  do
1580  {
1581  if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT))
1582  continue;
1583 
1584  (*count)++;
1585  } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
1586 
1587  if ((status <= COMMAND_LINE_ERROR) && (status >= COMMAND_LINE_ERROR_LAST))
1588  detect_status = -1;
1589 
1590  return detect_status;
1591 }
1592 
1593 static int freerdp_detect_posix_style_command_line_syntax(int argc, char** argv, size_t* count,
1594  BOOL ignoreUnknown)
1595 {
1596  int status = 0;
1597  DWORD flags = 0;
1598  int detect_status = 0;
1599  const COMMAND_LINE_ARGUMENT_A* arg = NULL;
1600  COMMAND_LINE_ARGUMENT_A largs[ARRAYSIZE(global_cmd_args)];
1601  memcpy(largs, global_cmd_args, sizeof(global_cmd_args));
1602 
1603  flags = COMMAND_LINE_SEPARATOR_SPACE | COMMAND_LINE_SILENCE_PARSER;
1604  flags |= COMMAND_LINE_SIGIL_DASH | COMMAND_LINE_SIGIL_DOUBLE_DASH;
1605  flags |= COMMAND_LINE_SIGIL_ENABLE_DISABLE;
1606 
1607  if (ignoreUnknown)
1608  {
1609  flags |= COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
1610  }
1611 
1612  *count = 0;
1613  detect_status = 0;
1614  CommandLineClearArgumentsA(largs);
1615  status = CommandLineParseArgumentsA(argc, argv, largs, flags, NULL,
1616  freerdp_detect_command_line_pre_filter, NULL);
1617 
1618  if (status < 0)
1619  return status;
1620 
1621  arg = largs;
1622 
1623  do
1624  {
1625  if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT))
1626  continue;
1627 
1628  (*count)++;
1629  } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
1630 
1631  if ((status <= COMMAND_LINE_ERROR) && (status >= COMMAND_LINE_ERROR_LAST))
1632  detect_status = -1;
1633 
1634  return detect_status;
1635 }
1636 
1637 static BOOL freerdp_client_detect_command_line(int argc, char** argv, DWORD* flags)
1638 {
1639  int posix_cli_status = 0;
1640  size_t posix_cli_count = 0;
1641  int windows_cli_status = 0;
1642  size_t windows_cli_count = 0;
1643  const BOOL ignoreUnknown = TRUE;
1644  windows_cli_status = freerdp_detect_windows_style_command_line_syntax(
1645  argc, argv, &windows_cli_count, ignoreUnknown);
1646  posix_cli_status =
1647  freerdp_detect_posix_style_command_line_syntax(argc, argv, &posix_cli_count, ignoreUnknown);
1648 
1649  /* Default is POSIX syntax */
1650  *flags = COMMAND_LINE_SEPARATOR_SPACE;
1651  *flags |= COMMAND_LINE_SIGIL_DASH | COMMAND_LINE_SIGIL_DOUBLE_DASH;
1652  *flags |= COMMAND_LINE_SIGIL_ENABLE_DISABLE;
1653 
1654  if (posix_cli_status <= COMMAND_LINE_STATUS_PRINT)
1655  return FALSE;
1656 
1657  /* Check, if this may be windows style syntax... */
1658  if ((windows_cli_count && (windows_cli_count >= posix_cli_count)) ||
1659  (windows_cli_status <= COMMAND_LINE_STATUS_PRINT))
1660  {
1661  windows_cli_count = 1;
1662  *flags = COMMAND_LINE_SEPARATOR_COLON;
1663  *flags |= COMMAND_LINE_SIGIL_SLASH | COMMAND_LINE_SIGIL_PLUS_MINUS;
1664  }
1665 
1666  WLog_DBG(TAG, "windows: %d/%" PRIuz " posix: %d/%" PRIuz "", windows_cli_status,
1667  windows_cli_count, posix_cli_status, posix_cli_count);
1668  if ((posix_cli_count == 0) && (windows_cli_count == 0))
1669  {
1670  if ((posix_cli_status == COMMAND_LINE_ERROR) && (windows_cli_status == COMMAND_LINE_ERROR))
1671  return TRUE;
1672  }
1673  return FALSE;
1674 }
1675 
1676 int freerdp_client_settings_command_line_status_print(rdpSettings* settings, int status, int argc,
1677  char** argv)
1678 {
1679  return freerdp_client_settings_command_line_status_print_ex(settings, status, argc, argv, NULL);
1680 }
1681 
1682 static void freerdp_client_print_keyboard_type_list(const char* msg, DWORD type)
1683 {
1684  size_t count = 0;
1685  RDP_KEYBOARD_LAYOUT* layouts = NULL;
1686  layouts = freerdp_keyboard_get_layouts(type, &count);
1687 
1688  printf("\n%s\n", msg);
1689 
1690  for (size_t x = 0; x < count; x++)
1691  {
1692  const RDP_KEYBOARD_LAYOUT* layout = &layouts[x];
1693  printf("0x%08" PRIX32 "\t%s\n", layout->code, layout->name);
1694  }
1695 
1696  freerdp_keyboard_layouts_free(layouts, count);
1697 }
1698 
1699 static void freerdp_client_print_keyboard_list(void)
1700 {
1701  freerdp_client_print_keyboard_type_list("Keyboard Layouts", RDP_KEYBOARD_LAYOUT_TYPE_STANDARD);
1702  freerdp_client_print_keyboard_type_list("Keyboard Layout Variants",
1703  RDP_KEYBOARD_LAYOUT_TYPE_VARIANT);
1704  freerdp_client_print_keyboard_type_list("Keyboard Layout Variants",
1705  RDP_KEYBOARD_LAYOUT_TYPE_IME);
1706 }
1707 
1708 static void freerdp_client_print_timezone_list(void)
1709 {
1710  DWORD index = 0;
1711  DYNAMIC_TIME_ZONE_INFORMATION info = { 0 };
1712  while (EnumDynamicTimeZoneInformation(index++, &info) != ERROR_NO_MORE_ITEMS)
1713  {
1714  char TimeZoneKeyName[ARRAYSIZE(info.TimeZoneKeyName) + 1] = { 0 };
1715 
1716  (void)ConvertWCharNToUtf8(info.TimeZoneKeyName, ARRAYSIZE(info.TimeZoneKeyName),
1717  TimeZoneKeyName, ARRAYSIZE(TimeZoneKeyName));
1718  printf("%" PRIu32 ": '%s'\n", index, TimeZoneKeyName);
1719  }
1720 }
1721 
1722 static void freerdp_client_print_tune_list(const rdpSettings* settings)
1723 {
1724  SSIZE_T type = 0;
1725 
1726  for (SSIZE_T x = 0; x < FreeRDP_Settings_StableAPI_MAX; x++)
1727  {
1728  const char* name = freerdp_settings_get_name_for_key(x);
1730 
1731  // NOLINTBEGIN(clang-analyzer-optin.core.EnumCastOutOfRange)
1732  switch (type)
1733  {
1734  case RDP_SETTINGS_TYPE_BOOL:
1735  printf("%" PRIdz "\t%50s\tBOOL\t%s\n", x, name,
1736  freerdp_settings_get_bool(settings, (FreeRDP_Settings_Keys_Bool)x)
1737  ? "TRUE"
1738  : "FALSE");
1739  break;
1740  case RDP_SETTINGS_TYPE_UINT16:
1741  printf("%" PRIdz "\t%50s\tUINT16\t%" PRIu16 "\n", x, name,
1742  freerdp_settings_get_uint16(settings, (FreeRDP_Settings_Keys_UInt16)x));
1743  break;
1744  case RDP_SETTINGS_TYPE_INT16:
1745  printf("%" PRIdz "\t%50s\tINT16\t%" PRId16 "\n", x, name,
1746  freerdp_settings_get_int16(settings, (FreeRDP_Settings_Keys_Int16)x));
1747  break;
1748  case RDP_SETTINGS_TYPE_UINT32:
1749  printf("%" PRIdz "\t%50s\tUINT32\t%" PRIu32 "\n", x, name,
1750  freerdp_settings_get_uint32(settings, (FreeRDP_Settings_Keys_UInt32)x));
1751  break;
1752  case RDP_SETTINGS_TYPE_INT32:
1753  printf("%" PRIdz "\t%50s\tINT32\t%" PRId32 "\n", x, name,
1754  freerdp_settings_get_int32(settings, (FreeRDP_Settings_Keys_Int32)x));
1755  break;
1756  case RDP_SETTINGS_TYPE_UINT64:
1757  printf("%" PRIdz "\t%50s\tUINT64\t%" PRIu64 "\n", x, name,
1758  freerdp_settings_get_uint64(settings, (FreeRDP_Settings_Keys_UInt64)x));
1759  break;
1760  case RDP_SETTINGS_TYPE_INT64:
1761  printf("%" PRIdz "\t%50s\tINT64\t%" PRId64 "\n", x, name,
1762  freerdp_settings_get_int64(settings, (FreeRDP_Settings_Keys_Int64)x));
1763  break;
1764  case RDP_SETTINGS_TYPE_STRING:
1765  printf("%" PRIdz "\t%50s\tSTRING\t%s"
1766  "\n",
1767  x, name,
1768  freerdp_settings_get_string(settings, (FreeRDP_Settings_Keys_String)x));
1769  break;
1770  case RDP_SETTINGS_TYPE_POINTER:
1771  printf("%" PRIdz "\t%50s\tPOINTER\t%p"
1772  "\n",
1773  x, name,
1774  freerdp_settings_get_pointer(settings, (FreeRDP_Settings_Keys_Pointer)x));
1775  break;
1776  default:
1777  break;
1778  }
1779  // NOLINTEND(clang-analyzer-optin.core.EnumCastOutOfRange)
1780  }
1781 }
1782 
1783 int freerdp_client_settings_command_line_status_print_ex(rdpSettings* settings, int status,
1784  int argc, char** argv,
1785  const COMMAND_LINE_ARGUMENT_A* custom)
1786 {
1787  const COMMAND_LINE_ARGUMENT_A* arg = NULL;
1788  COMMAND_LINE_ARGUMENT_A largs[ARRAYSIZE(global_cmd_args)];
1789  memcpy(largs, global_cmd_args, sizeof(global_cmd_args));
1790 
1791  if (status == COMMAND_LINE_STATUS_PRINT_VERSION)
1792  {
1793  freerdp_client_print_version();
1794  goto out;
1795  }
1796 
1797  if (status == COMMAND_LINE_STATUS_PRINT_BUILDCONFIG)
1798  {
1799  freerdp_client_print_version_ex(argc, argv);
1800  freerdp_client_print_buildconfig_ex(argc, argv);
1801  goto out;
1802  }
1803  else if (status == COMMAND_LINE_STATUS_PRINT)
1804  {
1805  (void)CommandLineParseArgumentsA(argc, argv, largs, 0x112, NULL, NULL, NULL);
1806 
1807  arg = CommandLineFindArgumentA(largs, "list");
1808  WINPR_ASSERT(arg);
1809 
1810  if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)
1811  {
1812  if (option_equals("timezones", arg->Value))
1813  freerdp_client_print_timezone_list();
1814  else if (option_equals("tune", arg->Value))
1815  freerdp_client_print_tune_list(settings);
1816  else if (option_equals("kbd", arg->Value))
1817  freerdp_client_print_keyboard_list();
1818  else if (option_starts_with("kbd-lang", arg->Value))
1819  {
1820  const char* val = NULL;
1821  if (option_starts_with("kbd-lang:", arg->Value))
1822  val = &arg->Value[9];
1823  else if (!option_equals("kbd-lang", arg->Value))
1824  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
1825 
1826  if (val && strchr(val, ','))
1827  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
1828  freerdp_client_print_codepages(val);
1829  }
1830  else if (option_equals("kbd-scancode", arg->Value))
1831  freerdp_client_print_scancodes();
1832  else if (option_equals("monitor", arg->Value))
1833  {
1834  if (!freerdp_settings_set_bool(settings, FreeRDP_ListMonitors, TRUE))
1835  return COMMAND_LINE_ERROR;
1836  }
1837  else if (option_starts_with("smartcard", arg->Value))
1838  {
1839  BOOL opts = FALSE;
1840  if (option_starts_with("smartcard:", arg->Value))
1841  opts = TRUE;
1842  else if (!option_equals("smartcard", arg->Value))
1843  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
1844 
1845  if (opts)
1846  {
1847  const char* sub = strchr(arg->Value, ':') + 1;
1848  const CmdLineSubOptions options[] = {
1849  { "pkinit-anchors:", FreeRDP_PkinitAnchors, CMDLINE_SUBOPTION_STRING,
1850  NULL },
1851  { "pkcs11-module:", FreeRDP_Pkcs11Module, CMDLINE_SUBOPTION_STRING, NULL }
1852  };
1853 
1854  size_t count = 0;
1855 
1856  char** ptr = CommandLineParseCommaSeparatedValuesEx("smartcard", sub, &count);
1857  if (!ptr)
1858  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
1859  if (count < 2)
1860  {
1861  CommandLineParserFree(ptr);
1862  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
1863  }
1864 
1865  for (size_t x = 1; x < count; x++)
1866  {
1867  const char* cur = ptr[x];
1868  if (!parseSubOptions(settings, options, ARRAYSIZE(options), cur))
1869  {
1870  CommandLineParserFree(ptr);
1871  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
1872  }
1873  }
1874 
1875  CommandLineParserFree(ptr);
1876  }
1877 
1878  freerdp_smartcard_list(settings);
1879  }
1880  else
1881  {
1882  freerdp_client_print_command_line_help_ex(argc, argv, custom);
1883  return COMMAND_LINE_ERROR;
1884  }
1885  }
1886 #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)
1887  arg = CommandLineFindArgumentA(largs, "tune-list");
1888  WINPR_ASSERT(arg);
1889 
1890  if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)
1891  {
1892  WLog_WARN(TAG, "Option /tune-list is deprecated, use /list:tune instead");
1893  freerdp_client_print_tune_list(settings);
1894  }
1895 
1896  arg = CommandLineFindArgumentA(largs, "kbd-lang-list");
1897  WINPR_ASSERT(arg);
1898 
1899  if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)
1900  {
1901  WLog_WARN(TAG, "Option /kbd-lang-list is deprecated, use /list:kbd-lang instead");
1902  freerdp_client_print_codepages(arg->Value);
1903  }
1904 
1905  arg = CommandLineFindArgumentA(largs, "kbd-list");
1906  WINPR_ASSERT(arg);
1907 
1908  if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
1909  {
1910  WLog_WARN(TAG, "Option /kbd-list is deprecated, use /list:kbd instead");
1911  freerdp_client_print_keyboard_list();
1912  }
1913 
1914  arg = CommandLineFindArgumentA(largs, "monitor-list");
1915  WINPR_ASSERT(arg);
1916 
1917  if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
1918  {
1919  WLog_WARN(TAG, "Option /monitor-list is deprecated, use /list:monitor instead");
1920  if (!freerdp_settings_set_bool(settings, FreeRDP_ListMonitors, TRUE))
1921  return COMMAND_LINE_ERROR;
1922  }
1923 
1924  arg = CommandLineFindArgumentA(largs, "smartcard-list");
1925  WINPR_ASSERT(arg);
1926 
1927  if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
1928  {
1929  WLog_WARN(TAG, "Option /smartcard-list is deprecated, use /list:smartcard instead");
1930  freerdp_smartcard_list(settings);
1931  }
1932 
1933  arg = CommandLineFindArgumentA(largs, "kbd-scancode-list");
1934  WINPR_ASSERT(arg);
1935 
1936  if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
1937  {
1938  WLog_WARN(TAG,
1939  "Option /kbd-scancode-list is deprecated, use /list:kbd-scancode instead");
1940  freerdp_client_print_scancodes();
1941  goto out;
1942  }
1943 #endif
1944  goto out;
1945  }
1946  else if (status < 0)
1947  {
1948  freerdp_client_print_command_line_help_ex(argc, argv, custom);
1949  goto out;
1950  }
1951 
1952 out:
1953  if (status <= COMMAND_LINE_STATUS_PRINT && status >= COMMAND_LINE_STATUS_PRINT_LAST)
1954  return 0;
1955  return status;
1956 }
1957 
1966 static BOOL parseSizeValue(const char* input, unsigned long* v1, unsigned long* v2)
1967 {
1968  const char* xcharpos = NULL;
1969  char* endPtr = NULL;
1970  unsigned long v = 0;
1971  errno = 0;
1972  v = strtoul(input, &endPtr, 10);
1973 
1974  if ((v == 0 || v == ULONG_MAX) && (errno != 0))
1975  return FALSE;
1976 
1977  if (v1)
1978  *v1 = v;
1979 
1980  xcharpos = strchr(input, 'x');
1981 
1982  if (!xcharpos || xcharpos != endPtr)
1983  return FALSE;
1984 
1985  errno = 0;
1986  v = strtoul(xcharpos + 1, &endPtr, 10);
1987 
1988  if ((v == 0 || v == ULONG_MAX) && (errno != 0))
1989  return FALSE;
1990 
1991  if (*endPtr != '\0')
1992  return FALSE;
1993 
1994  if (v2)
1995  *v2 = v;
1996 
1997  return TRUE;
1998 }
1999 
2000 static BOOL prepare_default_settings(rdpSettings* settings, COMMAND_LINE_ARGUMENT_A* args,
2001  BOOL rdp_file)
2002 {
2003  const char* arguments[] = { "network", "gfx", "rfx", "bpp" };
2004  WINPR_ASSERT(settings);
2005  WINPR_ASSERT(args);
2006 
2007  if (rdp_file)
2008  return FALSE;
2009 
2010  for (size_t x = 0; x < ARRAYSIZE(arguments); x++)
2011  {
2012  const char* arg = arguments[x];
2013  const COMMAND_LINE_ARGUMENT_A* p = CommandLineFindArgumentA(args, arg);
2014  if (p && (p->Flags & COMMAND_LINE_ARGUMENT_PRESENT))
2015  return FALSE;
2016  }
2017 
2018  return freerdp_set_connection_type(settings, CONNECTION_TYPE_AUTODETECT);
2019 }
2020 
2021 static BOOL setSmartcardEmulation(const char* value, rdpSettings* settings)
2022 {
2023  return freerdp_settings_set_bool(settings, FreeRDP_SmartcardEmulation, TRUE);
2024 }
2025 
2026 const char* option_starts_with(const char* what, const char* val)
2027 {
2028  WINPR_ASSERT(what);
2029  WINPR_ASSERT(val);
2030  const size_t wlen = strlen(what);
2031 
2032  if (_strnicmp(what, val, wlen) != 0)
2033  return NULL;
2034  return &val[wlen];
2035 }
2036 
2037 BOOL option_ends_with(const char* str, const char* ext)
2038 {
2039  WINPR_ASSERT(str);
2040  WINPR_ASSERT(ext);
2041  const size_t strLen = strlen(str);
2042  const size_t extLen = strlen(ext);
2043 
2044  if (strLen < extLen)
2045  return FALSE;
2046 
2047  return _strnicmp(&str[strLen - extLen], ext, extLen) == 0;
2048 }
2049 
2050 BOOL option_equals(const char* what, const char* val)
2051 {
2052  WINPR_ASSERT(what);
2053  WINPR_ASSERT(val);
2054  return _stricmp(what, val) == 0;
2055 }
2056 
2057 typedef enum
2058 {
2059  PARSE_ON,
2060  PARSE_OFF,
2061  PARSE_NONE,
2062  PARSE_FAIL
2063 } PARSE_ON_OFF_RESULT;
2064 
2065 static PARSE_ON_OFF_RESULT parse_on_off_option(const char* value)
2066 {
2067  WINPR_ASSERT(value);
2068  const char* sep = strchr(value, ':');
2069  if (!sep)
2070  return PARSE_NONE;
2071  if (option_equals("on", &sep[1]))
2072  return PARSE_ON;
2073  if (option_equals("off", &sep[1]))
2074  return PARSE_OFF;
2075  return PARSE_FAIL;
2076 }
2077 
2078 typedef enum
2079 {
2080  CLIP_DIR_PARSE_ALL,
2081  CLIP_DIR_PARSE_OFF,
2082  CLIP_DIR_PARSE_LOCAL,
2083  CLIP_DIR_PARSE_REMOTE,
2084  CLIP_DIR_PARSE_FAIL
2085 } PARSE_CLIP_DIR_RESULT;
2086 
2087 static PARSE_CLIP_DIR_RESULT parse_clip_direciton_to_option(const char* value)
2088 {
2089  WINPR_ASSERT(value);
2090  const char* sep = strchr(value, ':');
2091  if (!sep)
2092  return CLIP_DIR_PARSE_FAIL;
2093  if (option_equals("all", &sep[1]))
2094  return CLIP_DIR_PARSE_ALL;
2095  if (option_equals("off", &sep[1]))
2096  return CLIP_DIR_PARSE_OFF;
2097  if (option_equals("local", &sep[1]))
2098  return CLIP_DIR_PARSE_LOCAL;
2099  if (option_equals("remote", &sep[1]))
2100  return CLIP_DIR_PARSE_REMOTE;
2101  return CLIP_DIR_PARSE_FAIL;
2102 }
2103 
2104 static int parse_tls_ciphers(rdpSettings* settings, const char* Value)
2105 {
2106  const char* ciphers = NULL;
2107  if (!Value)
2108  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2109 
2110  if (option_equals(Value, "netmon"))
2111  {
2112  ciphers = "ALL:!ECDH:!ADH:!DHE";
2113  }
2114  else if (option_equals(Value, "ma"))
2115  {
2116  ciphers = "AES128-SHA";
2117  }
2118  else
2119  {
2120  ciphers = Value;
2121  }
2122 
2123  if (!freerdp_settings_set_string(settings, FreeRDP_AllowedTlsCiphers, ciphers))
2124  return COMMAND_LINE_ERROR_MEMORY;
2125  return 0;
2126 }
2127 
2128 static int parse_tls_seclevel(rdpSettings* settings, const char* Value)
2129 {
2130  LONGLONG val = 0;
2131 
2132  if (!value_to_int(Value, &val, 0, 5))
2133  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2134 
2135  if (!freerdp_settings_set_uint32(settings, FreeRDP_TlsSecLevel, (UINT32)val))
2136  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2137  return 0;
2138 }
2139 
2140 static int parse_tls_secrets_file(rdpSettings* settings, const char* Value)
2141 {
2142  if (!Value)
2143  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2144 
2145  if (!freerdp_settings_set_string(settings, FreeRDP_TlsSecretsFile, Value))
2146  return COMMAND_LINE_ERROR_MEMORY;
2147  return 0;
2148 }
2149 
2150 static int parse_tls_enforce(rdpSettings* settings, const char* Value)
2151 {
2152  UINT16 version = TLS1_2_VERSION;
2153 
2154  if (Value)
2155  {
2156  struct map_t
2157  {
2158  const char* name;
2159  UINT16 version;
2160  };
2161  const struct map_t map[] = { { "1.0", TLS1_VERSION },
2162  { "1.1", TLS1_1_VERSION },
2163  { "1.2", TLS1_2_VERSION }
2164 #if defined(TLS1_3_VERSION)
2165  ,
2166  { "1.3", TLS1_3_VERSION }
2167 #endif
2168  };
2169 
2170  for (size_t x = 0; x < ARRAYSIZE(map); x++)
2171  {
2172  const struct map_t* cur = &map[x];
2173  if (option_equals(cur->name, Value))
2174  {
2175  version = cur->version;
2176  break;
2177  }
2178  }
2179  }
2180 
2181  if (!(freerdp_settings_set_uint16(settings, FreeRDP_TLSMinVersion, version) &&
2182  freerdp_settings_set_uint16(settings, FreeRDP_TLSMaxVersion, version)))
2183  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2184  return 0;
2185 }
2186 
2187 static int parse_tls_cipher_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
2188 {
2189  int rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2190  CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "tls")
2191  {
2192  if (option_starts_with("ciphers:", arg->Value))
2193  rc = parse_tls_ciphers(settings, &arg->Value[8]);
2194  else if (option_starts_with("seclevel:", arg->Value))
2195  rc = parse_tls_seclevel(settings, &arg->Value[9]);
2196  else if (option_starts_with("secrets-file:", arg->Value))
2197  rc = parse_tls_secrets_file(settings, &arg->Value[13]);
2198  else if (option_starts_with("enforce:", arg->Value))
2199  rc = parse_tls_enforce(settings, &arg->Value[8]);
2200  }
2201 
2202 #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)
2203  CommandLineSwitchCase(arg, "tls-ciphers")
2204  {
2205  WLog_WARN(TAG, "Option /tls-ciphers is deprecated, use /tls:ciphers instead");
2206  rc = parse_tls_ciphers(settings, arg->Value);
2207  }
2208  CommandLineSwitchCase(arg, "tls-seclevel")
2209  {
2210  WLog_WARN(TAG, "Option /tls-seclevel is deprecated, use /tls:seclevel instead");
2211  rc = parse_tls_seclevel(settings, arg->Value);
2212  }
2213  CommandLineSwitchCase(arg, "tls-secrets-file")
2214  {
2215  WLog_WARN(TAG, "Option /tls-secrets-file is deprecated, use /tls:secrets-file instead");
2216  rc = parse_tls_secrets_file(settings, arg->Value);
2217  }
2218  CommandLineSwitchCase(arg, "enforce-tlsv1_2")
2219  {
2220  WLog_WARN(TAG, "Option /enforce-tlsv1_2 is deprecated, use /tls:enforce:1.2 instead");
2221  rc = parse_tls_enforce(settings, "1.2");
2222  }
2223 #endif
2224  CommandLineSwitchDefault(arg)
2225  {
2226  }
2227  CommandLineSwitchEnd(arg)
2228 
2229  return rc;
2230 }
2231 
2232 static int parse_tls_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
2233 {
2234  WINPR_ASSERT(settings);
2235  WINPR_ASSERT(arg);
2236 
2237  size_t count = 0;
2238  char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);
2239  for (size_t x = 0; x < count; x++)
2240  {
2241  COMMAND_LINE_ARGUMENT_A larg = *arg;
2242  larg.Value = ptr[x];
2243 
2244  int rc = parse_tls_cipher_options(settings, &larg);
2245  if (rc != 0)
2246  {
2247  CommandLineParserFree(ptr);
2248  return rc;
2249  }
2250  }
2251  CommandLineParserFree(ptr);
2252  return 0;
2253 }
2254 
2255 static int parse_gfx_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
2256 {
2257  WINPR_ASSERT(settings);
2258  WINPR_ASSERT(arg);
2259 
2260  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportGraphicsPipeline, TRUE))
2261  return COMMAND_LINE_ERROR;
2262 
2263  if (arg->Value)
2264  {
2265  int rc = CHANNEL_RC_OK;
2266  size_t count = 0;
2267  char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);
2268  if (!ptr || (count == 0))
2269  rc = COMMAND_LINE_ERROR;
2270  else
2271  {
2272  BOOL GfxH264 = FALSE;
2273  BOOL GfxAVC444 = FALSE;
2274  BOOL RemoteFxCodec = FALSE;
2275  BOOL GfxProgressive = FALSE;
2276  BOOL codecSelected = FALSE;
2277 
2278  for (size_t x = 0; x < count; x++)
2279  {
2280  const char* val = ptr[x];
2281 #ifdef WITH_GFX_H264
2282  if (option_starts_with("AVC444", val))
2283  {
2284  const PARSE_ON_OFF_RESULT bval = parse_on_off_option(val);
2285  if (bval == PARSE_FAIL)
2286  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2287  else
2288  GfxAVC444 = bval != PARSE_OFF;
2289  codecSelected = TRUE;
2290  }
2291  else if (option_starts_with("AVC420", val))
2292  {
2293  const PARSE_ON_OFF_RESULT bval = parse_on_off_option(val);
2294  if (bval == PARSE_FAIL)
2295  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2296  else
2297  GfxH264 = bval != PARSE_OFF;
2298  codecSelected = TRUE;
2299  }
2300  else
2301 #endif
2302  if (option_starts_with("RFX", val))
2303  {
2304  const PARSE_ON_OFF_RESULT bval = parse_on_off_option(val);
2305  if (bval == PARSE_FAIL)
2306  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2307  else
2308  RemoteFxCodec = bval != PARSE_OFF;
2309  codecSelected = TRUE;
2310  }
2311  else if (option_starts_with("progressive", val))
2312  {
2313  const PARSE_ON_OFF_RESULT bval = parse_on_off_option(val);
2314  if (bval == PARSE_FAIL)
2315  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2316  else
2317  GfxProgressive = bval != PARSE_OFF;
2318  codecSelected = TRUE;
2319  }
2320  else if (option_starts_with("mask:", val))
2321  {
2322  ULONGLONG v = 0;
2323  const char* uv = &val[5];
2324  if (!value_to_uint(uv, &v, 0, UINT32_MAX))
2325  rc = COMMAND_LINE_ERROR;
2326  else
2327  {
2328  if (!freerdp_settings_set_uint32(settings, FreeRDP_GfxCapsFilter,
2329  (UINT32)v))
2330  rc = COMMAND_LINE_ERROR;
2331  }
2332  }
2333  else if (option_starts_with("small-cache", val))
2334  {
2335  const PARSE_ON_OFF_RESULT bval = parse_on_off_option(val);
2336  if (bval == PARSE_FAIL)
2337  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2338  else if (!freerdp_settings_set_bool(settings, FreeRDP_GfxSmallCache,
2339  bval != PARSE_OFF))
2340  rc = COMMAND_LINE_ERROR;
2341  }
2342  else if (option_starts_with("thin-client", val))
2343  {
2344  const PARSE_ON_OFF_RESULT bval = parse_on_off_option(val);
2345  if (bval == PARSE_FAIL)
2346  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2347  else if (!freerdp_settings_set_bool(settings, FreeRDP_GfxThinClient,
2348  bval != PARSE_OFF))
2349  rc = COMMAND_LINE_ERROR;
2350  if ((rc == CHANNEL_RC_OK) && (bval > 0))
2351  {
2352  if (!freerdp_settings_set_bool(settings, FreeRDP_GfxSmallCache,
2353  bval != PARSE_OFF))
2354  rc = COMMAND_LINE_ERROR;
2355  }
2356  }
2357  else if (option_starts_with("frame-ack", val))
2358  {
2359  const PARSE_ON_OFF_RESULT bval = parse_on_off_option(val);
2360  if (bval == PARSE_FAIL)
2361  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2362  else if (!freerdp_settings_set_bool(settings, FreeRDP_GfxSuspendFrameAck,
2363  bval == PARSE_OFF))
2364  rc = COMMAND_LINE_ERROR;
2365  }
2366  else
2367  rc = COMMAND_LINE_ERROR;
2368  }
2369 
2370  if ((rc == CHANNEL_RC_OK) && codecSelected)
2371  {
2372  if (!freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444, GfxAVC444))
2373  rc = COMMAND_LINE_ERROR;
2374  if (!freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444v2, GfxAVC444))
2375  rc = COMMAND_LINE_ERROR;
2376  if (!freerdp_settings_set_bool(settings, FreeRDP_GfxH264, GfxH264))
2377  rc = COMMAND_LINE_ERROR;
2378  if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, RemoteFxCodec))
2379  rc = COMMAND_LINE_ERROR;
2380  if (!freerdp_settings_set_bool(settings, FreeRDP_GfxProgressive, GfxProgressive))
2381  rc = COMMAND_LINE_ERROR;
2382  }
2383  }
2384  CommandLineParserFree(ptr);
2385  if (rc != CHANNEL_RC_OK)
2386  return rc;
2387  }
2388  return CHANNEL_RC_OK;
2389 }
2390 
2391 static int parse_kbd_layout(rdpSettings* settings, const char* value)
2392 {
2393  WINPR_ASSERT(settings);
2394  WINPR_ASSERT(value);
2395 
2396  int rc = 0;
2397  LONGLONG ival = 0;
2398  const BOOL isInt = value_to_int(value, &ival, 1, UINT32_MAX);
2399  if (!isInt)
2400  {
2401  ival = freerdp_map_keyboard_layout_name_to_id(value);
2402 
2403  if (ival == 0)
2404  {
2405  WLog_ERR(TAG, "Could not identify keyboard layout: %s", value);
2406  WLog_ERR(TAG, "Use /list:kbd to list available layouts");
2407  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2408  }
2409  }
2410 
2411  if (rc == 0)
2412  {
2413  if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardLayout, (UINT32)ival))
2414  rc = COMMAND_LINE_ERROR;
2415  }
2416  return rc;
2417 }
2418 
2419 #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)
2420 static int parse_codec_cache_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
2421 {
2422  WINPR_ASSERT(settings);
2423  WINPR_ASSERT(arg);
2424 
2425  if (!arg->Value)
2426  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2427  if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheV3Enabled, TRUE))
2428  return COMMAND_LINE_ERROR;
2429 
2430  if (option_equals(arg->Value, "rfx"))
2431  {
2432  if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE))
2433  return COMMAND_LINE_ERROR;
2434  }
2435  else if (option_equals(arg->Value, "nsc"))
2436  {
2437  if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, TRUE))
2438  return COMMAND_LINE_ERROR;
2439  }
2440 
2441 #if defined(WITH_JPEG)
2442  else if (option_equals(arg->Value, "jpeg"))
2443  {
2444  if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, TRUE))
2445  return COMMAND_LINE_ERROR;
2446 
2447  if (freerdp_settings_get_uint32(settings, FreeRDP_JpegQuality) == 0)
2448  {
2449  if (!freerdp_settings_set_uint32(settings, FreeRDP_JpegQuality, 75))
2450  return COMMAND_LINE_ERROR;
2451  }
2452  }
2453 
2454 #endif
2455  return 0;
2456 }
2457 #endif
2458 
2459 static BOOL check_kbd_remap_valid(const char* token)
2460 {
2461  DWORD key = 0;
2462  DWORD value = 0;
2463 
2464  WINPR_ASSERT(token);
2465  /* The remapping is only allowed for scancodes, so maximum is 999=999 */
2466  if (strlen(token) > 10)
2467  return FALSE;
2468 
2469  if (!freerdp_extract_key_value(token, &key, &value))
2470  {
2471  WLog_WARN(TAG, "/kbd:remap invalid entry '%s'", token);
2472  return FALSE;
2473  }
2474  return TRUE;
2475 }
2476 
2477 static int parse_host_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
2478 {
2479  WINPR_ASSERT(settings);
2480  WINPR_ASSERT(arg);
2481 
2482  if (!arg->Value)
2483  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2484  if (!freerdp_settings_set_string(settings, FreeRDP_ServerHostname, NULL))
2485  return COMMAND_LINE_ERROR_MEMORY;
2486  char* p = strchr(arg->Value, '[');
2487 
2488  /* ipv4 */
2489  if (!p)
2490  {
2491  const char scheme[] = "://";
2492  const char* val = strstr(arg->Value, scheme);
2493  if (val)
2494  val += strnlen(scheme, sizeof(scheme));
2495  else
2496  val = arg->Value;
2497  p = strchr(val, ':');
2498 
2499  if (p)
2500  {
2501  LONGLONG lval = 0;
2502  size_t length = 0;
2503 
2504  if (!value_to_int(&p[1], &lval, 1, UINT16_MAX))
2505  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2506 
2507  length = (size_t)(p - arg->Value);
2508  if (!freerdp_settings_set_uint32(settings, FreeRDP_ServerPort, (UINT16)lval))
2509  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2510  if (!freerdp_settings_set_string_len(settings, FreeRDP_ServerHostname, arg->Value,
2511  length))
2512  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2513  }
2514  else
2515  {
2516  if (!freerdp_settings_set_string(settings, FreeRDP_ServerHostname, arg->Value))
2517  return COMMAND_LINE_ERROR_MEMORY;
2518  }
2519  }
2520  else /* ipv6 */
2521  {
2522  size_t length = 0;
2523  char* p2 = strchr(arg->Value, ']');
2524 
2525  /* not a valid [] ipv6 addr found */
2526  if (!p2)
2527  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2528 
2529  length = (size_t)(p2 - p);
2530  if (!freerdp_settings_set_string_len(settings, FreeRDP_ServerHostname, p + 1, length - 1))
2531  return COMMAND_LINE_ERROR_MEMORY;
2532 
2533  if (*(p2 + 1) == ':')
2534  {
2535  LONGLONG val = 0;
2536 
2537  if (!value_to_int(&p2[2], &val, 0, UINT16_MAX))
2538  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2539 
2540  if (!freerdp_settings_set_uint32(settings, FreeRDP_ServerPort, (UINT16)val))
2541  return COMMAND_LINE_ERROR;
2542  }
2543 
2544  printf("hostname %s port %" PRIu32 "\n",
2545  freerdp_settings_get_string(settings, FreeRDP_ServerHostname),
2546  freerdp_settings_get_uint32(settings, FreeRDP_ServerPort));
2547  }
2548  return 0;
2549 }
2550 
2551 static int parse_redirect_prefer_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
2552 {
2553  WINPR_ASSERT(settings);
2554  WINPR_ASSERT(arg);
2555 
2556  size_t count = 0;
2557  char* cur = arg->Value;
2558  if (!arg->Value)
2559  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2560  if (!freerdp_settings_set_uint32(settings, FreeRDP_RedirectionPreferType, 0))
2561  return COMMAND_LINE_ERROR;
2562 
2563  UINT32 value = 0;
2564  do
2565  {
2566  UINT32 mask = 0;
2567  char* next = strchr(cur, ',');
2568 
2569  if (next)
2570  {
2571  *next = '\0';
2572  next++;
2573  }
2574 
2575  if (option_equals("fqdn", cur))
2576  mask = 0x06U;
2577  else if (option_equals("ip", cur))
2578  mask = 0x05U;
2579  else if (option_equals("netbios", cur))
2580  mask = 0x03U;
2581  else
2582  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2583 
2584  cur = next;
2585  mask = (mask & 0x07);
2586  value |= mask << (count * 3);
2587  count++;
2588  } while (cur != NULL);
2589 
2590  if (!freerdp_settings_set_uint32(settings, FreeRDP_RedirectionPreferType, value))
2591  return COMMAND_LINE_ERROR;
2592 
2593  if (count > 3)
2594  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2595  return 0;
2596 }
2597 
2598 static int parse_prevent_session_lock_options(rdpSettings* settings,
2599  const COMMAND_LINE_ARGUMENT_A* arg)
2600 {
2601  WINPR_ASSERT(settings);
2602  WINPR_ASSERT(arg);
2603 
2604  if (!freerdp_settings_set_uint32(settings, FreeRDP_FakeMouseMotionInterval, 180))
2605  return COMMAND_LINE_ERROR_MEMORY;
2606 
2607  if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
2608  {
2609  LONGLONG val = 0;
2610 
2611  if (!value_to_int(arg->Value, &val, 1, UINT32_MAX))
2612  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2613 
2614  if (!freerdp_settings_set_uint32(settings, FreeRDP_FakeMouseMotionInterval, (UINT32)val))
2615  return COMMAND_LINE_ERROR_MEMORY;
2616  }
2617 
2618  return 0;
2619 }
2620 
2621 static int parse_vmconnect_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
2622 {
2623  WINPR_ASSERT(settings);
2624  WINPR_ASSERT(arg);
2625 
2626  if (!freerdp_settings_set_bool(settings, FreeRDP_VmConnectMode, TRUE))
2627  return COMMAND_LINE_ERROR;
2628 
2629  UINT32 port = freerdp_settings_get_uint32(settings, FreeRDP_ServerPort);
2630  if (port == 3389)
2631  port = 2179;
2632 
2633  if (!freerdp_settings_set_uint32(settings, FreeRDP_ServerPort, port))
2634  return COMMAND_LINE_ERROR;
2635  if (!freerdp_settings_set_bool(settings, FreeRDP_NegotiateSecurityLayer, FALSE))
2636  return COMMAND_LINE_ERROR;
2637 
2638  if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
2639  {
2640  if (!freerdp_settings_set_bool(settings, FreeRDP_SendPreconnectionPdu, TRUE))
2641  return COMMAND_LINE_ERROR;
2642 
2643  if (!freerdp_settings_set_string(settings, FreeRDP_PreconnectionBlob, arg->Value))
2644  return COMMAND_LINE_ERROR_MEMORY;
2645  }
2646  return 0;
2647 }
2648 
2649 static int parse_size_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
2650 {
2651  int status = 0;
2652  WINPR_ASSERT(settings);
2653  WINPR_ASSERT(arg);
2654 
2655  if (!arg->Value)
2656  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2657  char* p = strchr(arg->Value, 'x');
2658 
2659  if (p)
2660  {
2661  unsigned long w = 0;
2662  unsigned long h = 0;
2663 
2664  if (!parseSizeValue(arg->Value, &w, &h) || (w > UINT16_MAX) || (h > UINT16_MAX))
2665  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2666 
2667  if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, (UINT32)w))
2668  return COMMAND_LINE_ERROR;
2669  if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, (UINT32)h))
2670  return COMMAND_LINE_ERROR;
2671  }
2672  else
2673  {
2674  char* str = _strdup(arg->Value);
2675  if (!str)
2676  return COMMAND_LINE_ERROR_MEMORY;
2677 
2678  p = strchr(str, '%');
2679 
2680  if (p)
2681  {
2682  BOOL partial = FALSE;
2683 
2684  status = COMMAND_LINE_ERROR;
2685  if (strchr(p, 'w'))
2686  {
2687  if (!freerdp_settings_set_bool(settings, FreeRDP_PercentScreenUseWidth, TRUE))
2688  goto fail;
2689  partial = TRUE;
2690  }
2691 
2692  if (strchr(p, 'h'))
2693  {
2694  if (!freerdp_settings_set_bool(settings, FreeRDP_PercentScreenUseHeight, TRUE))
2695  goto fail;
2696  partial = TRUE;
2697  }
2698 
2699  if (!partial)
2700  {
2701  if (!freerdp_settings_set_bool(settings, FreeRDP_PercentScreenUseWidth, TRUE))
2702  goto fail;
2703  if (!freerdp_settings_set_bool(settings, FreeRDP_PercentScreenUseHeight, TRUE))
2704  goto fail;
2705  }
2706 
2707  *p = '\0';
2708  {
2709  LONGLONG val = 0;
2710 
2711  if (!value_to_int(str, &val, 0, 100))
2712  {
2713  status = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2714  goto fail;
2715  }
2716 
2717  if (!freerdp_settings_set_uint32(settings, FreeRDP_PercentScreen, (UINT32)val))
2718  goto fail;
2719  }
2720 
2721  status = 0;
2722  }
2723 
2724  fail:
2725  free(str);
2726  }
2727 
2728  return status;
2729 }
2730 
2731 static int parse_monitors_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
2732 {
2733  WINPR_ASSERT(settings);
2734  WINPR_ASSERT(arg);
2735 
2736  if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
2737  {
2738  size_t count = 0;
2739  UINT32* MonitorIds = NULL;
2740  char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);
2741 
2742  if (!ptr)
2743  return COMMAND_LINE_ERROR_MEMORY;
2744 
2745  if (count > 16)
2746  count = 16;
2747 
2748  if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorIds, NULL, count))
2749  {
2750  CommandLineParserFree(ptr);
2751  return FALSE;
2752  }
2753 
2754  MonitorIds = freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorIds, 0);
2755  for (UINT32 i = 0; i < count; i++)
2756  {
2757  LONGLONG val = 0;
2758 
2759  if (!value_to_int(ptr[i], &val, 0, UINT16_MAX))
2760  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2761 
2762  MonitorIds[i] = (UINT32)val;
2763  }
2764 
2765  CommandLineParserFree(ptr);
2766  }
2767 
2768  return 0;
2769 }
2770 
2771 static int parse_dynamic_resolution_options(rdpSettings* settings,
2772  const COMMAND_LINE_ARGUMENT_A* arg)
2773 {
2774  WINPR_ASSERT(settings);
2775  WINPR_ASSERT(arg);
2776 
2777  const BOOL val = arg->Value != 0;
2778 
2779  if (val && freerdp_settings_get_bool(settings, FreeRDP_SmartSizing))
2780  {
2781  WLog_ERR(TAG, "Smart sizing and dynamic resolution are mutually exclusive options");
2782  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2783  }
2784 
2785  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportDisplayControl, val))
2786  return COMMAND_LINE_ERROR;
2787  if (!freerdp_settings_set_bool(settings, FreeRDP_DynamicResolutionUpdate, val))
2788  return COMMAND_LINE_ERROR;
2789 
2790  return 0;
2791 }
2792 
2793 static int parse_smart_sizing_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
2794 {
2795  WINPR_ASSERT(settings);
2796  WINPR_ASSERT(arg);
2797 
2798  if (freerdp_settings_get_bool(settings, FreeRDP_DynamicResolutionUpdate))
2799  {
2800  WLog_ERR(TAG, "Smart sizing and dynamic resolution are mutually exclusive options");
2801  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2802  }
2803 
2804  if (!freerdp_settings_set_bool(settings, FreeRDP_SmartSizing, TRUE))
2805  return COMMAND_LINE_ERROR;
2806 
2807  if (arg->Value)
2808  {
2809  unsigned long w = 0;
2810  unsigned long h = 0;
2811 
2812  if (!parseSizeValue(arg->Value, &w, &h) || (w > UINT16_MAX) || (h > UINT16_MAX))
2813  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2814 
2815  if (!freerdp_settings_set_uint32(settings, FreeRDP_SmartSizingWidth, (UINT32)w))
2816  return COMMAND_LINE_ERROR;
2817  if (!freerdp_settings_set_uint32(settings, FreeRDP_SmartSizingHeight, (UINT32)h))
2818  return COMMAND_LINE_ERROR;
2819  }
2820  return 0;
2821 }
2822 
2823 static int parse_bpp_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
2824 {
2825  WINPR_ASSERT(settings);
2826  WINPR_ASSERT(arg);
2827 
2828  LONGLONG val = 0;
2829 
2830  if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))
2831  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2832 
2833  switch (val)
2834  {
2835  case 32:
2836  case 24:
2837  case 16:
2838  case 15:
2839  case 8:
2840  if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, (UINT32)val))
2841  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2842  break;
2843 
2844  default:
2845  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2846  }
2847  return 0;
2848 }
2849 
2850 static int parse_kbd_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
2851 {
2852  WINPR_ASSERT(settings);
2853  WINPR_ASSERT(arg);
2854 
2855  int rc = CHANNEL_RC_OK;
2856  size_t count = 0;
2857  char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);
2858  if (!ptr || (count == 0))
2859  rc = COMMAND_LINE_ERROR;
2860  else
2861  {
2862  for (size_t x = 0; x < count; x++)
2863  {
2864  const char* val = ptr[x];
2865 
2866  if (option_starts_with("remap:", val))
2867  {
2868  /* Append this new occurrence to the already existing list */
2869  char* now = _strdup(&val[6]);
2870  const char* old =
2871  freerdp_settings_get_string(settings, FreeRDP_KeyboardRemappingList);
2872 
2873  /* Basic sanity test. Entries must be like <key>=<value>, e.g. 1=2 */
2874  if (!check_kbd_remap_valid(now))
2875  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2876  else if (old)
2877  {
2878  const size_t olen = strlen(old);
2879  const size_t alen = strlen(now);
2880  const size_t tlen = olen + alen + 2;
2881  char* tmp = calloc(tlen, sizeof(char));
2882  if (!tmp)
2883  rc = COMMAND_LINE_ERROR_MEMORY;
2884  else
2885  (void)_snprintf(tmp, tlen, "%s,%s", old, now);
2886  free(now);
2887  now = tmp;
2888  }
2889 
2890  if (rc == 0)
2891  {
2892  if (!freerdp_settings_set_string(settings, FreeRDP_KeyboardRemappingList, now))
2893  rc = COMMAND_LINE_ERROR;
2894  }
2895  free(now);
2896  }
2897  else if (option_starts_with("layout:", val))
2898  {
2899  rc = parse_kbd_layout(settings, &val[7]);
2900  }
2901  else if (option_starts_with("lang:", val))
2902  {
2903  LONGLONG ival = 0;
2904  const BOOL isInt = value_to_int(&val[5], &ival, 1, UINT32_MAX);
2905  if (!isInt)
2906  ival = freerdp_get_locale_id_from_string(&val[5]);
2907 
2908  if (ival <= 0)
2909  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2910  else if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardCodePage,
2911  (UINT32)ival))
2912  rc = COMMAND_LINE_ERROR;
2913  }
2914  else if (option_starts_with("type:", val))
2915  {
2916  LONGLONG ival = 0;
2917  const BOOL isInt = value_to_int(&val[5], &ival, 1, UINT32_MAX);
2918  if (!isInt)
2919  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2920  else if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardType, (UINT32)ival))
2921  rc = COMMAND_LINE_ERROR;
2922  }
2923  else if (option_starts_with("subtype:", val))
2924  {
2925  LONGLONG ival = 0;
2926  const BOOL isInt = value_to_int(&val[8], &ival, 1, UINT32_MAX);
2927  if (!isInt)
2928  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2929  else if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardSubType,
2930  (UINT32)ival))
2931  rc = COMMAND_LINE_ERROR;
2932  }
2933  else if (option_starts_with("fn-key:", val))
2934  {
2935  LONGLONG ival = 0;
2936  const BOOL isInt = value_to_int(&val[7], &ival, 1, UINT32_MAX);
2937  if (!isInt)
2938  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2939  else if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardFunctionKey,
2940  (UINT32)ival))
2941  rc = COMMAND_LINE_ERROR;
2942  }
2943  else if (option_starts_with("unicode", val))
2944  {
2945  const PARSE_ON_OFF_RESULT bval = parse_on_off_option(val);
2946  if (bval == PARSE_FAIL)
2947  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2948  else if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput,
2949  bval != PARSE_OFF))
2950  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2951  }
2952  else if (option_starts_with("pipe:", val))
2953  {
2954  if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput, TRUE))
2955  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2956  else if (!freerdp_settings_set_string(settings, FreeRDP_KeyboardPipeName, &val[5]))
2957  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2958  }
2959 #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)
2960  else if (count == 1)
2961  {
2962  /* Legacy, allow /kbd:<value> for setting keyboard layout */
2963  rc = parse_kbd_layout(settings, val);
2964  }
2965 #endif
2966  else
2967  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2968 
2969  if (rc != 0)
2970  break;
2971  }
2972  }
2973  CommandLineParserFree(ptr);
2974  return rc;
2975 }
2976 
2977 static int parse_proxy_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
2978 {
2979  WINPR_ASSERT(settings);
2980  WINPR_ASSERT(arg);
2981 
2982  /* initial value */
2983  if (!freerdp_settings_set_uint32(settings, FreeRDP_ProxyType, PROXY_TYPE_HTTP))
2984  return COMMAND_LINE_ERROR_MEMORY;
2985 
2986  if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
2987  {
2988  const char* cur = arg->Value;
2989 
2990  if (!cur)
2991  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2992  /* value is [scheme://][user:password@]hostname:port */
2993  if (!proxy_parse_uri(settings, cur))
2994  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
2995  }
2996  else
2997  {
2998  WLog_ERR(TAG, "Option http-proxy needs argument.");
2999  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3000  }
3001  return 0;
3002 }
3003 
3004 static int parse_dump_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
3005 {
3006  WINPR_ASSERT(settings);
3007  WINPR_ASSERT(arg);
3008 
3009  BOOL failed = FALSE;
3010  size_t count = 0;
3011  char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);
3012  if (!ptr)
3013  failed = TRUE;
3014  else
3015  {
3016  BOOL modernsyntax = FALSE;
3017  BOOL oldsyntax = FALSE;
3018  for (size_t x = 0; (x < count) && !failed; x++)
3019  {
3020  const char* carg = ptr[x];
3021  if (option_starts_with("file:", carg))
3022  {
3023  const char* val = &carg[5];
3024  if (oldsyntax)
3025  failed = TRUE;
3026  else if (!freerdp_settings_set_string(settings, FreeRDP_TransportDumpFile, val))
3027  failed = TRUE;
3028  modernsyntax = TRUE;
3029  }
3030  else if (option_equals("replay", carg))
3031  {
3032  if (!freerdp_settings_set_bool(settings, FreeRDP_TransportDump, FALSE))
3033  failed = TRUE;
3034  else if (!freerdp_settings_set_bool(settings, FreeRDP_TransportDumpReplay, TRUE))
3035  failed = TRUE;
3036  }
3037  else if (option_equals("record", carg))
3038  {
3039  if (!freerdp_settings_set_bool(settings, FreeRDP_TransportDump, TRUE))
3040  failed = TRUE;
3041  else if (!freerdp_settings_set_bool(settings, FreeRDP_TransportDumpReplay, FALSE))
3042  failed = TRUE;
3043  }
3044  else if (option_equals("nodelay", carg))
3045  {
3046  if (oldsyntax)
3047  failed = TRUE;
3048  else if (!freerdp_settings_set_bool(settings, FreeRDP_TransportDumpReplayNodelay,
3049  TRUE))
3050  failed = TRUE;
3051  modernsyntax = TRUE;
3052  }
3053  else
3054  {
3055  /* compat:
3056  * support syntax record,<filename> and replay,<filename>
3057  */
3058  if (modernsyntax)
3059  failed = TRUE;
3060  else if (!freerdp_settings_set_string(settings, FreeRDP_TransportDumpFile, carg))
3061  failed = TRUE;
3062  oldsyntax = TRUE;
3063  }
3064  }
3065 
3066  if (oldsyntax && (count != 2))
3067  failed = TRUE;
3068  }
3069  CommandLineParserFree(ptr);
3070  if (failed)
3071  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3072  return 0;
3073 }
3074 
3075 static int parse_clipboard_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
3076 {
3077  WINPR_ASSERT(settings);
3078  WINPR_ASSERT(arg);
3079 
3080  if (arg->Value == BoolValueTrue || arg->Value == BoolValueFalse)
3081  {
3082  if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectClipboard,
3083  (arg->Value == BoolValueTrue)))
3084  return COMMAND_LINE_ERROR;
3085  }
3086  else
3087  {
3088  int rc = 0;
3089  size_t count = 0;
3090  char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);
3091  for (size_t x = 0; (x < count) && (rc == 0); x++)
3092  {
3093  const char* usesel = "use-selection:";
3094 
3095  const char* cur = ptr[x];
3096  if (option_starts_with(usesel, cur))
3097  {
3098  const char* val = &cur[strlen(usesel)];
3099  if (!freerdp_settings_set_string(settings, FreeRDP_ClipboardUseSelection, val))
3100  rc = COMMAND_LINE_ERROR_MEMORY;
3101  if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectClipboard, TRUE))
3102  return COMMAND_LINE_ERROR;
3103  }
3104  else if (option_starts_with("direction-to", cur))
3105  {
3106  const UINT32 mask =
3107  freerdp_settings_get_uint32(settings, FreeRDP_ClipboardFeatureMask) &
3108  (uint32_t)~(CLIPRDR_FLAG_LOCAL_TO_REMOTE | CLIPRDR_FLAG_REMOTE_TO_LOCAL);
3109  const PARSE_CLIP_DIR_RESULT bval = parse_clip_direciton_to_option(cur);
3110  UINT32 bflags = 0;
3111  switch (bval)
3112  {
3113  case CLIP_DIR_PARSE_ALL:
3114  bflags |= CLIPRDR_FLAG_LOCAL_TO_REMOTE | CLIPRDR_FLAG_REMOTE_TO_LOCAL;
3115  break;
3116  case CLIP_DIR_PARSE_LOCAL:
3117  bflags |= CLIPRDR_FLAG_REMOTE_TO_LOCAL;
3118  break;
3119  case CLIP_DIR_PARSE_REMOTE:
3120  bflags |= CLIPRDR_FLAG_LOCAL_TO_REMOTE;
3121  break;
3122  case CLIP_DIR_PARSE_OFF:
3123  break;
3124  case CLIP_DIR_PARSE_FAIL:
3125  default:
3126  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3127  break;
3128  }
3129 
3130  if (!freerdp_settings_set_uint32(settings, FreeRDP_ClipboardFeatureMask,
3131  mask | bflags))
3132  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3133  }
3134  else if (option_starts_with("files-to", cur))
3135  {
3136  const UINT32 mask =
3137  freerdp_settings_get_uint32(settings, FreeRDP_ClipboardFeatureMask) &
3138  (uint32_t)~(CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES |
3139  CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES);
3140  const PARSE_CLIP_DIR_RESULT bval = parse_clip_direciton_to_option(cur);
3141  UINT32 bflags = 0;
3142  switch (bval)
3143  {
3144  case CLIP_DIR_PARSE_ALL:
3145  bflags |=
3146  CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES | CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES;
3147  break;
3148  case CLIP_DIR_PARSE_LOCAL:
3149  bflags |= CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES;
3150  break;
3151  case CLIP_DIR_PARSE_REMOTE:
3152  bflags |= CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES;
3153  break;
3154  case CLIP_DIR_PARSE_OFF:
3155  break;
3156  case CLIP_DIR_PARSE_FAIL:
3157  default:
3158  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3159  break;
3160  }
3161 
3162  if (!freerdp_settings_set_uint32(settings, FreeRDP_ClipboardFeatureMask,
3163  mask | bflags))
3164  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3165  }
3166  else
3167  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3168  }
3169  CommandLineParserFree(ptr);
3170 
3171  if (rc)
3172  return rc;
3173  }
3174  return 0;
3175 }
3176 
3177 static int parse_audio_mode_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
3178 {
3179  WINPR_ASSERT(settings);
3180  WINPR_ASSERT(arg);
3181 
3182  LONGLONG val = 0;
3183 
3184  if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))
3185  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3186 
3187  switch (val)
3188  {
3189  case AUDIO_MODE_REDIRECT:
3190  if (!freerdp_settings_set_bool(settings, FreeRDP_AudioPlayback, TRUE))
3191  return COMMAND_LINE_ERROR;
3192  break;
3193 
3194  case AUDIO_MODE_PLAY_ON_SERVER:
3195  if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteConsoleAudio, TRUE))
3196  return COMMAND_LINE_ERROR;
3197  break;
3198 
3199  case AUDIO_MODE_NONE:
3200  if (!freerdp_settings_set_bool(settings, FreeRDP_AudioPlayback, FALSE))
3201  return COMMAND_LINE_ERROR;
3202  if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteConsoleAudio, FALSE))
3203  return COMMAND_LINE_ERROR;
3204  break;
3205 
3206  default:
3207  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3208  }
3209  return 0;
3210 }
3211 
3212 static int parse_network_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
3213 {
3214  WINPR_ASSERT(settings);
3215  WINPR_ASSERT(arg);
3216 
3217  UINT32 type = CONNECTION_TYPE_INVALID;
3218 
3219  if (option_equals(arg->Value, "invalid"))
3220  type = CONNECTION_TYPE_INVALID;
3221  else if (option_equals(arg->Value, "modem"))
3222  type = CONNECTION_TYPE_MODEM;
3223  else if (option_equals(arg->Value, "broadband"))
3224  type = CONNECTION_TYPE_BROADBAND_HIGH;
3225  else if (option_equals(arg->Value, "broadband-low"))
3226  type = CONNECTION_TYPE_BROADBAND_LOW;
3227  else if (option_equals(arg->Value, "broadband-high"))
3228  type = CONNECTION_TYPE_BROADBAND_HIGH;
3229  else if (option_equals(arg->Value, "wan"))
3230  type = CONNECTION_TYPE_WAN;
3231  else if (option_equals(arg->Value, "lan"))
3232  type = CONNECTION_TYPE_LAN;
3233  else if ((option_equals(arg->Value, "autodetect")) || (option_equals(arg->Value, "auto")) ||
3234  (option_equals(arg->Value, "detect")))
3235  {
3236  type = CONNECTION_TYPE_AUTODETECT;
3237  }
3238  else
3239  {
3240  LONGLONG val = 0;
3241 
3242  if (!value_to_int(arg->Value, &val, 0, 7))
3243  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3244 
3245  type = (UINT32)val;
3246  }
3247 
3248  if (!freerdp_set_connection_type(settings, type))
3249  return COMMAND_LINE_ERROR;
3250  return 0;
3251 }
3252 
3253 static int parse_sec_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
3254 {
3255  WINPR_ASSERT(settings);
3256  WINPR_ASSERT(arg);
3257 
3258  size_t count = 0;
3259  char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);
3260  if (count == 0)
3261  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3262 
3263  FreeRDP_Settings_Keys_Bool singleOptionWithoutOnOff = FreeRDP_BOOL_UNUSED;
3264  for (size_t x = 0; x < count; x++)
3265  {
3266  const char* cur = ptr[x];
3267  const PARSE_ON_OFF_RESULT bval = parse_on_off_option(cur);
3268  if (bval == PARSE_FAIL)
3269  {
3270  CommandLineParserFree(ptr);
3271  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3272  }
3273 
3274  const BOOL val = bval != PARSE_OFF;
3275  FreeRDP_Settings_Keys_Bool id = FreeRDP_BOOL_UNUSED;
3276  if (option_starts_with("rdp", cur)) /* Standard RDP */
3277  {
3278  id = FreeRDP_RdpSecurity;
3279  if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, val))
3280  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3281  }
3282  else if (option_starts_with("tls", cur)) /* TLS */
3283  id = FreeRDP_TlsSecurity;
3284  else if (option_starts_with("nla", cur)) /* NLA */
3285  id = FreeRDP_NlaSecurity;
3286  else if (option_starts_with("ext", cur)) /* NLA Extended */
3287  id = FreeRDP_ExtSecurity;
3288  else if (option_equals("aad", cur)) /* RDSAAD */
3289  id = FreeRDP_AadSecurity;
3290  else
3291  {
3292  WLog_ERR(TAG, "unknown protocol security: %s", arg->Value);
3293  CommandLineParserFree(ptr);
3294  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3295  }
3296 
3297  if ((bval == PARSE_NONE) && (count == 1))
3298  singleOptionWithoutOnOff = id;
3299  if (!freerdp_settings_set_bool(settings, id, val))
3300  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3301  }
3302 
3303  if (singleOptionWithoutOnOff != FreeRDP_BOOL_UNUSED)
3304  {
3305  const FreeRDP_Settings_Keys_Bool options[] = { FreeRDP_AadSecurity,
3306  FreeRDP_UseRdpSecurityLayer,
3307  FreeRDP_RdpSecurity, FreeRDP_NlaSecurity,
3308  FreeRDP_TlsSecurity };
3309 
3310  for (size_t i = 0; i < ARRAYSIZE(options); i++)
3311  {
3312  if (!freerdp_settings_set_bool(settings, options[i], FALSE))
3313  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3314  }
3315 
3316  if (!freerdp_settings_set_bool(settings, singleOptionWithoutOnOff, TRUE))
3317  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3318  if (singleOptionWithoutOnOff == FreeRDP_RdpSecurity)
3319  {
3320  if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, TRUE))
3321  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3322  }
3323  }
3324  CommandLineParserFree(ptr);
3325  return 0;
3326 }
3327 
3328 static int parse_encryption_methods_options(rdpSettings* settings,
3329  const COMMAND_LINE_ARGUMENT_A* arg)
3330 {
3331  WINPR_ASSERT(settings);
3332  WINPR_ASSERT(arg);
3333 
3334  if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
3335  {
3336  size_t count = 0;
3337  char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);
3338 
3339  UINT32 EncryptionMethods = 0;
3340  for (UINT32 i = 0; i < count; i++)
3341  {
3342  if (option_equals(ptr[i], "40"))
3343  EncryptionMethods |= ENCRYPTION_METHOD_40BIT;
3344  else if (option_equals(ptr[i], "56"))
3345  EncryptionMethods |= ENCRYPTION_METHOD_56BIT;
3346  else if (option_equals(ptr[i], "128"))
3347  EncryptionMethods |= ENCRYPTION_METHOD_128BIT;
3348  else if (option_equals(ptr[i], "FIPS"))
3349  EncryptionMethods |= ENCRYPTION_METHOD_FIPS;
3350  else
3351  WLog_ERR(TAG, "unknown encryption method '%s'", ptr[i]);
3352  }
3353 
3354  if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionMethods, EncryptionMethods))
3355  return COMMAND_LINE_ERROR;
3356  CommandLineParserFree(ptr);
3357  }
3358  return 0;
3359 }
3360 
3361 static int parse_cert_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
3362 {
3363  WINPR_ASSERT(settings);
3364  WINPR_ASSERT(arg);
3365 
3366  int rc = 0;
3367  size_t count = 0;
3368  char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);
3369  for (size_t x = 0; (x < count) && (rc == 0); x++)
3370  {
3371  const char deny[] = "deny";
3372  const char ignore[] = "ignore";
3373  const char tofu[] = "tofu";
3374  const char name[] = "name:";
3375  const char fingerprints[] = "fingerprint:";
3376 
3377  const char* cur = ptr[x];
3378  if (option_equals(deny, cur))
3379  {
3380  if (!freerdp_settings_set_bool(settings, FreeRDP_AutoDenyCertificate, TRUE))
3381  return COMMAND_LINE_ERROR;
3382  }
3383  else if (option_equals(ignore, cur))
3384  {
3385  if (!freerdp_settings_set_bool(settings, FreeRDP_IgnoreCertificate, TRUE))
3386  return COMMAND_LINE_ERROR;
3387  }
3388  else if (option_equals(tofu, cur))
3389  {
3390  if (!freerdp_settings_set_bool(settings, FreeRDP_AutoAcceptCertificate, TRUE))
3391  return COMMAND_LINE_ERROR;
3392  }
3393  else if (option_starts_with(name, cur))
3394  {
3395  const char* val = &cur[strnlen(name, sizeof(name))];
3396  if (!freerdp_settings_set_string(settings, FreeRDP_CertificateName, val))
3397  rc = COMMAND_LINE_ERROR_MEMORY;
3398  }
3399  else if (option_starts_with(fingerprints, cur))
3400  {
3401  const char* val = &cur[strnlen(fingerprints, sizeof(fingerprints))];
3402  if (!freerdp_settings_append_string(settings, FreeRDP_CertificateAcceptedFingerprints,
3403  ",", val))
3404  rc = COMMAND_LINE_ERROR_MEMORY;
3405  }
3406  else
3407  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3408  }
3409  CommandLineParserFree(ptr);
3410 
3411  return rc;
3412 }
3413 
3414 static int parse_mouse_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
3415 {
3416  WINPR_ASSERT(settings);
3417  WINPR_ASSERT(arg);
3418 
3419  size_t count = 0;
3420  char** ptr = CommandLineParseCommaSeparatedValuesEx("mouse", arg->Value, &count);
3421  int rc = 0;
3422  if (ptr)
3423  {
3424  for (size_t x = 1; x < count; x++)
3425  {
3426  const char* cur = ptr[x];
3427 
3428  const PARSE_ON_OFF_RESULT bval = parse_on_off_option(cur);
3429  if (bval == PARSE_FAIL)
3430  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3431  else
3432  {
3433  const BOOL val = bval != PARSE_OFF;
3434 
3435  if (option_starts_with("relative", cur))
3436  {
3437  if (!freerdp_settings_set_bool(settings, FreeRDP_MouseUseRelativeMove, val))
3438  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3439  }
3440  else if (option_starts_with("grab", cur))
3441  {
3442  if (!freerdp_settings_set_bool(settings, FreeRDP_GrabMouse, val))
3443  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3444  }
3445  }
3446 
3447  if (rc != 0)
3448  break;
3449  }
3450  }
3451  CommandLineParserFree(ptr);
3452 
3453  return rc;
3454 }
3455 
3456 static int parse_floatbar_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
3457 {
3458  WINPR_ASSERT(settings);
3459  WINPR_ASSERT(arg);
3460 
3461  /* Defaults are enabled, visible, sticky, fullscreen */
3462  UINT32 Floatbar = 0x0017;
3463 
3464  if (arg->Value)
3465  {
3466  char* start = arg->Value;
3467 
3468  do
3469  {
3470  char* cur = start;
3471  start = strchr(start, ',');
3472 
3473  if (start)
3474  {
3475  *start = '\0';
3476  start = start + 1;
3477  }
3478 
3479  /* sticky:[on|off] */
3480  if (option_starts_with("sticky:", cur))
3481  {
3482  Floatbar &= ~0x02u;
3483 
3484  const PARSE_ON_OFF_RESULT bval = parse_on_off_option(cur);
3485  switch (bval)
3486  {
3487  case PARSE_ON:
3488  case PARSE_NONE:
3489  Floatbar |= 0x02u;
3490  break;
3491  case PARSE_OFF:
3492  Floatbar &= ~0x02u;
3493  break;
3494  case PARSE_FAIL:
3495  default:
3496  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3497  }
3498  }
3499  /* default:[visible|hidden] */
3500  else if (option_starts_with("default:", cur))
3501  {
3502  const char* val = cur + 8;
3503  Floatbar &= ~0x04u;
3504 
3505  if (option_equals("visible", val))
3506  Floatbar |= 0x04u;
3507  else if (option_equals("hidden", val))
3508  Floatbar &= ~0x04u;
3509  else
3510  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3511  }
3512  /* show:[always|fullscreen|window] */
3513  else if (option_starts_with("show:", cur))
3514  {
3515  const char* val = cur + 5;
3516  Floatbar &= ~0x30u;
3517 
3518  if (option_equals("always", val))
3519  Floatbar |= 0x30u;
3520  else if (option_equals("fullscreen", val))
3521  Floatbar |= 0x10u;
3522  else if (option_equals("window", val))
3523  Floatbar |= 0x20u;
3524  else
3525  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3526  }
3527  else
3528  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3529  } while (start);
3530  }
3531  if (!freerdp_settings_set_uint32(settings, FreeRDP_Floatbar, Floatbar))
3532  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3533  return 0;
3534 }
3535 
3536 static int parse_reconnect_cookie_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
3537 {
3538  WINPR_ASSERT(settings);
3539  WINPR_ASSERT(arg);
3540 
3541  BYTE* base64 = NULL;
3542  size_t length = 0;
3543  if (!arg->Value)
3544  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3545 
3546  crypto_base64_decode((const char*)(arg->Value), strlen(arg->Value), &base64, &length);
3547 
3548  if ((base64 != NULL) && (length == sizeof(ARC_SC_PRIVATE_PACKET)))
3549  {
3550  if (!freerdp_settings_set_pointer_len(settings, FreeRDP_ServerAutoReconnectCookie, base64,
3551  1))
3552  return COMMAND_LINE_ERROR;
3553  }
3554  else
3555  {
3556  WLog_ERR(TAG, "reconnect-cookie: invalid base64 '%s'", arg->Value);
3557  }
3558 
3559  free(base64);
3560  return 0;
3561 }
3562 
3563 static int parse_scale_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
3564 {
3565  WINPR_ASSERT(settings);
3566  WINPR_ASSERT(arg);
3567 
3568  LONGLONG val = 0;
3569 
3570  if (!value_to_int(arg->Value, &val, 100, 180))
3571  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3572 
3573  switch (val)
3574  {
3575  case 100:
3576  case 140:
3577  case 180:
3578  if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopScaleFactor, (UINT32)val))
3579  return COMMAND_LINE_ERROR;
3580  if (!freerdp_settings_set_uint32(settings, FreeRDP_DeviceScaleFactor, (UINT32)val))
3581  return COMMAND_LINE_ERROR;
3582  break;
3583 
3584  default:
3585  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3586  }
3587  return 0;
3588 }
3589 
3590 static int parse_scale_device_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
3591 {
3592  WINPR_ASSERT(settings);
3593  WINPR_ASSERT(arg);
3594 
3595  LONGLONG val = 0;
3596 
3597  if (!value_to_int(arg->Value, &val, 100, 180))
3598  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3599 
3600  switch (val)
3601  {
3602  case 100:
3603  case 140:
3604  case 180:
3605  if (!freerdp_settings_set_uint32(settings, FreeRDP_DeviceScaleFactor, (UINT32)val))
3606  return COMMAND_LINE_ERROR;
3607  break;
3608 
3609  default:
3610  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3611  }
3612  return 0;
3613 }
3614 
3615 static int parse_smartcard_logon_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
3616 {
3617  WINPR_ASSERT(settings);
3618  WINPR_ASSERT(arg);
3619 
3620  size_t count = 0;
3621 
3622  if (!freerdp_settings_set_bool(settings, FreeRDP_SmartcardLogon, TRUE))
3623  return COMMAND_LINE_ERROR;
3624 
3625  char** ptr = CommandLineParseCommaSeparatedValuesEx("smartcard-logon", arg->Value, &count);
3626  if (ptr)
3627  {
3628  const CmdLineSubOptions opts[] = {
3629  { "cert:", FreeRDP_SmartcardCertificate, CMDLINE_SUBOPTION_FILE,
3630  setSmartcardEmulation },
3631  { "key:", FreeRDP_SmartcardPrivateKey, CMDLINE_SUBOPTION_FILE, setSmartcardEmulation },
3632  { "pin:", FreeRDP_Password, CMDLINE_SUBOPTION_STRING, NULL },
3633  { "csp:", FreeRDP_CspName, CMDLINE_SUBOPTION_STRING, NULL },
3634  { "reader:", FreeRDP_ReaderName, CMDLINE_SUBOPTION_STRING, NULL },
3635  { "card:", FreeRDP_CardName, CMDLINE_SUBOPTION_STRING, NULL },
3636  { "container:", FreeRDP_ContainerName, CMDLINE_SUBOPTION_STRING, NULL }
3637  };
3638 
3639  for (size_t x = 1; x < count; x++)
3640  {
3641  const char* cur = ptr[x];
3642  if (!parseSubOptions(settings, opts, ARRAYSIZE(opts), cur))
3643  {
3644  CommandLineParserFree(ptr);
3645  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3646  }
3647  }
3648  }
3649  CommandLineParserFree(ptr);
3650  return 0;
3651 }
3652 
3653 static int parse_tune_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
3654 {
3655  WINPR_ASSERT(settings);
3656  WINPR_ASSERT(arg);
3657 
3658  size_t count = 0;
3659  char** ptr = CommandLineParseCommaSeparatedValuesEx("tune", arg->Value, &count);
3660  if (!ptr)
3661  return COMMAND_LINE_ERROR;
3662  for (size_t x = 1; x < count; x++)
3663  {
3664  const char* cur = ptr[x];
3665  char* sep = strchr(cur, ':');
3666  if (!sep)
3667  {
3668  CommandLineParserFree(ptr);
3669  return COMMAND_LINE_ERROR;
3670  }
3671  *sep++ = '\0';
3672  if (!freerdp_settings_set_value_for_name(settings, cur, sep))
3673  {
3674  CommandLineParserFree(ptr);
3675  return COMMAND_LINE_ERROR;
3676  }
3677  }
3678 
3679  CommandLineParserFree(ptr);
3680  return 0;
3681 }
3682 
3683 static int parse_app_option_program(rdpSettings* settings, const char* cmd)
3684 {
3685  const FreeRDP_Settings_Keys_Bool ids[] = { FreeRDP_RemoteApplicationMode,
3686  FreeRDP_RemoteAppLanguageBarSupported,
3687  FreeRDP_Workarea, FreeRDP_DisableWallpaper,
3688  FreeRDP_DisableFullWindowDrag };
3689 
3690  if (!freerdp_settings_set_string(settings, FreeRDP_RemoteApplicationProgram, cmd))
3691  return COMMAND_LINE_ERROR_MEMORY;
3692 
3693  for (size_t y = 0; y < ARRAYSIZE(ids); y++)
3694  {
3695  if (!freerdp_settings_set_bool(settings, ids[y], TRUE))
3696  return COMMAND_LINE_ERROR;
3697  }
3698  return CHANNEL_RC_OK;
3699 }
3700 
3701 static int parse_aad_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
3702 {
3703  WINPR_ASSERT(settings);
3704  WINPR_ASSERT(arg);
3705 
3706  int rc = CHANNEL_RC_OK;
3707  size_t count = 0;
3708  char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);
3709  if (!ptr || (count == 0))
3710  rc = COMMAND_LINE_ERROR;
3711  else
3712  {
3713  struct app_map
3714  {
3715  const char* name;
3716  SSIZE_T id;
3717  int (*fkt)(rdpSettings* settings, const char* value);
3718  };
3719  const struct app_map amap[] = { { "tenantid:", FreeRDP_GatewayAvdAadtenantid,
3720  parse_app_option_program },
3721  { "ad:", FreeRDP_GatewayAzureActiveDirectory, NULL } };
3722  for (size_t x = 0; x < count; x++)
3723  {
3724  BOOL handled = FALSE;
3725  const char* val = ptr[x];
3726 
3727  if (option_starts_with("use-tenantid", val))
3728  {
3729  PARSE_ON_OFF_RESULT bval = parse_on_off_option(val);
3730  if (bval == PARSE_FAIL)
3731  {
3732  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3733  break;
3734  }
3735  else
3736  {
3737  if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayAvdUseTenantid,
3738  bval != PARSE_OFF))
3739  {
3740  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3741  break;
3742  }
3743  }
3744  continue;
3745  }
3746  for (size_t y = 0; y < ARRAYSIZE(amap); y++)
3747  {
3748  const struct app_map* cur = &amap[y];
3749  if (option_starts_with(cur->name, val))
3750  {
3751  const char* xval = &val[strlen(cur->name)];
3752  if (cur->fkt)
3753  rc = cur->fkt(settings, xval);
3754  else
3755  {
3756  const char* name = freerdp_settings_get_name_for_key(cur->id);
3757  if (!freerdp_settings_set_value_for_name(settings, name, xval))
3758  rc = COMMAND_LINE_ERROR_MEMORY;
3759  }
3760 
3761  handled = TRUE;
3762  break;
3763  }
3764  }
3765 
3766  if (!handled)
3767  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3768 
3769  if (rc != 0)
3770  break;
3771  }
3772  }
3773 
3774  CommandLineParserFree(ptr);
3775  return rc;
3776 }
3777 
3778 static int parse_app_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
3779 {
3780  WINPR_ASSERT(settings);
3781  WINPR_ASSERT(arg);
3782 
3783  int rc = CHANNEL_RC_OK;
3784  size_t count = 0;
3785  char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);
3786  if (!ptr || (count == 0))
3787  rc = COMMAND_LINE_ERROR;
3788  else
3789  {
3790  struct app_map
3791  {
3792  const char* name;
3793  SSIZE_T id;
3794  int (*fkt)(rdpSettings* settings, const char* value);
3795  };
3796  const struct app_map amap[] = { { "program:", FreeRDP_RemoteApplicationProgram,
3797  parse_app_option_program },
3798  { "workdir:", FreeRDP_RemoteApplicationWorkingDir, NULL },
3799  { "name:", FreeRDP_RemoteApplicationName, NULL },
3800  { "icon:", FreeRDP_RemoteApplicationIcon, NULL },
3801  { "cmd:", FreeRDP_RemoteApplicationCmdLine, NULL },
3802  { "file:", FreeRDP_RemoteApplicationFile, NULL },
3803  { "guid:", FreeRDP_RemoteApplicationGuid, NULL },
3804  { "hidef:", FreeRDP_HiDefRemoteApp, NULL } };
3805  for (size_t x = 0; x < count; x++)
3806  {
3807  BOOL handled = FALSE;
3808  const char* val = ptr[x];
3809 
3810  for (size_t y = 0; y < ARRAYSIZE(amap); y++)
3811  {
3812  const struct app_map* cur = &amap[y];
3813  if (option_starts_with(cur->name, val))
3814  {
3815  const char* xval = &val[strlen(cur->name)];
3816  if (cur->fkt)
3817  rc = cur->fkt(settings, xval);
3818  else
3819  {
3820  const char* name = freerdp_settings_get_name_for_key(cur->id);
3821  if (!freerdp_settings_set_value_for_name(settings, name, xval))
3822  rc = COMMAND_LINE_ERROR_MEMORY;
3823  }
3824 
3825  handled = TRUE;
3826  break;
3827  }
3828  }
3829 
3830 #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)
3831  if (!handled && (count == 1))
3832  {
3833  /* Legacy path, allow /app:command and /app:||command syntax */
3834  rc = parse_app_option_program(settings, val);
3835  }
3836  else
3837 #endif
3838  if (!handled)
3839  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3840 
3841  if (rc != 0)
3842  break;
3843  }
3844  }
3845 
3846  CommandLineParserFree(ptr);
3847  return rc;
3848 }
3849 
3850 static int parse_cache_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
3851 {
3852  WINPR_ASSERT(settings);
3853  WINPR_ASSERT(arg);
3854 
3855  int rc = CHANNEL_RC_OK;
3856  size_t count = 0;
3857  char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);
3858  if (!ptr || (count == 0))
3859  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3860 
3861  for (size_t x = 0; x < count; x++)
3862  {
3863  const char* val = ptr[x];
3864 
3865  if (option_starts_with("codec:", val))
3866  {
3867  if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheV3Enabled, TRUE))
3868  rc = COMMAND_LINE_ERROR;
3869  else if (option_equals(arg->Value, "rfx"))
3870  {
3871  if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE))
3872  rc = COMMAND_LINE_ERROR;
3873  }
3874  else if (option_equals(arg->Value, "nsc"))
3875  {
3876  if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, TRUE))
3877  rc = COMMAND_LINE_ERROR;
3878  }
3879 
3880 #if defined(WITH_JPEG)
3881  else if (option_equals(arg->Value, "jpeg"))
3882  {
3883  if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, TRUE))
3884  rc = COMMAND_LINE_ERROR;
3885 
3886  if (freerdp_settings_get_uint32(settings, FreeRDP_JpegQuality) == 0)
3887  {
3888  if (!freerdp_settings_set_uint32(settings, FreeRDP_JpegQuality, 75))
3889  return COMMAND_LINE_ERROR;
3890  }
3891  }
3892 
3893 #endif
3894  }
3895  else if (option_starts_with("persist-file:", val))
3896  {
3897 
3898  if (!freerdp_settings_set_string(settings, FreeRDP_BitmapCachePersistFile, &val[13]))
3899  rc = COMMAND_LINE_ERROR_MEMORY;
3900  else if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled, TRUE))
3901  rc = COMMAND_LINE_ERROR;
3902  }
3903  else
3904  {
3905  const PARSE_ON_OFF_RESULT bval = parse_on_off_option(val);
3906  if (bval == PARSE_FAIL)
3907  rc = COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
3908  else
3909  {
3910  if (option_starts_with("bitmap", val))
3911  {
3912  if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheEnabled,
3913  bval != PARSE_OFF))
3914  rc = COMMAND_LINE_ERROR;
3915  }
3916  else if (option_starts_with("glyph", val))
3917  {
3918  if (!freerdp_settings_set_uint32(settings, FreeRDP_GlyphSupportLevel,
3919  bval != PARSE_OFF ? GLYPH_SUPPORT_FULL
3920  : GLYPH_SUPPORT_NONE))
3921  rc = COMMAND_LINE_ERROR;
3922  }
3923  else if (option_starts_with("persist", val))
3924  {
3925  if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled,
3926  bval != PARSE_OFF))
3927  rc = COMMAND_LINE_ERROR;
3928  }
3929  else if (option_starts_with("offscreen", val))
3930  {
3931  if (!freerdp_settings_set_uint32(settings, FreeRDP_OffscreenSupportLevel,
3932  bval != PARSE_OFF))
3933  rc = COMMAND_LINE_ERROR;
3934  }
3935  }
3936  }
3937  }
3938 
3939  CommandLineParserFree(ptr);
3940  return rc;
3941 }
3942 
3943 static BOOL parse_gateway_host_option(rdpSettings* settings, const char* host)
3944 {
3945  WINPR_ASSERT(settings);
3946  WINPR_ASSERT(host);
3947 
3948  char* name = NULL;
3949  int port = -1;
3950  if (!freerdp_parse_hostname(host, &name, &port))
3951  return FALSE;
3952  const BOOL rc = freerdp_settings_set_string(settings, FreeRDP_GatewayHostname, name);
3953  free(name);
3954  if (!rc)
3955  return FALSE;
3956  if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayUseSameCredentials, TRUE))
3957  return FALSE;
3958  if (!freerdp_set_gateway_usage_method(settings, TSC_PROXY_MODE_DIRECT))
3959  return FALSE;
3960 
3961  return TRUE;
3962 }
3963 
3964 static BOOL parse_gateway_cred_option(rdpSettings* settings, const char* value,
3965  FreeRDP_Settings_Keys_String what)
3966 {
3967  WINPR_ASSERT(settings);
3968  WINPR_ASSERT(value);
3969 
3970  switch (what)
3971  {
3972  case FreeRDP_GatewayUsername:
3973  if (!freerdp_parse_username_settings(value, settings, FreeRDP_GatewayUsername,
3974  FreeRDP_GatewayDomain))
3975  return FALSE;
3976  break;
3977  default:
3978  if (!freerdp_settings_set_string(settings, what, value))
3979  return FALSE;
3980  break;
3981  }
3982 
3983  return freerdp_settings_set_bool(settings, FreeRDP_GatewayUseSameCredentials, FALSE);
3984 }
3985 
3986 static BOOL parse_gateway_type_option(rdpSettings* settings, const char* value)
3987 {
3988  WINPR_ASSERT(settings);
3989  WINPR_ASSERT(value);
3990 
3991  if (option_equals(value, "rpc"))
3992  {
3993  if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayRpcTransport, TRUE) ||
3994  !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpTransport, FALSE) ||
3995  !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpUseWebsockets, FALSE) ||
3996  !freerdp_settings_set_bool(settings, FreeRDP_GatewayArmTransport, FALSE))
3997  return FALSE;
3998  }
3999  else
4000  {
4001  if (option_equals(value, "http"))
4002  {
4003  if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayRpcTransport, FALSE) ||
4004  !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpTransport, TRUE) ||
4005  !freerdp_settings_set_bool(settings, FreeRDP_GatewayArmTransport, FALSE))
4006  return FALSE;
4007  }
4008  else if (option_equals(value, "auto"))
4009  {
4010  if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayRpcTransport, TRUE) ||
4011  !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpTransport, TRUE) ||
4012  !freerdp_settings_set_bool(settings, FreeRDP_GatewayArmTransport, FALSE))
4013  return FALSE;
4014  }
4015  else if (option_equals(value, "arm"))
4016  {
4017  if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayRpcTransport, FALSE) ||
4018  !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpTransport, FALSE) ||
4019  !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpUseWebsockets, FALSE) ||
4020  !freerdp_settings_set_bool(settings, FreeRDP_GatewayArmTransport, TRUE))
4021  return FALSE;
4022  }
4023  }
4024  return TRUE;
4025 }
4026 
4027 static BOOL parse_gateway_usage_option(rdpSettings* settings, const char* value)
4028 {
4029  UINT32 type = 0;
4030 
4031  WINPR_ASSERT(settings);
4032  WINPR_ASSERT(value);
4033 
4034  if (option_equals(value, "none"))
4035  type = TSC_PROXY_MODE_NONE_DIRECT;
4036  else if (option_equals(value, "direct"))
4037  type = TSC_PROXY_MODE_DIRECT;
4038  else if (option_equals(value, "detect"))
4039  type = TSC_PROXY_MODE_DETECT;
4040  else if (option_equals(value, "default"))
4041  type = TSC_PROXY_MODE_DEFAULT;
4042  else
4043  {
4044  LONGLONG val = 0;
4045 
4046  if (!value_to_int(value, &val, TSC_PROXY_MODE_NONE_DIRECT, TSC_PROXY_MODE_NONE_DETECT))
4047  return FALSE;
4048  }
4049 
4050  return freerdp_set_gateway_usage_method(settings, type);
4051 }
4052 
4053 static BOOL parse_gateway_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* arg)
4054 {
4055  BOOL rc = FALSE;
4056 
4057  WINPR_ASSERT(settings);
4058  WINPR_ASSERT(arg);
4059 
4060  size_t count = 0;
4061  char** ptr = CommandLineParseCommaSeparatedValues(arg->Value, &count);
4062  if (count == 0)
4063  return TRUE;
4064  WINPR_ASSERT(ptr);
4065 
4066  if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayEnabled, TRUE))
4067  goto fail;
4068 
4069  BOOL allowHttpOpts = FALSE;
4070  for (size_t x = 0; x < count; x++)
4071  {
4072  BOOL validOption = FALSE;
4073  const char* argval = ptr[x];
4074 
4075  WINPR_ASSERT(argval);
4076 
4077  const char* gw = option_starts_with("g:", argval);
4078  if (gw)
4079  {
4080  if (!parse_gateway_host_option(settings, gw))
4081  goto fail;
4082  validOption = TRUE;
4083  allowHttpOpts = FALSE;
4084  }
4085 
4086  const char* gu = option_starts_with("u:", argval);
4087  if (gu)
4088  {
4089  if (!parse_gateway_cred_option(settings, gu, FreeRDP_GatewayUsername))
4090  goto fail;
4091  validOption = TRUE;
4092  allowHttpOpts = FALSE;
4093  }
4094 
4095  const char* gd = option_starts_with("d:", argval);
4096  if (gd)
4097  {
4098  if (!parse_gateway_cred_option(settings, gd, FreeRDP_GatewayDomain))
4099  goto fail;
4100  validOption = TRUE;
4101  allowHttpOpts = FALSE;
4102  }
4103 
4104  const char* gp = option_starts_with("p:", argval);
4105  if (gp)
4106  {
4107  if (!parse_gateway_cred_option(settings, gp, FreeRDP_GatewayPassword))
4108  goto fail;
4109  validOption = TRUE;
4110  allowHttpOpts = FALSE;
4111  }
4112 
4113  const char* gt = option_starts_with("type:", argval);
4114  if (gt)
4115  {
4116  if (!parse_gateway_type_option(settings, gt))
4117  goto fail;
4118  validOption = TRUE;
4119  allowHttpOpts = freerdp_settings_get_bool(settings, FreeRDP_GatewayHttpTransport);
4120  }
4121 
4122  const char* gat = option_starts_with("access-token:", argval);
4123  if (gat)
4124  {
4125  if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAccessToken, gat))
4126  goto fail;
4127  validOption = TRUE;
4128  allowHttpOpts = FALSE;
4129  }
4130 
4131  const char* bearer = option_starts_with("bearer:", argval);
4132  if (bearer)
4133  {
4134  if (!freerdp_settings_set_string(settings, FreeRDP_GatewayHttpExtAuthBearer, bearer))
4135  goto fail;
4136  validOption = TRUE;
4137  allowHttpOpts = FALSE;
4138  }
4139 
4140  const char* gwurl = option_starts_with("url:", argval);
4141  if (gwurl)
4142  {
4143  if (!freerdp_settings_set_string(settings, FreeRDP_GatewayUrl, gwurl))
4144  goto fail;
4145  if (!freerdp_set_gateway_usage_method(settings, TSC_PROXY_MODE_DIRECT))
4146  goto fail;
4147  validOption = TRUE;
4148  allowHttpOpts = FALSE;
4149  }
4150 
4151  const char* um = option_starts_with("usage-method:", argval);
4152  if (um)
4153  {
4154  if (!parse_gateway_usage_option(settings, um))
4155  goto fail;
4156  validOption = TRUE;
4157  allowHttpOpts = FALSE;
4158  }
4159 
4160  if (allowHttpOpts)
4161  {
4162  if (option_equals(argval, "no-websockets"))
4163  {
4164  if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpUseWebsockets, FALSE))
4165  goto fail;
4166  validOption = TRUE;
4167  }
4168  else if (option_equals(argval, "extauth-sspi-ntlm"))
4169  {
4170  if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpExtAuthSspiNtlm, TRUE))
4171  goto fail;
4172  validOption = TRUE;
4173  }
4174  }
4175 
4176  if (!validOption)
4177  goto fail;
4178  }
4179 
4180  rc = TRUE;
4181 fail:
4182  CommandLineParserFree(ptr);
4183  return rc;
4184 }
4185 
4186 static void fill_credential_string(COMMAND_LINE_ARGUMENT_A* args, const char* value)
4187 {
4188  WINPR_ASSERT(args);
4189  WINPR_ASSERT(value);
4190 
4191  const COMMAND_LINE_ARGUMENT_A* arg = CommandLineFindArgumentA(args, value);
4192  if (!arg)
4193  return;
4194 
4195  if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
4196  FillMemory(arg->Value, strlen(arg->Value), '*');
4197 }
4198 
4199 static void fill_credential_strings(COMMAND_LINE_ARGUMENT_A* args)
4200 {
4201  const char* credentials[] = {
4202  "p",
4203  "smartcard-logon",
4204 #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)
4205  "gp",
4206  "gat",
4207 #endif
4208  "pth",
4209  "reconnect-cookie",
4210  "assistance"
4211  };
4212 
4213  for (size_t x = 0; x < ARRAYSIZE(credentials); x++)
4214  {
4215  const char* cred = credentials[x];
4216  fill_credential_string(args, cred);
4217  }
4218 
4219  const COMMAND_LINE_ARGUMENT_A* arg = CommandLineFindArgumentA(args, "gateway");
4220  if (arg && ((arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT) != 0))
4221  {
4222  const char* gwcreds[] = { "p:", "access-token:" };
4223  char* saveptr = NULL;
4224  char* tok = strtok_s(arg->Value, ",", &saveptr);
4225  while (tok)
4226  {
4227  for (size_t x = 0; x < ARRAYSIZE(gwcreds); x++)
4228  {
4229  const char* opt = gwcreds[x];
4230  if (option_starts_with(opt, tok))
4231  {
4232  char* val = &tok[strlen(opt)];
4233  FillMemory(val, strlen(val), '*');
4234  }
4235  }
4236  tok = strtok_s(NULL, ",", &saveptr);
4237  }
4238  }
4239 }
4240 
4241 static int freerdp_client_settings_parse_command_line_arguments_int(
4242  rdpSettings* settings, int argc, char* argv[], BOOL allowUnknown,
4243  COMMAND_LINE_ARGUMENT_A* largs, size_t count,
4244  int (*handle_option)(const COMMAND_LINE_ARGUMENT_A* arg, void* custom), void* handle_userdata)
4245 {
4246  char* user = NULL;
4247  int status = 0;
4248  BOOL ext = FALSE;
4249  BOOL assist = FALSE;
4250  DWORD flags = 0;
4251  BOOL promptForPassword = FALSE;
4252  BOOL compatibility = FALSE;
4253  const COMMAND_LINE_ARGUMENT_A* arg = NULL;
4254 
4255  /* Command line detection fails if only a .rdp or .msrcIncident file
4256  * is supplied. Check this case first, only then try to detect
4257  * legacy command line syntax. */
4258  if (argc > 1)
4259  {
4260  ext = option_is_rdp_file(argv[1]);
4261  assist = option_is_incident_file(argv[1]);
4262  }
4263 
4264  if (!ext && !assist)
4265  compatibility = freerdp_client_detect_command_line(argc, argv, &flags);
4266  else
4267  compatibility = freerdp_client_detect_command_line(argc - 1, &argv[1], &flags);
4268 
4269  if (!freerdp_settings_set_string(settings, FreeRDP_ProxyHostname, NULL))
4270  return -1;
4271  if (!freerdp_settings_set_string(settings, FreeRDP_ProxyUsername, NULL))
4272  return -1;
4273  if (!freerdp_settings_set_string(settings, FreeRDP_ProxyPassword, NULL))
4274  return -1;
4275 
4276  if (compatibility)
4277  {
4278  WLog_WARN(TAG, "Unsupported command line syntax!");
4279  WLog_WARN(TAG, "FreeRDP 1.0 style syntax was dropped with version 3!");
4280  return -1;
4281  }
4282  else
4283  {
4284  if (allowUnknown)
4285  flags |= COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
4286 
4287  if (ext)
4288  {
4289  if (freerdp_client_settings_parse_connection_file(settings, argv[1]))
4290  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
4291  }
4292 
4293  if (assist)
4294  {
4295  if (freerdp_client_settings_parse_assistance_file(settings, argc, argv) < 0)
4296  return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
4297  }
4298 
4299  CommandLineClearArgumentsA(largs);
4300  status = CommandLineParseArgumentsA(argc, argv, largs, flags, settings,
4301  freerdp_client_command_line_pre_filter,
4302  freerdp_client_command_line_post_filter);
4303 
4304  if (status < 0)
4305  return status;
4306 
4307  prepare_default_settings(settings, largs, ext);
4308  }
4309 
4310  CommandLineFindArgumentA(largs, "v");
4311  arg = largs;
4312  errno = 0;
4313 
4314  /* Disable unicode input unless requested. */
4315  if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput, FALSE))
4316  return COMMAND_LINE_ERROR_MEMORY;
4317 
4318  do
4319  {
4320  BOOL enable = arg->Value ? TRUE : FALSE;
4321 
4322  if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT))
4323  continue;
4324 
4325  CommandLineSwitchStart(arg)
4326 
4327  CommandLineSwitchCase(arg, "v")
4328  {
4329  const int rc = parse_host_options(settings, arg);
4330  if (rc != 0)
4331  return fail_at(arg, rc);
4332  }
4333  CommandLineSwitchCase(arg, "spn-class")
4334  {
4335  if (!freerdp_settings_set_string(settings, FreeRDP_AuthenticationServiceClass,
4336  arg->Value))
4337  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
4338  }
4339  CommandLineSwitchCase(arg, "sspi-module")
4340  {
4341  if (!freerdp_settings_set_string(settings, FreeRDP_SspiModule, arg->Value))
4342  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
4343  }
4344  CommandLineSwitchCase(arg, "winscard-module")
4345  {
4346  if (!freerdp_settings_set_string(settings, FreeRDP_WinSCardModule, arg->Value))
4347  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
4348  }
4349  CommandLineSwitchCase(arg, "redirect-prefer")
4350  {
4351  const int rc = parse_redirect_prefer_options(settings, arg);
4352  if (rc != 0)
4353  return fail_at(arg, rc);
4354  }
4355  CommandLineSwitchCase(arg, "credentials-delegation")
4356  {
4357  if (!freerdp_settings_set_bool(settings, FreeRDP_DisableCredentialsDelegation, !enable))
4358  return fail_at(arg, COMMAND_LINE_ERROR);
4359  }
4360  CommandLineSwitchCase(arg, "prevent-session-lock")
4361  {
4362  const int rc = parse_prevent_session_lock_options(settings, arg);
4363  if (rc != 0)
4364  return fail_at(arg, rc);
4365  }
4366  CommandLineSwitchCase(arg, "vmconnect")
4367  {
4368  const int rc = parse_vmconnect_options(settings, arg);
4369  if (rc != 0)
4370  return fail_at(arg, rc);
4371  }
4372  CommandLineSwitchCase(arg, "w")
4373  {
4374  LONGLONG val = 0;
4375 
4376  if (!value_to_int(arg->Value, &val, -1, UINT32_MAX))
4377  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
4378 
4379  if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, (UINT32)val))
4380  return fail_at(arg, COMMAND_LINE_ERROR);
4381  }
4382  CommandLineSwitchCase(arg, "h")
4383  {
4384  LONGLONG val = 0;
4385 
4386  if (!value_to_int(arg->Value, &val, -1, UINT32_MAX))
4387  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
4388 
4389  if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, (UINT32)val))
4390  return fail_at(arg, COMMAND_LINE_ERROR);
4391  }
4392  CommandLineSwitchCase(arg, "size")
4393  {
4394  const int rc = parse_size_options(settings, arg);
4395  if (rc != 0)
4396  return fail_at(arg, rc);
4397  }
4398  CommandLineSwitchCase(arg, "f")
4399  {
4400  if (!freerdp_settings_set_bool(settings, FreeRDP_Fullscreen, enable))
4401  return fail_at(arg, COMMAND_LINE_ERROR);
4402  }
4403  CommandLineSwitchCase(arg, "suppress-output")
4404  {
4405  if (!freerdp_settings_set_bool(settings, FreeRDP_SuppressOutput, enable))
4406  return fail_at(arg, COMMAND_LINE_ERROR);
4407  }
4408  CommandLineSwitchCase(arg, "multimon")
4409  {
4410  if (!freerdp_settings_set_bool(settings, FreeRDP_UseMultimon, TRUE))
4411  return fail_at(arg, COMMAND_LINE_ERROR);
4412 
4413  if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
4414  {
4415  if (option_equals(arg->Value, str_force))
4416  {
4417  if (!freerdp_settings_set_bool(settings, FreeRDP_ForceMultimon, TRUE))
4418  return fail_at(arg, COMMAND_LINE_ERROR);
4419  }
4420  }
4421  }
4422  CommandLineSwitchCase(arg, "span")
4423  {
4424  if (!freerdp_settings_set_bool(settings, FreeRDP_SpanMonitors, enable))
4425  return fail_at(arg, COMMAND_LINE_ERROR);
4426  }
4427  CommandLineSwitchCase(arg, "workarea")
4428  {
4429  if (!freerdp_settings_set_bool(settings, FreeRDP_Workarea, enable))
4430  return fail_at(arg, COMMAND_LINE_ERROR);
4431  }
4432  CommandLineSwitchCase(arg, "monitors")
4433  {
4434  const int rc = parse_monitors_options(settings, arg);
4435  if (rc != 0)
4436  return fail_at(arg, rc);
4437  }
4438  CommandLineSwitchCase(arg, "t")
4439  {
4440  if (!freerdp_settings_set_string(settings, FreeRDP_WindowTitle, arg->Value))
4441  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
4442  }
4443  CommandLineSwitchCase(arg, "decorations")
4444  {
4445  if (!freerdp_settings_set_bool(settings, FreeRDP_Decorations, enable))
4446  return fail_at(arg, COMMAND_LINE_ERROR);
4447  }
4448  CommandLineSwitchCase(arg, "dynamic-resolution")
4449  {
4450  const int rc = parse_dynamic_resolution_options(settings, arg);
4451  if (rc != 0)
4452  return fail_at(arg, rc);
4453  }
4454  CommandLineSwitchCase(arg, "smart-sizing")
4455  {
4456  const int rc = parse_smart_sizing_options(settings, arg);
4457  if (rc != 0)
4458  return fail_at(arg, rc);
4459  }
4460  CommandLineSwitchCase(arg, "bpp")
4461  {
4462  const int rc = parse_bpp_options(settings, arg);
4463  if (rc != 0)
4464  return fail_at(arg, rc);
4465  }
4466  CommandLineSwitchCase(arg, "admin")
4467  {
4468  if (!freerdp_settings_set_bool(settings, FreeRDP_ConsoleSession, enable))
4469  return fail_at(arg, COMMAND_LINE_ERROR);
4470  }
4471  CommandLineSwitchCase(arg, "relax-order-checks")
4472  {
4473  if (!freerdp_settings_set_bool(settings, FreeRDP_AllowUnanouncedOrdersFromServer,
4474  enable))
4475  return fail_at(arg, COMMAND_LINE_ERROR);
4476  }
4477  CommandLineSwitchCase(arg, "restricted-admin")
4478  {
4479  if (!freerdp_settings_set_bool(settings, FreeRDP_ConsoleSession, enable))
4480  return fail_at(arg, COMMAND_LINE_ERROR);
4481  if (!freerdp_settings_set_bool(settings, FreeRDP_RestrictedAdminModeRequired, enable))
4482  return fail_at(arg, COMMAND_LINE_ERROR);
4483  }
4484  CommandLineSwitchCase(arg, "remoteGuard")
4485  {
4486  if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteCredentialGuard, TRUE))
4487  return fail_at(arg, COMMAND_LINE_ERROR);
4488  if (!freerdp_settings_set_bool(settings, FreeRDP_ExtSecurity, TRUE))
4489  return fail_at(arg, COMMAND_LINE_ERROR);
4490  }
4491  CommandLineSwitchCase(arg, "pth")
4492  {
4493  if (!freerdp_settings_set_bool(settings, FreeRDP_ConsoleSession, TRUE))
4494  return fail_at(arg, COMMAND_LINE_ERROR);
4495  if (!freerdp_settings_set_bool(settings, FreeRDP_RestrictedAdminModeRequired, TRUE))
4496  return fail_at(arg, COMMAND_LINE_ERROR);
4497 
4498  if (!freerdp_settings_set_string(settings, FreeRDP_PasswordHash, arg->Value))
4499  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
4500  }
4501  CommandLineSwitchCase(arg, "client-hostname")
4502  {
4503  if (!freerdp_settings_set_string(settings, FreeRDP_ClientHostname, arg->Value))
4504  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
4505  }
4506  CommandLineSwitchCase(arg, "kbd")
4507  {
4508  int rc = parse_kbd_options(settings, arg);
4509  if (rc != 0)
4510  return fail_at(arg, rc);
4511  }
4512 #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)
4513  CommandLineSwitchCase(arg, "kbd-remap")
4514  {
4515  WLog_WARN(TAG, "/kbd-remap:<key>=<value>,<key2>=<value2> is deprecated, use "
4516  "/kbd:remap:<key>=<value>,remap:<key2>=<value2>,... instead");
4517  if (!freerdp_settings_set_string(settings, FreeRDP_KeyboardRemappingList, arg->Value))
4518  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
4519  }
4520  CommandLineSwitchCase(arg, "kbd-lang")
4521  {
4522  LONGLONG val = 0;
4523 
4524  WLog_WARN(TAG, "/kbd-lang:<value> is deprecated, use /kbd:lang:<value> instead");
4525  if (!value_to_int(arg->Value, &val, 1, UINT32_MAX))
4526  {
4527  WLog_ERR(TAG, "Could not identify keyboard active language %s", arg->Value);
4528  WLog_ERR(TAG, "Use /list:kbd-lang to list available layouts");
4529  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
4530  }
4531 
4532  if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardCodePage, (UINT32)val))
4533  return fail_at(arg, COMMAND_LINE_ERROR);
4534  }
4535  CommandLineSwitchCase(arg, "kbd-type")
4536  {
4537  LONGLONG val = 0;
4538 
4539  WLog_WARN(TAG, "/kbd-type:<value> is deprecated, use /kbd:type:<value> instead");
4540  if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))
4541  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
4542 
4543  if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardType, (UINT32)val))
4544  return fail_at(arg, COMMAND_LINE_ERROR);
4545  }
4546  CommandLineSwitchCase(arg, "kbd-unicode")
4547  {
4548  WLog_WARN(TAG, "/kbd-unicode is deprecated, use /kbd:unicode[:on|off] instead");
4549  if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput, enable))
4550  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
4551  }
4552  CommandLineSwitchCase(arg, "kbd-subtype")
4553  {
4554  LONGLONG val = 0;
4555 
4556  WLog_WARN(TAG, "/kbd-subtype:<value> is deprecated, use /kbd:subtype:<value> instead");
4557  if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))
4558  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
4559 
4560  if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardSubType, (UINT32)val))
4561  return fail_at(arg, COMMAND_LINE_ERROR);
4562  }
4563  CommandLineSwitchCase(arg, "kbd-fn-key")
4564  {
4565  LONGLONG val = 0;
4566 
4567  WLog_WARN(TAG, "/kbd-fn-key:<value> is deprecated, use /kbd:fn-key:<value> instead");
4568  if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))
4569  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
4570 
4571  if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardFunctionKey, (UINT32)val))
4572  return fail_at(arg, COMMAND_LINE_ERROR);
4573  }
4574 #endif
4575  CommandLineSwitchCase(arg, "u")
4576  {
4577  WINPR_ASSERT(arg->Value);
4578  user = arg->Value;
4579  }
4580  CommandLineSwitchCase(arg, "d")
4581  {
4582  if (!freerdp_settings_set_string(settings, FreeRDP_Domain, arg->Value))
4583  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
4584  }
4585  CommandLineSwitchCase(arg, "p")
4586  {
4587  if (!freerdp_settings_set_string(settings, FreeRDP_Password, arg->Value))
4588  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
4589  }
4590  CommandLineSwitchCase(arg, "gateway")
4591  {
4592  if (!parse_gateway_options(settings, arg))
4593  return fail_at(arg, COMMAND_LINE_ERROR);
4594  }
4595  CommandLineSwitchCase(arg, "proxy")
4596  {
4597  const int rc = parse_proxy_options(settings, arg);
4598  if (rc != 0)
4599  return fail_at(arg, rc);
4600  }
4601 #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)
4602  CommandLineSwitchCase(arg, "g")
4603  {
4604  if (!parse_gateway_host_option(settings, arg->Value))
4605  return fail_at(arg, COMMAND_LINE_ERROR);
4606  }
4607  CommandLineSwitchCase(arg, "gu")
4608  {
4609  if (!parse_gateway_cred_option(settings, arg->Value, FreeRDP_GatewayUsername))
4610  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
4611  }
4612  CommandLineSwitchCase(arg, "gd")
4613  {
4614  if (!parse_gateway_cred_option(settings, arg->Value, FreeRDP_GatewayDomain))
4615  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
4616  }
4617  CommandLineSwitchCase(arg, "gp")
4618  {
4619  if (!parse_gateway_cred_option(settings, arg->Value, FreeRDP_GatewayPassword))
4620  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
4621  }
4622  CommandLineSwitchCase(arg, "gt")
4623  {
4624  if (!parse_gateway_type_option(settings, arg->Value))
4625  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
4626  }
4627  CommandLineSwitchCase(arg, "gat")
4628  {
4629  if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAccessToken, arg->Value))
4630  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
4631  }
4632  CommandLineSwitchCase(arg, "gateway-usage-method")
4633  {
4634  if (!parse_gateway_usage_option(settings, arg->Value))
4635  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
4636  }
4637 #endif
4638  CommandLineSwitchCase(arg, "azure")
4639  {
4640  int rc = parse_aad_options(settings, arg);
4641  if (rc != 0)
4642  return fail_at(arg, rc);
4643  }
4644  CommandLineSwitchCase(arg, "app")
4645  {
4646  int rc = parse_app_options(settings, arg);
4647  if (rc != 0)
4648  return fail_at(arg, rc);
4649  }
4650  CommandLineSwitchCase(arg, "load-balance-info")
4651  {
4652  WINPR_ASSERT(arg->Value);
4653  if (!freerdp_settings_set_pointer_len(settings, FreeRDP_LoadBalanceInfo, arg->Value,
4654  strlen(arg->Value)))
4655  return fail_at(arg, COMMAND_LINE_ERROR);
4656  }
4657 #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)
4658  CommandLineSwitchCase(arg, "app-workdir")
4659  {
4660  WLog_WARN(
4661  TAG,
4662  "/app-workdir:<directory> is deprecated, use /app:workdir:<directory> instead");
4663  if (!freerdp_settings_set_string(settings, FreeRDP_RemoteApplicationWorkingDir,
4664  arg->Value))
4665  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
4666  }
4667  CommandLineSwitchCase(arg, "app-name")
4668  {
4669  WLog_WARN(TAG, "/app-name:<directory> is deprecated, use /app:name:<name> instead");
4670  if (!freerdp_settings_set_string(settings, FreeRDP_RemoteApplicationName, arg->Value))
4671  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
4672  }
4673  CommandLineSwitchCase(arg, "app-icon")
4674  {
4675  WLog_WARN(TAG, "/app-icon:<filename> is deprecated, use /app:icon:<filename> instead");
4676  if (!freerdp_settings_set_string(settings, FreeRDP_RemoteApplicationIcon, arg->Value))
4677  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
4678  }
4679  CommandLineSwitchCase(arg, "app-cmd")
4680  {
4681  WLog_WARN(TAG, "/app-cmd:<command> is deprecated, use /app:cmd:<command> instead");
4682  if (!freerdp_settings_set_string(settings, FreeRDP_RemoteApplicationCmdLine,
4683  arg->Value))
4684  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
4685  }
4686  CommandLineSwitchCase(arg, "app-file")
4687  {
4688  WLog_WARN(TAG, "/app-file:<filename> is deprecated, use /app:file:<filename> instead");
4689  if (!freerdp_settings_set_string(settings, FreeRDP_RemoteApplicationFile, arg->Value))
4690  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
4691  }
4692  CommandLineSwitchCase(arg, "app-guid")
4693  {
4694  WLog_WARN(TAG, "/app-guid:<guid> is deprecated, use /app:guid:<guid> instead");
4695  if (!freerdp_settings_set_string(settings, FreeRDP_RemoteApplicationGuid, arg->Value))
4696  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
4697  }
4698 #endif
4699  CommandLineSwitchCase(arg, "compression")
4700  {
4701  if (!freerdp_settings_set_bool(settings, FreeRDP_CompressionEnabled, enable))
4702  return fail_at(arg, COMMAND_LINE_ERROR);
4703  }
4704  CommandLineSwitchCase(arg, "compression-level")
4705  {
4706  LONGLONG val = 0;
4707 
4708  if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))
4709  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
4710 
4711  if (!freerdp_settings_set_uint32(settings, FreeRDP_CompressionLevel, (UINT32)val))
4712  return fail_at(arg, COMMAND_LINE_ERROR);
4713  }
4714  CommandLineSwitchCase(arg, "drives")
4715  {
4716  if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectDrives, enable))
4717  return fail_at(arg, COMMAND_LINE_ERROR);
4718  }
4719  CommandLineSwitchCase(arg, "dump")
4720  {
4721  const int rc = parse_dump_options(settings, arg);
4722  if (rc != 0)
4723  return fail_at(arg, rc);
4724  }
4725  CommandLineSwitchCase(arg, "disable-output")
4726  {
4727  if (!freerdp_settings_set_bool(settings, FreeRDP_DeactivateClientDecoding, enable))
4728  return fail_at(arg, COMMAND_LINE_ERROR);
4729  }
4730  CommandLineSwitchCase(arg, "home-drive")
4731  {
4732  if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectHomeDrive, enable))
4733  return fail_at(arg, COMMAND_LINE_ERROR);
4734  }
4735  CommandLineSwitchCase(arg, "ipv4")
4736  {
4737  if (arg->Value != NULL && strncmp(arg->Value, str_force, ARRAYSIZE(str_force)) == 0)
4738  {
4739  if (!freerdp_settings_set_uint32(settings, FreeRDP_ForceIPvX, 4))
4740  return fail_at(arg, COMMAND_LINE_ERROR);
4741  }
4742  else
4743  {
4744  if (!freerdp_settings_set_bool(settings, FreeRDP_PreferIPv6OverIPv4, FALSE))
4745  return fail_at(arg, COMMAND_LINE_ERROR);
4746  }
4747  }
4748  CommandLineSwitchCase(arg, "ipv6")
4749  {
4750  if (arg->Value != NULL && strncmp(arg->Value, str_force, ARRAYSIZE(str_force)) == 0)
4751  {
4752  if (!freerdp_settings_set_uint32(settings, FreeRDP_ForceIPvX, 6))
4753  return fail_at(arg, COMMAND_LINE_ERROR);
4754  }
4755  else
4756  {
4757  if (!freerdp_settings_set_bool(settings, FreeRDP_PreferIPv6OverIPv4, TRUE))
4758  return fail_at(arg, COMMAND_LINE_ERROR);
4759  }
4760  }
4761  CommandLineSwitchCase(arg, "clipboard")
4762  {
4763  const int rc = parse_clipboard_options(settings, arg);
4764  if (rc != 0)
4765  return fail_at(arg, rc);
4766  }
4767  CommandLineSwitchCase(arg, "server-name")
4768  {
4769  if (!freerdp_settings_set_string(settings, FreeRDP_UserSpecifiedServerName, arg->Value))
4770  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
4771  }
4772  CommandLineSwitchCase(arg, "shell")
4773  {
4774  if (!freerdp_settings_set_string(settings, FreeRDP_AlternateShell, arg->Value))
4775  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
4776  }
4777  CommandLineSwitchCase(arg, "shell-dir")
4778  {
4779  if (!freerdp_settings_set_string(settings, FreeRDP_ShellWorkingDirectory, arg->Value))
4780  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
4781  }
4782  CommandLineSwitchCase(arg, "audio-mode")
4783  {
4784  const int rc = parse_audio_mode_options(settings, arg);
4785  if (rc != 0)
4786  return fail_at(arg, rc);
4787  }
4788  CommandLineSwitchCase(arg, "network")
4789  {
4790  const int rc = parse_network_options(settings, arg);
4791  if (rc != 0)
4792  return fail_at(arg, rc);
4793  }
4794  CommandLineSwitchCase(arg, "fonts")
4795  {
4796  if (!freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, enable))
4797  return fail_at(arg, COMMAND_LINE_ERROR);
4798  }
4799  CommandLineSwitchCase(arg, "wallpaper")
4800  {
4801  if (!freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, !enable))
4802  return fail_at(arg, COMMAND_LINE_ERROR);
4803  }
4804  CommandLineSwitchCase(arg, "window-drag")
4805  {
4806  if (!freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, !enable))
4807  return fail_at(arg, COMMAND_LINE_ERROR);
4808  }
4809  CommandLineSwitchCase(arg, "window-position")
4810  {
4811  unsigned long x = 0;
4812  unsigned long y = 0;
4813 
4814  if (!arg->Value)
4815  return fail_at(arg, COMMAND_LINE_ERROR_MISSING_ARGUMENT);
4816 
4817  if (!parseSizeValue(arg->Value, &x, &y) || x > UINT16_MAX || y > UINT16_MAX)
4818  {
4819  WLog_ERR(TAG, "invalid window-position argument");
4820  return fail_at(arg, COMMAND_LINE_ERROR_MISSING_ARGUMENT);
4821  }
4822 
4823  if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopPosX, (UINT32)x))
4824  return fail_at(arg, COMMAND_LINE_ERROR);
4825  if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopPosY, (UINT32)y))
4826  return fail_at(arg, COMMAND_LINE_ERROR);
4827  }
4828  CommandLineSwitchCase(arg, "menu-anims")
4829  {
4830  if (!freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, !enable))
4831  return fail_at(arg, COMMAND_LINE_ERROR);
4832  }
4833  CommandLineSwitchCase(arg, "themes")
4834  {
4835  if (!freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, !enable))
4836  return fail_at(arg, COMMAND_LINE_ERROR);
4837  }
4838  CommandLineSwitchCase(arg, "timeout")
4839  {
4840  ULONGLONG val = 0;
4841  if (!value_to_uint(arg->Value, &val, 1, 600000))
4842  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
4843  if (!freerdp_settings_set_uint32(settings, FreeRDP_TcpAckTimeout, (UINT32)val))
4844  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
4845  }
4846  CommandLineSwitchCase(arg, "timezone")
4847  {
4848  BOOL found = FALSE;
4849  DWORD index = 0;
4850  DYNAMIC_TIME_ZONE_INFORMATION info = { 0 };
4851  char TimeZoneKeyName[ARRAYSIZE(info.TimeZoneKeyName) + 1] = { 0 };
4852  while (EnumDynamicTimeZoneInformation(index++, &info) != ERROR_NO_MORE_ITEMS)
4853  {
4854  (void)ConvertWCharNToUtf8(info.TimeZoneKeyName, ARRAYSIZE(info.TimeZoneKeyName),
4855  TimeZoneKeyName, ARRAYSIZE(TimeZoneKeyName));
4856 
4857  WINPR_ASSERT(arg->Value);
4858  if (strncmp(TimeZoneKeyName, arg->Value, ARRAYSIZE(TimeZoneKeyName)) == 0)
4859  {
4860  found = TRUE;
4861  break;
4862  }
4863  }
4864  if (!found)
4865  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
4866 
4867  if (!freerdp_settings_set_string(settings, FreeRDP_DynamicDSTTimeZoneKeyName,
4868  TimeZoneKeyName))
4869  return fail_at(arg, COMMAND_LINE_ERROR);
4870 
4871  TIME_ZONE_INFORMATION* tz =
4872  freerdp_settings_get_pointer_writable(settings, FreeRDP_ClientTimeZone);
4873  if (!tz)
4874  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
4875 
4876  tz->Bias = info.Bias;
4877  tz->DaylightBias = info.DaylightBias;
4878  tz->DaylightDate = info.DaylightDate;
4879  memcpy(tz->DaylightName, info.DaylightName, sizeof(tz->DaylightName));
4880  tz->StandardBias = info.StandardBias;
4881  tz->StandardDate = info.StandardDate;
4882  memcpy(tz->StandardName, info.StandardName, sizeof(tz->StandardName));
4883  }
4884  CommandLineSwitchCase(arg, "aero")
4885  {
4886  if (!freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, enable))
4887  return fail_at(arg, COMMAND_LINE_ERROR);
4888  }
4889  CommandLineSwitchCase(arg, "gdi")
4890  {
4891  if (option_equals(arg->Value, "sw"))
4892  {
4893  if (!freerdp_settings_set_bool(settings, FreeRDP_SoftwareGdi, TRUE))
4894  return fail_at(arg, COMMAND_LINE_ERROR);
4895  }
4896  else if (option_equals(arg->Value, "hw"))
4897  {
4898  if (!freerdp_settings_set_bool(settings, FreeRDP_SoftwareGdi, FALSE))
4899  return fail_at(arg, COMMAND_LINE_ERROR);
4900  }
4901  else
4902  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
4903  }
4904  CommandLineSwitchCase(arg, "gfx")
4905  {
4906  int rc = parse_gfx_options(settings, arg);
4907  if (rc != 0)
4908  return fail_at(arg, rc);
4909  }
4910 #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)
4911  CommandLineSwitchCase(arg, "gfx-thin-client")
4912  {
4913  WLog_WARN(TAG, "/gfx-thin-client is deprecated, use /gfx:thin-client[:on|off] instead");
4914  if (!freerdp_settings_set_bool(settings, FreeRDP_GfxThinClient, enable))
4915  return fail_at(arg, COMMAND_LINE_ERROR);
4916 
4917  if (freerdp_settings_get_bool(settings, FreeRDP_GfxThinClient))
4918  {
4919  if (!freerdp_settings_set_bool(settings, FreeRDP_GfxSmallCache, TRUE))
4920  return fail_at(arg, COMMAND_LINE_ERROR);
4921  }
4922 
4923  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportGraphicsPipeline, TRUE))
4924  return fail_at(arg, COMMAND_LINE_ERROR);
4925  }
4926  CommandLineSwitchCase(arg, "gfx-small-cache")
4927  {
4928  WLog_WARN(TAG, "/gfx-small-cache is deprecated, use /gfx:small-cache[:on|off] instead");
4929  if (!freerdp_settings_set_bool(settings, FreeRDP_GfxSmallCache, enable))
4930  return fail_at(arg, COMMAND_LINE_ERROR);
4931 
4932  if (enable)
4933  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportGraphicsPipeline, TRUE))
4934  return fail_at(arg, COMMAND_LINE_ERROR);
4935  }
4936  CommandLineSwitchCase(arg, "gfx-progressive")
4937  {
4938  WLog_WARN(TAG, "/gfx-progressive is deprecated, use /gfx:progressive[:on|off] instead");
4939  if (!freerdp_settings_set_bool(settings, FreeRDP_GfxProgressive, enable))
4940  return fail_at(arg, COMMAND_LINE_ERROR);
4941  if (!freerdp_settings_set_bool(settings, FreeRDP_GfxThinClient, !enable))
4942  return fail_at(arg, COMMAND_LINE_ERROR);
4943 
4944  if (enable)
4945  {
4946  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportGraphicsPipeline, TRUE))
4947  return fail_at(arg, COMMAND_LINE_ERROR);
4948  }
4949  }
4950 #ifdef WITH_GFX_H264
4951  CommandLineSwitchCase(arg, "gfx-h264")
4952  {
4953  WLog_WARN(TAG, "/gfx-h264 is deprecated, use /gfx:avc420 instead");
4954  int rc = parse_gfx_options(settings, arg);
4955  if (rc != 0)
4956  return fail_at(arg, rc);
4957  }
4958 #endif
4959 #endif
4960  CommandLineSwitchCase(arg, "rfx")
4961  {
4962  if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, enable))
4963  return fail_at(arg, COMMAND_LINE_ERROR);
4964  }
4965  CommandLineSwitchCase(arg, "rfx-mode")
4966  {
4967  if (!arg->Value)
4968  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
4969 
4970  if (option_equals(arg->Value, "video"))
4971  {
4972  if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x00))
4973  return fail_at(arg, COMMAND_LINE_ERROR);
4974  }
4975  else if (option_equals(arg->Value, "image"))
4976  {
4977  if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxImageCodec, TRUE))
4978  return fail_at(arg, COMMAND_LINE_ERROR);
4979  if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x02))
4980  return fail_at(arg, COMMAND_LINE_ERROR);
4981  }
4982  }
4983  CommandLineSwitchCase(arg, "frame-ack")
4984  {
4985  LONGLONG val = 0;
4986 
4987  if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))
4988  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
4989 
4990  if (!freerdp_settings_set_uint32(settings, FreeRDP_FrameAcknowledge, (UINT32)val))
4991  return fail_at(arg, COMMAND_LINE_ERROR);
4992  }
4993  CommandLineSwitchCase(arg, "nsc")
4994  {
4995  if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, enable))
4996  return fail_at(arg, COMMAND_LINE_ERROR);
4997  }
4998 #if defined(WITH_JPEG)
4999  CommandLineSwitchCase(arg, "jpeg")
5000  {
5001  if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, enable))
5002  return fail_at(arg, COMMAND_LINE_ERROR);
5003  if (!freerdp_settings_set_uint32(settings, FreeRDP_JpegQuality, 75))
5004  return fail_at(arg, COMMAND_LINE_ERROR);
5005  }
5006  CommandLineSwitchCase(arg, "jpeg-quality")
5007  {
5008  LONGLONG val = 0;
5009 
5010  if (!value_to_int(arg->Value, &val, 0, 100))
5011  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
5012 
5013  if (!freerdp_settings_set_uint32(settings, FreeRDP_JpegQuality, (UINT32)val))
5014  return fail_at(arg, COMMAND_LINE_ERROR);
5015  }
5016 #endif
5017  CommandLineSwitchCase(arg, "nego")
5018  {
5019  if (!freerdp_settings_set_bool(settings, FreeRDP_NegotiateSecurityLayer, enable))
5020  return fail_at(arg, COMMAND_LINE_ERROR);
5021  }
5022  CommandLineSwitchCase(arg, "pcb")
5023  {
5024  if (!freerdp_settings_set_bool(settings, FreeRDP_SendPreconnectionPdu, TRUE))
5025  return fail_at(arg, COMMAND_LINE_ERROR);
5026 
5027  if (!freerdp_settings_set_string(settings, FreeRDP_PreconnectionBlob, arg->Value))
5028  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
5029  }
5030  CommandLineSwitchCase(arg, "pcid")
5031  {
5032  LONGLONG val = 0;
5033 
5034  if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))
5035  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
5036 
5037  if (!freerdp_settings_set_bool(settings, FreeRDP_SendPreconnectionPdu, TRUE))
5038  return fail_at(arg, COMMAND_LINE_ERROR);
5039  if (!freerdp_settings_set_uint32(settings, FreeRDP_PreconnectionId, (UINT32)val))
5040  return fail_at(arg, COMMAND_LINE_ERROR);
5041  }
5042 #ifdef _WIN32
5043  CommandLineSwitchCase(arg, "connect-child-session")
5044  {
5045  if (!freerdp_settings_set_string(settings, FreeRDP_AuthenticationServiceClass,
5046  "vs-debug") ||
5047  !freerdp_settings_set_string(settings, FreeRDP_ServerHostname, "localhost") ||
5048  !freerdp_settings_set_string(settings, FreeRDP_AuthenticationPackageList, "ntlm") ||
5049  !freerdp_settings_set_string(settings, FreeRDP_ClientAddress, "0.0.0.0") ||
5050  !freerdp_settings_set_bool(settings, FreeRDP_NegotiateSecurityLayer, FALSE) ||
5051  !freerdp_settings_set_bool(settings, FreeRDP_VmConnectMode, TRUE) ||
5052  !freerdp_settings_set_bool(settings, FreeRDP_ConnectChildSession, TRUE) ||
5053  !freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, TRUE) ||
5054  !freerdp_settings_set_uint32(settings, FreeRDP_AuthenticationLevel, 0) ||
5055  !freerdp_settings_set_bool(settings, FreeRDP_NetworkAutoDetect, TRUE) ||
5056  !freerdp_settings_set_uint32(settings, FreeRDP_ConnectionType, CONNECTION_TYPE_LAN))
5057  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
5058  }
5059 #endif
5060  CommandLineSwitchCase(arg, "sec")
5061  {
5062  const int rc = parse_sec_options(settings, arg);
5063  if (rc != 0)
5064  return fail_at(arg, rc);
5065  }
5066  CommandLineSwitchCase(arg, "encryption-methods")
5067  {
5068  const int rc = parse_encryption_methods_options(settings, arg);
5069  if (rc != 0)
5070  return fail_at(arg, rc);
5071  }
5072  CommandLineSwitchCase(arg, "args-from")
5073  {
5074  WLog_ERR(TAG, "/args-from:%s can not be used in combination with other arguments!",
5075  arg->Value);
5076  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
5077  }
5078  CommandLineSwitchCase(arg, "from-stdin")
5079  {
5080  if (!freerdp_settings_set_bool(settings, FreeRDP_CredentialsFromStdin, TRUE))
5081  return fail_at(arg, COMMAND_LINE_ERROR);
5082 
5083  if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
5084  {
5085  if (!arg->Value)
5086  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
5087  promptForPassword = (option_equals(arg->Value, str_force));
5088 
5089  if (!promptForPassword)
5090  return fail_at(arg, COMMAND_LINE_ERROR);
5091  }
5092  }
5093  CommandLineSwitchCase(arg, "log-level")
5094  {
5095  wLog* root = WLog_GetRoot();
5096 
5097  if (!WLog_SetStringLogLevel(root, arg->Value))
5098  return fail_at(arg, COMMAND_LINE_ERROR);
5099  }
5100  CommandLineSwitchCase(arg, "log-filters")
5101  {
5102  if (!WLog_AddStringLogFilters(arg->Value))
5103  return fail_at(arg, COMMAND_LINE_ERROR);
5104  }
5105 #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)
5106  CommandLineSwitchCase(arg, "sec-rdp")
5107  {
5108  WLog_WARN(TAG, "/sec-rdp is deprecated, use /sec:rdp[:on|off] instead");
5109  if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, enable))
5110  return fail_at(arg, COMMAND_LINE_ERROR);
5111  }
5112  CommandLineSwitchCase(arg, "sec-tls")
5113  {
5114  WLog_WARN(TAG, "/sec-tls is deprecated, use /sec:tls[:on|off] instead");
5115  if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, enable))
5116  return fail_at(arg, COMMAND_LINE_ERROR);
5117  }
5118  CommandLineSwitchCase(arg, "sec-nla")
5119  {
5120  WLog_WARN(TAG, "/sec-nla is deprecated, use /sec:nla[:on|off] instead");
5121  if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, enable))
5122  return fail_at(arg, COMMAND_LINE_ERROR);
5123  }
5124  CommandLineSwitchCase(arg, "sec-ext")
5125  {
5126  WLog_WARN(TAG, "/sec-ext is deprecated, use /sec:ext[:on|off] instead");
5127  if (!freerdp_settings_set_bool(settings, FreeRDP_ExtSecurity, enable))
5128  return fail_at(arg, COMMAND_LINE_ERROR);
5129  }
5130 #endif
5131  CommandLineSwitchCase(arg, "tls")
5132  {
5133  int rc = parse_tls_options(settings, arg);
5134  if (rc != 0)
5135  return fail_at(arg, rc);
5136  }
5137 #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)
5138  CommandLineSwitchCase(arg, "tls-ciphers")
5139  {
5140  WLog_WARN(TAG, "/tls-ciphers:<cipher list> is deprecated, use "
5141  "/tls:ciphers:<cipher list> instead");
5142  int rc = parse_tls_cipher_options(settings, arg);
5143  if (rc != 0)
5144  return fail_at(arg, rc);
5145  }
5146  CommandLineSwitchCase(arg, "tls-seclevel")
5147  {
5148  WLog_WARN(TAG,
5149  "/tls-seclevel:<level> is deprecated, use /tls:sec-level:<level> instead");
5150  int rc = parse_tls_cipher_options(settings, arg);
5151  if (rc != 0)
5152  return fail_at(arg, rc);
5153  }
5154  CommandLineSwitchCase(arg, "tls-secrets-file")
5155  {
5156  WLog_WARN(TAG, "/tls-secrets-file:<filename> is deprecated, use "
5157  "/tls:secrets-file:<filename> instead");
5158  int rc = parse_tls_cipher_options(settings, arg);
5159  if (rc != 0)
5160  return fail_at(arg, rc);
5161  }
5162  CommandLineSwitchCase(arg, "enforce-tlsv1_2")
5163  {
5164  WLog_WARN(TAG, "/enforce-tlsv1_2 is deprecated, use /tls:enforce:1.2 instead");
5165  int rc = parse_tls_cipher_options(settings, arg);
5166  if (rc != 0)
5167  return fail_at(arg, rc);
5168  }
5169 #endif
5170  CommandLineSwitchCase(arg, "cert")
5171  {
5172  const int rc = parse_cert_options(settings, arg);
5173  if (rc != 0)
5174  return fail_at(arg, rc);
5175  }
5176 
5177 #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)
5178  CommandLineSwitchCase(arg, "cert-name")
5179  {
5180  WLog_WARN(TAG, "/cert-name is deprecated, use /cert:name instead");
5181  if (!freerdp_settings_set_string(settings, FreeRDP_CertificateName, arg->Value))
5182  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
5183  }
5184  CommandLineSwitchCase(arg, "cert-ignore")
5185  {
5186  WLog_WARN(TAG, "/cert-ignore is deprecated, use /cert:ignore instead");
5187  if (!freerdp_settings_set_bool(settings, FreeRDP_IgnoreCertificate, enable))
5188  return fail_at(arg, COMMAND_LINE_ERROR);
5189  }
5190  CommandLineSwitchCase(arg, "cert-tofu")
5191  {
5192  WLog_WARN(TAG, "/cert-tofu is deprecated, use /cert:tofu instead");
5193  if (!freerdp_settings_set_bool(settings, FreeRDP_AutoAcceptCertificate, enable))
5194  return fail_at(arg, COMMAND_LINE_ERROR);
5195  }
5196  CommandLineSwitchCase(arg, "cert-deny")
5197  {
5198  WLog_WARN(TAG, "/cert-deny is deprecated, use /cert:deny instead");
5199  if (!freerdp_settings_set_bool(settings, FreeRDP_AutoDenyCertificate, enable))
5200  return fail_at(arg, COMMAND_LINE_ERROR);
5201  }
5202 #endif
5203  CommandLineSwitchCase(arg, "authentication")
5204  {
5205  if (!freerdp_settings_set_bool(settings, FreeRDP_Authentication, enable))
5206  return fail_at(arg, COMMAND_LINE_ERROR);
5207  }
5208  CommandLineSwitchCase(arg, "encryption")
5209  {
5210  if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, !enable))
5211  return fail_at(arg, COMMAND_LINE_ERROR);
5212  }
5213  CommandLineSwitchCase(arg, "grab-keyboard")
5214  {
5215  if (!freerdp_settings_set_bool(settings, FreeRDP_GrabKeyboard, enable))
5216  return fail_at(arg, COMMAND_LINE_ERROR);
5217  }
5218  CommandLineSwitchCase(arg, "grab-mouse")
5219  {
5220  if (!freerdp_settings_set_bool(settings, FreeRDP_GrabMouse, enable))
5221  return fail_at(arg, COMMAND_LINE_ERROR);
5222  }
5223  CommandLineSwitchCase(arg, "mouse-relative")
5224  {
5225  if (!freerdp_settings_set_bool(settings, FreeRDP_MouseUseRelativeMove, enable))
5226  return fail_at(arg, COMMAND_LINE_ERROR);
5227  }
5228  CommandLineSwitchCase(arg, "mouse")
5229  {
5230  const int rc = parse_mouse_options(settings, arg);
5231  if (rc != 0)
5232  return fail_at(arg, rc);
5233  }
5234  CommandLineSwitchCase(arg, "unmap-buttons")
5235  {
5236  if (!freerdp_settings_set_bool(settings, FreeRDP_UnmapButtons, enable))
5237  return fail_at(arg, COMMAND_LINE_ERROR);
5238  }
5239  CommandLineSwitchCase(arg, "toggle-fullscreen")
5240  {
5241  if (!freerdp_settings_set_bool(settings, FreeRDP_ToggleFullscreen, enable))
5242  return fail_at(arg, COMMAND_LINE_ERROR);
5243  }
5244  CommandLineSwitchCase(arg, "force-console-callbacks")
5245  {
5246  if (!freerdp_settings_set_bool(settings, FreeRDP_UseCommonStdioCallbacks, enable))
5247  return fail_at(arg, COMMAND_LINE_ERROR);
5248  }
5249  CommandLineSwitchCase(arg, "floatbar")
5250  {
5251  const int rc = parse_floatbar_options(settings, arg);
5252  if (rc != 0)
5253  return fail_at(arg, rc);
5254  }
5255  CommandLineSwitchCase(arg, "mouse-motion")
5256  {
5257  if (!freerdp_settings_set_bool(settings, FreeRDP_MouseMotion, enable))
5258  return fail_at(arg, COMMAND_LINE_ERROR);
5259  }
5260  CommandLineSwitchCase(arg, "parent-window")
5261  {
5262  ULONGLONG val = 0;
5263 
5264  if (!value_to_uint(arg->Value, &val, 0, UINT64_MAX))
5265  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
5266 
5267  if (!freerdp_settings_set_uint64(settings, FreeRDP_ParentWindowId, (UINT64)val))
5268  return fail_at(arg, COMMAND_LINE_ERROR);
5269  }
5270  CommandLineSwitchCase(arg, "client-build-number")
5271  {
5272  ULONGLONG val = 0;
5273 
5274  if (!value_to_uint(arg->Value, &val, 0, UINT32_MAX))
5275  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
5276  if (!freerdp_settings_set_uint32(settings, FreeRDP_ClientBuild, (UINT32)val))
5277  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
5278  }
5279  CommandLineSwitchCase(arg, "cache")
5280  {
5281  int rc = parse_cache_options(settings, arg);
5282  if (rc != 0)
5283  return fail_at(arg, rc);
5284  }
5285 #if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)
5286  CommandLineSwitchCase(arg, "bitmap-cache")
5287  {
5288  WLog_WARN(TAG, "/bitmap-cache is deprecated, use /cache:bitmap[:on|off] instead");
5289  if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheEnabled, enable))
5290  return fail_at(arg, COMMAND_LINE_ERROR);
5291  }
5292  CommandLineSwitchCase(arg, "persist-cache")
5293  {
5294  WLog_WARN(TAG, "/persist-cache is deprecated, use /cache:persist[:on|off] instead");
5295  if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled, enable))
5296  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
5297  }
5298  CommandLineSwitchCase(arg, "persist-cache-file")
5299  {
5300  WLog_WARN(TAG, "/persist-cache-file:<filename> is deprecated, use "
5301  "/cache:persist-file:<filename> instead");
5302  if (!freerdp_settings_set_string(settings, FreeRDP_BitmapCachePersistFile, arg->Value))
5303  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
5304 
5305  if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled, TRUE))
5306  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
5307  }
5308  CommandLineSwitchCase(arg, "offscreen-cache")
5309  {
5310  WLog_WARN(TAG, "/bitmap-cache is deprecated, use /cache:bitmap[:on|off] instead");
5311  if (!freerdp_settings_set_uint32(settings, FreeRDP_OffscreenSupportLevel,
5312  (UINT32)enable))
5313  return fail_at(arg, COMMAND_LINE_ERROR);
5314  }
5315  CommandLineSwitchCase(arg, "glyph-cache")
5316  {
5317  WLog_WARN(TAG, "/glyph-cache is deprecated, use /cache:glyph[:on|off] instead");
5318  if (!freerdp_settings_set_uint32(settings, FreeRDP_GlyphSupportLevel,
5319  arg->Value ? GLYPH_SUPPORT_FULL : GLYPH_SUPPORT_NONE))
5320  return fail_at(arg, COMMAND_LINE_ERROR);
5321  }
5322  CommandLineSwitchCase(arg, "codec-cache")
5323  {
5324  WLog_WARN(TAG,
5325  "/codec-cache:<option> is deprecated, use /cache:codec:<option> instead");
5326  const int rc = parse_codec_cache_options(settings, arg);
5327  if (rc != 0)
5328  return fail_at(arg, rc);
5329  }
5330 #endif
5331  CommandLineSwitchCase(arg, "max-fast-path-size")
5332  {
5333  LONGLONG val = 0;
5334 
5335  if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))
5336  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
5337 
5338  if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
5339  (UINT32)val))
5340  return fail_at(arg, COMMAND_LINE_ERROR);
5341  }
5342  CommandLineSwitchCase(arg, "auto-request-control")
5343  {
5344  if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteAssistanceRequestControl,
5345  enable))
5346  return fail_at(arg, COMMAND_LINE_ERROR);
5347  }
5348  CommandLineSwitchCase(arg, "async-update")
5349  {
5350  if (!freerdp_settings_set_bool(settings, FreeRDP_AsyncUpdate, enable))
5351  return fail_at(arg, COMMAND_LINE_ERROR);
5352  }
5353  CommandLineSwitchCase(arg, "async-channels")
5354  {
5355  if (!freerdp_settings_set_bool(settings, FreeRDP_AsyncChannels, enable))
5356  return fail_at(arg, COMMAND_LINE_ERROR);
5357  }
5358  CommandLineSwitchCase(arg, "wm-class")
5359  {
5360  if (!freerdp_settings_set_string(settings, FreeRDP_WmClass, arg->Value))
5361  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
5362  }
5363  CommandLineSwitchCase(arg, "play-rfx")
5364  {
5365  if (!freerdp_settings_set_string(settings, FreeRDP_PlayRemoteFxFile, arg->Value))
5366  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
5367 
5368  if (!freerdp_settings_set_bool(settings, FreeRDP_PlayRemoteFx, TRUE))
5369  return fail_at(arg, COMMAND_LINE_ERROR);
5370  }
5371  CommandLineSwitchCase(arg, "auth-only")
5372  {
5373  if (!freerdp_settings_set_bool(settings, FreeRDP_AuthenticationOnly, enable))
5374  return fail_at(arg, COMMAND_LINE_ERROR);
5375  }
5376  CommandLineSwitchCase(arg, "auth-pkg-list")
5377  {
5378  if (!freerdp_settings_set_string(settings, FreeRDP_AuthenticationPackageList,
5379  arg->Value))
5380  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
5381  }
5382  CommandLineSwitchCase(arg, "auto-reconnect")
5383  {
5384  if (!freerdp_settings_set_bool(settings, FreeRDP_AutoReconnectionEnabled, enable))
5385  return fail_at(arg, COMMAND_LINE_ERROR);
5386  }
5387  CommandLineSwitchCase(arg, "auto-reconnect-max-retries")
5388  {
5389  LONGLONG val = 0;
5390 
5391  if (!value_to_int(arg->Value, &val, 0, 1000))
5392  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
5393 
5394  if (!freerdp_settings_set_uint32(settings, FreeRDP_AutoReconnectMaxRetries,
5395  (UINT32)val))
5396  return fail_at(arg, COMMAND_LINE_ERROR);
5397  }
5398  CommandLineSwitchCase(arg, "reconnect-cookie")
5399  {
5400  const int rc = parse_reconnect_cookie_options(settings, arg);
5401  if (rc != 0)
5402  return fail_at(arg, rc);
5403  }
5404  CommandLineSwitchCase(arg, "print-reconnect-cookie")
5405  {
5406  if (!freerdp_settings_set_bool(settings, FreeRDP_PrintReconnectCookie, enable))
5407  return fail_at(arg, COMMAND_LINE_ERROR);
5408  }
5409  CommandLineSwitchCase(arg, "pwidth")
5410  {
5411  LONGLONG val = 0;
5412 
5413  if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))
5414  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
5415 
5416  if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopPhysicalWidth, (UINT32)val))
5417  return fail_at(arg, COMMAND_LINE_ERROR);
5418  }
5419  CommandLineSwitchCase(arg, "pheight")
5420  {
5421  LONGLONG val = 0;
5422 
5423  if (!value_to_int(arg->Value, &val, 0, UINT32_MAX))
5424  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
5425 
5426  if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopPhysicalHeight, (UINT32)val))
5427  return fail_at(arg, COMMAND_LINE_ERROR);
5428  }
5429  CommandLineSwitchCase(arg, "orientation")
5430  {
5431  LONGLONG val = 0;
5432 
5433  if (!value_to_int(arg->Value, &val, 0, UINT16_MAX))
5434  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
5435 
5436  if (!freerdp_settings_set_uint16(settings, FreeRDP_DesktopOrientation, (UINT16)val))
5437  return fail_at(arg, COMMAND_LINE_ERROR);
5438  }
5439  CommandLineSwitchCase(arg, "old-license")
5440  {
5441  if (!freerdp_settings_set_bool(settings, FreeRDP_OldLicenseBehaviour, TRUE))
5442  return fail_at(arg, COMMAND_LINE_ERROR);
5443  }
5444  CommandLineSwitchCase(arg, "scale")
5445  {
5446  const int rc = parse_scale_options(settings, arg);
5447  if (rc != 0)
5448  return fail_at(arg, rc);
5449  }
5450  CommandLineSwitchCase(arg, "scale-desktop")
5451  {
5452  LONGLONG val = 0;
5453 
5454  if (!value_to_int(arg->Value, &val, 100, 500))
5455  return fail_at(arg, COMMAND_LINE_ERROR);
5456 
5457  if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopScaleFactor, (UINT32)val))
5458  return fail_at(arg, COMMAND_LINE_ERROR);
5459  }
5460  CommandLineSwitchCase(arg, "scale-device")
5461  {
5462  const int rc = parse_scale_device_options(settings, arg);
5463  if (rc != 0)
5464  return fail_at(arg, rc);
5465  }
5466  CommandLineSwitchCase(arg, "action-script")
5467  {
5468  if (!freerdp_settings_set_string(settings, FreeRDP_ActionScript, arg->Value))
5469  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
5470  }
5471  CommandLineSwitchCase(arg, RDP2TCP_DVC_CHANNEL_NAME)
5472  {
5473  if (!freerdp_settings_set_string(settings, FreeRDP_RDP2TCPArgs, arg->Value))
5474  return fail_at(arg, COMMAND_LINE_ERROR_MEMORY);
5475  }
5476  CommandLineSwitchCase(arg, "fipsmode")
5477  {
5478  if (!freerdp_settings_set_bool(settings, FreeRDP_FIPSMode, enable))
5479  return fail_at(arg, COMMAND_LINE_ERROR);
5480  }
5481  CommandLineSwitchCase(arg, "smartcard-logon")
5482  {
5483  const int rc = parse_smartcard_logon_options(settings, arg);
5484  if (rc != 0)
5485  return fail_at(arg, rc);
5486  }
5487  CommandLineSwitchCase(arg, "tune")
5488  {
5489  const int rc = parse_tune_options(settings, arg);
5490  if (rc != 0)
5491  return fail_at(arg, rc);
5492  }
5493  CommandLineSwitchDefault(arg)
5494  {
5495  if (handle_option)
5496  {
5497  const int rc = handle_option(arg, handle_userdata);
5498  if (rc != 0)
5499  return fail_at(arg, rc);
5500  }
5501  }
5502  CommandLineSwitchEnd(arg)
5503  } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
5504 
5505  if (user)
5506  {
5507  if (!freerdp_settings_get_string(settings, FreeRDP_Domain) && user)
5508  {
5509  if (!freerdp_settings_set_string(settings, FreeRDP_Username, NULL))
5510  return COMMAND_LINE_ERROR;
5511 
5512  if (!freerdp_settings_set_string(settings, FreeRDP_Domain, NULL))
5513  return COMMAND_LINE_ERROR;
5514 
5515  if (!freerdp_parse_username_settings(user, settings, FreeRDP_Username, FreeRDP_Domain))
5516  return COMMAND_LINE_ERROR;
5517  }
5518  else
5519  {
5520  if (!freerdp_settings_set_string(settings, FreeRDP_Username, user))
5521  return COMMAND_LINE_ERROR;
5522  }
5523  }
5524 
5525  if (promptForPassword)
5526  {
5527  freerdp* instance = freerdp_settings_get_pointer_writable(settings, FreeRDP_instance);
5528  if (!freerdp_settings_get_string(settings, FreeRDP_Password))
5529  {
5530  char buffer[512 + 1] = { 0 };
5531 
5532  if (!freerdp_passphrase_read(instance->context, "Password: ", buffer,
5533  ARRAYSIZE(buffer) - 1, 1))
5534  return COMMAND_LINE_ERROR;
5535  if (!freerdp_settings_set_string(settings, FreeRDP_Password, buffer))
5536  return COMMAND_LINE_ERROR;
5537  }
5538 
5539  if (freerdp_settings_get_bool(settings, FreeRDP_GatewayEnabled) &&
5540  !freerdp_settings_get_bool(settings, FreeRDP_GatewayUseSameCredentials))
5541  {
5542  if (!freerdp_settings_get_string(settings, FreeRDP_GatewayPassword))
5543  {
5544  char buffer[512 + 1] = { 0 };
5545 
5546  if (!freerdp_passphrase_read(instance->context, "Gateway Password: ", buffer,
5547  ARRAYSIZE(buffer) - 1, 1))
5548  return COMMAND_LINE_ERROR;
5549  if (!freerdp_settings_set_string(settings, FreeRDP_GatewayPassword, buffer))
5550  return COMMAND_LINE_ERROR;
5551  }
5552  }
5553  }
5554 
5555  freerdp_performance_flags_make(settings);
5556 
5557  if (freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec) ||
5558  freerdp_settings_get_bool(settings, FreeRDP_NSCodec) ||
5559  freerdp_settings_get_bool(settings, FreeRDP_SupportGraphicsPipeline))
5560  {
5561  if (!freerdp_settings_set_bool(settings, FreeRDP_FastPathOutput, TRUE))
5562  return COMMAND_LINE_ERROR;
5563  if (!freerdp_settings_set_bool(settings, FreeRDP_FrameMarkerCommandEnabled, TRUE))
5564  return COMMAND_LINE_ERROR;
5565  }
5566 
5567  arg = CommandLineFindArgumentA(largs, "port");
5568  if (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT)
5569  {
5570  LONGLONG val = 0;
5571 
5572  if (!value_to_int(arg->Value, &val, 1, UINT16_MAX))
5573  return fail_at(arg, COMMAND_LINE_ERROR_UNEXPECTED_VALUE);
5574 
5575  if (!freerdp_settings_set_uint32(settings, FreeRDP_ServerPort, (UINT32)val))
5576  return fail_at(arg, COMMAND_LINE_ERROR);
5577  }
5578 
5579  if (freerdp_settings_get_bool(settings, FreeRDP_VmConnectMode))
5580  {
5581  const COMMAND_LINE_ARGUMENT_A* nego = CommandLineFindArgumentA(largs, "nego");
5582  if (nego)
5583  return fail_at(arg, COMMAND_LINE_ERROR);
5584 
5585  const UINT32 port = freerdp_settings_get_uint32(settings, FreeRDP_ServerPort);
5586  WLog_INFO(TAG, "/vmconnect uses custom port %" PRIu32, port);
5587  }
5588 
5589  fill_credential_strings(largs);
5590 
5591  return status;
5592 }
5593 
5594 static void argv_free(int* pargc, char** pargv[])
5595 {
5596  WINPR_ASSERT(pargc);
5597  WINPR_ASSERT(pargv);
5598  const int argc = *pargc;
5599  char** argv = *pargv;
5600  *pargc = 0;
5601  *pargv = NULL;
5602 
5603  if (!argv)
5604  return;
5605  for (int x = 0; x < argc; x++)
5606  free(argv[x]);
5607  free((void*)argv);
5608 }
5609 
5610 static BOOL argv_append(int* pargc, char** pargv[], char* what)
5611 {
5612  WINPR_ASSERT(pargc);
5613  WINPR_ASSERT(pargv);
5614 
5615  if (*pargc < 0)
5616  return FALSE;
5617 
5618  if (!what)
5619  return FALSE;
5620 
5621  int nargc = *pargc + 1;
5622  char** tmp = (char**)realloc((void*)*pargv, (size_t)nargc * sizeof(char*));
5623  if (!tmp)
5624  return FALSE;
5625 
5626  tmp[*pargc] = what;
5627  *pargv = tmp;
5628  *pargc = nargc;
5629  return TRUE;
5630 }
5631 
5632 static BOOL argv_append_dup(int* pargc, char** pargv[], const char* what)
5633 {
5634  char* copy = NULL;
5635  if (what)
5636  copy = _strdup(what);
5637 
5638  const BOOL rc = argv_append(pargc, pargv, copy);
5639  if (!rc)
5640  free(copy);
5641  return rc;
5642 }
5643 
5644 static BOOL args_from_fp(FILE* fp, int* aargc, char** aargv[], const char* file, const char* cmd)
5645 {
5646  BOOL success = FALSE;
5647 
5648  WINPR_ASSERT(aargc);
5649  WINPR_ASSERT(aargv);
5650  WINPR_ASSERT(cmd);
5651 
5652  if (!fp)
5653  {
5654  WLog_ERR(TAG, "Failed to read command line options from file '%s'", file);
5655  return FALSE;
5656  }
5657  if (!argv_append_dup(aargc, aargv, cmd))
5658  goto fail;
5659  while (!feof(fp))
5660  {
5661  char* line = NULL;
5662  size_t size = 0;
5663  INT64 rc = GetLine(&line, &size, fp);
5664  if ((rc < 0) || !line)
5665  {
5666  /* abort if GetLine failed due to reaching EOF */
5667  if (feof(fp))
5668  break;
5669  goto fail;
5670  }
5671 
5672  while (rc > 0)
5673  {
5674  const char cur = (line[rc - 1]);
5675  if ((cur == '\n') || (cur == '\r'))
5676  {
5677  line[rc - 1] = '\0';
5678  rc--;
5679  }
5680  else
5681  break;
5682  }
5683  /* abort on empty lines */
5684  if (rc == 0)
5685  {
5686  free(line);
5687  break;
5688  }
5689  if (!argv_append(aargc, aargv, line))
5690  {
5691  free(line);
5692  goto fail;
5693  }
5694  }
5695 
5696  success = TRUE;
5697 fail:
5698  fclose(fp);
5699  if (!success)
5700  argv_free(aargc, aargv);
5701  return success;
5702 }
5703 
5704 static BOOL args_from_env(const char* name, int* aargc, char** aargv[], const char* arg,
5705  const char* cmd)
5706 {
5707  BOOL success = FALSE;
5708  char* env = NULL;
5709 
5710  WINPR_ASSERT(aargc);
5711  WINPR_ASSERT(aargv);
5712  WINPR_ASSERT(cmd);
5713 
5714  if (!name)
5715  {
5716  WLog_ERR(TAG, "%s - environment variable name empty", arg);
5717  goto cleanup;
5718  }
5719 
5720  const DWORD size = GetEnvironmentVariableX(name, env, 0);
5721  if (size == 0)
5722  {
5723  WLog_ERR(TAG, "%s - no environment variable '%s'", arg, name);
5724  goto cleanup;
5725  }
5726  env = calloc(size + 1, sizeof(char));
5727  if (!env)
5728  goto cleanup;
5729  const DWORD rc = GetEnvironmentVariableX(name, env, size);
5730  if (rc != size - 1)
5731  goto cleanup;
5732  if (rc == 0)
5733  {
5734  WLog_ERR(TAG, "%s - environment variable '%s' is empty", arg);
5735  goto cleanup;
5736  }
5737 
5738  if (!argv_append_dup(aargc, aargv, cmd))
5739  goto cleanup;
5740 
5741  char* context = NULL;
5742  char* tok = strtok_s(env, "\n", &context);
5743  while (tok)
5744  {
5745  if (!argv_append_dup(aargc, aargv, tok))
5746  goto cleanup;
5747  tok = strtok_s(NULL, "\n", &context);
5748  }
5749 
5750  success = TRUE;
5751 cleanup:
5752  free(env);
5753  if (!success)
5754  argv_free(aargc, aargv);
5755  return success;
5756 }
5757 
5758 int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, int oargc,
5759  char* oargv[], BOOL allowUnknown)
5760 {
5761  return freerdp_client_settings_parse_command_line_arguments_ex(
5762  settings, oargc, oargv, allowUnknown, NULL, 0, NULL, NULL);
5763 }
5764 
5765 int freerdp_client_settings_parse_command_line_arguments_ex(
5766  rdpSettings* settings, int oargc, char** oargv, BOOL allowUnknown,
5767  COMMAND_LINE_ARGUMENT_A* args, size_t count,
5768  int (*handle_option)(const COMMAND_LINE_ARGUMENT_A* arg, void* custom), void* handle_userdata)
5769 {
5770  int argc = oargc;
5771  char** argv = oargv;
5772  int res = -1;
5773  int aargc = 0;
5774  char** aargv = NULL;
5775  if ((argc == 2) && option_starts_with("/args-from:", argv[1]))
5776  {
5777  BOOL success = FALSE;
5778  const char* file = strchr(argv[1], ':') + 1;
5779  FILE* fp = stdin;
5780 
5781  if (option_starts_with("fd:", file))
5782  {
5783  ULONGLONG result = 0;
5784  const char* val = strchr(file, ':') + 1;
5785  if (!value_to_uint(val, &result, 0, INT_MAX))
5786  return -1;
5787  fp = fdopen((int)result, "r");
5788  success = args_from_fp(fp, &aargc, &aargv, file, oargv[0]);
5789  }
5790  else if (strncmp(file, "env:", 4) == 0)
5791  {
5792  const char* name = strchr(file, ':') + 1;
5793  success = args_from_env(name, &aargc, &aargv, oargv[1], oargv[0]);
5794  }
5795  else if (strcmp(file, "stdin") != 0)
5796  {
5797  fp = winpr_fopen(file, "r");
5798  success = args_from_fp(fp, &aargc, &aargv, file, oargv[0]);
5799  }
5800  else
5801  success = args_from_fp(fp, &aargc, &aargv, file, oargv[0]);
5802 
5803  if (!success)
5804  return -1;
5805  argc = aargc;
5806  argv = aargv;
5807  }
5808 
5809  WINPR_ASSERT(count <= SSIZE_MAX);
5810  size_t lcount = 0;
5811  COMMAND_LINE_ARGUMENT_A* largs = create_merged_args(args, (SSIZE_T)count, &lcount);
5812  if (!largs)
5813  goto fail;
5814 
5815  res = freerdp_client_settings_parse_command_line_arguments_int(
5816  settings, argc, argv, allowUnknown, largs, lcount, handle_option, handle_userdata);
5817 fail:
5818  free(largs);
5819  argv_free(&aargc, &aargv);
5820  return res;
5821 }
5822 
5823 static BOOL freerdp_client_load_static_channel_addin(rdpChannels* channels, rdpSettings* settings,
5824  const char* name, void* data)
5825 {
5826  PVIRTUALCHANNELENTRY entry = NULL;
5827  PVIRTUALCHANNELENTRY pvce = freerdp_load_channel_addin_entry(
5828  name, NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC | FREERDP_ADDIN_CHANNEL_ENTRYEX);
5829  PVIRTUALCHANNELENTRYEX pvceex = WINPR_FUNC_PTR_CAST(pvce, PVIRTUALCHANNELENTRYEX);
5830 
5831  if (!pvceex)
5832  entry = freerdp_load_channel_addin_entry(name, NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC);
5833 
5834  if (pvceex)
5835  {
5836  if (freerdp_channels_client_load_ex(channels, settings, pvceex, data) == 0)
5837  {
5838  WLog_DBG(TAG, "loading channelEx %s", name);
5839  return TRUE;
5840  }
5841  }
5842  else if (entry)
5843  {
5844  if (freerdp_channels_client_load(channels, settings, entry, data) == 0)
5845  {
5846  WLog_DBG(TAG, "loading channel %s", name);
5847  return TRUE;
5848  }
5849  }
5850 
5851  return FALSE;
5852 }
5853 
5854 typedef struct
5855 {
5856  FreeRDP_Settings_Keys_Bool settingId;
5857  const char* channelName;
5858  void* args;
5859 } ChannelToLoad;
5860 
5861 BOOL freerdp_client_load_addins(rdpChannels* channels, rdpSettings* settings)
5862 {
5863  ChannelToLoad dynChannels[] = {
5864 #if defined(CHANNEL_AINPUT_CLIENT)
5865  { FreeRDP_BOOL_UNUSED, AINPUT_CHANNEL_NAME, NULL }, /* always loaded */
5866 #endif
5867  { FreeRDP_AudioCapture, AUDIN_CHANNEL_NAME, NULL },
5868  { FreeRDP_AudioPlayback, RDPSND_CHANNEL_NAME, NULL },
5869 #ifdef CHANNEL_RDPEI_CLIENT
5870  { FreeRDP_MultiTouchInput, RDPEI_CHANNEL_NAME, NULL },
5871 #endif
5872  { FreeRDP_SupportGraphicsPipeline, RDPGFX_CHANNEL_NAME, NULL },
5873  { FreeRDP_SupportEchoChannel, ECHO_CHANNEL_NAME, NULL },
5874  { FreeRDP_SupportSSHAgentChannel, "sshagent", NULL },
5875  { FreeRDP_SupportDisplayControl, DISP_CHANNEL_NAME, NULL },
5876  { FreeRDP_SupportGeometryTracking, GEOMETRY_CHANNEL_NAME, NULL },
5877  { FreeRDP_SupportVideoOptimized, VIDEO_CHANNEL_NAME, NULL },
5878  { FreeRDP_RemoteCredentialGuard, RDPEAR_CHANNEL_NAME, NULL },
5879  };
5880 
5881  ChannelToLoad staticChannels[] = {
5882  { FreeRDP_AudioPlayback, RDPSND_CHANNEL_NAME, NULL },
5883  { FreeRDP_RedirectClipboard, CLIPRDR_SVC_CHANNEL_NAME, NULL },
5884 #if defined(CHANNEL_ENCOMSP_CLIENT)
5885  { FreeRDP_EncomspVirtualChannel, ENCOMSP_SVC_CHANNEL_NAME, settings },
5886 #endif
5887  { FreeRDP_RemdeskVirtualChannel, REMDESK_SVC_CHANNEL_NAME, settings },
5888  { FreeRDP_RemoteApplicationMode, RAIL_SVC_CHANNEL_NAME, settings }
5889  };
5890 
5894  for (size_t i = 0; i < ARRAYSIZE(dynChannels); i++)
5895  {
5896  if ((dynChannels[i].settingId == FreeRDP_BOOL_UNUSED) ||
5897  freerdp_settings_get_bool(settings, dynChannels[i].settingId))
5898  {
5899  const char* const p[] = { dynChannels[i].channelName };
5900 
5901  if (!freerdp_client_add_dynamic_channel(settings, ARRAYSIZE(p), p))
5902  return FALSE;
5903  }
5904  }
5905 
5909  if ((freerdp_static_channel_collection_find(settings, RDPSND_CHANNEL_NAME)) ||
5910  (freerdp_dynamic_channel_collection_find(settings, RDPSND_CHANNEL_NAME))
5911 #if defined(CHANNEL_TSMF_CLIENT)
5912  || (freerdp_dynamic_channel_collection_find(settings, "tsmf"))
5913 #endif
5914  )
5915  {
5916  if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))
5917  return FALSE; /* rdpsnd requires rdpdr to be registered */
5918  if (!freerdp_settings_set_bool(settings, FreeRDP_AudioPlayback, TRUE))
5919  return FALSE; /* Both rdpsnd and tsmf require this flag to be set */
5920  }
5921 
5922  if (freerdp_dynamic_channel_collection_find(settings, AUDIN_CHANNEL_NAME))
5923  {
5924  if (!freerdp_settings_set_bool(settings, FreeRDP_AudioCapture, TRUE))
5925  return FALSE;
5926  }
5927 
5928  if (freerdp_settings_get_bool(settings, FreeRDP_NetworkAutoDetect) ||
5929  freerdp_settings_get_bool(settings, FreeRDP_SupportHeartbeatPdu) ||
5930  freerdp_settings_get_bool(settings, FreeRDP_SupportMultitransport))
5931  {
5932  if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))
5933  return FALSE; /* these RDP8 features require rdpdr to be registered */
5934  }
5935 
5936  const char* DrivesToRedirect = freerdp_settings_get_string(settings, FreeRDP_DrivesToRedirect);
5937 
5938  if (DrivesToRedirect && (strlen(DrivesToRedirect) != 0))
5939  {
5940  /*
5941  * Drives to redirect:
5942  *
5943  * Very similar to DevicesToRedirect, but can contain a
5944  * comma-separated list of drive letters to redirect.
5945  */
5946  char* value = NULL;
5947  char* tok = NULL;
5948  char* context = NULL;
5949 
5950  value = _strdup(DrivesToRedirect);
5951  if (!value)
5952  return FALSE;
5953 
5954  tok = strtok_s(value, ";", &context);
5955  if (!tok)
5956  {
5957  WLog_ERR(TAG, "DrivesToRedirect contains invalid data: '%s'", DrivesToRedirect);
5958  free(value);
5959  return FALSE;
5960  }
5961 
5962  while (tok)
5963  {
5964  /* Syntax: Comma separated list of the following entries:
5965  * '*' ... Redirect all drives, including hotplug
5966  * 'DynamicDrives' ... hotplug
5967  * '%' ... user home directory
5968  * <label>(<path>) ... One or more paths to redirect.
5969  * <path>(<label>) ... One or more paths to redirect.
5970  * <path> ... One or more paths to redirect.
5971  */
5972  /* TODO: Need to properly escape labels and paths */
5973  BOOL success = 0;
5974  const char* name = NULL;
5975  const char* drive = tok;
5976  char* subcontext = NULL;
5977  char* start = strtok_s(tok, "(", &subcontext);
5978  char* end = strtok_s(NULL, ")", &subcontext);
5979  if (start && end)
5980  name = end;
5981 
5982  if (freerdp_path_valid(name, NULL) && freerdp_path_valid(drive, NULL))
5983  {
5984  success = freerdp_client_add_drive(settings, name, NULL);
5985  if (success)
5986  success = freerdp_client_add_drive(settings, drive, NULL);
5987  }
5988  else
5989  success = freerdp_client_add_drive(settings, drive, name);
5990 
5991  if (!success)
5992  {
5993  free(value);
5994  return FALSE;
5995  }
5996 
5997  tok = strtok_s(NULL, ";", &context);
5998  }
5999  free(value);
6000 
6001  if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))
6002  return FALSE;
6003  }
6004  else if (freerdp_settings_get_bool(settings, FreeRDP_RedirectDrives))
6005  {
6006  if (!freerdp_device_collection_find(settings, "drive"))
6007  {
6008  const char* const params[] = { "drive", "media", "*" };
6009 
6010  if (!freerdp_client_add_device_channel(settings, ARRAYSIZE(params), params))
6011  return FALSE;
6012  }
6013  }
6014 
6015  if (freerdp_settings_get_bool(settings, FreeRDP_RedirectDrives) ||
6016  freerdp_settings_get_bool(settings, FreeRDP_RedirectHomeDrive) ||
6017  freerdp_settings_get_bool(settings, FreeRDP_RedirectSerialPorts) ||
6018  freerdp_settings_get_bool(settings, FreeRDP_RedirectSmartCards) ||
6019  freerdp_settings_get_bool(settings, FreeRDP_RedirectPrinters))
6020  {
6021  if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))
6022  return FALSE; /* All of these features require rdpdr */
6023  }
6024 
6025  if (freerdp_settings_get_bool(settings, FreeRDP_RedirectHomeDrive))
6026  {
6027  if (!freerdp_device_collection_find(settings, "drive"))
6028  {
6029  const char* params[] = { "drive", "home", "%" };
6030 
6031  if (!freerdp_client_add_device_channel(settings, ARRAYSIZE(params), params))
6032  return FALSE;
6033  }
6034  }
6035 
6036  if (freerdp_settings_get_bool(settings, FreeRDP_DeviceRedirection))
6037  {
6038  if (!freerdp_client_load_static_channel_addin(channels, settings, RDPDR_SVC_CHANNEL_NAME,
6039  settings))
6040  return FALSE;
6041 
6042  if (!freerdp_static_channel_collection_find(settings, RDPSND_CHANNEL_NAME) &&
6043  !freerdp_dynamic_channel_collection_find(settings, RDPSND_CHANNEL_NAME))
6044  {
6045  const char* const params[] = { RDPSND_CHANNEL_NAME, "sys:fake" };
6046 
6047  if (!freerdp_client_add_static_channel(settings, ARRAYSIZE(params), params))
6048  return FALSE;
6049 
6050  if (!freerdp_client_add_dynamic_channel(settings, ARRAYSIZE(params), params))
6051  return FALSE;
6052  }
6053  }
6054 
6055  if (freerdp_settings_get_bool(settings, FreeRDP_RedirectSmartCards))
6056  {
6057  if (!freerdp_device_collection_find_type(settings, RDPDR_DTYP_SMARTCARD))
6058  {
6059  RDPDR_DEVICE* smartcard = freerdp_device_new(RDPDR_DTYP_SMARTCARD, 0, NULL);
6060 
6061  if (!smartcard)
6062  return FALSE;
6063 
6064  if (!freerdp_device_collection_add(settings, smartcard))
6065  {
6066  freerdp_device_free(smartcard);
6067  return FALSE;
6068  }
6069  }
6070  }
6071 
6072  if (freerdp_settings_get_bool(settings, FreeRDP_RedirectPrinters))
6073  {
6074  if (!freerdp_device_collection_find_type(settings, RDPDR_DTYP_PRINT))
6075  {
6076  RDPDR_DEVICE* printer = freerdp_device_new(RDPDR_DTYP_PRINT, 0, NULL);
6077 
6078  if (!printer)
6079  return FALSE;
6080 
6081  if (!freerdp_device_collection_add(settings, printer))
6082  {
6083  freerdp_device_free(printer);
6084  return FALSE;
6085  }
6086  }
6087  }
6088 
6089  if (freerdp_settings_get_bool(settings, FreeRDP_LyncRdpMode))
6090  {
6091  if (!freerdp_settings_set_bool(settings, FreeRDP_EncomspVirtualChannel, TRUE))
6092  return FALSE;
6093  if (!freerdp_settings_set_bool(settings, FreeRDP_RemdeskVirtualChannel, TRUE))
6094  return FALSE;
6095  if (!freerdp_settings_set_bool(settings, FreeRDP_CompressionEnabled, FALSE))
6096  return FALSE;
6097  }
6098 
6099  if (freerdp_settings_get_bool(settings, FreeRDP_RemoteAssistanceMode))
6100  {
6101  if (!freerdp_settings_set_bool(settings, FreeRDP_EncomspVirtualChannel, TRUE))
6102  return FALSE;
6103  if (!freerdp_settings_set_bool(settings, FreeRDP_RemdeskVirtualChannel, TRUE))
6104  return FALSE;
6105  if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE))
6106  return FALSE;
6107  }
6108 
6109  /* step 3: schedule some static channels to load depending on the settings */
6110  for (size_t i = 0; i < ARRAYSIZE(staticChannels); i++)
6111  {
6112  if ((staticChannels[i].settingId == 0) ||
6113  freerdp_settings_get_bool(settings, staticChannels[i].settingId))
6114  {
6115  if (staticChannels[i].args)
6116  {
6117  if (!freerdp_client_load_static_channel_addin(
6118  channels, settings, staticChannels[i].channelName, staticChannels[i].args))
6119  return FALSE;
6120  }
6121  else
6122  {
6123  const char* const p[] = { staticChannels[i].channelName };
6124  if (!freerdp_client_add_static_channel(settings, ARRAYSIZE(p), p))
6125  return FALSE;
6126  }
6127  }
6128  }
6129 
6130  char* RDP2TCPArgs = freerdp_settings_get_string_writable(settings, FreeRDP_RDP2TCPArgs);
6131  if (RDP2TCPArgs)
6132  {
6133  if (!freerdp_client_load_static_channel_addin(channels, settings, RDP2TCP_DVC_CHANNEL_NAME,
6134  RDP2TCPArgs))
6135  return FALSE;
6136  }
6137 
6138  /* step 4: do the static channels loading and init */
6139  for (UINT32 i = 0; i < freerdp_settings_get_uint32(settings, FreeRDP_StaticChannelCount); i++)
6140  {
6141  ADDIN_ARGV* _args =
6142  freerdp_settings_get_pointer_array_writable(settings, FreeRDP_StaticChannelArray, i);
6143 
6144  if (!freerdp_client_load_static_channel_addin(channels, settings, _args->argv[0], _args))
6145  return FALSE;
6146  }
6147 
6148  if (freerdp_settings_get_uint32(settings, FreeRDP_DynamicChannelCount) > 0)
6149  {
6150  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportDynamicChannels, TRUE))
6151  return FALSE;
6152  }
6153 
6154  if (freerdp_settings_get_bool(settings, FreeRDP_SupportDynamicChannels))
6155  {
6156  if (!freerdp_client_load_static_channel_addin(channels, settings, DRDYNVC_SVC_CHANNEL_NAME,
6157  settings))
6158  return FALSE;
6159  }
6160 
6161  return TRUE;
6162 }
6163 
6164 void freerdp_client_warn_unmaintained(int argc, char* argv[])
6165 {
6166  const char* app = (argc > 0) ? argv[0] : "INVALID_ARGV";
6167  const DWORD log_level = WLOG_WARN;
6168  wLog* log = WLog_Get(TAG);
6169  WINPR_ASSERT(log);
6170 
6171  if (!WLog_IsLevelActive(log, log_level))
6172  return;
6173 
6174  WLog_Print_unchecked(log, log_level, "[unmaintained] %s client is currently unmaintained!",
6175  app);
6176  WLog_Print_unchecked(
6177  log, log_level,
6178  " If problems occur please check https://github.com/FreeRDP/FreeRDP/issues for "
6179  "known issues!");
6180  WLog_Print_unchecked(
6181  log, log_level,
6182  "Be prepared to fix issues yourself though as nobody is actively working on this.");
6183  WLog_Print_unchecked(
6184  log, log_level,
6185  " Developers hang out in https://matrix.to/#/#FreeRDP:matrix.org?via=matrix.org "
6186  "- dont hesitate to ask some questions. (replies might take some time depending "
6187  "on your timezone) - if you intend using this component write us a message");
6188 }
6189 
6190 void freerdp_client_warn_experimental(int argc, char* argv[])
6191 {
6192  const char* app = (argc > 0) ? argv[0] : "INVALID_ARGV";
6193  const DWORD log_level = WLOG_WARN;
6194  wLog* log = WLog_Get(TAG);
6195  WINPR_ASSERT(log);
6196 
6197  if (!WLog_IsLevelActive(log, log_level))
6198  return;
6199 
6200  WLog_Print_unchecked(log, log_level, "[experimental] %s client is currently experimental!",
6201  app);
6202  WLog_Print_unchecked(
6203  log, log_level,
6204  " If problems occur please check https://github.com/FreeRDP/FreeRDP/issues for "
6205  "known issues or create a new one!");
6206  WLog_Print_unchecked(
6207  log, log_level,
6208  " Developers hang out in https://matrix.to/#/#FreeRDP:matrix.org?via=matrix.org "
6209  "- dont hesitate to ask some questions. (replies might take some time depending "
6210  "on your timezone)");
6211 }
6212 
6213 void freerdp_client_warn_deprecated(int argc, char* argv[])
6214 {
6215  const char* app = (argc > 0) ? argv[0] : "INVALID_ARGV";
6216  const DWORD log_level = WLOG_WARN;
6217  wLog* log = WLog_Get(TAG);
6218  WINPR_ASSERT(log);
6219 
6220  if (!WLog_IsLevelActive(log, log_level))
6221  return;
6222 
6223  WLog_Print_unchecked(log, log_level, "[deprecated] %s client has been deprecated", app);
6224  WLog_Print_unchecked(log, log_level, "As replacement there is a SDL based client available.");
6225  WLog_Print_unchecked(
6226  log, log_level,
6227  "If you are interested in keeping %s alive get in touch with the developers", app);
6228  WLog_Print_unchecked(
6229  log, log_level,
6230  "The project is hosted at https://github.com/freerdp/freerdp and "
6231  " developers hang out in https://matrix.to/#/#FreeRDP:matrix.org?via=matrix.org "
6232  "- dont hesitate to ask some questions. (replies might take some time depending "
6233  "on your timezone)");
6234 }
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *param)
Sets a string settings value. The param is copied.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API const void * freerdp_settings_get_pointer(const rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id)
Returns a immutable pointer settings value.
FREERDP_API INT64 freerdp_settings_get_int64(const rdpSettings *settings, FreeRDP_Settings_Keys_Int64 id)
Returns a INT64 settings value.
FREERDP_API char * freerdp_settings_get_string_writable(rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a string settings value.
FREERDP_API SSIZE_T freerdp_settings_get_type_for_key(SSIZE_T key)
Get a key type for the key index.
Definition: settings_str.c:407
FREERDP_API UINT64 freerdp_settings_get_uint64(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt64 id)
Returns a UINT64 settings value.
FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
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 UINT16 freerdp_settings_get_uint16(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt16 id)
Returns a UINT16 settings value.
FREERDP_API BOOL freerdp_set_gateway_usage_method(rdpSettings *settings, UINT32 GatewayUsageMethod)
FREERDP_API BOOL freerdp_settings_set_uint64(rdpSettings *settings, FreeRDP_Settings_Keys_UInt64 id, UINT64 param)
Sets a UINT64 settings value.
FREERDP_API INT32 freerdp_settings_get_int32(const rdpSettings *settings, FreeRDP_Settings_Keys_Int32 id)
Returns a INT32 settings value.
FREERDP_API BOOL freerdp_settings_set_string_len(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *param, size_t len)
Sets a string settings value. The param is copied.
FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 param)
Sets a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_append_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *separator, const char *param)
appends a string to a settings value. The param is copied. If the initial value of the setting was no...
FREERDP_API BOOL freerdp_settings_set_uint16(rdpSettings *settings, FreeRDP_Settings_Keys_UInt16 id, UINT16 param)
Sets a UINT16 settings value.
FREERDP_API INT16 freerdp_settings_get_int16(const rdpSettings *settings, FreeRDP_Settings_Keys_Int16 id)
Returns a INT16 settings value.
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL param)
Sets a BOOL settings value.
FREERDP_API void * freerdp_settings_get_pointer_writable(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id)
Returns a mutable pointer settings value.
FREERDP_API const char * freerdp_settings_get_name_for_key(SSIZE_T key)
Returns the type name for a key.
Definition: settings_str.c:418