Coverage Report

Created: 2023-11-19 06:16

/src/FreeRDP/libfreerdp/common/assistance.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Remote Assistance
4
 *
5
 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include <freerdp/config.h>
21
22
#include <errno.h>
23
24
#include <winpr/wtypes.h>
25
#include <winpr/collections.h>
26
#include <winpr/string.h>
27
#include <winpr/crt.h>
28
#include <winpr/crypto.h>
29
#include <winpr/print.h>
30
#include <winpr/windows.h>
31
#include <winpr/ssl.h>
32
#include <winpr/file.h>
33
34
#include <freerdp/log.h>
35
#include <freerdp/client/file.h>
36
#include <freerdp/client/cmdline.h>
37
38
#include <freerdp/assistance.h>
39
40
#define TAG FREERDP_TAG("common")
41
42
struct rdp_assistance_file
43
{
44
  UINT32 Type;
45
46
  char* Username;
47
  char* LHTicket;
48
  char* RCTicket;
49
  char* PassStub;
50
  UINT32 DtStart;
51
  UINT32 DtLength;
52
  BOOL LowSpeed;
53
  BOOL RCTicketEncrypted;
54
55
  char* ConnectionString1;
56
  char* ConnectionString2;
57
58
  BYTE* EncryptedPassStub;
59
  size_t EncryptedPassStubLength;
60
61
  BYTE* EncryptedLHTicket;
62
  size_t EncryptedLHTicketLength;
63
64
  wArrayList* MachineAddresses;
65
  wArrayList* MachinePorts;
66
  wArrayList* MachineUris;
67
68
  char* RASessionId;
69
  char* RASpecificParams;
70
  char* RASpecificParams2;
71
72
  char* filename;
73
  char* password;
74
};
75
76
static char* strrstr(const char* haystack, size_t len, const char* needle)
77
2.05k
{
78
2.05k
  if (*needle == '\0')
79
0
    return (char*)haystack;
80
81
2.05k
  char* result = NULL;
82
2.05k
  for (;;)
83
4.73k
  {
84
4.73k
    char* p = strstr(haystack, needle);
85
4.73k
    if (p == NULL)
86
2.05k
      break;
87
2.68k
    if (p > haystack + len)
88
0
      return NULL;
89
90
2.68k
    result = p;
91
2.68k
    haystack = p + 1;
92
2.68k
  }
93
94
2.05k
  return result;
95
2.05k
}
96
97
static BOOL update_option(char** opt, const char* val, size_t len)
98
3.76k
{
99
3.76k
  WINPR_ASSERT(opt);
100
3.76k
  free(*opt);
101
3.76k
  *opt = NULL;
102
103
3.76k
  if (!val && (len != 0))
104
0
    return FALSE;
105
3.76k
  else if (!val && (len == 0))
106
2.97k
    return TRUE;
107
790
  *opt = strndup(val, len);
108
790
  return *opt != NULL;
109
3.76k
}
110
111
static BOOL update_name(rdpAssistanceFile* file, const char* name)
112
0
{
113
0
  WINPR_ASSERT(file);
114
115
0
  if (!name)
116
0
  {
117
0
    WLog_ERR(TAG, "ASSISTANCE file %s invalid name", name);
118
0
    return FALSE;
119
0
  }
120
121
0
  free(file->filename);
122
0
  file->filename = _strdup(name);
123
0
  return file->filename != NULL;
124
0
}
125
126
static BOOL update_password(rdpAssistanceFile* file, const char* password)
127
2.68k
{
128
2.68k
  WINPR_ASSERT(file);
129
2.68k
  free(file->password);
130
2.68k
  file->password = NULL;
131
2.68k
  if (!password)
132
1.34k
    return TRUE;
133
1.34k
  file->password = _strdup(password);
134
1.34k
  return file->password != NULL;
135
2.68k
}
136
137
static BOOL update_connectionstring2_nocopy(rdpAssistanceFile* file, char* str)
138
1.83k
{
139
1.83k
  WINPR_ASSERT(file);
140
1.83k
  free(file->ConnectionString2);
141
1.83k
  file->ConnectionString2 = NULL;
142
1.83k
  if (!str)
143
1.34k
    return TRUE;
144
493
  file->ConnectionString2 = str;
145
493
  return file->ConnectionString2 != NULL;
146
1.83k
}
147
148
static BOOL update_connectionstring2(rdpAssistanceFile* file, const char* str, size_t len)
149
1.75k
{
150
1.75k
  char* strc = NULL;
151
1.75k
  if (!str && (len != 0))
152
0
    return FALSE;
153
154
1.75k
  if (str && (len > 0))
155
412
  {
156
412
    strc = strndup(str, len);
157
412
    if (!strc)
158
0
      return FALSE;
159
412
  }
160
1.75k
  return update_connectionstring2_nocopy(file, strc);
161
1.75k
}
162
163
static BOOL update_connectionstring2_wchar(rdpAssistanceFile* file, const WCHAR* str, size_t len)
164
157
{
165
157
  char* strc = NULL;
166
167
157
  if (!str && (len != 0))
168
0
    return FALSE;
169
170
157
  if (str && (len > 0))
171
156
  {
172
156
    strc = ConvertWCharNToUtf8Alloc(str, len, NULL);
173
156
    if (!strc)
174
75
      return FALSE;
175
156
  }
176
82
  return update_connectionstring2_nocopy(file, strc);
177
157
}
178
179
/**
180
 * Password encryption in establishing a remote assistance session of type 1:
181
 * http://blogs.msdn.com/b/openspecification/archive/2011/10/31/password-encryption-in-establishing-a-remote-assistance-session-of-type-1.aspx
182
 *
183
 * Creation of PassStub for the Remote Assistance Ticket:
184
 * http://social.msdn.microsoft.com/Forums/en-US/6316c3f4-ea09-4343-a4a1-9cca46d70d28/creation-of-passstub-for-the-remote-assistance-ticket?forum=os_windowsprotocols
185
 */
186
187
/**
188
 * CryptDeriveKey Function:
189
 * http://msdn.microsoft.com/en-us/library/windows/desktop/aa379916/
190
 *
191
 * Let n be the required derived key length, in bytes.
192
 * The derived key is the first n bytes of the hash value after the hash computation
193
 * has been completed by CryptDeriveKey. If the hash is not a member of the SHA-2
194
 * family and the required key is for either 3DES or AES, the key is derived as follows:
195
 *
196
 * Form a 64-byte buffer by repeating the constant 0x36 64 times.
197
 * Let k be the length of the hash value that is represented by the input parameter hBaseData.
198
 * Set the first k bytes of the buffer to the result of an XOR operation of the first k bytes
199
 * of the buffer with the hash value that is represented by the input parameter hBaseData.
200
 *
201
 * Form a 64-byte buffer by repeating the constant 0x5C 64 times.
202
 * Set the first k bytes of the buffer to the result of an XOR operation of the first k bytes
203
 * of the buffer with the hash value that is represented by the input parameter hBaseData.
204
 *
205
 * Hash the result of step 1 by using the same hash algorithm as that used to compute the hash
206
 * value that is represented by the hBaseData parameter.
207
 *
208
 * Hash the result of step 2 by using the same hash algorithm as that used to compute the hash
209
 * value that is represented by the hBaseData parameter.
210
 *
211
 * Concatenate the result of step 3 with the result of step 4.
212
 * Use the first n bytes of the result of step 5 as the derived key.
213
 */
214
215
static BOOL freerdp_assistance_crypt_derive_key_sha1(BYTE* hash, size_t hashLength, BYTE* key,
216
                                                     size_t keyLength)
217
368
{
218
368
  BOOL rc = FALSE;
219
368
  BYTE pad1[64] = { 0 };
220
368
  BYTE pad2[64] = { 0 };
221
222
368
  memset(pad1, 0x36, sizeof(pad1));
223
368
  memset(pad2, 0x5C, sizeof(pad2));
224
225
7.72k
  for (size_t i = 0; i < hashLength; i++)
226
7.36k
  {
227
7.36k
    pad1[i] ^= hash[i];
228
7.36k
    pad2[i] ^= hash[i];
229
7.36k
  }
230
231
368
  BYTE* buffer = (BYTE*)calloc(hashLength, 2);
232
233
368
  if (!buffer)
234
0
    goto fail;
235
236
368
  if (!winpr_Digest(WINPR_MD_SHA1, pad1, 64, buffer, hashLength))
237
0
    goto fail;
238
239
368
  if (!winpr_Digest(WINPR_MD_SHA1, pad2, 64, &buffer[hashLength], hashLength))
240
0
    goto fail;
241
242
368
  CopyMemory(key, buffer, keyLength);
243
368
  rc = TRUE;
244
368
fail:
245
368
  free(buffer);
246
368
  return rc;
247
368
}
248
249
static BOOL append_address(rdpAssistanceFile* file, const char* host, const char* port)
250
931k
{
251
931k
  WINPR_ASSERT(file);
252
253
931k
  errno = 0;
254
931k
  unsigned long p = strtoul(port, NULL, 0);
255
256
931k
  if ((errno != 0) || (p == 0) || (p > UINT16_MAX))
257
138
  {
258
138
    WLog_ERR(TAG, "Failed to parse ASSISTANCE file: ConnectionString2 invalid port value %s",
259
138
             port);
260
138
    return FALSE;
261
138
  }
262
263
931k
  if (!ArrayList_Append(file->MachineAddresses, _strdup(host)))
264
0
    return FALSE;
265
931k
  return ArrayList_Append(file->MachinePorts, (void*)(uintptr_t)p);
266
931k
}
267
268
static BOOL freerdp_assistance_parse_address_list(rdpAssistanceFile* file, char* list)
269
232
{
270
232
  WINPR_ASSERT(file);
271
272
232
  WLog_DBG(TAG, "freerdp_assistance_parse_address_list list=%s", list);
273
274
232
  BOOL rc = FALSE;
275
276
232
  if (!list)
277
0
    return FALSE;
278
279
232
  char* strp = list;
280
232
  char* s = ";";
281
282
  // get the first token
283
232
  char* token = strtok(strp, s);
284
285
  // walk through other tokens
286
932k
  while (token != NULL)
287
931k
  {
288
931k
    char* port = strchr(token, ':');
289
931k
    if (!port)
290
2
      goto out;
291
931k
    *port = '\0';
292
931k
    port++;
293
294
931k
    if (!append_address(file, token, port))
295
138
      goto out;
296
297
931k
    token = strtok(NULL, s);
298
931k
  }
299
92
  rc = TRUE;
300
232
out:
301
232
  return rc;
302
92
}
303
304
static BOOL freerdp_assistance_parse_connection_string1(rdpAssistanceFile* file)
305
388
{
306
388
  char* tokens[8] = { 0 };
307
388
  BOOL rc = FALSE;
308
309
388
  WINPR_ASSERT(file);
310
311
388
  if (!file->RCTicket)
312
44
    return FALSE;
313
314
  /**
315
   * <ProtocolVersion>,<protocolType>,<machineAddressList>,<assistantAccountPwd>,
316
   * <RASessionID>,<RASessionName>,<RASessionPwd>,<protocolSpecificParms>
317
   */
318
344
  char* str = _strdup(file->RCTicket);
319
320
344
  if (!str)
321
0
    goto error;
322
323
344
  const size_t length = strlen(str);
324
325
344
  int count = 1;
326
3.97M
  for (size_t i = 0; i < length; i++)
327
3.97M
  {
328
3.97M
    if (str[i] == ',')
329
1.05M
      count++;
330
3.97M
  }
331
332
344
  if (count != 8)
333
43
    goto error;
334
335
301
  count = 0;
336
301
  tokens[count++] = str;
337
338
2.81M
  for (size_t i = 0; i < length; i++)
339
2.81M
  {
340
2.81M
    if (str[i] == ',')
341
2.10k
    {
342
2.10k
      str[i] = '\0';
343
2.10k
      tokens[count++] = &str[i + 1];
344
2.10k
    }
345
2.81M
  }
346
347
301
  if (strcmp(tokens[0], "65538") != 0)
348
61
    goto error;
349
350
240
  if (strcmp(tokens[1], "1") != 0)
351
2
    goto error;
352
353
238
  if (strcmp(tokens[3], "*") != 0)
354
2
    goto error;
355
356
236
  if (strcmp(tokens[5], "*") != 0)
357
2
    goto error;
358
359
234
  if (strcmp(tokens[6], "*") != 0)
360
2
    goto error;
361
362
232
  file->RASessionId = _strdup(tokens[4]);
363
364
232
  if (!file->RASessionId)
365
0
    goto error;
366
367
232
  file->RASpecificParams = _strdup(tokens[7]);
368
369
232
  if (!file->RASpecificParams)
370
0
    goto error;
371
372
232
  if (!freerdp_assistance_parse_address_list(file, tokens[2]))
373
140
    goto error;
374
375
92
  rc = TRUE;
376
344
error:
377
344
  free(str);
378
344
  return rc;
379
92
}
380
381
/**
382
 * Decrypted Connection String 2:
383
 *
384
 * <E>
385
 * <A KH="BNRjdu97DyczQSRuMRrDWoue+HA="
386
 * ID="+ULZ6ifjoCa6cGPMLQiGHRPwkg6VyJqGwxMnO6GcelwUh9a6/FBq3It5ADSndmLL"/> <C> <T ID="1" SID="0"> <L
387
 * P="49228" N="fe80::1032:53d9:5a01:909b%3"/> <L P="49229" N="fe80::3d8f:9b2d:6b4e:6aa%6"/> <L
388
 * P="49230" N="192.168.1.200"/> <L P="49231" N="169.254.6.170"/>
389
 * </T>
390
 * </C>
391
 * </E>
392
 */
393
394
static BOOL freerdp_assistance_parse_attr(const char** opt, size_t* plength, const char* key,
395
                                          const char* tag)
396
315k
{
397
315k
  WINPR_ASSERT(opt);
398
315k
  WINPR_ASSERT(plength);
399
315k
  WINPR_ASSERT(key);
400
401
315k
  *opt = NULL;
402
315k
  *plength = 0;
403
315k
  if (!tag)
404
0
    return FALSE;
405
406
315k
  char bkey[128] = { 0 };
407
315k
  const int rc = _snprintf(bkey, sizeof(bkey), "%s=\"", key);
408
315k
  WINPR_ASSERT(rc > 0);
409
315k
  WINPR_ASSERT(rc < sizeof(bkey));
410
411
315k
  char* p = strstr(tag, bkey);
412
315k
  if (!p)
413
313k
    return TRUE;
414
415
2.12k
  p += strlen(bkey);
416
2.12k
  char* q = strchr(p, '"');
417
418
2.12k
  if (!q)
419
66
  {
420
66
    WLog_ERR(TAG, "Failed to parse ASSISTANCE file: ConnectionString2 invalid field '%s=%s'",
421
66
             key, p);
422
66
    return FALSE;
423
66
  }
424
425
2.06k
  if (p > q)
426
0
  {
427
0
    WLog_ERR(TAG,
428
0
             "Failed to parse ASSISTANCE file: ConnectionString2 invalid field "
429
0
             "order for '%s'",
430
0
             key);
431
0
    return FALSE;
432
0
  }
433
2.06k
  const size_t length = q - p;
434
2.06k
  *opt = p;
435
2.06k
  *plength = length;
436
437
2.06k
  return TRUE;
438
2.06k
}
439
440
static BOOL freerdp_assistance_parse_attr_str(char** opt, const char* key, const char* tag)
441
3.81k
{
442
3.81k
  const char* copt = NULL;
443
3.81k
  size_t size = 0;
444
3.81k
  if (!freerdp_assistance_parse_attr(&copt, &size, key, tag))
445
53
    return FALSE;
446
3.76k
  return update_option(opt, copt, size);
447
3.81k
}
448
449
static BOOL freerdp_assistance_parse_attr_bool(BOOL* opt, const char* key, const char* tag)
450
1.51k
{
451
1.51k
  const char* copt = NULL;
452
1.51k
  size_t size = 0;
453
454
1.51k
  WINPR_ASSERT(opt);
455
1.51k
  *opt = FALSE;
456
457
1.51k
  if (!freerdp_assistance_parse_attr(&copt, &size, key, tag))
458
2
    return FALSE;
459
1.51k
  if (size != 1)
460
1.50k
    return TRUE;
461
462
15
  *opt = (copt[0] == '1');
463
15
  return TRUE;
464
1.51k
}
465
466
static BOOL freerdp_assistance_parse_attr_uint32(UINT32* opt, const char* key, const char* tag)
467
105k
{
468
105k
  const char* copt = NULL;
469
105k
  size_t size = 0;
470
471
105k
  WINPR_ASSERT(opt);
472
105k
  *opt = 0;
473
474
105k
  if (!freerdp_assistance_parse_attr(&copt, &size, key, tag))
475
7
    return FALSE;
476
477
105k
  char buffer[64] = { 0 };
478
105k
  if (size >= sizeof(buffer))
479
28
  {
480
28
    WLog_WARN(TAG, "Invalid UINT32 string '%s' [%" PRIuz "]", copt, size);
481
28
    return FALSE;
482
28
  }
483
484
105k
  strncpy(buffer, copt, size);
485
105k
  errno = 0;
486
105k
  unsigned long val = strtoul(buffer, NULL, 0);
487
488
105k
  if ((errno != 0) || (val > UINT32_MAX))
489
72
  {
490
72
    WLog_ERR(TAG, "Failed to parse ASSISTANCE file: Invalid value %s", buffer);
491
72
    return FALSE;
492
72
  }
493
494
105k
  *opt = val;
495
496
105k
  return TRUE;
497
105k
}
498
499
static char* freerdp_assistance_contains_element(char* input, size_t ilen, const char* key,
500
                                                 size_t* plen, char** pdata, size_t* pdlen)
501
115k
{
502
115k
  WINPR_ASSERT(input);
503
115k
  WINPR_ASSERT(key);
504
115k
  WINPR_ASSERT(plen);
505
506
115k
  char bkey[128] = { 0 };
507
115k
  const int rc = _snprintf(bkey, sizeof(bkey), "<%s", key);
508
115k
  WINPR_ASSERT(rc > 0);
509
115k
  WINPR_ASSERT(rc < sizeof(bkey));
510
511
115k
  char* tag = strstr(input, bkey);
512
115k
  if (!tag || (tag > input + ilen))
513
2.01k
    return NULL;
514
515
113k
  char* data = tag + strnlen(bkey, sizeof(bkey));
516
517
  /* Ensure there is a valid delimiter following our token */
518
113k
  switch (data[0])
519
113k
  {
520
1.83k
    case '>':
521
111k
    case '/':
522
112k
    case ' ':
523
113k
    case '\t':
524
113k
      break;
525
375
    default:
526
375
      WLog_ERR(TAG,
527
375
               "Failed to parse ASSISTANCE file: ConnectionString2 missing delimiter after "
528
375
               "field %s",
529
375
               bkey);
530
375
      return NULL;
531
113k
  }
532
533
113k
  char* start = strstr(tag, ">");
534
535
113k
  if (!start || (start > input + ilen))
536
3.27k
  {
537
3.27k
    WLog_ERR(TAG, "Failed to parse ASSISTANCE file: ConnectionString2 missing field %s", bkey);
538
3.27k
    return NULL;
539
3.27k
  }
540
541
110k
  char* end = start;
542
110k
  char* dend = start - 1;
543
110k
  if (*dend != '/')
544
2.05k
  {
545
2.05k
    char ekey[128] = { 0 };
546
2.05k
    const int erc = _snprintf(ekey, sizeof(ekey), "</%s>", key);
547
2.05k
    WINPR_ASSERT(erc > 0);
548
2.05k
    WINPR_ASSERT(erc < sizeof(ekey));
549
2.05k
    const size_t offset = start - tag;
550
2.05k
    dend = end = strrstr(start, ilen - offset, ekey);
551
2.05k
    if (end)
552
1.98k
      end += strnlen(ekey, sizeof(ekey));
553
2.05k
  }
554
555
110k
  if (!end)
556
66
  {
557
66
    WLog_ERR(TAG,
558
66
             "Failed to parse ASSISTANCE file: ConnectionString2 missing end tag for field %s",
559
66
             key);
560
66
    return NULL;
561
66
  }
562
110k
  if (plen)
563
110k
    *plen = end - tag;
564
565
110k
  if (pdata)
566
109k
    *pdata = data;
567
110k
  if (pdlen)
568
109k
    *pdlen = dend - data;
569
110k
  return tag;
570
110k
}
571
572
/**! \brief this function returns a XML element identified by \b key
573
 * The input string will be manipulated, so that the element found is '\0' terminated.
574
 *
575
 * This function can not find multiple elements on the same level as the input string is changed!
576
 */
577
static BOOL freerdp_assistance_consume_input_and_get_element(char* input, const char* key,
578
                                                             char** element, size_t* elen)
579
2.60k
{
580
2.60k
  WINPR_ASSERT(input);
581
2.60k
  WINPR_ASSERT(key);
582
2.60k
  WINPR_ASSERT(element);
583
2.60k
  WINPR_ASSERT(elen);
584
585
2.60k
  size_t len = 0;
586
2.60k
  size_t dlen = 0;
587
2.60k
  char* data = NULL;
588
2.60k
  char* tag = freerdp_assistance_contains_element(input, strlen(input), key, &len, &data, &dlen);
589
2.60k
  if (!tag)
590
530
    return FALSE;
591
592
2.07k
  char* end = data + dlen;
593
2.07k
  *tag = '\0';
594
2.07k
  *end = '\0';
595
2.07k
  *element = data;
596
2.07k
  *elen = dlen + 1;
597
2.07k
  return TRUE;
598
2.60k
}
599
600
static BOOL freerdp_assistance_get_element(char* input, size_t ilen, const char* key,
601
                                           char** element, size_t* elen)
602
112k
{
603
112k
  WINPR_ASSERT(input);
604
112k
  WINPR_ASSERT(key);
605
112k
  WINPR_ASSERT(element);
606
112k
  WINPR_ASSERT(elen);
607
608
112k
  size_t len = 0;
609
112k
  size_t dlen = 0;
610
112k
  char* data = NULL;
611
112k
  char* tag = freerdp_assistance_contains_element(input, ilen, key, &len, &data, &dlen);
612
112k
  if (!tag)
613
5.16k
    return FALSE;
614
615
107k
  if (tag + len > input + ilen)
616
0
    return FALSE;
617
618
107k
  char* end = tag + len;
619
107k
  *element = data;
620
107k
  *elen = end - data + 1;
621
107k
  return TRUE;
622
107k
}
623
624
static BOOL freerdp_assistance_parse_all_elements_of(rdpAssistanceFile* file, char* data,
625
                                                     size_t len, const char* key,
626
                                                     BOOL (*fkt)(rdpAssistanceFile* file,
627
                                                                 char* data, size_t len))
628
5.36k
{
629
5.36k
  char* val = NULL;
630
5.36k
  size_t vlen = 0;
631
632
112k
  while (freerdp_assistance_get_element(data, len, key, &val, &vlen))
633
107k
  {
634
107k
    data = val + vlen;
635
107k
    len = strnlen(data, len);
636
107k
    if (vlen > 0)
637
107k
    {
638
107k
      val[vlen - 1] = '\0';
639
640
107k
      if (!fkt(file, val, vlen))
641
217
        return FALSE;
642
107k
    }
643
107k
  }
644
645
5.15k
  return TRUE;
646
5.36k
}
647
648
static BOOL freerdp_assistance_parse_all_elements_of_l(rdpAssistanceFile* file, char* data,
649
                                                       size_t len)
650
102k
{
651
102k
  UINT32 p = 0;
652
102k
  const char* n = NULL;
653
102k
  const char* u = NULL;
654
102k
  size_t nlen = 0;
655
102k
  size_t ulen = 0;
656
102k
  if (!freerdp_assistance_parse_attr_uint32(&p, "P", data))
657
1
    return FALSE;
658
102k
  if (!freerdp_assistance_parse_attr(&n, &nlen, "N", data))
659
1
    return FALSE;
660
102k
  if (!freerdp_assistance_parse_attr(&u, &ulen, "U", data))
661
1
    return FALSE;
662
663
102k
  if (!ArrayList_Append(file->MachineAddresses, strndup(n, nlen)))
664
0
    return FALSE;
665
102k
  if (!ArrayList_Append(file->MachineAddresses, strndup(u, ulen)))
666
0
    return FALSE;
667
102k
  if (!ArrayList_Append(file->MachinePorts, (void*)(uintptr_t)p))
668
0
    return FALSE;
669
102k
  return TRUE;
670
102k
}
671
672
static BOOL freerdp_assistance_parse_all_elements_of_t(rdpAssistanceFile* file, char* data,
673
                                                       size_t len)
674
842
{
675
842
  UINT32 id = 0;
676
842
  UINT32 sid = 0;
677
842
  if (!freerdp_assistance_parse_attr_uint32(&id, "ID", data))
678
103
    return FALSE;
679
739
  if (!freerdp_assistance_parse_attr_uint32(&sid, "SID", data))
680
1
    return FALSE;
681
738
  WLog_DBG(TAG, "transport id=%" PRIu32 ", sid=%" PRIu32, id, sid);
682
738
  return freerdp_assistance_parse_all_elements_of(file, data, len, "L",
683
738
                                                  freerdp_assistance_parse_all_elements_of_l);
684
739
}
685
686
static BOOL freerdp_assistance_parse_all_elements_of_c(rdpAssistanceFile* file, char* data,
687
                                                       size_t len)
688
4.23k
{
689
4.23k
  return freerdp_assistance_parse_all_elements_of(file, data, len, "T",
690
4.23k
                                                  freerdp_assistance_parse_all_elements_of_t);
691
4.23k
}
692
693
static BOOL freerdp_assistance_parse_find_elements_of_c(rdpAssistanceFile* file, char* data,
694
                                                        size_t len)
695
394
{
696
394
  return freerdp_assistance_parse_all_elements_of(file, data, len, "C",
697
394
                                                  freerdp_assistance_parse_all_elements_of_c);
698
394
}
699
700
static BOOL freerdp_assistance_parse_connection_string2(rdpAssistanceFile* file)
701
494
{
702
494
  BOOL rc = FALSE;
703
704
494
  WINPR_ASSERT(file);
705
706
494
  if (!file->ConnectionString2)
707
1
    return FALSE;
708
709
493
  char* str = _strdup(file->ConnectionString2);
710
493
  if (!str)
711
0
    goto out_fail;
712
713
493
  char* e = NULL;
714
493
  size_t elen = 0;
715
493
  if (!freerdp_assistance_consume_input_and_get_element(str, "E", &e, &elen))
716
84
    goto out_fail;
717
718
409
  if (!e || (elen == 0))
719
0
    goto out_fail;
720
721
409
  char* a = NULL;
722
409
  size_t alen = 0;
723
409
  if (!freerdp_assistance_get_element(e, elen, "A", &a, &alen))
724
15
    goto out_fail;
725
726
394
  if (!a || (alen == 0))
727
0
    goto out_fail;
728
729
394
  if (!freerdp_assistance_parse_find_elements_of_c(file, e, elen))
730
107
    goto out_fail;
731
732
  /* '\0' terminate the detected XML elements so
733
   * the parser can continue with terminated strings
734
   */
735
287
  a[alen] = '\0';
736
287
  if (!freerdp_assistance_parse_attr_str(&file->RASpecificParams, "KH", a))
737
45
    goto out_fail;
738
739
242
  if (!freerdp_assistance_parse_attr_str(&file->RASpecificParams2, "KH2", a))
740
2
    goto out_fail;
741
742
240
  if (!freerdp_assistance_parse_attr_str(&file->RASessionId, "ID", a))
743
2
    goto out_fail;
744
745
238
  rc = TRUE;
746
493
out_fail:
747
493
  free(str);
748
493
  return rc;
749
238
}
750
751
char* freerdp_assistance_construct_expert_blob(const char* name, const char* pass)
752
0
{
753
0
  size_t size;
754
0
  size_t nameLength;
755
0
  size_t passLength;
756
0
  char* ExpertBlob = NULL;
757
758
0
  if (!name || !pass)
759
0
    return NULL;
760
761
0
  nameLength = strlen(name) + strlen("NAME=");
762
0
  passLength = strlen(pass) + strlen("PASS=");
763
0
  size = nameLength + passLength + 64;
764
0
  ExpertBlob = (char*)calloc(1, size);
765
766
0
  if (!ExpertBlob)
767
0
    return NULL;
768
769
0
  sprintf_s(ExpertBlob, size, "%" PRIdz ";NAME=%s%" PRIdz ";PASS=%s", nameLength, name,
770
0
            passLength, pass);
771
0
  return ExpertBlob;
772
0
}
773
774
char* freerdp_assistance_generate_pass_stub(DWORD flags)
775
0
{
776
0
  UINT32 nums[14];
777
0
  char* passStub = NULL;
778
0
  char set1[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789*_";
779
0
  char set2[12] = "!@#$&^*()-+=";
780
0
  char set3[10] = "0123456789";
781
0
  char set4[26] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
782
0
  char set5[26] = "abcdefghijklmnopqrstuvwxyz";
783
0
  passStub = (char*)malloc(15);
784
785
0
  if (!passStub)
786
0
    return NULL;
787
788
  /**
789
   * PassStub generation:
790
   *
791
   * Characters 0 and 5-13 are from the set A-Z a-z 0-9 * _
792
   * Character 1 is from the set !@#$&^*()-+=
793
   * Character 2 is from the set 0-9
794
   * Character 3 is from the set A-Z
795
   * Character 4 is from the set a-z
796
   *
797
   * Example: WB^6HsrIaFmEpi
798
   */
799
0
  winpr_RAND(nums, sizeof(nums));
800
0
  passStub[0] = set1[nums[0] % sizeof(set1)];   /* character 0 */
801
0
  passStub[1] = set2[nums[1] % sizeof(set2)];   /* character 1 */
802
0
  passStub[2] = set3[nums[2] % sizeof(set3)];   /* character 2 */
803
0
  passStub[3] = set4[nums[3] % sizeof(set4)];   /* character 3 */
804
0
  passStub[4] = set5[nums[4] % sizeof(set5)];   /* character 4 */
805
0
  passStub[5] = set1[nums[5] % sizeof(set1)];   /* character 5 */
806
0
  passStub[6] = set1[nums[6] % sizeof(set1)];   /* character 6 */
807
0
  passStub[7] = set1[nums[7] % sizeof(set1)];   /* character 7 */
808
0
  passStub[8] = set1[nums[8] % sizeof(set1)];   /* character 8 */
809
0
  passStub[9] = set1[nums[9] % sizeof(set1)];   /* character 9 */
810
0
  passStub[10] = set1[nums[10] % sizeof(set1)]; /* character 10 */
811
0
  passStub[11] = set1[nums[11] % sizeof(set1)]; /* character 11 */
812
0
  passStub[12] = set1[nums[12] % sizeof(set1)]; /* character 12 */
813
0
  passStub[13] = set1[nums[13] % sizeof(set1)]; /* character 13 */
814
0
  passStub[14] = '\0';
815
0
  return passStub;
816
0
}
817
818
BYTE* freerdp_assistance_encrypt_pass_stub(const char* password, const char* passStub,
819
                                           size_t* pEncryptedSize)
820
92
{
821
92
  BOOL rc;
822
92
  size_t cbPasswordW;
823
92
  size_t cbPassStubW;
824
92
  size_t EncryptedSize;
825
92
  BYTE PasswordHash[WINPR_MD5_DIGEST_LENGTH];
826
92
  WINPR_CIPHER_CTX* rc4Ctx = NULL;
827
92
  BYTE* pbIn = NULL;
828
92
  BYTE* pbOut = NULL;
829
92
  size_t cbOut, cbIn, cbFinal;
830
92
  WCHAR* PasswordW = ConvertUtf8ToWCharAlloc(password, &cbPasswordW);
831
92
  WCHAR* PassStubW = ConvertUtf8ToWCharAlloc(passStub, &cbPassStubW);
832
833
92
  if (!PasswordW || !PassStubW)
834
1
    goto fail;
835
836
91
  cbPasswordW = (cbPasswordW) * sizeof(WCHAR);
837
91
  cbPassStubW = (cbPassStubW) * sizeof(WCHAR);
838
91
  if (!winpr_Digest(WINPR_MD_MD5, (BYTE*)PasswordW, cbPasswordW, (BYTE*)PasswordHash,
839
91
                    sizeof(PasswordHash)))
840
0
    goto fail;
841
842
91
  EncryptedSize = cbPassStubW + 4;
843
91
  pbIn = (BYTE*)calloc(1, EncryptedSize);
844
91
  pbOut = (BYTE*)calloc(1, EncryptedSize);
845
846
91
  if (!pbIn || !pbOut)
847
0
    goto fail;
848
849
91
  *((UINT32*)pbIn) = (UINT32)cbPassStubW;
850
91
  CopyMemory(&pbIn[4], PassStubW, cbPassStubW);
851
91
  rc4Ctx = winpr_Cipher_New(WINPR_CIPHER_ARC4_128, WINPR_ENCRYPT, PasswordHash, NULL);
852
853
91
  if (!rc4Ctx)
854
0
  {
855
0
    WLog_ERR(TAG, "winpr_Cipher_New failure");
856
0
    goto fail;
857
0
  }
858
859
91
  cbOut = cbFinal = 0;
860
91
  cbIn = EncryptedSize;
861
91
  rc = winpr_Cipher_Update(rc4Ctx, pbIn, cbIn, pbOut, &cbOut);
862
863
91
  if (!rc)
864
0
  {
865
0
    WLog_ERR(TAG, "winpr_Cipher_Update failure");
866
0
    goto fail;
867
0
  }
868
869
91
  if (!winpr_Cipher_Final(rc4Ctx, pbOut + cbOut, &cbFinal))
870
0
  {
871
0
    WLog_ERR(TAG, "winpr_Cipher_Final failure");
872
0
    goto fail;
873
0
  }
874
875
91
  winpr_Cipher_Free(rc4Ctx);
876
91
  free(pbIn);
877
91
  free(PasswordW);
878
91
  free(PassStubW);
879
91
  *pEncryptedSize = EncryptedSize;
880
91
  return pbOut;
881
1
fail:
882
1
  winpr_Cipher_Free(rc4Ctx);
883
1
  free(PasswordW);
884
1
  free(PassStubW);
885
1
  free(pbIn);
886
1
  free(pbOut);
887
1
  return NULL;
888
91
}
889
890
static BOOL freerdp_assistance_decrypt2(rdpAssistanceFile* file)
891
368
{
892
368
  BOOL rc = FALSE;
893
368
  int status = 0;
894
368
  size_t cbPasswordW;
895
368
  size_t cchOutW = 0;
896
368
  WINPR_CIPHER_CTX* aesDec = NULL;
897
368
  WCHAR* PasswordW = NULL;
898
368
  BYTE* pbIn = NULL;
899
368
  BYTE* pbOut = NULL;
900
368
  size_t cbOut, cbIn, cbFinal;
901
368
  BYTE DerivedKey[WINPR_AES_BLOCK_SIZE] = { 0 };
902
368
  BYTE InitializationVector[WINPR_AES_BLOCK_SIZE] = { 0 };
903
368
  BYTE PasswordHash[WINPR_SHA1_DIGEST_LENGTH] = { 0 };
904
905
368
  WINPR_ASSERT(file);
906
907
368
  if (!file->password)
908
0
    return FALSE;
909
910
368
  PasswordW = ConvertUtf8ToWCharAlloc(file->password, &cbPasswordW);
911
368
  if (!PasswordW)
912
0
  {
913
0
    WLog_ERR(TAG, "Failed to parse ASSISTANCE file: Conversion from UCS2 to UTF8 failed");
914
0
    return FALSE;
915
0
  }
916
917
368
  cbPasswordW = (cbPasswordW) * sizeof(WCHAR);
918
919
368
  if (!winpr_Digest(WINPR_MD_SHA1, (BYTE*)PasswordW, cbPasswordW, PasswordHash,
920
368
                    sizeof(PasswordHash)))
921
0
    goto fail;
922
923
368
  if (!freerdp_assistance_crypt_derive_key_sha1(PasswordHash, sizeof(PasswordHash), DerivedKey,
924
368
                                                sizeof(DerivedKey)))
925
0
    goto fail;
926
927
368
  aesDec =
928
368
      winpr_Cipher_New(WINPR_CIPHER_AES_128_CBC, WINPR_DECRYPT, DerivedKey, InitializationVector);
929
930
368
  if (!aesDec)
931
0
    goto fail;
932
933
368
  cbOut = cbFinal = 0;
934
368
  cbIn = (size_t)file->EncryptedLHTicketLength;
935
368
  pbIn = (BYTE*)file->EncryptedLHTicket;
936
368
  pbOut = (BYTE*)calloc(1, cbIn + WINPR_AES_BLOCK_SIZE + 2);
937
938
368
  if (!pbOut)
939
0
    goto fail;
940
941
368
  if (!winpr_Cipher_Update(aesDec, pbIn, cbIn, pbOut, &cbOut))
942
0
    goto fail;
943
944
368
  if (!winpr_Cipher_Final(aesDec, pbOut + cbOut, &cbFinal))
945
211
  {
946
211
    WLog_ERR(TAG, "winpr_Cipher_Final failure");
947
211
    goto fail;
948
211
  }
949
950
157
  cbOut += cbFinal;
951
157
  cbFinal = 0;
952
953
157
  union
954
157
  {
955
157
    const WCHAR* wc;
956
157
    const BYTE* b;
957
157
  } cnv;
958
959
157
  cnv.b = pbOut;
960
157
  cchOutW = cbOut / sizeof(WCHAR);
961
962
157
  if (!update_connectionstring2_wchar(file, cnv.wc, cchOutW))
963
75
  {
964
75
    WLog_ERR(TAG, "Failed to parse ASSISTANCE file: Conversion from UCS2 to UTF8 failed");
965
75
    goto fail;
966
75
  }
967
968
82
  if (!freerdp_assistance_parse_connection_string2(file))
969
82
    goto fail;
970
971
0
  rc = TRUE;
972
368
fail:
973
368
  winpr_Cipher_Free(aesDec);
974
368
  free(PasswordW);
975
368
  free(pbOut);
976
368
  WLog_DBG(TAG, "freerdp_assistance_parse_connection_string2: %d", status);
977
368
  return rc;
978
0
}
979
980
BYTE* freerdp_assistance_hex_string_to_bin(const void* raw, size_t* size)
981
630
{
982
630
  BYTE* buffer = NULL;
983
630
  if (!raw || !size)
984
0
    return NULL;
985
630
  *size = 0;
986
630
  const size_t length = strlen(raw);
987
630
  buffer = calloc(length, sizeof(BYTE));
988
630
  if (!buffer)
989
0
    return NULL;
990
630
  const size_t rc = winpr_HexStringToBinBuffer(raw, length, buffer, length);
991
630
  if (rc == 0)
992
2
  {
993
2
    free(buffer);
994
2
    return NULL;
995
2
  }
996
628
  *size = rc;
997
628
  return buffer;
998
630
}
999
1000
char* freerdp_assistance_bin_to_hex_string(const void* raw, size_t size)
1001
53
{
1002
53
  return winpr_BinToHexString(raw, size, FALSE);
1003
53
}
1004
1005
static int freerdp_assistance_parse_uploadinfo(rdpAssistanceFile* file, char* uploadinfo,
1006
                                               size_t uploadinfosize)
1007
899
{
1008
899
  const char escalated[9] = "Escalated";
1009
899
  const size_t esclen = sizeof(escalated);
1010
899
  const char* typestr = NULL;
1011
899
  size_t typelen = 0;
1012
1013
899
  if (!uploadinfo || (uploadinfosize == 0))
1014
0
    return -1;
1015
1016
899
  if (strnlen(uploadinfo, uploadinfosize) == uploadinfosize)
1017
0
  {
1018
0
    WLog_WARN(TAG, "UPLOADINFOR string is not '\0' terminated");
1019
0
    return -1;
1020
0
  }
1021
1022
899
  if (!freerdp_assistance_parse_attr(&typestr, &typelen, "TYPE", uploadinfo))
1023
2
    return -1;
1024
1025
897
  if ((typelen != esclen) || (strncmp(typestr, escalated, esclen) != 0))
1026
131
  {
1027
131
    WLog_ERR(TAG,
1028
131
             "Failed to parse ASSISTANCE file: Missing or invalid UPLOADINFO TYPE '%s' [%" PRIuz
1029
131
             "]",
1030
131
             typestr, typelen);
1031
131
    return -1;
1032
131
  }
1033
1034
766
  char* uploaddata = NULL;
1035
766
  size_t uploaddatasize = 0;
1036
766
  if (!freerdp_assistance_consume_input_and_get_element(uploadinfo, "UPLOADDATA", &uploaddata,
1037
766
                                                        &uploaddatasize))
1038
2
    return -1;
1039
1040
  /* Parse USERNAME */
1041
764
  if (!freerdp_assistance_parse_attr_str(&file->Username, "USERNAME", uploaddata))
1042
1
    return -1;
1043
1044
  /* Parse LHTICKET */
1045
763
  if (!freerdp_assistance_parse_attr_str(&file->LHTicket, "LHTICKET", uploaddata))
1046
1
    return -1;
1047
1048
  /* Parse RCTICKET */
1049
762
  if (!freerdp_assistance_parse_attr_str(&file->RCTicket, "RCTICKET", uploaddata))
1050
1
    return -1;
1051
1052
  /* Parse RCTICKETENCRYPTED */
1053
761
  if (!freerdp_assistance_parse_attr_bool(&file->RCTicketEncrypted, "RCTICKETENCRYPTED",
1054
761
                                          uploaddata))
1055
1
    return -1;
1056
1057
  /* Parse PassStub */
1058
760
  if (!freerdp_assistance_parse_attr_str(&file->PassStub, "PassStub", uploaddata))
1059
1
    return -1;
1060
1061
759
  if (file->PassStub)
1062
50
  {
1063
50
    const char* amp = "&amp;";
1064
50
    char* passtub = strstr(file->PassStub, amp);
1065
253
    while (passtub)
1066
203
    {
1067
203
      const char* end = passtub + 5;
1068
203
      const size_t len = strlen(end);
1069
203
      memmove(&passtub[1], end, len + 1);
1070
203
      passtub = strstr(passtub, amp);
1071
203
    }
1072
50
  }
1073
1074
  /* Parse DtStart */
1075
759
  if (!freerdp_assistance_parse_attr_uint32(&file->DtStart, "DtStart", uploaddata))
1076
1
    return -1;
1077
1078
  /* Parse DtLength */
1079
758
  if (!freerdp_assistance_parse_attr_uint32(&file->DtLength, "DtLength", uploaddata))
1080
1
    return -1;
1081
1082
  /* Parse L (LowSpeed) */
1083
757
  if (!freerdp_assistance_parse_attr_bool(&file->LowSpeed, "L", uploaddata))
1084
1
    return -1;
1085
1086
756
  file->Type = (file->LHTicket) ? 2 : 1;
1087
756
  int status = 0;
1088
1089
756
  switch (file->Type)
1090
756
  {
1091
368
    case 2:
1092
368
    {
1093
368
      file->EncryptedLHTicket = freerdp_assistance_hex_string_to_bin(
1094
368
          file->LHTicket, &file->EncryptedLHTicketLength);
1095
1096
368
      if (!freerdp_assistance_decrypt2(file))
1097
368
        status = -1;
1098
368
    }
1099
368
    break;
1100
1101
388
    case 1:
1102
388
    {
1103
388
      if (!freerdp_assistance_parse_connection_string1(file))
1104
296
        status = -1;
1105
388
    }
1106
388
    break;
1107
1108
0
    default:
1109
0
      return -1;
1110
756
  }
1111
1112
756
  if (status < 0)
1113
664
  {
1114
664
    WLog_ERR(TAG, "freerdp_assistance_parse_connection_string1 failure: %d", status);
1115
664
    return -1;
1116
664
  }
1117
1118
92
  file->EncryptedPassStub = freerdp_assistance_encrypt_pass_stub(file->password, file->PassStub,
1119
92
                                                                 &file->EncryptedPassStubLength);
1120
1121
92
  if (!file->EncryptedPassStub)
1122
1
    return -1;
1123
1124
91
  return 1;
1125
92
}
1126
1127
static int freerdp_assistance_parse_file_buffer_int(rdpAssistanceFile* file, char* buffer,
1128
                                                    size_t size, const char* password)
1129
1.34k
{
1130
1.34k
  WINPR_ASSERT(file);
1131
1.34k
  WINPR_ASSERT(buffer);
1132
1.34k
  WINPR_ASSERT(size > 0);
1133
1134
1.34k
  if (!update_password(file, password))
1135
0
    return -1;
1136
1137
1.34k
  char* uploadinfo = NULL;
1138
1.34k
  size_t uploadinfosize = 0;
1139
1.34k
  if (freerdp_assistance_consume_input_and_get_element(buffer, "UPLOADINFO", &uploadinfo,
1140
1.34k
                                                       &uploadinfosize))
1141
899
    return freerdp_assistance_parse_uploadinfo(file, uploadinfo, uploadinfosize);
1142
1143
444
  size_t elen = 0;
1144
444
  const char* estr = freerdp_assistance_contains_element(buffer, size, "E", &elen, NULL, NULL);
1145
444
  if (!estr || (elen == 0))
1146
32
  {
1147
32
    WLog_ERR(TAG, "Failed to parse ASSISTANCE file: Neither UPLOADINFO nor <E> found");
1148
32
    return -1;
1149
32
  }
1150
412
  if (!update_connectionstring2(file, estr, elen))
1151
0
    return -1;
1152
1153
412
  if (!freerdp_assistance_parse_connection_string2(file))
1154
174
    return -1;
1155
1156
238
  return 1;
1157
412
}
1158
1159
int freerdp_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* cbuffer, size_t size,
1160
                                         const char* password)
1161
1.34k
{
1162
1.34k
  WINPR_ASSERT(file);
1163
1.34k
  if (!password)
1164
0
  {
1165
0
    WLog_WARN(TAG, "empty password supplied");
1166
0
  }
1167
1168
1.34k
  if (!cbuffer || (size == 0))
1169
0
  {
1170
0
    WLog_WARN(TAG, "no data supplied [%p, %" PRIuz "]", cbuffer, size);
1171
0
    return -1;
1172
0
  }
1173
1174
1.34k
  char* abuffer = strndup(cbuffer, size);
1175
1.34k
  const size_t len = strnlen(cbuffer, size);
1176
1.34k
  if (len == size)
1177
1.34k
    WLog_WARN(TAG, "Input data not '\0' terminated");
1178
1179
1.34k
  if (!abuffer)
1180
0
    return -1;
1181
1182
1.34k
  const int rc = freerdp_assistance_parse_file_buffer_int(file, abuffer, len + 1, password);
1183
1.34k
  free(abuffer);
1184
1.34k
  return rc;
1185
1.34k
}
1186
1187
int freerdp_assistance_parse_file(rdpAssistanceFile* file, const char* name, const char* password)
1188
0
{
1189
0
  int status;
1190
0
  BYTE* buffer;
1191
0
  FILE* fp = NULL;
1192
0
  size_t readSize;
1193
0
  union
1194
0
  {
1195
0
    INT64 i64;
1196
0
    size_t s;
1197
0
  } fileSize;
1198
1199
0
  if (!update_name(file, name))
1200
0
    return -1;
1201
1202
0
  fp = winpr_fopen(name, "r");
1203
1204
0
  if (!fp)
1205
0
  {
1206
0
    WLog_ERR(TAG, "Failed to open ASSISTANCE file %s ", name);
1207
0
    return -1;
1208
0
  }
1209
1210
0
  _fseeki64(fp, 0, SEEK_END);
1211
0
  fileSize.i64 = _ftelli64(fp);
1212
0
  _fseeki64(fp, 0, SEEK_SET);
1213
1214
0
  if (fileSize.i64 < 1)
1215
0
  {
1216
0
    WLog_ERR(TAG, "Failed to read ASSISTANCE file %s ", name);
1217
0
    fclose(fp);
1218
0
    return -1;
1219
0
  }
1220
1221
0
  buffer = (BYTE*)malloc(fileSize.s + 2);
1222
1223
0
  if (!buffer)
1224
0
  {
1225
0
    fclose(fp);
1226
0
    return -1;
1227
0
  }
1228
1229
0
  readSize = fread(buffer, fileSize.s, 1, fp);
1230
1231
0
  if (!readSize)
1232
0
  {
1233
0
    if (!ferror(fp))
1234
0
      readSize = fileSize.s;
1235
0
  }
1236
1237
0
  fclose(fp);
1238
1239
0
  if (readSize < 1)
1240
0
  {
1241
0
    WLog_ERR(TAG, "Failed to read ASSISTANCE file %s ", name);
1242
0
    free(buffer);
1243
0
    buffer = NULL;
1244
0
    return -1;
1245
0
  }
1246
1247
0
  buffer[fileSize.s] = '\0';
1248
0
  buffer[fileSize.s + 1] = '\0';
1249
0
  status = freerdp_assistance_parse_file_buffer(file, (char*)buffer, fileSize.s, password);
1250
0
  free(buffer);
1251
0
  return status;
1252
0
}
1253
1254
BOOL freerdp_assistance_populate_settings_from_assistance_file(rdpAssistanceFile* file,
1255
                                                               rdpSettings* settings)
1256
0
{
1257
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteAssistanceMode, TRUE))
1258
0
    return FALSE;
1259
1260
0
  if (!file->RASessionId || !file->MachineAddresses)
1261
0
    return FALSE;
1262
1263
0
  if (!freerdp_settings_set_string(settings, FreeRDP_RemoteAssistanceSessionId,
1264
0
                                   file->RASessionId))
1265
0
    return FALSE;
1266
1267
0
  if (file->RCTicket)
1268
0
  {
1269
0
    if (!freerdp_settings_set_string(settings, FreeRDP_RemoteAssistanceRCTicket,
1270
0
                                     file->RCTicket))
1271
0
      return FALSE;
1272
0
  }
1273
0
  else
1274
0
  {
1275
0
    if (!freerdp_settings_set_string(settings, FreeRDP_RemoteAssistanceRCTicket,
1276
0
                                     file->ConnectionString2))
1277
0
      return FALSE;
1278
0
  }
1279
1280
0
  if (file->PassStub)
1281
0
  {
1282
0
    if (!freerdp_settings_set_string(settings, FreeRDP_RemoteAssistancePassStub,
1283
0
                                     file->PassStub))
1284
0
      return FALSE;
1285
0
  }
1286
1287
0
  if (ArrayList_Count(file->MachineAddresses) < 1)
1288
0
    return FALSE;
1289
1290
0
  const char* addr = ArrayList_GetItem(file->MachineAddresses, 0);
1291
0
  if (!freerdp_settings_set_string(settings, FreeRDP_ServerHostname, addr))
1292
0
    return FALSE;
1293
1294
0
  if (!freerdp_settings_set_string(settings, FreeRDP_AssistanceFile, file->filename))
1295
0
    return FALSE;
1296
1297
0
  if (!freerdp_settings_set_string(settings, FreeRDP_RemoteAssistancePassword, file->password))
1298
0
    return FALSE;
1299
1300
0
  if (file->Username)
1301
0
  {
1302
0
    if (!freerdp_settings_set_string(settings, FreeRDP_Username, file->Username))
1303
0
      return FALSE;
1304
0
  }
1305
1306
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteAssistanceMode, TRUE))
1307
0
    return FALSE;
1308
1309
0
  size_t ports = ArrayList_Count(file->MachinePorts);
1310
0
  if (ports < 1)
1311
0
    return FALSE;
1312
1313
0
  const UINT32 port = (UINT32)ArrayList_GetItem(file->MachinePorts, 0);
1314
0
  if (!freerdp_settings_set_uint32(settings, FreeRDP_ServerPort, port))
1315
0
    return FALSE;
1316
1317
0
  if (!freerdp_settings_set_pointer_len(settings, FreeRDP_TargetNetAddresses, NULL, ports))
1318
0
    return FALSE;
1319
0
  if (!freerdp_settings_set_pointer_len(settings, FreeRDP_TargetNetPorts, file->MachinePorts,
1320
0
                                        ports))
1321
0
    return FALSE;
1322
1323
0
  for (size_t i = 0; i < ArrayList_Count(file->MachineAddresses); i++)
1324
0
  {
1325
0
    const char* maddr = ArrayList_GetItem(file->MachineAddresses, i);
1326
0
    if (!freerdp_settings_set_pointer_array(settings, FreeRDP_TargetNetAddresses, i, maddr))
1327
0
      return FALSE;
1328
0
  }
1329
1330
0
  return TRUE;
1331
0
}
1332
1333
static BOOL setup_string(wArrayList* list)
1334
2.68k
{
1335
2.68k
  WINPR_ASSERT(list);
1336
1337
2.68k
  wObject* obj = ArrayList_Object(list);
1338
2.68k
  if (!obj)
1339
0
    return FALSE;
1340
2.68k
  obj->fnObjectFree = free;
1341
  // obj->fnObjectNew = _strdup;
1342
2.68k
  return TRUE;
1343
2.68k
}
1344
1345
rdpAssistanceFile* freerdp_assistance_file_new(void)
1346
1.34k
{
1347
1.34k
  winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
1348
1.34k
  rdpAssistanceFile* file = calloc(1, sizeof(rdpAssistanceFile));
1349
1.34k
  if (!file)
1350
0
    return NULL;
1351
1352
1.34k
  file->MachineAddresses = ArrayList_New(FALSE);
1353
1.34k
  file->MachinePorts = ArrayList_New(FALSE);
1354
1.34k
  file->MachineUris = ArrayList_New(FALSE);
1355
1356
1.34k
  if (!file->MachineAddresses || !file->MachinePorts || !file->MachineUris)
1357
0
    goto fail;
1358
1359
1.34k
  if (!setup_string(file->MachineAddresses) || !setup_string(file->MachineUris))
1360
0
    goto fail;
1361
1362
1.34k
  return file;
1363
1364
0
fail:
1365
0
  freerdp_assistance_file_free(file);
1366
0
  return NULL;
1367
1.34k
}
1368
1369
void freerdp_assistance_file_free(rdpAssistanceFile* file)
1370
1.34k
{
1371
1.34k
  if (!file)
1372
0
    return;
1373
1374
1.34k
  update_password(file, NULL);
1375
1.34k
  update_connectionstring2(file, NULL, 0);
1376
1.34k
  free(file->filename);
1377
1.34k
  free(file->Username);
1378
1.34k
  free(file->LHTicket);
1379
1.34k
  free(file->RCTicket);
1380
1.34k
  free(file->PassStub);
1381
1.34k
  free(file->ConnectionString1);
1382
1.34k
  free(file->EncryptedLHTicket);
1383
1.34k
  free(file->RASessionId);
1384
1.34k
  free(file->RASpecificParams);
1385
1.34k
  free(file->RASpecificParams2);
1386
1.34k
  free(file->EncryptedPassStub);
1387
1388
1.34k
  ArrayList_Free(file->MachineAddresses);
1389
1.34k
  ArrayList_Free(file->MachinePorts);
1390
1.34k
  ArrayList_Free(file->MachineUris);
1391
1.34k
  free(file);
1392
1.34k
}
1393
1394
void freerdp_assistance_print_file(rdpAssistanceFile* file, wLog* log, DWORD level)
1395
0
{
1396
0
  WINPR_ASSERT(file);
1397
1398
0
  WLog_Print(log, level, "Username: %s", file->Username);
1399
0
  WLog_Print(log, level, "LHTicket: %s", file->LHTicket);
1400
0
  WLog_Print(log, level, "RCTicket: %s", file->RCTicket);
1401
0
  WLog_Print(log, level, "RCTicketEncrypted: %" PRId32, file->RCTicketEncrypted);
1402
0
  WLog_Print(log, level, "PassStub: %s", file->PassStub);
1403
0
  WLog_Print(log, level, "DtStart: %" PRIu32, file->DtStart);
1404
0
  WLog_Print(log, level, "DtLength: %" PRIu32, file->DtLength);
1405
0
  WLog_Print(log, level, "LowSpeed: %" PRId32, file->LowSpeed);
1406
0
  WLog_Print(log, level, "RASessionId: %s", file->RASessionId);
1407
0
  WLog_Print(log, level, "RASpecificParams: %s", file->RASpecificParams);
1408
0
  WLog_Print(log, level, "RASpecificParams2: %s", file->RASpecificParams2);
1409
1410
0
  for (size_t x = 0; x < ArrayList_Count(file->MachineAddresses); x++)
1411
0
  {
1412
0
    UINT32 port = 0;
1413
0
    const char* uri = NULL;
1414
0
    const char* addr = ArrayList_GetItem(file->MachineAddresses, x);
1415
0
    if (x < ArrayList_Count(file->MachinePorts))
1416
0
      port = (UINT32)ArrayList_GetItem(file->MachinePorts, x);
1417
0
    if (x < ArrayList_Count(file->MachineUris))
1418
0
      uri = ArrayList_GetItem(file->MachineUris, x);
1419
1420
0
    WLog_Print(log, level, "MachineAddress [%" PRIdz ": %s", x, addr);
1421
0
    WLog_Print(log, level, "MachinePort    [%" PRIdz ": %" PRIu32, x, port);
1422
0
    WLog_Print(log, level, "MachineURI     [%" PRIdz ": %s", x, uri);
1423
0
  }
1424
0
}
1425
1426
BOOL freerdp_assistance_get_encrypted_pass_stub(rdpAssistanceFile* file, const char** pwd,
1427
                                                size_t* size)
1428
0
{
1429
0
  if (!file || !pwd || !size)
1430
0
    return FALSE;
1431
1432
0
  *pwd = (const char*)file->EncryptedPassStub;
1433
0
  *size = file->EncryptedPassStubLength;
1434
0
  return TRUE;
1435
0
}
1436
1437
int freerdp_assistance_set_connection_string2(rdpAssistanceFile* file, const char* string,
1438
                                              const char* password)
1439
0
{
1440
0
  if (!file || !string || !password)
1441
0
    return -1;
1442
1443
0
  char* str = _strdup(string);
1444
0
  if (!str)
1445
0
    return -1;
1446
1447
0
  if (!update_connectionstring2_nocopy(file, str))
1448
0
    return -1;
1449
0
  if (!update_password(file, password))
1450
0
    return -1;
1451
0
  return freerdp_assistance_parse_connection_string2(file);
1452
0
}