Coverage Report

Created: 2024-05-20 06:11

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