/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.49k  | { | 
80  | 2.49k  |   if (*needle == '\0')  | 
81  | 0  |     return haystack;  | 
82  |  |  | 
83  | 2.49k  |   char* result = NULL;  | 
84  | 2.49k  |   for (;;)  | 
85  | 5.48k  |   { | 
86  | 5.48k  |     char* p = strstr(haystack, needle);  | 
87  | 5.48k  |     if (p == NULL)  | 
88  | 2.49k  |       break;  | 
89  | 2.99k  |     if (p > haystack + len)  | 
90  | 0  |       return NULL;  | 
91  |  |  | 
92  | 2.99k  |     result = p;  | 
93  | 2.99k  |     haystack = p + 1;  | 
94  | 2.99k  |   }  | 
95  |  |  | 
96  | 2.49k  |   return result;  | 
97  | 2.49k  | }  | 
98  |  |  | 
99  |  | static BOOL update_option(char** opt, const char* val, size_t len)  | 
100  | 5.19k  | { | 
101  | 5.19k  |   WINPR_ASSERT(opt);  | 
102  | 5.19k  |   free(*opt);  | 
103  | 5.19k  |   *opt = NULL;  | 
104  |  |  | 
105  | 5.19k  |   if (!val && (len != 0))  | 
106  | 0  |     return FALSE;  | 
107  | 5.19k  |   else if (!val && (len == 0))  | 
108  | 3.84k  |     return TRUE;  | 
109  | 1.35k  |   *opt = strndup(val, len);  | 
110  | 1.35k  |   return *opt != NULL;  | 
111  | 5.19k  | }  | 
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.38k  | { | 
130  | 3.38k  |   WINPR_ASSERT(file);  | 
131  | 3.38k  |   free(file->password);  | 
132  | 3.38k  |   file->password = NULL;  | 
133  | 3.38k  |   if (!password)  | 
134  | 1.69k  |     return TRUE;  | 
135  | 1.69k  |   file->password = _strdup(password);  | 
136  | 1.69k  |   return file->password != NULL;  | 
137  | 3.38k  | }  | 
138  |  |  | 
139  |  | static BOOL update_connectionstring2_nocopy(rdpAssistanceFile* file, char* str)  | 
140  | 2.30k  | { | 
141  | 2.30k  |   WINPR_ASSERT(file);  | 
142  | 2.30k  |   free(file->ConnectionString2);  | 
143  | 2.30k  |   file->ConnectionString2 = NULL;  | 
144  | 2.30k  |   if (!str)  | 
145  | 1.69k  |     return TRUE;  | 
146  | 611  |   file->ConnectionString2 = str;  | 
147  | 611  |   return file->ConnectionString2 != NULL;  | 
148  | 2.30k  | }  | 
149  |  |  | 
150  |  | static BOOL update_connectionstring2(rdpAssistanceFile* file, const char* str, size_t len)  | 
151  | 2.13k  | { | 
152  | 2.13k  |   char* strc = NULL;  | 
153  | 2.13k  |   if (!str && (len != 0))  | 
154  | 0  |     return FALSE;  | 
155  |  |  | 
156  | 2.13k  |   if (str && (len > 0))  | 
157  | 440  |   { | 
158  | 440  |     strc = strndup(str, len);  | 
159  | 440  |     if (!strc)  | 
160  | 0  |       return FALSE;  | 
161  | 440  |   }  | 
162  | 2.13k  |   return update_connectionstring2_nocopy(file, strc);  | 
163  | 2.13k  | }  | 
164  |  |  | 
165  |  | static BOOL update_connectionstring2_wchar(rdpAssistanceFile* file, const WCHAR* str, size_t len)  | 
166  | 253  | { | 
167  | 253  |   char* strc = NULL;  | 
168  |  |  | 
169  | 253  |   if (!str && (len != 0))  | 
170  | 0  |     return FALSE;  | 
171  |  |  | 
172  | 253  |   if (str && (len > 0))  | 
173  | 252  |   { | 
174  | 252  |     strc = ConvertWCharNToUtf8Alloc(str, len, NULL);  | 
175  | 252  |     if (!strc)  | 
176  | 81  |       return FALSE;  | 
177  | 252  |   }  | 
178  | 172  |   return update_connectionstring2_nocopy(file, strc);  | 
179  | 253  | }  | 
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(const BYTE* hash, size_t hashLength, BYTE* key,  | 
218  |  |                                                      size_t keyLength)  | 
219  | 465  | { | 
220  | 465  |   BOOL rc = FALSE;  | 
221  | 465  |   BYTE pad1[64] = { 0 }; | 
222  | 465  |   BYTE pad2[64] = { 0 }; | 
223  |  |  | 
224  | 465  |   memset(pad1, 0x36, sizeof(pad1));  | 
225  | 465  |   memset(pad2, 0x5C, sizeof(pad2));  | 
226  |  |  | 
227  | 9.76k  |   for (size_t i = 0; i < hashLength; i++)  | 
228  | 9.30k  |   { | 
229  | 9.30k  |     pad1[i] ^= hash[i];  | 
230  | 9.30k  |     pad2[i] ^= hash[i];  | 
231  | 9.30k  |   }  | 
232  |  |  | 
233  | 465  |   BYTE* buffer = (BYTE*)calloc(hashLength, 2);  | 
234  |  |  | 
235  | 465  |   if (!buffer)  | 
236  | 0  |     goto fail;  | 
237  |  |  | 
238  | 465  |   if (!winpr_Digest(WINPR_MD_SHA1, pad1, 64, buffer, hashLength))  | 
239  | 0  |     goto fail;  | 
240  |  |  | 
241  | 465  |   if (!winpr_Digest(WINPR_MD_SHA1, pad2, 64, &buffer[hashLength], hashLength))  | 
242  | 0  |     goto fail;  | 
243  |  |  | 
244  | 465  |   CopyMemory(key, buffer, keyLength);  | 
245  | 465  |   rc = TRUE;  | 
246  | 465  | fail:  | 
247  | 465  |   free(buffer);  | 
248  | 465  |   return rc;  | 
249  | 465  | }  | 
250  |  |  | 
251  |  | static BOOL append_address_to_list(wArrayList* MachineAddresses, const char* str, size_t len)  | 
252  | 527k  | { | 
253  | 527k  |   char* copy = NULL;  | 
254  | 527k  |   if (len > 0)  | 
255  | 527k  |     copy = strndup(str, len);  | 
256  | 527k  |   if (!copy)  | 
257  | 32  |     return FALSE;  | 
258  |  |  | 
259  | 527k  |   const BOOL rc = ArrayList_Append(MachineAddresses, copy);  | 
260  | 527k  |   if (!rc)  | 
261  | 0  |     free(copy);  | 
262  |  |   // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): ArrayList_Append takes ownership of copy  | 
263  | 527k  |   return rc;  | 
264  | 527k  | }  | 
265  |  |  | 
266  |  | static BOOL append_address(rdpAssistanceFile* file, const char* host, const char* port)  | 
267  | 526k  | { | 
268  | 526k  |   WINPR_ASSERT(file);  | 
269  |  |  | 
270  | 526k  |   errno = 0;  | 
271  | 526k  |   unsigned long p = strtoul(port, NULL, 0);  | 
272  |  |  | 
273  | 526k  |   if ((errno != 0) || (p == 0) || (p > UINT16_MAX))  | 
274  | 138  |   { | 
275  | 138  |     WLog_ERR(TAG, "Failed to parse ASSISTANCE file: ConnectionString2 invalid port value %s",  | 
276  | 138  |              port);  | 
277  | 138  |     return FALSE;  | 
278  | 138  |   }  | 
279  |  |  | 
280  | 526k  |   if (!append_address_to_list(file->MachineAddresses, host, host ? strlen(host) : 0))  | 
281  | 32  |     return FALSE;  | 
282  | 526k  |   return ArrayList_Append(file->MachinePorts, (void*)(uintptr_t)p);  | 
283  | 526k  | }  | 
284  |  |  | 
285  |  | static BOOL freerdp_assistance_parse_address_list(rdpAssistanceFile* file, char* list)  | 
286  | 489  | { | 
287  | 489  |   WINPR_ASSERT(file);  | 
288  |  |  | 
289  | 489  |   WLog_DBG(TAG, "freerdp_assistance_parse_address_list list=%s", list);  | 
290  |  |  | 
291  | 489  |   BOOL rc = FALSE;  | 
292  |  |  | 
293  | 489  |   if (!list)  | 
294  | 0  |     return FALSE;  | 
295  |  |  | 
296  | 489  |   char* strp = list;  | 
297  | 489  |   char* s = ";";  | 
298  |  |  | 
299  |  |   // get the first token  | 
300  | 489  |   char* token = strtok(strp, s);  | 
301  |  |  | 
302  |  |   // walk through other tokens  | 
303  | 527k  |   while (token != NULL)  | 
304  | 526k  |   { | 
305  | 526k  |     char* port = strchr(token, ':');  | 
306  | 526k  |     if (!port)  | 
307  | 3  |       goto out;  | 
308  | 526k  |     *port = '\0';  | 
309  | 526k  |     port++;  | 
310  |  |  | 
311  | 526k  |     if (!append_address(file, token, port))  | 
312  | 170  |       goto out;  | 
313  |  |  | 
314  | 526k  |     token = strtok(NULL, s);  | 
315  | 526k  |   }  | 
316  | 316  |   rc = TRUE;  | 
317  | 489  | out:  | 
318  | 489  |   return rc;  | 
319  | 316  | }  | 
320  |  |  | 
321  |  | static BOOL freerdp_assistance_parse_connection_string1(rdpAssistanceFile* file)  | 
322  | 620  | { | 
323  | 620  |   char* tokens[8] = { 0 }; | 
324  | 620  |   BOOL rc = FALSE;  | 
325  |  |  | 
326  | 620  |   WINPR_ASSERT(file);  | 
327  |  |  | 
328  | 620  |   if (!file->RCTicket)  | 
329  | 29  |     return FALSE;  | 
330  |  |  | 
331  |  |   /**  | 
332  |  |    * <ProtocolVersion>,<protocolType>,<machineAddressList>,<assistantAccountPwd>,  | 
333  |  |    * <RASessionID>,<RASessionName>,<RASessionPwd>,<protocolSpecificParms>  | 
334  |  |    */  | 
335  | 591  |   char* str = _strdup(file->RCTicket);  | 
336  |  |  | 
337  | 591  |   if (!str)  | 
338  | 0  |     goto error;  | 
339  |  |  | 
340  | 591  |   const size_t length = strlen(str);  | 
341  |  |  | 
342  | 591  |   int count = 1;  | 
343  | 4.24M  |   for (size_t i = 0; i < length; i++)  | 
344  | 4.24M  |   { | 
345  | 4.24M  |     if (str[i] == ',')  | 
346  | 4.14k  |       count++;  | 
347  | 4.24M  |   }  | 
348  |  |  | 
349  | 591  |   if (count != 8)  | 
350  | 32  |     goto error;  | 
351  |  |  | 
352  | 559  |   count = 0;  | 
353  | 559  |   tokens[count++] = str;  | 
354  |  |  | 
355  | 4.24M  |   for (size_t i = 0; i < length; i++)  | 
356  | 4.24M  |   { | 
357  | 4.24M  |     if (str[i] == ',')  | 
358  | 3.91k  |     { | 
359  | 3.91k  |       str[i] = '\0';  | 
360  | 3.91k  |       tokens[count++] = &str[i + 1];  | 
361  | 3.91k  |     }  | 
362  | 4.24M  |   }  | 
363  |  |  | 
364  | 559  |   if (strcmp(tokens[0], "65538") != 0)  | 
365  | 60  |     goto error;  | 
366  |  |  | 
367  | 499  |   if (strcmp(tokens[1], "1") != 0)  | 
368  | 3  |     goto error;  | 
369  |  |  | 
370  | 496  |   if (strcmp(tokens[3], "*") != 0)  | 
371  | 3  |     goto error;  | 
372  |  |  | 
373  | 493  |   if (strcmp(tokens[5], "*") != 0)  | 
374  | 2  |     goto error;  | 
375  |  |  | 
376  | 491  |   if (strcmp(tokens[6], "*") != 0)  | 
377  | 2  |     goto error;  | 
378  |  |  | 
379  | 489  |   file->RASessionId = _strdup(tokens[4]);  | 
380  |  |  | 
381  | 489  |   if (!file->RASessionId)  | 
382  | 0  |     goto error;  | 
383  |  |  | 
384  | 489  |   file->RASpecificParams = _strdup(tokens[7]);  | 
385  |  |  | 
386  | 489  |   if (!file->RASpecificParams)  | 
387  | 0  |     goto error;  | 
388  |  |  | 
389  | 489  |   if (!freerdp_assistance_parse_address_list(file, tokens[2]))  | 
390  | 173  |     goto error;  | 
391  |  |  | 
392  | 316  |   rc = TRUE;  | 
393  | 591  | error:  | 
394  | 591  |   free(str);  | 
395  | 591  |   return rc;  | 
396  | 316  | }  | 
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.2k  | { | 
414  | 17.2k  |   WINPR_ASSERT(opt);  | 
415  | 17.2k  |   WINPR_ASSERT(plength);  | 
416  | 17.2k  |   WINPR_ASSERT(key);  | 
417  |  |  | 
418  | 17.2k  |   *opt = NULL;  | 
419  | 17.2k  |   *plength = 0;  | 
420  | 17.2k  |   if (!tag)  | 
421  | 0  |     return FALSE;  | 
422  |  |  | 
423  | 17.2k  |   char bkey[128] = { 0 }; | 
424  | 17.2k  |   const int rc = _snprintf(bkey, sizeof(bkey), "%s=\"", key);  | 
425  | 17.2k  |   WINPR_ASSERT(rc > 0);  | 
426  | 17.2k  |   WINPR_ASSERT((size_t)rc < sizeof(bkey));  | 
427  |  |  | 
428  | 17.2k  |   char* p = strstr(tag, bkey);  | 
429  | 17.2k  |   if (!p)  | 
430  | 12.8k  |     return TRUE;  | 
431  |  |  | 
432  | 4.47k  |   p += strlen(bkey);  | 
433  | 4.47k  |   char* q = strchr(p, '"');  | 
434  |  |  | 
435  | 4.47k  |   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.40k  |   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.40k  |   const size_t length = q - p;  | 
451  | 4.40k  |   *opt = p;  | 
452  | 4.40k  |   *plength = length;  | 
453  |  |  | 
454  | 4.40k  |   return TRUE;  | 
455  | 4.40k  | }  | 
456  |  |  | 
457  |  | static BOOL freerdp_assistance_parse_attr_str(char** opt, const char* key, const char* tag)  | 
458  | 5.24k  | { | 
459  | 5.24k  |   const char* copt = NULL;  | 
460  | 5.24k  |   size_t size = 0;  | 
461  | 5.24k  |   if (!freerdp_assistance_parse_attr(&copt, &size, key, tag))  | 
462  | 52  |     return FALSE;  | 
463  | 5.19k  |   return update_option(opt, copt, size);  | 
464  | 5.24k  | }  | 
465  |  |  | 
466  |  | static BOOL freerdp_assistance_parse_attr_bool(BOOL* opt, const char* key, const char* tag)  | 
467  | 2.17k  | { | 
468  | 2.17k  |   const char* copt = NULL;  | 
469  | 2.17k  |   size_t size = 0;  | 
470  |  |  | 
471  | 2.17k  |   WINPR_ASSERT(opt);  | 
472  | 2.17k  |   *opt = FALSE;  | 
473  |  |  | 
474  | 2.17k  |   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  | 12  |   *opt = (copt[0] == '1');  | 
480  | 12  |   return TRUE;  | 
481  | 2.17k  | }  | 
482  |  |  | 
483  |  | static BOOL freerdp_assistance_parse_attr_uint32(UINT32* opt, const char* key, const char* tag)  | 
484  | 5.30k  | { | 
485  | 5.30k  |   const char* copt = NULL;  | 
486  | 5.30k  |   size_t size = 0;  | 
487  |  |  | 
488  | 5.30k  |   WINPR_ASSERT(opt);  | 
489  | 5.30k  |   *opt = 0;  | 
490  |  |  | 
491  | 5.30k  |   if (!freerdp_assistance_parse_attr(&copt, &size, key, tag))  | 
492  | 7  |     return FALSE;  | 
493  |  |  | 
494  | 5.29k  |   char buffer[64] = { 0 }; | 
495  | 5.29k  |   if (size >= sizeof(buffer))  | 
496  | 30  |   { | 
497  | 30  |     WLog_WARN(TAG, "Invalid UINT32 string '%s' [%" PRIuz "]", copt, size);  | 
498  | 30  |     return FALSE;  | 
499  | 30  |   }  | 
500  |  |  | 
501  | 5.26k  |   strncpy(buffer, copt, size);  | 
502  | 5.26k  |   errno = 0;  | 
503  | 5.26k  |   unsigned long val = strtoul(buffer, NULL, 0);  | 
504  |  |  | 
505  | 5.26k  |   if ((errno != 0) || (val > UINT32_MAX))  | 
506  | 66  |   { | 
507  | 66  |     WLog_ERR(TAG, "Failed to parse ASSISTANCE file: Invalid value %s", buffer);  | 
508  | 66  |     return FALSE;  | 
509  | 66  |   }  | 
510  |  |  | 
511  | 5.19k  |   *opt = val;  | 
512  |  |  | 
513  | 5.19k  |   return TRUE;  | 
514  | 5.26k  | }  | 
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  | 16.0k  | { | 
519  | 16.0k  |   WINPR_ASSERT(input);  | 
520  | 16.0k  |   WINPR_ASSERT(key);  | 
521  | 16.0k  |   WINPR_ASSERT(plen);  | 
522  |  |  | 
523  | 16.0k  |   char bkey[128] = { 0 }; | 
524  | 16.0k  |   const int rc = _snprintf(bkey, sizeof(bkey), "<%s", key);  | 
525  | 16.0k  |   WINPR_ASSERT(rc > 0);  | 
526  | 16.0k  |   WINPR_ASSERT((size_t)rc < sizeof(bkey));  | 
527  |  |  | 
528  | 16.0k  |   char* tag = strstr(input, bkey);  | 
529  | 16.0k  |   if (!tag || (tag > input + ilen))  | 
530  | 2.22k  |     return NULL;  | 
531  |  |  | 
532  | 13.8k  |   char* data = tag + strnlen(bkey, sizeof(bkey));  | 
533  |  |  | 
534  |  |   /* Ensure there is a valid delimiter following our token */  | 
535  | 13.8k  |   switch (data[0])  | 
536  | 13.8k  |   { | 
537  | 2.25k  |     case '>':  | 
538  | 11.0k  |     case '/':  | 
539  | 11.9k  |     case ' ':  | 
540  | 13.4k  |     case '\t':  | 
541  | 13.4k  |       break;  | 
542  | 317  |     default:  | 
543  | 317  |       WLog_ERR(TAG,  | 
544  | 317  |                "Failed to parse ASSISTANCE file: ConnectionString2 missing delimiter after "  | 
545  | 317  |                "field %s",  | 
546  | 317  |                bkey);  | 
547  | 317  |       return NULL;  | 
548  | 13.8k  |   }  | 
549  |  |  | 
550  | 13.4k  |   char* start = strstr(tag, ">");  | 
551  |  |  | 
552  | 13.4k  |   if (!start || (start > input + ilen))  | 
553  | 3.16k  |   { | 
554  | 3.16k  |     WLog_ERR(TAG, "Failed to parse ASSISTANCE file: ConnectionString2 missing field %s", bkey);  | 
555  | 3.16k  |     return NULL;  | 
556  | 3.16k  |   }  | 
557  |  |  | 
558  | 10.3k  |   const char* end = start;  | 
559  | 10.3k  |   const char* dend = start - 1;  | 
560  | 10.3k  |   if (*dend != '/')  | 
561  | 2.49k  |   { | 
562  | 2.49k  |     char ekey[128] = { 0 }; | 
563  | 2.49k  |     const int erc = _snprintf(ekey, sizeof(ekey), "</%s>", key);  | 
564  | 2.49k  |     WINPR_ASSERT(erc > 0);  | 
565  | 2.49k  |     WINPR_ASSERT((size_t)erc < sizeof(ekey));  | 
566  | 2.49k  |     const size_t offset = start - tag;  | 
567  | 2.49k  |     dend = end = strrstr(start, ilen - offset, ekey);  | 
568  | 2.49k  |     if (end)  | 
569  | 2.43k  |       end += strnlen(ekey, sizeof(ekey));  | 
570  | 2.49k  |   }  | 
571  |  |  | 
572  | 10.3k  |   if (!end)  | 
573  | 60  |   { | 
574  | 60  |     WLog_ERR(TAG,  | 
575  | 60  |              "Failed to parse ASSISTANCE file: ConnectionString2 missing end tag for field %s",  | 
576  | 60  |              key);  | 
577  | 60  |     return NULL;  | 
578  | 60  |   }  | 
579  | 10.2k  |   if (plen)  | 
580  | 10.2k  |     *plen = end - tag;  | 
581  |  |  | 
582  | 10.2k  |   if (pdata)  | 
583  | 9.82k  |     *pdata = data;  | 
584  | 10.2k  |   if (pdlen)  | 
585  | 9.82k  |     *pdlen = dend - data;  | 
586  | 10.2k  |   return tag;  | 
587  | 10.3k  | }  | 
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.40k  | { | 
597  | 3.40k  |   WINPR_ASSERT(input);  | 
598  | 3.40k  |   WINPR_ASSERT(key);  | 
599  | 3.40k  |   WINPR_ASSERT(element);  | 
600  | 3.40k  |   WINPR_ASSERT(elen);  | 
601  |  |  | 
602  | 3.40k  |   size_t len = 0;  | 
603  | 3.40k  |   size_t dlen = 0;  | 
604  | 3.40k  |   char* data = NULL;  | 
605  | 3.40k  |   char* tag = freerdp_assistance_contains_element(input, strlen(input), key, &len, &data, &dlen);  | 
606  | 3.40k  |   if (!tag)  | 
607  | 645  |     return FALSE;  | 
608  |  |  | 
609  | 2.75k  |   char* end = data + dlen;  | 
610  | 2.75k  |   *tag = '\0';  | 
611  | 2.75k  |   *end = '\0';  | 
612  | 2.75k  |   *element = data;  | 
613  | 2.75k  |   *elen = dlen + 1;  | 
614  | 2.75k  |   return TRUE;  | 
615  | 3.40k  | }  | 
616  |  |  | 
617  |  | static BOOL freerdp_assistance_get_element(char* input, size_t ilen, const char* key,  | 
618  |  |                                            char** element, size_t* elen)  | 
619  | 12.1k  | { | 
620  | 12.1k  |   WINPR_ASSERT(input);  | 
621  | 12.1k  |   WINPR_ASSERT(key);  | 
622  | 12.1k  |   WINPR_ASSERT(element);  | 
623  | 12.1k  |   WINPR_ASSERT(elen);  | 
624  |  |  | 
625  | 12.1k  |   size_t len = 0;  | 
626  | 12.1k  |   size_t dlen = 0;  | 
627  | 12.1k  |   char* data = NULL;  | 
628  | 12.1k  |   char* tag = freerdp_assistance_contains_element(input, ilen, key, &len, &data, &dlen);  | 
629  | 12.1k  |   if (!tag)  | 
630  | 5.09k  |     return FALSE;  | 
631  |  |  | 
632  | 7.06k  |   if (tag + len > input + ilen)  | 
633  | 0  |     return FALSE;  | 
634  |  |  | 
635  | 7.06k  |   char* end = tag + len;  | 
636  | 7.06k  |   *element = data;  | 
637  | 7.06k  |   *elen = end - data + 1;  | 
638  | 7.06k  |   return TRUE;  | 
639  | 7.06k  | }  | 
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.29k  | { | 
646  | 5.29k  |   char* val = NULL;  | 
647  | 5.29k  |   size_t vlen = 0;  | 
648  |  |  | 
649  | 11.7k  |   while (freerdp_assistance_get_element(data, len, key, &val, &vlen))  | 
650  | 6.64k  |   { | 
651  | 6.64k  |     data = val + vlen;  | 
652  | 6.64k  |     len = strnlen(data, len);  | 
653  | 6.64k  |     if (vlen > 0)  | 
654  | 6.64k  |     { | 
655  | 6.64k  |       val[vlen - 1] = '\0';  | 
656  |  |  | 
657  | 6.64k  |       if (!fkt(file, val, vlen))  | 
658  | 218  |         return FALSE;  | 
659  | 6.64k  |     }  | 
660  | 6.64k  |   }  | 
661  |  |  | 
662  | 5.07k  |   return TRUE;  | 
663  | 5.29k  | }  | 
664  |  |  | 
665  |  | static BOOL freerdp_assistance_parse_all_elements_of_l(rdpAssistanceFile* file, char* data,  | 
666  |  |                                                        size_t len)  | 
667  | 1.67k  | { | 
668  | 1.67k  |   UINT32 p = 0;  | 
669  | 1.67k  |   const char* n = NULL;  | 
670  | 1.67k  |   const char* u = NULL;  | 
671  | 1.67k  |   size_t nlen = 0;  | 
672  | 1.67k  |   size_t ulen = 0;  | 
673  | 1.67k  |   if (!freerdp_assistance_parse_attr_uint32(&p, "P", data))  | 
674  | 2  |     return FALSE;  | 
675  | 1.67k  |   if (!freerdp_assistance_parse_attr(&n, &nlen, "N", data))  | 
676  | 1  |     return FALSE;  | 
677  | 1.67k  |   if (!freerdp_assistance_parse_attr(&u, &ulen, "U", data))  | 
678  | 5  |     return FALSE;  | 
679  |  |  | 
680  | 1.66k  |   if (n && (nlen > 0))  | 
681  | 743  |   { | 
682  | 743  |     if (!append_address_to_list(file->MachineAddresses, n, nlen))  | 
683  | 0  |       return FALSE;  | 
684  | 743  |     if (!ArrayList_Append(file->MachinePorts, (void*)(uintptr_t)p))  | 
685  | 0  |       return FALSE;  | 
686  | 743  |   }  | 
687  | 1.66k  |   if (u && (ulen > 0))  | 
688  | 320  |   { | 
689  | 320  |     if (!append_address_to_list(file->MachineAddresses, u, ulen))  | 
690  | 0  |       return FALSE;  | 
691  | 320  |     if (!ArrayList_Append(file->MachinePorts, (void*)(uintptr_t)p))  | 
692  | 0  |       return FALSE;  | 
693  | 320  |   }  | 
694  | 1.66k  |   return TRUE;  | 
695  | 1.66k  | }  | 
696  |  |  | 
697  |  | static BOOL freerdp_assistance_parse_all_elements_of_t(rdpAssistanceFile* file, char* data,  | 
698  |  |                                                        size_t len)  | 
699  | 771  | { | 
700  | 771  |   UINT32 id = 0;  | 
701  | 771  |   UINT32 sid = 0;  | 
702  | 771  |   if (!freerdp_assistance_parse_attr_uint32(&id, "ID", data))  | 
703  | 95  |     return FALSE;  | 
704  | 676  |   if (!freerdp_assistance_parse_attr_uint32(&sid, "SID", data))  | 
705  | 2  |     return FALSE;  | 
706  | 674  |   WLog_DBG(TAG, "transport id=%" PRIu32 ", sid=%" PRIu32, id, sid);  | 
707  | 674  |   return freerdp_assistance_parse_all_elements_of(file, data, len, "L",  | 
708  | 674  |                                                   freerdp_assistance_parse_all_elements_of_l);  | 
709  | 676  | }  | 
710  |  |  | 
711  |  | static BOOL freerdp_assistance_parse_all_elements_of_c(rdpAssistanceFile* file, char* data,  | 
712  |  |                                                        size_t len)  | 
713  | 4.19k  | { | 
714  | 4.19k  |   return freerdp_assistance_parse_all_elements_of(file, data, len, "T",  | 
715  | 4.19k  |                                                   freerdp_assistance_parse_all_elements_of_t);  | 
716  | 4.19k  | }  | 
717  |  |  | 
718  |  | static BOOL freerdp_assistance_parse_find_elements_of_c(rdpAssistanceFile* file, char* data,  | 
719  |  |                                                         size_t len)  | 
720  | 423  | { | 
721  | 423  |   return freerdp_assistance_parse_all_elements_of(file, data, len, "C",  | 
722  | 423  |                                                   freerdp_assistance_parse_all_elements_of_c);  | 
723  | 423  | }  | 
724  |  |  | 
725  |  | static BOOL freerdp_assistance_parse_connection_string2(rdpAssistanceFile* file)  | 
726  | 612  | { | 
727  | 612  |   BOOL rc = FALSE;  | 
728  |  |  | 
729  | 612  |   WINPR_ASSERT(file);  | 
730  |  |  | 
731  | 612  |   if (!file->ConnectionString2)  | 
732  | 1  |     return FALSE;  | 
733  |  |  | 
734  | 611  |   char* str = _strdup(file->ConnectionString2);  | 
735  | 611  |   if (!str)  | 
736  | 0  |     goto out_fail;  | 
737  |  |  | 
738  | 611  |   char* e = NULL;  | 
739  | 611  |   size_t elen = 0;  | 
740  | 611  |   if (!freerdp_assistance_consume_input_and_get_element(str, "E", &e, &elen))  | 
741  | 174  |     goto out_fail;  | 
742  |  |  | 
743  | 437  |   if (!e || (elen == 0))  | 
744  | 0  |     goto out_fail;  | 
745  |  |  | 
746  | 437  |   char* a = NULL;  | 
747  | 437  |   size_t alen = 0;  | 
748  | 437  |   if (!freerdp_assistance_get_element(e, elen, "A", &a, &alen))  | 
749  | 14  |     goto out_fail;  | 
750  |  |  | 
751  | 423  |   if (!a || (alen == 0))  | 
752  | 0  |     goto out_fail;  | 
753  |  |  | 
754  | 423  |   if (!freerdp_assistance_parse_find_elements_of_c(file, e, elen))  | 
755  | 105  |     goto out_fail;  | 
756  |  |  | 
757  |  |   /* '\0' terminate the detected XML elements so  | 
758  |  |    * the parser can continue with terminated strings  | 
759  |  |    */  | 
760  | 318  |   a[alen] = '\0';  | 
761  | 318  |   if (!freerdp_assistance_parse_attr_str(&file->RASpecificParams, "KH", a))  | 
762  | 40  |     goto out_fail;  | 
763  |  |  | 
764  | 278  |   if (!freerdp_assistance_parse_attr_str(&file->RASpecificParams2, "KH2", a))  | 
765  | 4  |     goto out_fail;  | 
766  |  |  | 
767  | 274  |   if (!freerdp_assistance_parse_attr_str(&file->RASessionId, "ID", a))  | 
768  | 3  |     goto out_fail;  | 
769  |  |  | 
770  | 271  |   rc = TRUE;  | 
771  | 611  | out_fail:  | 
772  | 611  |   free(str);  | 
773  | 611  |   return rc;  | 
774  | 271  | }  | 
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  |   (void)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  | 316  | { | 
846  | 316  |   BOOL rc = 0;  | 
847  | 316  |   size_t cbPasswordW = 0;  | 
848  | 316  |   size_t cbPassStubW = 0;  | 
849  | 316  |   size_t EncryptedSize = 0;  | 
850  | 316  |   BYTE PasswordHash[WINPR_MD5_DIGEST_LENGTH];  | 
851  | 316  |   WINPR_CIPHER_CTX* rc4Ctx = NULL;  | 
852  | 316  |   BYTE* pbIn = NULL;  | 
853  | 316  |   BYTE* pbOut = NULL;  | 
854  | 316  |   size_t cbOut = 0;  | 
855  | 316  |   size_t cbIn = 0;  | 
856  | 316  |   size_t cbFinal = 0;  | 
857  | 316  |   WCHAR* PasswordW = ConvertUtf8ToWCharAlloc(password, &cbPasswordW);  | 
858  | 316  |   WCHAR* PassStubW = ConvertUtf8ToWCharAlloc(passStub, &cbPassStubW);  | 
859  |  |  | 
860  | 316  |   if (!PasswordW || !PassStubW)  | 
861  | 82  |     goto fail;  | 
862  |  |  | 
863  | 234  |   cbPasswordW = (cbPasswordW) * sizeof(WCHAR);  | 
864  | 234  |   cbPassStubW = (cbPassStubW) * sizeof(WCHAR);  | 
865  | 234  |   if (!winpr_Digest(WINPR_MD_MD5, (BYTE*)PasswordW, cbPasswordW, (BYTE*)PasswordHash,  | 
866  | 234  |                     sizeof(PasswordHash)))  | 
867  | 0  |     goto fail;  | 
868  |  |  | 
869  | 234  |   EncryptedSize = cbPassStubW + 4;  | 
870  | 234  |   pbIn = (BYTE*)calloc(1, EncryptedSize);  | 
871  | 234  |   pbOut = (BYTE*)calloc(1, EncryptedSize);  | 
872  |  |  | 
873  | 234  |   if (!pbIn || !pbOut)  | 
874  | 0  |     goto fail;  | 
875  |  |  | 
876  | 234  |   *((UINT32*)pbIn) = (UINT32)cbPassStubW;  | 
877  | 234  |   CopyMemory(&pbIn[4], PassStubW, cbPassStubW);  | 
878  | 234  |   rc4Ctx = winpr_Cipher_New(WINPR_CIPHER_ARC4_128, WINPR_ENCRYPT, PasswordHash, NULL);  | 
879  |  |  | 
880  | 234  |   if (!rc4Ctx)  | 
881  | 0  |   { | 
882  | 0  |     WLog_ERR(TAG, "winpr_Cipher_New failure");  | 
883  | 0  |     goto fail;  | 
884  | 0  |   }  | 
885  |  |  | 
886  | 234  |   cbOut = cbFinal = 0;  | 
887  | 234  |   cbIn = EncryptedSize;  | 
888  | 234  |   rc = winpr_Cipher_Update(rc4Ctx, pbIn, cbIn, pbOut, &cbOut);  | 
889  |  |  | 
890  | 234  |   if (!rc)  | 
891  | 0  |   { | 
892  | 0  |     WLog_ERR(TAG, "winpr_Cipher_Update failure");  | 
893  | 0  |     goto fail;  | 
894  | 0  |   }  | 
895  |  |  | 
896  | 234  |   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  | 234  |   winpr_Cipher_Free(rc4Ctx);  | 
903  | 234  |   free(pbIn);  | 
904  | 234  |   free(PasswordW);  | 
905  | 234  |   free(PassStubW);  | 
906  | 234  |   *pEncryptedSize = EncryptedSize;  | 
907  | 234  |   return pbOut;  | 
908  | 82  | fail:  | 
909  | 82  |   winpr_Cipher_Free(rc4Ctx);  | 
910  | 82  |   free(PasswordW);  | 
911  | 82  |   free(PassStubW);  | 
912  | 82  |   free(pbIn);  | 
913  | 82  |   free(pbOut);  | 
914  | 82  |   return NULL;  | 
915  | 234  | }  | 
916  |  |  | 
917  |  | static BOOL freerdp_assistance_decrypt2(rdpAssistanceFile* file)  | 
918  | 465  | { | 
919  | 465  |   BOOL rc = FALSE;  | 
920  | 465  |   int status = 0;  | 
921  | 465  |   size_t cbPasswordW = 0;  | 
922  | 465  |   size_t cchOutW = 0;  | 
923  | 465  |   WINPR_CIPHER_CTX* aesDec = NULL;  | 
924  | 465  |   WCHAR* PasswordW = NULL;  | 
925  | 465  |   BYTE* pbIn = NULL;  | 
926  | 465  |   BYTE* pbOut = NULL;  | 
927  | 465  |   size_t cbOut = 0;  | 
928  | 465  |   size_t cbIn = 0;  | 
929  | 465  |   size_t cbFinal = 0;  | 
930  | 465  |   BYTE DerivedKey[WINPR_AES_BLOCK_SIZE] = { 0 }; | 
931  | 465  |   BYTE InitializationVector[WINPR_AES_BLOCK_SIZE] = { 0 }; | 
932  | 465  |   BYTE PasswordHash[WINPR_SHA1_DIGEST_LENGTH] = { 0 }; | 
933  |  |  | 
934  | 465  |   WINPR_ASSERT(file);  | 
935  |  |  | 
936  | 465  |   if (!file->password)  | 
937  | 0  |     return FALSE;  | 
938  |  |  | 
939  | 465  |   PasswordW = ConvertUtf8ToWCharAlloc(file->password, &cbPasswordW);  | 
940  | 465  |   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  | 465  |   cbPasswordW = (cbPasswordW) * sizeof(WCHAR);  | 
947  |  |  | 
948  | 465  |   if (!winpr_Digest(WINPR_MD_SHA1, (BYTE*)PasswordW, cbPasswordW, PasswordHash,  | 
949  | 465  |                     sizeof(PasswordHash)))  | 
950  | 0  |     goto fail;  | 
951  |  |  | 
952  | 465  |   if (!freerdp_assistance_crypt_derive_key_sha1(PasswordHash, sizeof(PasswordHash), DerivedKey,  | 
953  | 465  |                                                 sizeof(DerivedKey)))  | 
954  | 0  |     goto fail;  | 
955  |  |  | 
956  | 465  |   aesDec =  | 
957  | 465  |       winpr_Cipher_New(WINPR_CIPHER_AES_128_CBC, WINPR_DECRYPT, DerivedKey, InitializationVector);  | 
958  |  |  | 
959  | 465  |   if (!aesDec)  | 
960  | 0  |     goto fail;  | 
961  |  |  | 
962  | 465  |   cbOut = cbFinal = 0;  | 
963  | 465  |   cbIn = file->EncryptedLHTicketLength;  | 
964  | 465  |   pbIn = file->EncryptedLHTicket;  | 
965  | 465  |   pbOut = (BYTE*)calloc(1, cbIn + WINPR_AES_BLOCK_SIZE + 2);  | 
966  |  |  | 
967  | 465  |   if (!pbOut)  | 
968  | 0  |     goto fail;  | 
969  |  |  | 
970  | 465  |   if (!winpr_Cipher_Update(aesDec, pbIn, cbIn, pbOut, &cbOut))  | 
971  | 0  |     goto fail;  | 
972  |  |  | 
973  | 465  |   if (!winpr_Cipher_Final(aesDec, pbOut + cbOut, &cbFinal))  | 
974  | 212  |   { | 
975  | 212  |     WLog_ERR(TAG, "winpr_Cipher_Final failure");  | 
976  | 212  |     goto fail;  | 
977  | 212  |   }  | 
978  |  |  | 
979  | 253  |   cbOut += cbFinal;  | 
980  | 253  |   cbFinal = 0;  | 
981  |  |  | 
982  | 253  |   union  | 
983  | 253  |   { | 
984  | 253  |     const WCHAR* wc;  | 
985  | 253  |     const BYTE* b;  | 
986  | 253  |   } cnv;  | 
987  |  |  | 
988  | 253  |   cnv.b = pbOut;  | 
989  | 253  |   cchOutW = cbOut / sizeof(WCHAR);  | 
990  |  |  | 
991  | 253  |   if (!update_connectionstring2_wchar(file, cnv.wc, cchOutW))  | 
992  | 81  |   { | 
993  | 81  |     WLog_ERR(TAG, "Failed to parse ASSISTANCE file: Conversion from UCS2 to UTF8 failed");  | 
994  | 81  |     goto fail;  | 
995  | 81  |   }  | 
996  |  |  | 
997  | 172  |   if (!freerdp_assistance_parse_connection_string2(file))  | 
998  | 172  |     goto fail;  | 
999  |  |  | 
1000  | 0  |   rc = TRUE;  | 
1001  | 465  | fail:  | 
1002  | 465  |   winpr_Cipher_Free(aesDec);  | 
1003  | 465  |   free(PasswordW);  | 
1004  | 465  |   free(pbOut);  | 
1005  | 465  |   WLog_DBG(TAG, "freerdp_assistance_parse_connection_string2: %d", status);  | 
1006  | 465  |   return rc;  | 
1007  | 0  | }  | 
1008  |  |  | 
1009  |  | BYTE* freerdp_assistance_hex_string_to_bin(const void* raw, size_t* size)  | 
1010  | 724  | { | 
1011  | 724  |   BYTE* buffer = NULL;  | 
1012  | 724  |   if (!raw || !size)  | 
1013  | 0  |     return NULL;  | 
1014  | 724  |   *size = 0;  | 
1015  | 724  |   const size_t length = strlen(raw);  | 
1016  | 724  |   buffer = calloc(length, sizeof(BYTE));  | 
1017  | 724  |   if (!buffer)  | 
1018  | 0  |     return NULL;  | 
1019  | 724  |   const size_t rc = winpr_HexStringToBinBuffer(raw, length, buffer, length);  | 
1020  | 724  |   if (rc == 0)  | 
1021  | 2  |   { | 
1022  | 2  |     free(buffer);  | 
1023  | 2  |     return NULL;  | 
1024  | 2  |   }  | 
1025  | 722  |   *size = rc;  | 
1026  | 722  |   return buffer;  | 
1027  | 724  | }  | 
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  | 126  |   { | 
1056  | 126  |     WLog_ERR(TAG,  | 
1057  | 126  |              "Failed to parse ASSISTANCE file: Missing or invalid UPLOADINFO TYPE '%s' [%" PRIuz  | 
1058  | 126  |              "]",  | 
1059  | 126  |              typestr, typelen);  | 
1060  | 126  |     return -1;  | 
1061  | 126  |   }  | 
1062  |  |  | 
1063  | 1.09k  |   char* uploaddata = NULL;  | 
1064  | 1.09k  |   size_t uploaddatasize = 0;  | 
1065  | 1.09k  |   if (!freerdp_assistance_consume_input_and_get_element(uploadinfo, "UPLOADDATA", &uploaddata,  | 
1066  | 1.09k  |                                                         &uploaddatasize))  | 
1067  | 3  |     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  | 2  |     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  | 271  |   { | 
1092  | 271  |     const char* amp = "&";  | 
1093  | 271  |     char* passtub = strstr(file->PassStub, amp);  | 
1094  | 474  |     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  | 271  |   }  | 
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.08k  |   if (!freerdp_assistance_parse_attr_uint32(&file->DtLength, "DtLength", uploaddata))  | 
1109  | 3  |     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  | 465  |     case 2:  | 
1121  | 465  |     { | 
1122  | 465  |       file->EncryptedLHTicket = freerdp_assistance_hex_string_to_bin(  | 
1123  | 465  |           file->LHTicket, &file->EncryptedLHTicketLength);  | 
1124  |  |  | 
1125  | 465  |       if (!freerdp_assistance_decrypt2(file))  | 
1126  | 465  |         status = -1;  | 
1127  | 465  |     }  | 
1128  | 465  |     break;  | 
1129  |  |  | 
1130  | 620  |     case 1:  | 
1131  | 620  |     { | 
1132  | 620  |       if (!freerdp_assistance_parse_connection_string1(file))  | 
1133  | 304  |         status = -1;  | 
1134  | 620  |     }  | 
1135  | 620  |     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  | 316  |   file->EncryptedPassStub = freerdp_assistance_encrypt_pass_stub(file->password, file->PassStub,  | 
1148  | 316  |                                                                  &file->EncryptedPassStubLength);  | 
1149  |  |  | 
1150  | 316  |   if (!file->EncryptedPassStub)  | 
1151  | 82  |     return -1;  | 
1152  |  |  | 
1153  | 234  |   return 1;  | 
1154  | 316  | }  | 
1155  |  |  | 
1156  |  | static int freerdp_assistance_parse_file_buffer_int(rdpAssistanceFile* file, char* buffer,  | 
1157  |  |                                                     size_t size, const char* password)  | 
1158  | 1.69k  | { | 
1159  | 1.69k  |   WINPR_ASSERT(file);  | 
1160  | 1.69k  |   WINPR_ASSERT(buffer);  | 
1161  | 1.69k  |   WINPR_ASSERT(size > 0);  | 
1162  |  |  | 
1163  | 1.69k  |   if (!update_password(file, password))  | 
1164  | 0  |     return -1;  | 
1165  |  |  | 
1166  | 1.69k  |   char* uploadinfo = NULL;  | 
1167  | 1.69k  |   size_t uploadinfosize = 0;  | 
1168  | 1.69k  |   if (freerdp_assistance_consume_input_and_get_element(buffer, "UPLOADINFO", &uploadinfo,  | 
1169  | 1.69k  |                                                        &uploadinfosize))  | 
1170  | 1.22k  |     return freerdp_assistance_parse_uploadinfo(file, uploadinfo, uploadinfosize);  | 
1171  |  |  | 
1172  | 468  |   size_t elen = 0;  | 
1173  | 468  |   const char* estr = freerdp_assistance_contains_element(buffer, size, "E", &elen, NULL, NULL);  | 
1174  | 468  |   if (!estr || (elen == 0))  | 
1175  | 28  |   { | 
1176  | 28  |     WLog_ERR(TAG, "Failed to parse ASSISTANCE file: Neither UPLOADINFO nor <E> found");  | 
1177  | 28  |     return -1;  | 
1178  | 28  |   }  | 
1179  | 440  |   if (!update_connectionstring2(file, estr, elen))  | 
1180  | 0  |     return -1;  | 
1181  |  |  | 
1182  | 440  |   if (!freerdp_assistance_parse_connection_string2(file))  | 
1183  | 169  |     return -1;  | 
1184  |  |  | 
1185  | 271  |   return 1;  | 
1186  | 440  | }  | 
1187  |  |  | 
1188  |  | int freerdp_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* cbuffer, size_t size,  | 
1189  |  |                                          const char* password)  | 
1190  | 1.69k  | { | 
1191  | 1.69k  |   WINPR_ASSERT(file);  | 
1192  | 1.69k  |   if (!password)  | 
1193  | 0  |   { | 
1194  | 0  |     WLog_WARN(TAG, "empty password supplied");  | 
1195  | 0  |   }  | 
1196  |  |  | 
1197  | 1.69k  |   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.69k  |   char* abuffer = strndup(cbuffer, size);  | 
1204  | 1.69k  |   const size_t len = strnlen(cbuffer, size);  | 
1205  | 1.69k  |   if (len == size)  | 
1206  | 1.69k  |     WLog_WARN(TAG, "Input data not '\0' terminated");  | 
1207  |  |  | 
1208  | 1.69k  |   if (!abuffer)  | 
1209  | 0  |     return -1;  | 
1210  |  |  | 
1211  | 1.69k  |   const int rc = freerdp_assistance_parse_file_buffer_int(file, abuffer, len + 1, password);  | 
1212  | 1.69k  |   free(abuffer);  | 
1213  | 1.69k  |   return rc;  | 
1214  | 1.69k  | }  | 
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  |     (void)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  |     (void)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  |   (void)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  |   union  | 
1346  | 0  |   { | 
1347  | 0  |     UINT32 port;  | 
1348  | 0  |     void* data;  | 
1349  | 0  |   } cnv;  | 
1350  | 0  |   cnv.data = ArrayList_GetItem(file->MachinePorts, 0);  | 
1351  | 0  |   if (!freerdp_settings_set_uint32(settings, FreeRDP_ServerPort, cnv.port))  | 
1352  | 0  |     return FALSE;  | 
1353  |  |  | 
1354  | 0  |   if (!freerdp_target_net_adresses_reset(settings, ports))  | 
1355  | 0  |     return FALSE;  | 
1356  |  |  | 
1357  | 0  |   for (size_t x = 0; x < ports; x++)  | 
1358  | 0  |   { | 
1359  | 0  |     cnv.data = ArrayList_GetItem(file->MachinePorts, x);  | 
1360  | 0  |     if (!freerdp_settings_set_pointer_array(settings, FreeRDP_TargetNetPorts, x, &cnv.port))  | 
1361  | 0  |       return FALSE;  | 
1362  | 0  |   }  | 
1363  | 0  |   for (size_t i = 0; i < addresses; i++)  | 
1364  | 0  |   { | 
1365  | 0  |     const char* maddr = ArrayList_GetItem(file->MachineAddresses, i);  | 
1366  | 0  |     if (!freerdp_settings_set_pointer_array(settings, FreeRDP_TargetNetAddresses, i, maddr))  | 
1367  | 0  |       return FALSE;  | 
1368  | 0  |   }  | 
1369  |  |  | 
1370  | 0  |   return TRUE;  | 
1371  | 0  | }  | 
1372  |  |  | 
1373  |  | static BOOL setup_string(wArrayList* list)  | 
1374  | 3.38k  | { | 
1375  | 3.38k  |   WINPR_ASSERT(list);  | 
1376  |  |  | 
1377  | 3.38k  |   wObject* obj = ArrayList_Object(list);  | 
1378  | 3.38k  |   if (!obj)  | 
1379  | 0  |     return FALSE;  | 
1380  | 3.38k  |   obj->fnObjectFree = free;  | 
1381  |  |   // obj->fnObjectNew = wwinpr_ObjectStringClone;  | 
1382  | 3.38k  |   return TRUE;  | 
1383  | 3.38k  | }  | 
1384  |  |  | 
1385  |  | rdpAssistanceFile* freerdp_assistance_file_new(void)  | 
1386  | 1.69k  | { | 
1387  | 1.69k  |   winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);  | 
1388  | 1.69k  |   rdpAssistanceFile* file = calloc(1, sizeof(rdpAssistanceFile));  | 
1389  | 1.69k  |   if (!file)  | 
1390  | 0  |     return NULL;  | 
1391  |  |  | 
1392  | 1.69k  |   file->MachineAddresses = ArrayList_New(FALSE);  | 
1393  | 1.69k  |   file->MachinePorts = ArrayList_New(FALSE);  | 
1394  | 1.69k  |   file->MachineUris = ArrayList_New(FALSE);  | 
1395  |  |  | 
1396  | 1.69k  |   if (!file->MachineAddresses || !file->MachinePorts || !file->MachineUris)  | 
1397  | 0  |     goto fail;  | 
1398  |  |  | 
1399  | 1.69k  |   if (!setup_string(file->MachineAddresses) || !setup_string(file->MachineUris))  | 
1400  | 0  |     goto fail;  | 
1401  |  |  | 
1402  | 1.69k  |   return file;  | 
1403  |  |  | 
1404  | 0  | fail:  | 
1405  | 0  |   WINPR_PRAGMA_DIAG_PUSH  | 
1406  | 0  |   WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC  | 
1407  | 0  |   freerdp_assistance_file_free(file);  | 
1408  | 0  |   WINPR_PRAGMA_DIAG_POP  | 
1409  | 0  |   return NULL;  | 
1410  | 1.69k  | }  | 
1411  |  |  | 
1412  |  | void freerdp_assistance_file_free(rdpAssistanceFile* file)  | 
1413  | 1.69k  | { | 
1414  | 1.69k  |   if (!file)  | 
1415  | 0  |     return;  | 
1416  |  |  | 
1417  | 1.69k  |   update_password(file, NULL);  | 
1418  | 1.69k  |   update_connectionstring2(file, NULL, 0);  | 
1419  | 1.69k  |   free(file->filename);  | 
1420  | 1.69k  |   free(file->Username);  | 
1421  | 1.69k  |   free(file->LHTicket);  | 
1422  | 1.69k  |   free(file->RCTicket);  | 
1423  | 1.69k  |   free(file->PassStub);  | 
1424  | 1.69k  |   free(file->ConnectionString1);  | 
1425  | 1.69k  |   free(file->EncryptedLHTicket);  | 
1426  | 1.69k  |   free(file->RASessionId);  | 
1427  | 1.69k  |   free(file->RASpecificParams);  | 
1428  | 1.69k  |   free(file->RASpecificParams2);  | 
1429  | 1.69k  |   free(file->EncryptedPassStub);  | 
1430  |  |  | 
1431  | 1.69k  |   ArrayList_Free(file->MachineAddresses);  | 
1432  | 1.69k  |   ArrayList_Free(file->MachinePorts);  | 
1433  | 1.69k  |   ArrayList_Free(file->MachineUris);  | 
1434  | 1.69k  |   free(file);  | 
1435  | 1.69k  | }  | 
1436  |  |  | 
1437  |  | void freerdp_assistance_print_file(rdpAssistanceFile* file, wLog* log, DWORD level)  | 
1438  | 0  | { | 
1439  | 0  |   WINPR_ASSERT(file);  | 
1440  |  |  | 
1441  | 0  |   WLog_Print(log, level, "Username: %s", file->Username);  | 
1442  | 0  |   WLog_Print(log, level, "LHTicket: %s", file->LHTicket);  | 
1443  | 0  |   WLog_Print(log, level, "RCTicket: %s", file->RCTicket);  | 
1444  | 0  |   WLog_Print(log, level, "RCTicketEncrypted: %" PRId32, file->RCTicketEncrypted);  | 
1445  | 0  |   WLog_Print(log, level, "PassStub: %s", file->PassStub);  | 
1446  | 0  |   WLog_Print(log, level, "DtStart: %" PRIu32, file->DtStart);  | 
1447  | 0  |   WLog_Print(log, level, "DtLength: %" PRIu32, file->DtLength);  | 
1448  | 0  |   WLog_Print(log, level, "LowSpeed: %" PRId32, file->LowSpeed);  | 
1449  | 0  |   WLog_Print(log, level, "RASessionId: %s", file->RASessionId);  | 
1450  | 0  |   WLog_Print(log, level, "RASpecificParams: %s", file->RASpecificParams);  | 
1451  | 0  |   WLog_Print(log, level, "RASpecificParams2: %s", file->RASpecificParams2);  | 
1452  |  | 
  | 
1453  | 0  |   for (size_t x = 0; x < ArrayList_Count(file->MachineAddresses); x++)  | 
1454  | 0  |   { | 
1455  | 0  |     UINT32 port = 0;  | 
1456  | 0  |     const char* uri = NULL;  | 
1457  | 0  |     const char* addr = ArrayList_GetItem(file->MachineAddresses, x);  | 
1458  | 0  |     if (x < ArrayList_Count(file->MachinePorts))  | 
1459  | 0  |     { | 
1460  | 0  |       union  | 
1461  | 0  |       { | 
1462  | 0  |         UINT32 port;  | 
1463  | 0  |         void* data;  | 
1464  | 0  |       } cnv;  | 
1465  | 0  |       cnv.data = ArrayList_GetItem(file->MachinePorts, x);  | 
1466  | 0  |       port = cnv.port;  | 
1467  | 0  |     }  | 
1468  | 0  |     if (x < ArrayList_Count(file->MachineUris))  | 
1469  | 0  |       uri = ArrayList_GetItem(file->MachineUris, x);  | 
1470  |  | 
  | 
1471  | 0  |     WLog_Print(log, level, "MachineAddress [%" PRIdz ": %s", x, addr);  | 
1472  | 0  |     WLog_Print(log, level, "MachinePort    [%" PRIdz ": %" PRIu32, x, port);  | 
1473  | 0  |     WLog_Print(log, level, "MachineURI     [%" PRIdz ": %s", x, uri);  | 
1474  | 0  |   }  | 
1475  | 0  | }  | 
1476  |  |  | 
1477  |  | BOOL freerdp_assistance_get_encrypted_pass_stub(rdpAssistanceFile* file, const char** pwd,  | 
1478  |  |                                                 size_t* size)  | 
1479  | 0  | { | 
1480  | 0  |   if (!file || !pwd || !size)  | 
1481  | 0  |     return FALSE;  | 
1482  |  |  | 
1483  | 0  |   *pwd = (const char*)file->EncryptedPassStub;  | 
1484  | 0  |   *size = file->EncryptedPassStubLength;  | 
1485  | 0  |   return TRUE;  | 
1486  | 0  | }  | 
1487  |  |  | 
1488  |  | int freerdp_assistance_set_connection_string2(rdpAssistanceFile* file, const char* string,  | 
1489  |  |                                               const char* password)  | 
1490  | 0  | { | 
1491  | 0  |   if (!file || !string || !password)  | 
1492  | 0  |     return -1;  | 
1493  |  |  | 
1494  | 0  |   char* str = _strdup(string);  | 
1495  | 0  |   if (!str)  | 
1496  | 0  |     return -1;  | 
1497  |  |  | 
1498  | 0  |   if (!update_connectionstring2_nocopy(file, str))  | 
1499  | 0  |     return -1;  | 
1500  | 0  |   if (!update_password(file, password))  | 
1501  | 0  |     return -1;  | 
1502  | 0  |   return freerdp_assistance_parse_connection_string2(file);  | 
1503  | 0  | }  |