Coverage Report

Created: 2024-05-20 06:11

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