Coverage Report

Created: 2024-09-08 06:20

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