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