FreeRDP
Loading...
Searching...
No Matches
core/settings.c
1
22#include <freerdp/config.h>
23
24#include "settings.h"
25
26#include <freerdp/crypto/certificate.h>
27
28#include <ctype.h>
29
30#include <winpr/crt.h>
31#include <winpr/file.h>
32#include <winpr/path.h>
33#include <winpr/sysinfo.h>
34#include <winpr/registry.h>
35#include <winpr/wtsapi.h>
36
37#include <freerdp/version.h>
38#include <freerdp/settings.h>
39#include <freerdp/utils/string.h>
40#include <freerdp/utils/helpers.h>
41#include <freerdp/build-config.h>
42
43#include "../core/utils.h"
44#include "../crypto/certificate.h"
45#include "../crypto/privatekey.h"
46#include "capabilities.h"
47
48#define TAG FREERDP_TAG("settings")
49
50#ifdef _MSC_VER
51#pragma warning(push)
52#pragma warning(disable : 4244)
53#endif
54
55static const char client_dll[] = "C:\\Windows\\System32\\mstscax.dll";
56
57#define SERVER_KEY "Software\\%s\\Server"
58#define CLIENT_KEY "Software\\%s\\Client"
59#define BITMAP_CACHE_KEY CLIENT_KEY "\\BitmapCacheV2"
60#define GLYPH_CACHE_KEY CLIENT_KEY "\\GlyphCache"
61#define POINTER_CACHE_KEY CLIENT_KEY "\\PointerCache"
62
63struct bounds_t
64{
65 INT32 x;
66 INT32 y;
67 INT32 width;
68 INT32 height;
69};
70
71static const char* bounds2str(const struct bounds_t* bounds, char* buffer, size_t len)
72{
73 WINPR_ASSERT(bounds);
74 (void)_snprintf(buffer, len, "{%dx%d-%dx%d}", bounds->x, bounds->y, bounds->x + bounds->width,
75 bounds->y + bounds->height);
76 return buffer;
77}
78
79static struct bounds_t union_rect(const struct bounds_t* a, const struct bounds_t* b)
80{
81 WINPR_ASSERT(a);
82 WINPR_ASSERT(b);
83
84 struct bounds_t u = *a;
85 if (b->x < u.x)
86 u.x = b->x;
87 if (b->y < u.y)
88 u.y = b->y;
89
90 const INT32 rightA = a->x + a->width;
91 const INT32 rightB = b->x + b->width;
92 const INT32 right = MAX(rightA, rightB);
93 u.width = right - u.x;
94
95 const INT32 bottomA = a->y + a->height;
96 const INT32 bottomB = b->y + b->height;
97 const INT32 bottom = MAX(bottomA, bottomB);
98 u.height = bottom - u.y;
99
100 return u;
101}
102
103static BOOL intersect_rects(const struct bounds_t* r1, const struct bounds_t* r2)
104{
105 WINPR_ASSERT(r1);
106 WINPR_ASSERT(r2);
107
108 const INT32 left = MAX(r1->x, r2->x);
109 const INT32 top = MAX(r1->y, r2->y);
110 const INT32 right = MIN(r1->x + r1->width, r2->x + r2->width);
111 const INT32 bottom = MIN(r1->y + r1->height, r2->y + r2->height);
112
113 return (left < right) && (top < bottom);
114}
115
116static BOOL align_rects(const struct bounds_t* r1, const struct bounds_t* r2)
117{
118 WINPR_ASSERT(r1);
119 WINPR_ASSERT(r2);
120
121 const INT32 left = MAX(r1->x, r2->x);
122 const INT32 top = MAX(r1->y, r2->y);
123 const INT32 right = MIN(r1->x + r1->width, r2->x + r2->width);
124 const INT32 bottom = MIN(r1->y + r1->height, r2->y + r2->height);
125
126 return (left == right) || (top == bottom);
127}
128
129static BOOL settings_reg_query_dword_val(HKEY hKey, const TCHAR* sub, DWORD* value)
130{
131 DWORD dwType = 0;
132 DWORD dwSize = 0;
133
134 dwSize = sizeof(DWORD);
135 if (RegQueryValueEx(hKey, sub, nullptr, &dwType, (BYTE*)value, &dwSize) != ERROR_SUCCESS)
136 return FALSE;
137 if (dwType != REG_DWORD)
138 return FALSE;
139
140 return TRUE;
141}
142
143static BOOL settings_reg_query_word_val(HKEY hKey, const TCHAR* sub, UINT16* value)
144{
145 DWORD dwValue = 0;
146
147 if (!settings_reg_query_dword_val(hKey, sub, &dwValue))
148 return FALSE;
149
150 if (dwValue > UINT16_MAX)
151 return FALSE;
152
153 *value = (UINT16)dwValue;
154 return TRUE;
155}
156
157static BOOL settings_reg_query_bool_val(HKEY hKey, const TCHAR* sub, BOOL* value)
158{
159 DWORD dwValue = 0;
160
161 if (!settings_reg_query_dword_val(hKey, sub, &dwValue))
162 return FALSE;
163 *value = dwValue != 0;
164 return TRUE;
165}
166
167static BOOL settings_reg_query_dword(rdpSettings* settings, FreeRDP_Settings_Keys_UInt32 id,
168 HKEY hKey, const TCHAR* sub)
169{
170 DWORD dwValue = 0;
171
172 if (!settings_reg_query_dword_val(hKey, sub, &dwValue))
173 return FALSE;
174
175 return freerdp_settings_set_uint32(settings, id, dwValue);
176}
177
178static BOOL settings_reg_query_bool(rdpSettings* settings, FreeRDP_Settings_Keys_Bool id, HKEY hKey,
179 const TCHAR* sub)
180{
181 DWORD dwValue = 0;
182
183 if (!settings_reg_query_dword_val(hKey, sub, &dwValue))
184 return FALSE;
185
186 return freerdp_settings_set_bool(settings, id, (dwValue != 0));
187}
188
189static void settings_client_load_hkey_local_machine(rdpSettings* settings)
190{
191 {
192 char* key = freerdp_getApplicatonDetailsRegKey(CLIENT_KEY);
193 if (key)
194 {
195 HKEY hKey = nullptr;
196 const LONG status =
197 RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
198 free(key);
199
200 if (status == ERROR_SUCCESS)
201 {
202 settings_reg_query_dword(settings, FreeRDP_DesktopWidth, hKey, _T("DesktopWidth"));
203 settings_reg_query_dword(settings, FreeRDP_DesktopHeight, hKey,
204 _T("DesktopHeight"));
205 settings_reg_query_bool(settings, FreeRDP_Fullscreen, hKey, _T("Fullscreen"));
206 settings_reg_query_dword(settings, FreeRDP_ColorDepth, hKey, _T("ColorDepth"));
207 settings_reg_query_dword(settings, FreeRDP_KeyboardType, hKey, _T("KeyboardType"));
208 settings_reg_query_dword(settings, FreeRDP_KeyboardSubType, hKey,
209 _T("KeyboardSubType"));
210 settings_reg_query_dword(settings, FreeRDP_KeyboardFunctionKey, hKey,
211 _T("KeyboardFunctionKeys"));
212 settings_reg_query_dword(settings, FreeRDP_KeyboardLayout, hKey,
213 _T("KeyboardLayout"));
214 settings_reg_query_bool(settings, FreeRDP_ExtSecurity, hKey, _T("ExtSecurity"));
215 settings_reg_query_bool(settings, FreeRDP_NlaSecurity, hKey, _T("NlaSecurity"));
216 settings_reg_query_bool(settings, FreeRDP_TlsSecurity, hKey, _T("TlsSecurity"));
217 settings_reg_query_bool(settings, FreeRDP_RdpSecurity, hKey, _T("RdpSecurity"));
218 settings_reg_query_bool(settings, FreeRDP_MstscCookieMode, hKey,
219 _T("MstscCookieMode"));
220 settings_reg_query_dword(settings, FreeRDP_CookieMaxLength, hKey,
221 _T("CookieMaxLength"));
222 settings_reg_query_bool(settings, FreeRDP_BitmapCacheEnabled, hKey,
223 _T("BitmapCache"));
224 settings_reg_query_dword(settings, FreeRDP_OffscreenSupportLevel, hKey,
225 _T("OffscreenBitmapCache"));
226 settings_reg_query_dword(settings, FreeRDP_OffscreenCacheSize, hKey,
227 _T("OffscreenBitmapCacheSize"));
228 settings_reg_query_dword(settings, FreeRDP_OffscreenCacheEntries, hKey,
229 _T("OffscreenBitmapCacheEntries"));
230 RegCloseKey(hKey);
231 }
232 }
233 }
234 {
235 char* key = freerdp_getApplicatonDetailsRegKey(BITMAP_CACHE_KEY);
236 if (key)
237 {
238 HKEY hKey = nullptr;
239 const LONG status =
240 RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
241 free(key);
242
243 if (status == ERROR_SUCCESS)
244 {
245 settings_reg_query_dword(settings, FreeRDP_BitmapCacheV2NumCells, hKey,
246 _T("NumCells"));
247 for (unsigned x = 0; x < 5; x++)
248 {
249 DWORD val = 0;
250 TCHAR numentries[64] = WINPR_C_ARRAY_INIT;
251 TCHAR persist[64] = WINPR_C_ARRAY_INIT;
252 BITMAP_CACHE_V2_CELL_INFO cache = WINPR_C_ARRAY_INIT;
253 (void)_sntprintf(numentries, ARRAYSIZE(numentries), _T("Cell%uNumEntries"), x);
254 (void)_sntprintf(persist, ARRAYSIZE(persist), _T("Cell%uPersistent"), x);
255 if (!settings_reg_query_dword_val(hKey, numentries, &val) ||
256 !settings_reg_query_bool_val(hKey, persist, &cache.persistent))
257 continue;
258
259 if (!freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo,
260 x, &cache))
261 WLog_WARN(TAG, "Failed to load registry keys to settings!");
262 cache.numEntries = val;
263 }
264
265 settings_reg_query_bool(settings, FreeRDP_AllowCacheWaitingList, hKey,
266 _T("AllowCacheWaitingList"));
267 RegCloseKey(hKey);
268 }
269 }
270 }
271 {
272 char* key = freerdp_getApplicatonDetailsRegKey(GLYPH_CACHE_KEY);
273 if (key)
274 {
275 HKEY hKey = nullptr;
276 const LONG status =
277 RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
278 free(key);
279
280 if (status == ERROR_SUCCESS)
281 {
282 unsigned x = 0;
283 UINT32 GlyphSupportLevel = 0;
284 settings_reg_query_dword(settings, FreeRDP_GlyphSupportLevel, hKey,
285 _T("SupportLevel"));
286 for (; x < 10; x++)
287 {
288 GLYPH_CACHE_DEFINITION cache = WINPR_C_ARRAY_INIT;
289 TCHAR numentries[64] = WINPR_C_ARRAY_INIT;
290 TCHAR maxsize[64] = WINPR_C_ARRAY_INIT;
291 (void)_sntprintf(numentries, ARRAYSIZE(numentries), _T("Cache%uNumEntries"), x);
292 (void)_sntprintf(maxsize, ARRAYSIZE(maxsize), _T("Cache%uMaxCellSize"), x);
293
294 settings_reg_query_word_val(hKey, numentries, &cache.cacheEntries);
295 settings_reg_query_word_val(hKey, maxsize, &cache.cacheMaximumCellSize);
296 if (!freerdp_settings_set_pointer_array(settings, FreeRDP_GlyphCache, x,
297 &cache))
298 WLog_WARN(TAG, "Failed to store GlyphCache %u", x);
299 }
300 {
301 GLYPH_CACHE_DEFINITION cache = WINPR_C_ARRAY_INIT;
302 settings_reg_query_word_val(hKey, _T("FragCacheNumEntries"),
303 &cache.cacheEntries);
304 settings_reg_query_word_val(hKey, _T("FragCacheMaxCellSize"),
305 &cache.cacheMaximumCellSize);
306 if (!freerdp_settings_set_pointer_array(settings, FreeRDP_FragCache, x, &cache))
307 WLog_WARN(TAG, "Failed to store FragCache");
308 }
309
310 RegCloseKey(hKey);
311
312 if (!freerdp_settings_set_uint32(settings, FreeRDP_GlyphSupportLevel,
313 GlyphSupportLevel))
314 WLog_WARN(TAG, "Failed to load registry keys to settings!");
315 }
316 }
317 }
318 {
319 char* key = freerdp_getApplicatonDetailsRegKey(POINTER_CACHE_KEY);
320 if (key)
321 {
322 HKEY hKey = nullptr;
323 const LONG status =
324 RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
325 free(key);
326
327 if (status == ERROR_SUCCESS)
328 {
329 settings_reg_query_dword(settings, FreeRDP_LargePointerFlag, hKey,
330 _T("LargePointer"));
331 settings_reg_query_dword(settings, FreeRDP_PointerCacheSize, hKey,
332 _T("PointerCacheSize"));
333 settings_reg_query_dword(settings, FreeRDP_ColorPointerCacheSize, hKey,
334 _T("ColorPointerCacheSize"));
335 RegCloseKey(hKey);
336 }
337 }
338 }
339}
340
341static void settings_server_load_hkey_local_machine(rdpSettings* settings)
342{
343 HKEY hKey = nullptr;
344
345 char* key = freerdp_getApplicatonDetailsRegKey(SERVER_KEY);
346 if (!key)
347 return;
348
349 const LONG status =
350 RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
351 free(key);
352
353 if (status != ERROR_SUCCESS)
354 return;
355
356 settings_reg_query_bool(settings, FreeRDP_ExtSecurity, hKey, _T("ExtSecurity"));
357 settings_reg_query_bool(settings, FreeRDP_NlaSecurity, hKey, _T("NlaSecurity"));
358 settings_reg_query_bool(settings, FreeRDP_TlsSecurity, hKey, _T("TlsSecurity"));
359 settings_reg_query_dword(settings, FreeRDP_TlsSecLevel, hKey, _T("TlsSecLevel"));
360 settings_reg_query_bool(settings, FreeRDP_RdpSecurity, hKey, _T("RdpSecurity"));
361
362 RegCloseKey(hKey);
363}
364
365static void settings_load_hkey_local_machine(rdpSettings* settings)
366{
367 if (freerdp_settings_get_bool(settings, FreeRDP_ServerMode))
368 settings_server_load_hkey_local_machine(settings);
369 else
370 settings_client_load_hkey_local_machine(settings);
371}
372
373static BOOL settings_init_computer_name(rdpSettings* settings)
374{
375 CHAR computerName[MAX_COMPUTERNAME_LENGTH + 1] = WINPR_C_ARRAY_INIT;
376 DWORD nSize = ARRAYSIZE(computerName);
377
378 if (!GetComputerNameExA(ComputerNameNetBIOS, computerName, &nSize))
379 return FALSE;
380
381 if (!freerdp_settings_set_string(settings, FreeRDP_ComputerName, computerName))
382 return FALSE;
383 return freerdp_settings_set_string(settings, FreeRDP_ClientHostname, computerName);
384}
385
386void freerdp_settings_print_warnings(const rdpSettings* settings)
387{
388 const UINT32 level = freerdp_settings_get_uint32(settings, FreeRDP_GlyphSupportLevel);
389 if (level != GLYPH_SUPPORT_NONE)
390 {
391 char buffer[32] = WINPR_C_ARRAY_INIT;
392 WLog_WARN(TAG, "[experimental] enabled GlyphSupportLevel %s, expect visual artefacts!",
393 freerdp_settings_glyph_level_string(level, buffer, sizeof(buffer)));
394 }
395}
396
397static BOOL monitor_operlaps(const rdpSettings* settings, UINT32 orig, UINT32 start, UINT32 count,
398 const rdpMonitor* compare)
399{
400 const struct bounds_t rect1 = {
401 .x = compare->x, .y = compare->y, .width = compare->width, .height = compare->height
402 };
403 for (UINT32 x = start; x < count; x++)
404 {
405 const rdpMonitor* monitor =
406 freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorDefArray, x);
407 const struct bounds_t rect2 = {
408 .x = monitor->x, .y = monitor->y, .width = monitor->width, .height = monitor->height
409 };
410
411 if (intersect_rects(&rect1, &rect2))
412 {
413 char buffer1[32] = WINPR_C_ARRAY_INIT;
414 char buffer2[32] = WINPR_C_ARRAY_INIT;
415
416 WLog_ERR(TAG, "Monitor %" PRIu32 " and %" PRIu32 " are overlapping:", orig, x);
417 WLog_ERR(TAG, "%s overlapps with %s", bounds2str(&rect1, buffer1, sizeof(buffer1)),
418 bounds2str(&rect2, buffer2, sizeof(buffer2)));
419 WLog_ERR(
420 TAG,
421 "Mulitimonitor mode requested, but local layout has gaps or overlapping areas!");
422 WLog_ERR(TAG,
423 "Please reconfigure your local monitor setup so that there are no gaps or "
424 "overlapping areas!");
425 return TRUE;
426 }
427 }
428 return FALSE;
429}
430
431static BOOL monitor_has_gaps(const rdpSettings* settings, UINT32 start, UINT32 count,
432 const rdpMonitor* compare, UINT32** graph)
433{
434 const struct bounds_t rect1 = {
435 .x = compare->x, .y = compare->y, .width = compare->width, .height = compare->height
436 };
437
438 BOOL hasNeighbor = FALSE;
439 for (UINT32 i = 0; i < count; i++)
440 {
441 if (i == start)
442 continue;
443
444 const rdpMonitor* monitor =
445 freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorDefArray, i);
446
447 const struct bounds_t rect2 = {
448 .x = monitor->x, .y = monitor->y, .width = monitor->width, .height = monitor->height
449 };
450 if (align_rects(&rect1, &rect2))
451 {
452 hasNeighbor = TRUE;
453 graph[start][i] = 1;
454 graph[i][start] = 1;
455 }
456 }
457
458 if (!hasNeighbor)
459 {
460 WLog_ERR(TAG,
461 "Monitor configuration has gaps! Monitor %" PRIu32 " does not have any neighbor",
462 start);
463 }
464
465 return !hasNeighbor;
466}
467
468static void alloc_free(UINT32** ptr)
469{
470 free((void*)ptr);
471}
472
473WINPR_ATTR_MALLOC(alloc_free, 1)
474WINPR_ATTR_NODISCARD
475static UINT32** alloc_array(size_t count)
476{
477 // NOLINTNEXTLINE(clang-analyzer-unix.MallocSizeof)
478 BYTE* array = calloc(count * sizeof(uintptr_t), count * sizeof(UINT32));
479 UINT32** dst = WINPR_PACKED_ALIGN_CAST(UINT32**, array);
480 UINT32* val = WINPR_PACKED_ALIGN_CAST(UINT32*, (array + count * sizeof(uintptr_t)));
481 for (size_t x = 0; x < count; x++)
482 dst[x] = &val[x];
483
484 return dst;
485}
486
487/* Monitors in the array need to:
488 *
489 * 1. be connected to another monitor (edges touch but don't overlap or have gaps)
490 * 2. all monitors need to be connected so there are no separate groups.
491 *
492 * So, what we do here is we use dijkstra algorithm to find a path from any start node
493 * (lazy as we are we always use the first in the array) to each other node.
494 */
495static BOOL find_path_exists_with_dijkstra(UINT32** graph, size_t count, UINT32 start)
496{
497 if (count < 1)
498 return FALSE;
499
500 WINPR_ASSERT(start < count);
501
502 UINT32** cost = alloc_array(count);
503 WINPR_ASSERT(cost);
504
505 UINT32* distance = calloc(count, sizeof(UINT32));
506 WINPR_ASSERT(distance);
507
508 UINT32* visited = calloc(count, sizeof(UINT32));
509 WINPR_ASSERT(visited);
510
511 UINT32* parent = calloc(count, sizeof(UINT32));
512 WINPR_ASSERT(parent);
513
514 for (size_t x = 0; x < count; x++)
515 {
516 for (size_t y = 0; y < count; y++)
517 {
518 if (graph[x][y] == 0)
519 cost[x][y] = UINT32_MAX;
520 else
521 cost[x][y] = graph[x][y];
522 }
523 }
524
525 for (UINT32 x = 0; x < count; x++)
526 {
527 distance[x] = cost[start][x];
528 parent[x] = start;
529 visited[x] = 0;
530 }
531
532 distance[start] = 0;
533 visited[start] = 1;
534
535 size_t pos = 1;
536 UINT32 nextnode = UINT32_MAX;
537 while (pos < count - 1)
538 {
539 UINT32 mindistance = UINT32_MAX;
540
541 for (UINT32 x = 0; x < count; x++)
542 {
543 if ((distance[x] < mindistance) && !visited[x])
544 {
545 mindistance = distance[x];
546 nextnode = x;
547 }
548 }
549
550 visited[nextnode] = 1;
551
552 for (size_t y = 0; y < count; y++)
553 {
554 if (!visited[y])
555 {
556 UINT32 dist = mindistance + cost[nextnode][y];
557 if (dist < distance[y])
558 {
559 distance[y] = dist;
560 parent[y] = nextnode;
561 }
562 }
563 }
564 pos++;
565 }
566
567 BOOL rc = TRUE;
568 for (size_t x = 0; x < count; x++)
569 {
570 if (x != start)
571 {
572 if (distance[x] == UINT32_MAX)
573 {
574 WLog_ERR(TAG, "monitor %" PRIu32 " not connected with monitor %" PRIuz, start, x);
575 rc = FALSE;
576 break;
577 }
578 }
579 }
580 alloc_free(cost);
581 free(distance);
582 free(visited);
583 free(parent);
584
585 return rc;
586}
587
588static BOOL freerdp_settings_client_monitors_have_gaps(const rdpSettings* settings)
589{
590 BOOL rc = TRUE;
591 const UINT32 count = freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount);
592 if (count <= 1)
593 return FALSE;
594
595 UINT32** graph = alloc_array(count);
596 WINPR_ASSERT(graph);
597
598 for (UINT32 x = 0; x < count; x++)
599 {
600 const rdpMonitor* monitor =
601 freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorDefArray, x);
602 if (monitor_has_gaps(settings, x, count, monitor, graph))
603 goto fail;
604 }
605
606 rc = !find_path_exists_with_dijkstra(graph, count, 0);
607
608fail:
609 alloc_free(graph);
610
611 return rc;
612}
613
614static void log_monitor(UINT32 idx, const rdpMonitor* monitor, wLog* log, DWORD level)
615{
616 WINPR_ASSERT(monitor);
617
618 WLog_Print(log, level,
619 "[%" PRIu32 "] [%s] {%dx%d-%dx%d} [%" PRIu32 "] {%" PRIu32 "x%" PRIu32
620 ", orientation: %s [%" PRIu32 "], desktopScale: %" PRIu32 ", deviceScale: %" PRIu32
621 "}",
622 idx, monitor->is_primary ? "primary" : " ", monitor->x, monitor->y,
623 monitor->width, monitor->height, monitor->orig_screen,
624 monitor->attributes.physicalWidth, monitor->attributes.physicalHeight,
625 freerdp_desktop_rotation_flags_to_string(monitor->attributes.orientation),
626 monitor->attributes.orientation, monitor->attributes.desktopScaleFactor,
627 monitor->attributes.deviceScaleFactor);
628}
629
630static void log_monitor_configuration(const rdpSettings* settings, wLog* log, DWORD level)
631{
632 const UINT32 count = freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount);
633 WLog_Print(log, level, "[BEGIN] MonitorDefArray[%" PRIu32 "]", count);
634 for (UINT32 x = 0; x < count; x++)
635 {
636 const rdpMonitor* monitor =
637 freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorDefArray, x);
638 log_monitor(x, monitor, log, level);
639 }
640 WLog_Print(log, level, "[END] MonitorDefArray[%" PRIu32 "]", count);
641}
642
643static BOOL freerdp_settings_client_monitors_overlap(const rdpSettings* settings)
644{
645 const UINT32 count = freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount);
646 for (UINT32 x = 0; x < count; x++)
647 {
648 const rdpMonitor* monitor =
649 freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorDefArray, x);
650 if (monitor_operlaps(settings, x, x + 1, count, monitor))
651 return TRUE;
652 }
653 return FALSE;
654}
655
656/* See [MS-RDPBCGR] 2.2.1.3.6.1 for details on limits
657 * https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/c3964b39-3d54-4ae1-a84a-ceaed311e0f6
658 */
659static BOOL freerdp_settings_client_monitors_check_primary_and_origin(const rdpSettings* settings)
660{
661 const UINT32 count = freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount);
662 BOOL havePrimary = FALSE;
663 BOOL foundOrigin = FALSE;
664 BOOL primaryIsOrigin = FALSE;
665 BOOL rc = TRUE;
666
667 struct bounds_t bounds = WINPR_C_ARRAY_INIT;
668
669 if (count == 0)
670 {
671 WLog_WARN(TAG, "Monitor configuration empty.");
672 return TRUE;
673 }
674
675 for (UINT32 x = 0; x < count; x++)
676 {
677 const rdpMonitor* monitor =
678 freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorDefArray, x);
679 struct bounds_t cur = {
680 .x = monitor->x, .y = monitor->y, .width = monitor->width, .height = monitor->height
681 };
682
683 bounds = union_rect(&bounds, &cur);
684
685 if (monitor->is_primary)
686 {
687 if (havePrimary)
688 {
689 WLog_ERR(TAG, "Monitor configuration contains multiple primary monitors!");
690 rc = FALSE;
691 }
692 havePrimary = TRUE;
693 }
694
695 if ((monitor->x == 0) && (monitor->y == 0))
696 {
697 if (foundOrigin)
698 {
699 WLog_ERR(TAG, "Monitor configuration does have multiple origin 0/0");
700 rc = FALSE;
701 }
702 foundOrigin = TRUE;
703 primaryIsOrigin = monitor->is_primary != 0;
704 }
705 }
706
707 if ((bounds.width > 32766) || (bounds.width < 200))
708 {
709 WLog_ERR(TAG,
710 "Monitor configuration virtual desktop width must be 200 <= %" PRId32 " <= 32766",
711 bounds.width);
712 rc = FALSE;
713 }
714 if ((bounds.height > 32766) || (bounds.height < 200))
715 {
716 WLog_ERR(TAG,
717 "Monitor configuration virtual desktop height must be 200 <= %" PRId32 " <= 32766",
718 bounds.height);
719 rc = FALSE;
720 }
721
722 if (!havePrimary)
723 {
724 WLog_ERR(TAG, "Monitor configuration does not contain a primary monitor!");
725 rc = FALSE;
726 }
727 if (!foundOrigin)
728 {
729 WLog_ERR(TAG, "Monitor configuration must start at 0/0 for first monitor!");
730 rc = FALSE;
731 }
732 if (!primaryIsOrigin)
733 {
734 WLog_ERR(TAG, "Monitor configuration must start at 0/0 for primary monitor!");
735 rc = FALSE;
736 }
737
738 return rc;
739}
740
741BOOL freerdp_settings_check_client_after_preconnect(const rdpSettings* settings)
742{
743 wLog* log = WLog_Get(TAG);
744 BOOL rc = TRUE;
745 log_monitor_configuration(settings, log, WLOG_DEBUG);
746 if (freerdp_settings_client_monitors_overlap(settings))
747 rc = FALSE;
748 if (freerdp_settings_client_monitors_have_gaps(settings))
749 rc = FALSE;
750 if (!freerdp_settings_client_monitors_check_primary_and_origin(settings))
751 rc = FALSE;
752 if (!rc)
753 {
754 DWORD level = WLOG_ERROR;
755 WLog_Print(log, level, "Invalid or unsupported monitor configuration detected");
756 WLog_Print(log, level, "Check if the configuration is valid.");
757 WLog_Print(log, level,
758 "If you suspect a bug create a new issue at "
759 "https://github.com/FreeRDP/FreeRDP/issues/new");
760 WLog_Print(
761 log, level,
762 "Provide at least the following log lines detailing your monitor configuration:");
763 log_monitor_configuration(settings, log, level);
764 }
765
766 return rc;
767}
768
769BOOL freerdp_settings_set_default_order_support(rdpSettings* settings)
770{
771 BYTE* OrderSupport = freerdp_settings_get_pointer_writable(settings, FreeRDP_OrderSupport);
772 if (!OrderSupport)
773 return FALSE;
774
775 ZeroMemory(OrderSupport, 32);
776 OrderSupport[NEG_DSTBLT_INDEX] = TRUE;
777 OrderSupport[NEG_PATBLT_INDEX] = TRUE;
778 OrderSupport[NEG_SCRBLT_INDEX] = TRUE;
779 OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE;
780 OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE;
781 OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE;
782 OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE;
783 OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE;
784 OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE;
785 OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE;
786 OrderSupport[NEG_LINETO_INDEX] = TRUE;
787 OrderSupport[NEG_POLYLINE_INDEX] = TRUE;
788 OrderSupport[NEG_MEMBLT_INDEX] =
789 freerdp_settings_get_bool(settings, FreeRDP_BitmapCacheEnabled) ? 1 : 0;
790 OrderSupport[NEG_MEM3BLT_INDEX] =
791 freerdp_settings_get_bool(settings, FreeRDP_BitmapCacheEnabled) ? 1 : 0;
792 OrderSupport[NEG_MEMBLT_V2_INDEX] =
793 freerdp_settings_get_bool(settings, FreeRDP_BitmapCacheEnabled) ? 1 : 0;
794 OrderSupport[NEG_MEM3BLT_V2_INDEX] =
795 freerdp_settings_get_bool(settings, FreeRDP_BitmapCacheEnabled) ? 1 : 0;
796 OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE;
797 OrderSupport[NEG_GLYPH_INDEX_INDEX] =
798 freerdp_settings_get_uint32(settings, FreeRDP_GlyphSupportLevel) != GLYPH_SUPPORT_NONE;
799 OrderSupport[NEG_FAST_INDEX_INDEX] =
800 freerdp_settings_get_uint32(settings, FreeRDP_GlyphSupportLevel) != GLYPH_SUPPORT_NONE;
801 OrderSupport[NEG_FAST_GLYPH_INDEX] =
802 freerdp_settings_get_uint32(settings, FreeRDP_GlyphSupportLevel) != GLYPH_SUPPORT_NONE;
803 OrderSupport[NEG_POLYGON_SC_INDEX] = FALSE;
804 OrderSupport[NEG_POLYGON_CB_INDEX] = FALSE;
805 OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE;
806 OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE;
807 return TRUE;
808}
809
811{
812 return freerdp_GetConfigFilePath(FALSE, "");
813}
814
815rdpSettings* freerdp_settings_new(DWORD flags)
816{
817 const BOOL server = ((flags & FREERDP_SETTINGS_SERVER_MODE) != 0);
818 const BOOL remote = ((flags & FREERDP_SETTINGS_REMOTE_MODE) != 0);
819 rdpSettings* settings = (rdpSettings*)calloc(1, sizeof(rdpSettings));
820
821 if (!settings)
822 return nullptr;
823
824 {
825 const char* vendor = freerdp_getApplicationDetailsVendor();
826 const char* product = freerdp_getApplicationDetailsProduct();
827 const char* details = freerdp_getApplicationDetailsString();
828 char* issuer1 = nullptr;
829 char* issuer2 = nullptr;
830 char* issuer3 = nullptr;
831 size_t len = 0;
832 (void)winpr_asprintf(&issuer1, &len, "%s-licenser", freerdp_getApplicationDetailsString());
833 (void)winpr_asprintf(&issuer2, &len, "%s-licenser", freerdp_getApplicationDetailsVendor());
834 (void)winpr_asprintf(&issuer3, &len, "%s-licenser", freerdp_getApplicationDetailsProduct());
835
836 char* issuers[] = { WINPR_CAST_CONST_PTR_AWAY(vendor, char*),
837 WINPR_CAST_CONST_PTR_AWAY(product, char*),
838 WINPR_CAST_CONST_PTR_AWAY(details, char*),
839 issuer1,
840 issuer2,
841 issuer3 };
842
843 const BOOL res = freerdp_server_license_issuers_copy(settings, issuers, ARRAYSIZE(issuers));
844 free(issuer1);
845 free(issuer2);
846 free(issuer3);
847 if (!res)
848 goto out_fail;
849 }
850 if (!server && !remote)
851 {
852 if (!freerdp_settings_set_string(settings, FreeRDP_GatewayHttpUserAgent,
853 FREERDP_USER_AGENT))
854 goto out_fail;
855 if (!freerdp_settings_set_string(settings, FreeRDP_GatewayHttpMsUserAgent,
856 FREERDP_USER_AGENT))
857 goto out_fail;
858
859 if (!freerdp_settings_set_string(settings, FreeRDP_GatewayHttpReferer, ""))
860 goto out_fail;
861 if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAvdAccessTokenFormat,
862 "ms-appx-web%%3a%%2f%%2fMicrosoft.AAD.BrokerPlugin%%2f%s"))
863 goto out_fail;
864 if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAvdAccessAadFormat,
865 "https%%3A%%2F%%2F%s%%2F%s%%2Foauth2%%2Fnativeclient"))
866 goto out_fail;
867 if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAvdScope,
868 "https%3A%2F%2Fwww.wvd.microsoft.com%2F.default%20openid%"
869 "20profile%20offline_access"))
870
871 goto out_fail;
872 if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAvdClientID,
873 "a85cf173-4192-42f8-81fa-777a763e6e2c"))
874 goto out_fail;
875 if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAzureActiveDirectory,
876 "login.microsoftonline.com"))
877 goto out_fail;
878 if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAvdAadtenantid, "common"))
879 goto out_fail;
880 if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayAvdUseTenantid, FALSE))
881 goto out_fail;
882 if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopPhysicalWidth, 1000))
883 goto out_fail;
884 if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopPhysicalHeight, 1000))
885 goto out_fail;
886 if (!freerdp_settings_set_uint16(settings, FreeRDP_DesktopOrientation,
887 ORIENTATION_LANDSCAPE))
888 goto out_fail;
889 if (!freerdp_settings_set_uint32(settings, FreeRDP_DeviceScaleFactor, 100))
890 goto out_fail;
891 if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopScaleFactor, 100))
892 goto out_fail;
893 }
894 if (!freerdp_settings_set_uint32(settings, FreeRDP_SurfaceCommandsSupported,
895 SURFCMDS_SET_SURFACE_BITS | SURFCMDS_STREAM_SURFACE_BITS |
896 SURFCMDS_FRAME_MARKER))
897 goto out_fail;
898
899 if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR3))
900 goto out_fail;
901
902 if (!freerdp_settings_set_uint16(settings, FreeRDP_CapsProtocolVersion,
903 TS_CAPS_PROTOCOLVERSION))
904 goto out_fail;
905
906 if (!freerdp_settings_set_uint32(settings, FreeRDP_ClipboardFeatureMask,
907 CLIPRDR_FLAG_DEFAULT_MASK))
908 goto out_fail;
909 if (!freerdp_settings_set_string(settings, FreeRDP_ServerLicenseCompanyName,
910 freerdp_getApplicationDetailsVendor()))
911 goto out_fail;
912
913 {
914 size_t len = 0;
915 char* val = nullptr;
916 (void)winpr_asprintf(&val, &len, "%s-licensing-server",
917 freerdp_getApplicationDetailsProduct());
918 if (!val)
919 goto out_fail;
920
921 const BOOL rc =
922 freerdp_settings_set_string(settings, FreeRDP_ServerLicenseProductName, val);
923 free(val);
924 if (!rc)
925 goto out_fail;
926 }
927
928 if (!freerdp_settings_set_uint32(settings, FreeRDP_ServerLicenseProductVersion, 1))
929 goto out_fail;
930
931 if (!freerdp_settings_set_uint16(settings, FreeRDP_SupportedColorDepths,
932 RNS_UD_32BPP_SUPPORT | RNS_UD_24BPP_SUPPORT |
933 RNS_UD_16BPP_SUPPORT | RNS_UD_15BPP_SUPPORT))
934 goto out_fail;
935
936 const UINT32 railflags = TS_RAIL_CLIENTSTATUS_ALLOWLOCALMOVESIZE |
937 TS_RAIL_CLIENTSTATUS_ZORDER_SYNC |
938 TS_RAIL_CLIENTSTATUS_WINDOW_RESIZE_MARGIN_SUPPORTED |
939 TS_RAIL_CLIENTSTATUS_APPBAR_REMOTING_SUPPORTED |
940 TS_RAIL_CLIENTSTATUS_POWER_DISPLAY_REQUEST_SUPPORTED |
941 TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED;
942 if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteAppFeatureFlags, railflags))
943 goto out_fail;
944
945 if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput, TRUE) ||
946 !freerdp_settings_set_bool(settings, FreeRDP_HasHorizontalWheel, TRUE) ||
947 !freerdp_settings_set_bool(settings, FreeRDP_HasExtendedMouseEvent, TRUE) ||
948 !freerdp_settings_set_bool(settings, FreeRDP_HasQoeEvent, TRUE) ||
949 !freerdp_settings_set_bool(settings, FreeRDP_HasRelativeMouseEvent, TRUE) ||
950 !freerdp_settings_set_bool(settings, FreeRDP_HiDefRemoteApp, TRUE) ||
952 settings, FreeRDP_RemoteApplicationSupportMask,
953 RAIL_LEVEL_SUPPORTED | RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED |
954 RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED | RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED |
955 RAIL_LEVEL_SERVER_TO_CLIENT_IME_SYNC_SUPPORTED |
956 RAIL_LEVEL_HIDE_MINIMIZED_APPS_SUPPORTED | RAIL_LEVEL_WINDOW_CLOAKING_SUPPORTED |
957 RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED) ||
958 !freerdp_settings_set_uint16(settings, FreeRDP_TextANSICodePage, CP_UTF8) ||
959 !freerdp_settings_set_uint16(settings, FreeRDP_OrderSupportFlags,
960 NEGOTIATE_ORDER_SUPPORT | ZERO_BOUNDS_DELTA_SUPPORT |
961 COLOR_INDEX_SUPPORT) ||
962 !freerdp_settings_set_bool(settings, FreeRDP_SupportHeartbeatPdu, TRUE) ||
963 !freerdp_settings_set_bool(settings, FreeRDP_ServerMode, server) ||
964 !freerdp_settings_set_bool(settings, FreeRDP_WaitForOutputBufferFlush, TRUE) ||
965 !freerdp_settings_set_uint32(settings, FreeRDP_ClusterInfoFlags, REDIRECTION_SUPPORTED) ||
966 !freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, 1024) ||
967 !freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, 768) ||
968 !freerdp_settings_set_bool(settings, FreeRDP_Workarea, FALSE) ||
969 !freerdp_settings_set_bool(settings, FreeRDP_Fullscreen, FALSE) ||
970 !freerdp_settings_set_bool(settings, FreeRDP_GrabKeyboard, TRUE) ||
971 !freerdp_settings_set_bool(settings, FreeRDP_Decorations, TRUE) ||
972 !freerdp_settings_set_uint32(settings, FreeRDP_RdpVersion, RDP_VERSION_10_12) ||
973 !freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, 32) ||
974 !freerdp_settings_set_bool(settings, FreeRDP_AadSecurity, FALSE) ||
975 !freerdp_settings_set_bool(settings, FreeRDP_ExtSecurity, FALSE) ||
976 !freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, TRUE) ||
977 !freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, TRUE) ||
978 !freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, TRUE) ||
979 !freerdp_settings_set_bool(settings, FreeRDP_RdstlsSecurity, FALSE) ||
980 !freerdp_settings_set_bool(settings, FreeRDP_NegotiateSecurityLayer, TRUE) ||
981 !freerdp_settings_set_bool(settings, FreeRDP_RestrictedAdminModeRequired, FALSE) ||
982 !freerdp_settings_set_bool(settings, FreeRDP_RestrictedAdminModeSupported, TRUE) ||
983 !freerdp_settings_set_bool(settings, FreeRDP_MstscCookieMode, FALSE) ||
984 !freerdp_settings_set_uint32(settings, FreeRDP_CookieMaxLength,
985 DEFAULT_COOKIE_MAX_LENGTH) ||
986 !freerdp_settings_set_uint32(settings, FreeRDP_ClientBuild,
987 18363) || /* Windows 10, Version 1909 */
988 !freerdp_settings_set_uint32(settings, FreeRDP_KeyboardType, WINPR_KBD_TYPE_IBM_ENHANCED) ||
989 !freerdp_settings_set_uint32(settings, FreeRDP_KeyboardSubType, 0) ||
990 !freerdp_settings_set_uint32(settings, FreeRDP_KeyboardFunctionKey, 12) ||
991 !freerdp_settings_set_uint32(settings, FreeRDP_KeyboardLayout, 0) ||
992 !freerdp_settings_set_uint32(settings, FreeRDP_KeyboardHook,
993 KEYBOARD_HOOK_FULLSCREEN_ONLY) ||
994 !freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, FALSE) ||
995 !freerdp_settings_set_bool(settings, FreeRDP_SaltedChecksum, TRUE) ||
996 !freerdp_settings_set_uint32(settings, FreeRDP_ServerPort, 3389) ||
997 !freerdp_settings_set_uint32(settings, FreeRDP_GatewayPort, 443) ||
998 !freerdp_settings_set_bool(settings, FreeRDP_DesktopResize, TRUE) ||
999 !freerdp_settings_set_bool(settings, FreeRDP_ToggleFullscreen, TRUE) ||
1000 !freerdp_settings_set_uint32(settings, FreeRDP_DesktopPosX, UINT32_MAX) ||
1001 !freerdp_settings_set_uint32(settings, FreeRDP_DesktopPosY, UINT32_MAX) ||
1002 !freerdp_settings_set_bool(settings, FreeRDP_SoftwareGdi, TRUE) ||
1003 !freerdp_settings_set_bool(settings, FreeRDP_UnmapButtons, FALSE) ||
1004 !freerdp_settings_set_uint32(settings, FreeRDP_PerformanceFlags, PERF_FLAG_NONE) ||
1005 !freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, TRUE) ||
1006 !freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, FALSE) ||
1007 !freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, FALSE) ||
1008 !freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, TRUE) ||
1009 !freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, TRUE) ||
1010 !freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE) ||
1011 !freerdp_settings_set_uint32(settings, FreeRDP_ConnectionType,
1012 CONNECTION_TYPE_AUTODETECT) ||
1013 !freerdp_settings_set_bool(settings, FreeRDP_NetworkAutoDetect, TRUE) ||
1014 !freerdp_settings_set_uint32(settings, FreeRDP_EncryptionMethods, ENCRYPTION_METHOD_NONE) ||
1015 !freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel, ENCRYPTION_LEVEL_NONE) ||
1016 !freerdp_settings_set_bool(settings, FreeRDP_FIPSMode, FALSE) ||
1017 !freerdp_settings_set_bool(settings, FreeRDP_CompressionEnabled, TRUE) ||
1018 !freerdp_settings_set_bool(settings, FreeRDP_LogonNotify, TRUE) ||
1019 !freerdp_settings_set_uint32(settings, FreeRDP_BrushSupportLevel, BRUSH_COLOR_FULL) ||
1020 !freerdp_settings_set_uint32(settings, FreeRDP_CompressionLevel, PACKET_COMPR_TYPE_RDP61) ||
1021 !freerdp_settings_set_bool(settings, FreeRDP_Authentication, TRUE) ||
1022 !freerdp_settings_set_bool(settings, FreeRDP_AuthenticationOnly, FALSE) ||
1023 !freerdp_settings_set_bool(settings, FreeRDP_CredentialsFromStdin, FALSE) ||
1024 !freerdp_settings_set_bool(settings, FreeRDP_DisableCredentialsDelegation, FALSE) ||
1025 !freerdp_settings_set_uint32(settings, FreeRDP_AuthenticationLevel, 2) ||
1026 !freerdp_settings_set_uint32(settings, FreeRDP_ChannelCount, 0) ||
1027 !freerdp_settings_set_bool(settings, FreeRDP_CertificateCallbackPreferPEM, FALSE) ||
1028 !freerdp_settings_set_uint32(settings, FreeRDP_KeySpec, AT_KEYEXCHANGE))
1029 goto out_fail;
1030
1031 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_ChannelDefArray, nullptr,
1032 CHANNEL_MAX_COUNT))
1033 goto out_fail;
1034
1035 if (!freerdp_settings_set_bool(settings, FreeRDP_SupportMonitorLayoutPdu, FALSE))
1036 goto out_fail;
1037
1038 if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorCount, 0))
1039 goto out_fail;
1040
1041 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorDefArray, nullptr, 32))
1042 goto out_fail;
1043
1044 if (!freerdp_settings_set_int32(settings, FreeRDP_MonitorLocalShiftX, 0))
1045 goto out_fail;
1046
1047 if (!freerdp_settings_set_int32(settings, FreeRDP_MonitorLocalShiftY, 0))
1048 goto out_fail;
1049
1050 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorIds, nullptr, 0))
1051 goto out_fail;
1052
1053 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultitransportFlags,
1054 TRANSPORT_TYPE_UDP_FECR))
1055 goto out_fail;
1056 if (!freerdp_settings_set_bool(settings, FreeRDP_SupportMultitransport, TRUE))
1057 goto out_fail;
1058
1059 if (!settings_init_computer_name(settings))
1060 goto out_fail;
1061
1062 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerCertificate, nullptr, 1))
1063 goto out_fail;
1064
1065 if (!freerdp_capability_buffer_resize(settings, 32, FALSE))
1066 goto out_fail;
1067
1068 {
1069 char tmp[32] = WINPR_C_ARRAY_INIT;
1070 if (!freerdp_settings_set_string_len(settings, FreeRDP_ClientProductId, tmp, sizeof(tmp)))
1071 goto out_fail;
1072 }
1073
1074 /* [MS-RDPBCGR] 2.2.7.1.5 Pointer Capability Set (TS_POINTER_CAPABILITYSET)
1075 *
1076 * if we are in server mode send a reasonable large cache size,
1077 * if we are in client mode just set the value to the maximum we want to
1078 * support and during capability exchange that size will be limited to the
1079 * sizes the server supports
1080 *
1081 * We have chosen 128 cursors in cache which is at worst 128 * 576kB (384x384 pixel cursor with
1082 * 32bit color depth)
1083 * */
1084 if (freerdp_settings_get_bool(settings, FreeRDP_ServerMode))
1085 {
1086 if (!freerdp_settings_set_uint32(settings, FreeRDP_PointerCacheSize, 25) ||
1087 !freerdp_settings_set_uint32(settings, FreeRDP_ColorPointerCacheSize, 25))
1088 goto out_fail;
1089 }
1090 else
1091 {
1092 if (!freerdp_settings_set_uint32(settings, FreeRDP_PointerCacheSize, 128) ||
1093 !freerdp_settings_set_uint32(settings, FreeRDP_ColorPointerCacheSize, 128))
1094 goto out_fail;
1095 }
1096
1097 if (!freerdp_settings_set_uint32(settings, FreeRDP_LargePointerFlag,
1098 (LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384)) ||
1099 !freerdp_settings_set_bool(settings, FreeRDP_SoundBeepsEnabled, TRUE) ||
1100 !freerdp_settings_set_bool(settings, FreeRDP_DrawGdiPlusEnabled, FALSE) ||
1101 !freerdp_settings_set_bool(settings, FreeRDP_DrawAllowSkipAlpha, TRUE) ||
1102 !freerdp_settings_set_bool(settings, FreeRDP_DrawAllowColorSubsampling, FALSE) ||
1103 !freerdp_settings_set_bool(settings, FreeRDP_DrawAllowDynamicColorFidelity, TRUE) ||
1104 !freerdp_settings_set_bool(settings, FreeRDP_FrameMarkerCommandEnabled, TRUE) ||
1105 !freerdp_settings_set_bool(settings, FreeRDP_SurfaceFrameMarkerEnabled, TRUE) ||
1106 !freerdp_settings_set_bool(settings, FreeRDP_AllowCacheWaitingList, TRUE) ||
1107 !freerdp_settings_set_uint32(settings, FreeRDP_BitmapCacheV2NumCells, 5))
1108 goto out_fail;
1109 settings->BitmapCacheV2CellInfo =
1111
1112 if (!settings->BitmapCacheV2CellInfo)
1113 goto out_fail;
1114
1115 {
1116 BITMAP_CACHE_V2_CELL_INFO cache = WINPR_C_ARRAY_INIT;
1117 cache.numEntries = 600;
1118 if (!freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, 0,
1119 &cache) ||
1120 !freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, 1, &cache))
1121 goto out_fail;
1122 cache.numEntries = 2048;
1123 if (!freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, 2,
1124 &cache) ||
1125 !freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, 4, &cache))
1126 goto out_fail;
1127 cache.numEntries = 4096;
1128 if (!freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, 3, &cache))
1129 goto out_fail;
1130 }
1131 if (!freerdp_settings_set_bool(settings, FreeRDP_NoBitmapCompressionHeader, TRUE) ||
1132 !freerdp_settings_set_bool(settings, FreeRDP_RefreshRect, TRUE) ||
1133 !freerdp_settings_set_bool(settings, FreeRDP_SuppressOutput, TRUE) ||
1134 !freerdp_settings_set_uint32(settings, FreeRDP_GlyphSupportLevel, GLYPH_SUPPORT_NONE))
1135 goto out_fail;
1136 settings->GlyphCache = calloc(10, sizeof(GLYPH_CACHE_DEFINITION));
1137
1138 if (!settings->GlyphCache)
1139 goto out_fail;
1140
1141 settings->FragCache = calloc(1, sizeof(GLYPH_CACHE_DEFINITION));
1142
1143 if (!settings->FragCache)
1144 goto out_fail;
1145
1146 for (size_t x = 0; x < 10; x++)
1147 {
1148 GLYPH_CACHE_DEFINITION cache = WINPR_C_ARRAY_INIT;
1149 cache.cacheEntries = 254;
1150 switch (x)
1151 {
1152 case 0:
1153 case 1:
1154 cache.cacheMaximumCellSize = 4;
1155 break;
1156 case 2:
1157 case 3:
1158 cache.cacheMaximumCellSize = 8;
1159 break;
1160 case 4:
1161 cache.cacheMaximumCellSize = 16;
1162 break;
1163 case 5:
1164 cache.cacheMaximumCellSize = 32;
1165 break;
1166 case 6:
1167 cache.cacheMaximumCellSize = 64;
1168 break;
1169 case 7:
1170 cache.cacheMaximumCellSize = 128;
1171 break;
1172 case 8:
1173 cache.cacheMaximumCellSize = 256;
1174 break;
1175 case 9:
1176 cache.cacheMaximumCellSize = 256;
1177 break;
1178 default:
1179 goto out_fail;
1180 }
1181
1182 if (!freerdp_settings_set_pointer_array(settings, FreeRDP_GlyphCache, x, &cache))
1183 goto out_fail;
1184 }
1185 {
1186 GLYPH_CACHE_DEFINITION cache = WINPR_C_ARRAY_INIT;
1187 cache.cacheEntries = 256;
1188 cache.cacheMaximumCellSize = 256;
1189 if (!freerdp_settings_set_pointer_array(settings, FreeRDP_FragCache, 0, &cache))
1190 goto out_fail;
1191 }
1192 if (!freerdp_settings_set_uint32(settings, FreeRDP_OffscreenSupportLevel, 0) ||
1193 !freerdp_settings_set_uint32(settings, FreeRDP_OffscreenCacheSize, 7680) ||
1194 !freerdp_settings_set_uint32(settings, FreeRDP_OffscreenCacheEntries, 2000) ||
1195 !freerdp_settings_set_uint32(settings, FreeRDP_DrawNineGridCacheSize, 2560) ||
1196 !freerdp_settings_set_uint32(settings, FreeRDP_DrawNineGridCacheEntries, 256) ||
1197 !freerdp_settings_set_string(settings, FreeRDP_ClientDir, client_dll) ||
1198 !freerdp_settings_get_string(settings, FreeRDP_ClientDir) ||
1199 !freerdp_settings_set_uint32(settings, FreeRDP_RemoteWndSupportLevel,
1200 WINDOW_LEVEL_SUPPORTED | WINDOW_LEVEL_SUPPORTED_EX) ||
1201 !freerdp_settings_set_uint32(settings, FreeRDP_RemoteAppNumIconCaches, 3) ||
1202 !freerdp_settings_set_uint32(settings, FreeRDP_RemoteAppNumIconCacheEntries, 12) ||
1203 !freerdp_settings_set_uint32(settings, FreeRDP_VCChunkSize,
1204 (server && !remote) ? CHANNEL_CHUNK_MAX_LENGTH
1205 : CHANNEL_CHUNK_LENGTH) ||
1206 /* [MS-RDPBCGR] 2.2.7.2.7 Large Pointer Capability Set (TS_LARGE_POINTER_CAPABILITYSET)
1207 requires at least this size */
1208 !freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
1209 server ? 0 : 608299) ||
1210 !freerdp_settings_set_bool(settings, FreeRDP_GatewayUseSameCredentials, FALSE) ||
1211 !freerdp_settings_set_bool(settings, FreeRDP_GatewayBypassLocal, FALSE) ||
1212 !freerdp_settings_set_bool(settings, FreeRDP_GatewayRpcTransport, TRUE) ||
1213 !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpTransport, TRUE) ||
1214 !freerdp_settings_set_bool(settings, FreeRDP_GatewayUdpTransport, TRUE) ||
1215 !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpUseWebsockets, TRUE) ||
1216 !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpExtAuthSspiNtlm, FALSE) ||
1217 !freerdp_settings_set_bool(settings, FreeRDP_GatewayArmTransport, FALSE) ||
1218 !freerdp_settings_set_bool(settings, FreeRDP_FastPathInput, TRUE) ||
1219 !freerdp_settings_set_bool(settings, FreeRDP_FastPathOutput, TRUE) ||
1220 !freerdp_settings_set_bool(settings, FreeRDP_LongCredentialsSupported, TRUE) ||
1221 !freerdp_settings_set_uint32(settings, FreeRDP_FrameAcknowledge, 2) ||
1222 !freerdp_settings_set_bool(settings, FreeRDP_MouseMotion, TRUE) ||
1223 !freerdp_settings_set_uint32(settings, FreeRDP_NSCodecColorLossLevel, 3) ||
1224 !freerdp_settings_set_bool(settings, FreeRDP_NSCodecAllowSubsampling, TRUE) ||
1225 !freerdp_settings_set_bool(settings, FreeRDP_NSCodecAllowDynamicColorFidelity, TRUE) ||
1226 !freerdp_settings_set_bool(settings, FreeRDP_AutoReconnectionEnabled, FALSE) ||
1227 !freerdp_settings_set_uint32(settings, FreeRDP_AutoReconnectMaxRetries, 20) ||
1228 !freerdp_settings_set_bool(settings, FreeRDP_GfxThinClient, FALSE) ||
1229 !freerdp_settings_set_bool(settings, FreeRDP_GfxSmallCache, TRUE) ||
1230 !freerdp_settings_set_bool(settings, FreeRDP_GfxProgressive, FALSE) ||
1231 !freerdp_settings_set_bool(settings, FreeRDP_GfxProgressiveV2, FALSE) ||
1232 !freerdp_settings_set_bool(settings, FreeRDP_GfxPlanar, TRUE) ||
1233 !freerdp_settings_set_bool(settings, FreeRDP_GfxH264, FALSE) ||
1234 !freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444, FALSE) ||
1235 !freerdp_settings_set_bool(settings, FreeRDP_GfxCodecAV1, TRUE) ||
1236 !freerdp_settings_set_uint32(settings, FreeRDP_GfxCodecAV1Profile, 1) ||
1237 !freerdp_settings_set_bool(settings, FreeRDP_GfxSendQoeAck, FALSE) ||
1238 !freerdp_settings_set_bool(settings, FreeRDP_SupportDisplayControl, TRUE))
1239 goto out_fail;
1240 {
1241 ARC_CS_PRIVATE_PACKET cookie = WINPR_C_ARRAY_INIT;
1242 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_ClientAutoReconnectCookie, &cookie,
1243 1))
1244 goto out_fail;
1245 }
1246 {
1247 ARC_SC_PRIVATE_PACKET cookie = WINPR_C_ARRAY_INIT;
1248 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_ServerAutoReconnectCookie, &cookie,
1249 1))
1250 goto out_fail;
1251 }
1252
1253 settings->ClientTimeZone = (LPTIME_ZONE_INFORMATION)calloc(1, sizeof(TIME_ZONE_INFORMATION));
1254
1255 if (!settings->ClientTimeZone)
1256 goto out_fail;
1257
1258 if (!settings->ServerMode)
1259 {
1260 DYNAMIC_TIME_ZONE_INFORMATION dynamic = WINPR_C_ARRAY_INIT;
1262 freerdp_settings_get_pointer_writable(settings, FreeRDP_ClientTimeZone);
1263 WINPR_ASSERT(tz);
1264
1265 GetTimeZoneInformation(tz);
1266 GetDynamicTimeZoneInformation(&dynamic);
1267
1268 if (!freerdp_settings_set_string_from_utf16N(settings, FreeRDP_DynamicDSTTimeZoneKeyName,
1269 dynamic.TimeZoneKeyName,
1270 ARRAYSIZE(dynamic.TimeZoneKeyName)))
1271 goto out_fail;
1272
1273 if (!freerdp_settings_set_bool(settings, FreeRDP_DynamicDaylightTimeDisabled,
1274 dynamic.DynamicDaylightTimeDisabled))
1275 goto out_fail;
1276 }
1277
1278 if (!freerdp_settings_set_bool(settings, FreeRDP_TcpKeepAlive, TRUE) ||
1279 !freerdp_settings_set_uint32(settings, FreeRDP_TcpKeepAliveRetries, 3) ||
1280 !freerdp_settings_set_uint32(settings, FreeRDP_TcpKeepAliveDelay, 5) ||
1281 !freerdp_settings_set_uint32(settings, FreeRDP_TcpKeepAliveInterval, 2) ||
1282 !freerdp_settings_set_uint32(settings, FreeRDP_TcpAckTimeout, 9000) ||
1283 !freerdp_settings_set_uint32(settings, FreeRDP_TcpConnectTimeout, 15000))
1284 goto out_fail;
1285
1286 /* Bound for waiting on a gateway HTTP response (status/header phase and body phase each),
1287 * separate from FreeRDP_TcpConnectTimeout, which only bounds TCP connection establishment. */
1288 if (!freerdp_settings_set_uint32(settings, FreeRDP_GatewayResponseTimeout, 15000))
1289 goto out_fail;
1290
1291 if (!freerdp_settings_get_bool(settings, FreeRDP_ServerMode))
1292 {
1293 BOOL rc = FALSE;
1294 char* path = nullptr;
1295 if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectClipboard, TRUE))
1296 goto out_fail;
1297 /* these values are used only by the client part */
1298 path = GetKnownPath(KNOWN_PATH_HOME);
1299 rc = freerdp_settings_set_string(settings, FreeRDP_HomePath, path);
1300 free(path);
1301
1302 if (!rc || !freerdp_settings_get_string(settings, FreeRDP_HomePath))
1303 goto out_fail;
1304
1305 char* config = freerdp_settings_get_config_path();
1306 rc = freerdp_settings_set_string(settings, FreeRDP_ConfigPath, config);
1307 if (rc)
1308 {
1309 char* action = GetCombinedPath(config, "action.sh");
1310 rc = freerdp_settings_set_string(settings, FreeRDP_ActionScript, action);
1311 free(action);
1312 }
1313
1314 free(config);
1315 if (!rc)
1316 goto out_fail;
1317 }
1318
1319 settings_load_hkey_local_machine(settings);
1320
1321 if (!freerdp_settings_set_bool(settings, FreeRDP_SmartcardLogon, FALSE))
1322 goto out_fail;
1323 if (!freerdp_settings_set_uint32(settings, FreeRDP_TlsSecLevel, FREERDP_TLS_SECLEVEL_112BIT))
1324 goto out_fail;
1325 settings->OrderSupport = calloc(1, 32);
1326
1327 if (!freerdp_settings_set_uint16(settings, FreeRDP_TLSMinVersion, TLS1_2_VERSION))
1328 goto out_fail;
1329 if (!freerdp_settings_set_uint16(settings, FreeRDP_TLSMaxVersion, 0))
1330 goto out_fail;
1331
1332 if (!settings->OrderSupport)
1333 goto out_fail;
1334
1335 if (!freerdp_settings_set_default_order_support(settings))
1336 goto out_fail;
1337
1338 {
1339 const BOOL enable = freerdp_settings_get_bool(settings, FreeRDP_ServerMode);
1340 {
1341 const FreeRDP_Settings_Keys_Bool keys[] = { FreeRDP_SupportGraphicsPipeline,
1342 FreeRDP_SupportStatusInfoPdu,
1343 FreeRDP_SupportErrorInfoPdu,
1344 FreeRDP_SupportAsymetricKeys };
1345
1346 for (size_t x = 0; x < ARRAYSIZE(keys); x++)
1347 {
1348 if (!freerdp_settings_set_bool(settings, keys[x], enable))
1349 goto out_fail;
1350 }
1351 }
1352 }
1353
1354 if (!freerdp_settings_set_bool(settings, FreeRDP_SupportDynamicTimeZone, TRUE))
1355 goto out_fail;
1356 if (!freerdp_settings_set_bool(settings, FreeRDP_SupportSkipChannelJoin, TRUE))
1357 goto out_fail;
1358
1359 UUID corrId = WINPR_C_ARRAY_INIT;
1360 if (UuidCreate(&corrId) != RPC_S_OK)
1361 goto out_fail;
1362
1363 char buffer[64] = WINPR_C_ARRAY_INIT;
1364 if (!freerdp_settings_set_string(settings, FreeRDP_CorrelationId,
1365 guid2str(&corrId, buffer, sizeof(buffer))))
1366 goto out_fail;
1367
1368 return settings;
1369out_fail:
1370 WINPR_PRAGMA_DIAG_PUSH
1371 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1372 freerdp_settings_free(settings);
1373 WINPR_PRAGMA_DIAG_POP
1374 return nullptr;
1375}
1376
1377static void freerdp_settings_free_internal(rdpSettings* settings)
1378{
1379 freerdp_server_license_issuers_free(settings);
1380 freerdp_target_net_addresses_free(settings);
1381 freerdp_device_collection_free(settings);
1382 freerdp_static_channel_collection_free(settings);
1383 freerdp_dynamic_channel_collection_free(settings);
1384
1385 freerdp_capability_buffer_free(settings);
1386
1387 /* Free all strings, set other pointers nullptr */
1388 freerdp_settings_free_keys(settings, TRUE);
1389}
1390
1391static void freerdp_settings_free_internal_ensure_reset(rdpSettings* settings)
1392{
1393 settings->ServerLicenseProductIssuersCount = 0;
1394 settings->ServerLicenseProductIssuers = nullptr;
1395
1396 settings->ReceivedCapabilitiesSize = 0;
1397}
1398
1399void freerdp_settings_free(rdpSettings* settings)
1400{
1401 if (!settings)
1402 return;
1403
1404 freerdp_settings_free_internal(settings);
1405 free(settings);
1406}
1407
1408static BOOL freerdp_settings_int_buffer_copy(rdpSettings* dst, const rdpSettings* settings)
1409{
1410 BOOL rc = FALSE;
1411
1412 if (!dst || !settings)
1413 return FALSE;
1414
1415 typedef struct
1416 {
1417 FreeRDP_Settings_Keys_UInt32 lenKey;
1418 FreeRDP_Settings_Keys_Pointer pointerKey;
1419 } PointerDefs;
1420
1421 PointerDefs pointerDefs[] = {
1422 /* */
1423 { FreeRDP_LoadBalanceInfoLength, FreeRDP_LoadBalanceInfo },
1424 { FreeRDP_ServerRandomLength, FreeRDP_ServerRandom },
1425 { FreeRDP_ClientRandomLength, FreeRDP_ClientRandom },
1426 { FreeRDP_ServerCertificateLength, FreeRDP_ServerCertificate },
1427 { FreeRDP_ChannelDefArraySize, FreeRDP_ChannelDefArray },
1428 { FreeRDP_NumMonitorIds, FreeRDP_MonitorIds },
1429 { FreeRDP_BitmapCacheV2NumCells, FreeRDP_BitmapCacheV2CellInfo },
1430 { FreeRDP_RedirectionPasswordLength, FreeRDP_RedirectionPassword },
1431 { FreeRDP_RedirectionTsvUrlLength, FreeRDP_RedirectionTsvUrl },
1432 { FreeRDP_RedirectionGuidLength, FreeRDP_RedirectionGuid },
1433 { FreeRDP_MonitorDefArraySize, FreeRDP_MonitorDefArray }
1434 };
1435
1436 for (size_t i = 0; i < ARRAYSIZE(pointerDefs); i++)
1437 {
1438 const PointerDefs* keys = &pointerDefs[i];
1439 UINT32 n = freerdp_settings_get_uint32(settings, keys->lenKey);
1440
1441 const void* ptr = freerdp_settings_get_pointer(settings, keys->pointerKey);
1442 if (!freerdp_settings_set_pointer_len(dst, keys->pointerKey, ptr, n))
1443 goto out_fail;
1444 }
1445
1446 if (!freerdp_server_license_issuers_copy(dst, settings->ServerLicenseProductIssuers,
1447 settings->ServerLicenseProductIssuersCount))
1448 goto out_fail;
1449
1450 if (settings->RdpServerCertificate)
1451 {
1452 rdpCertificate* cert = freerdp_certificate_clone(settings->RdpServerCertificate);
1453 if (!cert)
1454 goto out_fail;
1455 if (!freerdp_settings_set_pointer_len(dst, FreeRDP_RdpServerCertificate, cert, 1))
1456 {
1457 freerdp_certificate_free(cert);
1458 goto out_fail;
1459 }
1460 }
1461 else
1462 {
1463 if (!freerdp_settings_set_pointer_len(dst, FreeRDP_RdpServerCertificate, nullptr, 0))
1464 goto out_fail;
1465 }
1466
1467 if (settings->RdpServerRsaKey)
1468 {
1469 rdpPrivateKey* key = freerdp_key_clone(settings->RdpServerRsaKey);
1470 if (!key)
1471 goto out_fail;
1472 if (!freerdp_settings_set_pointer_len(dst, FreeRDP_RdpServerRsaKey, key, 1))
1473 {
1474 freerdp_key_free(key);
1475 goto out_fail;
1476 }
1477 }
1478 else
1479 {
1480 if (!freerdp_settings_set_pointer_len(dst, FreeRDP_RdpServerRsaKey, nullptr, 0))
1481 goto out_fail;
1482 }
1483
1484 if (!freerdp_settings_set_uint32(dst, FreeRDP_ChannelCount,
1485 freerdp_settings_get_uint32(settings, FreeRDP_ChannelCount)))
1486 goto out_fail;
1487
1488 if (settings->OrderSupport)
1489 {
1490 dst->OrderSupport = calloc(32, sizeof(BYTE));
1491 if (!dst->OrderSupport)
1492 goto out_fail;
1493
1494 CopyMemory(dst->OrderSupport, settings->OrderSupport, 32);
1495 }
1496
1497 if (!freerdp_capability_buffer_copy(dst, settings))
1498 goto out_fail;
1499
1500 {
1501 const UINT32 glyphCacheCount = 10;
1502 const GLYPH_CACHE_DEFINITION* glyphCache =
1503 freerdp_settings_get_pointer(settings, FreeRDP_GlyphCache);
1504 if (!freerdp_settings_set_pointer_len(dst, FreeRDP_GlyphCache, glyphCache, glyphCacheCount))
1505 goto out_fail;
1506 }
1507
1508 {
1509 const UINT32 fragCacheCount = 1;
1510 const GLYPH_CACHE_DEFINITION* fragCache =
1511 freerdp_settings_get_pointer(settings, FreeRDP_FragCache);
1512 if (!freerdp_settings_set_pointer_len(dst, FreeRDP_FragCache, fragCache, fragCacheCount))
1513 goto out_fail;
1514 }
1515
1517 dst, FreeRDP_ClientAutoReconnectCookie,
1518 freerdp_settings_get_pointer(settings, FreeRDP_ClientAutoReconnectCookie), 1))
1519 goto out_fail;
1521 dst, FreeRDP_ServerAutoReconnectCookie,
1522 freerdp_settings_get_pointer(settings, FreeRDP_ServerAutoReconnectCookie), 1))
1523 goto out_fail;
1524
1525 {
1526 const TIME_ZONE_INFORMATION* tz =
1527 freerdp_settings_get_pointer(settings, FreeRDP_ClientTimeZone);
1528 if (!freerdp_settings_set_pointer_len(dst, FreeRDP_ClientTimeZone, tz, 1))
1529 goto out_fail;
1530 }
1531
1532 {
1533 const UINT32 nrports = freerdp_settings_get_uint32(settings, FreeRDP_TargetNetAddressCount);
1534 if (!freerdp_target_net_adresses_reset(dst, nrports))
1535 goto out_fail;
1536
1537 for (UINT32 i = 0; i < nrports; i++)
1538 {
1539 const char* address =
1540 freerdp_settings_get_pointer_array(settings, FreeRDP_TargetNetAddresses, i);
1541 const UINT32* port =
1542 freerdp_settings_get_pointer_array(settings, FreeRDP_TargetNetPorts, i);
1543
1544 if (!freerdp_settings_set_pointer_array(dst, FreeRDP_TargetNetAddresses, i, address))
1545 goto out_fail;
1546 if (!freerdp_settings_set_pointer_array(dst, FreeRDP_TargetNetPorts, i, port))
1547 goto out_fail;
1548 }
1549 }
1550
1551 {
1552 const UINT32 len = freerdp_settings_get_uint32(settings, FreeRDP_DeviceArraySize);
1553 const UINT32 count = freerdp_settings_get_uint32(settings, FreeRDP_DeviceCount);
1554
1555 if (len < count)
1556 goto out_fail;
1557 if (!freerdp_settings_set_pointer_len(dst, FreeRDP_DeviceArray, nullptr, len))
1558 goto out_fail;
1559 if (!freerdp_settings_set_uint32(dst, FreeRDP_DeviceCount, count))
1560 goto out_fail;
1561
1562 for (size_t index = 0; index < count; index++)
1563 {
1564 const RDPDR_DEVICE* argv =
1565 freerdp_settings_get_pointer_array(settings, FreeRDP_DeviceArray, index);
1566 WINPR_ASSERT(argv);
1567 if (!freerdp_settings_set_pointer_array(dst, FreeRDP_DeviceArray, index, argv))
1568 goto out_fail;
1569 }
1570 WINPR_ASSERT(dst->DeviceArray || (len == 0));
1571 WINPR_ASSERT(len >= count);
1572 }
1573 {
1574 const UINT32 len = freerdp_settings_get_uint32(dst, FreeRDP_StaticChannelArraySize);
1575 const UINT32 count = freerdp_settings_get_uint32(settings, FreeRDP_StaticChannelCount);
1576
1577 if (len < count)
1578 goto out_fail;
1579 if (!freerdp_settings_set_pointer_len(dst, FreeRDP_StaticChannelArray, nullptr, len))
1580 goto out_fail;
1581 if (!freerdp_settings_set_uint32(dst, FreeRDP_StaticChannelCount, count))
1582 goto out_fail;
1583
1584 for (size_t index = 0; index < count; index++)
1585 {
1586 const ADDIN_ARGV* argv =
1587 freerdp_settings_get_pointer_array(settings, FreeRDP_StaticChannelArray, index);
1588 WINPR_ASSERT(argv);
1589 if (!freerdp_settings_set_pointer_array(dst, FreeRDP_StaticChannelArray, index, argv))
1590 goto out_fail;
1591 }
1592 }
1593 {
1594 const UINT32 len = freerdp_settings_get_uint32(dst, FreeRDP_DynamicChannelArraySize);
1595 const UINT32 count = freerdp_settings_get_uint32(settings, FreeRDP_DynamicChannelCount);
1596
1597 if (len < count)
1598 goto out_fail;
1599 if (!freerdp_settings_set_pointer_len(dst, FreeRDP_DynamicChannelArray, nullptr, len))
1600 goto out_fail;
1601 if (!freerdp_settings_set_uint32(dst, FreeRDP_DynamicChannelCount, count))
1602 goto out_fail;
1603
1604 for (size_t index = 0; index < count; index++)
1605 {
1606 const ADDIN_ARGV* argv =
1607 freerdp_settings_get_pointer_array(settings, FreeRDP_DynamicChannelArray, index);
1608 WINPR_ASSERT(argv);
1609 if (!freerdp_settings_set_pointer_array(dst, FreeRDP_DynamicChannelArray, index, argv))
1610 goto out_fail;
1611 }
1612 }
1613
1614 rc = freerdp_settings_set_string(dst, FreeRDP_ActionScript,
1615 freerdp_settings_get_string(settings, FreeRDP_ActionScript));
1616
1617out_fail:
1618 return rc;
1619}
1620
1621BOOL freerdp_settings_copy(rdpSettings* dst, const rdpSettings* src)
1622{
1623 BOOL rc = 0;
1624
1625 if (!dst || !src)
1626 return FALSE;
1627
1628 /* This is required to free all non string buffers */
1629 freerdp_settings_free_internal(dst);
1630
1631 /* This copies everything except allocated non string buffers. reset all allocated buffers to
1632 * nullptr to fix issues during cleanup */
1633 rc = freerdp_settings_clone_keys(dst, src);
1634 if (!rc)
1635 goto out_fail;
1636 freerdp_settings_free_internal_ensure_reset(dst);
1637
1638 /* Begin copying */
1639 if (!freerdp_settings_int_buffer_copy(dst, src))
1640 goto out_fail;
1641 return TRUE;
1642out_fail:
1643 freerdp_settings_free_internal(dst);
1644 return FALSE;
1645}
1646
1647rdpSettings* freerdp_settings_clone(const rdpSettings* settings)
1648{
1649 rdpSettings* dst = (rdpSettings*)calloc(1, sizeof(rdpSettings));
1650
1651 if (!freerdp_settings_copy(dst, settings))
1652 goto out_fail;
1653
1654 return dst;
1655out_fail:
1656 WINPR_PRAGMA_DIAG_PUSH
1657 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1659 WINPR_PRAGMA_DIAG_POP
1660 return nullptr;
1661}
1662#ifdef _MSC_VER
1663#pragma warning(pop)
1664#endif
1665
1666static void zfree(WCHAR* str, size_t len)
1667{
1668 if (str)
1669 memset(str, 0, len * sizeof(WCHAR));
1670 free(str);
1671}
1672
1673BOOL identity_set_from_settings_with_pwd(SEC_WINNT_AUTH_IDENTITY* identity,
1674 const rdpSettings* settings,
1675 FreeRDP_Settings_Keys_String UserId,
1676 FreeRDP_Settings_Keys_String DomainId,
1677 const WCHAR* Password, size_t pwdLen)
1678{
1679 WINPR_ASSERT(identity);
1680 WINPR_ASSERT(settings);
1681
1682 size_t UserLen = 0;
1683 size_t DomainLen = 0;
1684
1685 WCHAR* Username = freerdp_settings_get_string_as_utf16(settings, UserId, &UserLen);
1686 WCHAR* Domain = freerdp_settings_get_string_as_utf16(settings, DomainId, &DomainLen);
1687
1688 const int rc = sspi_SetAuthIdentityWithLengthW(identity, Username, UserLen, Domain, DomainLen,
1689 Password, pwdLen);
1690 zfree(Username, UserLen);
1691 zfree(Domain, DomainLen);
1692 return (rc >= 0);
1693}
1694
1695BOOL identity_set_from_settings(SEC_WINNT_AUTH_IDENTITY_W* identity, const rdpSettings* settings,
1696 FreeRDP_Settings_Keys_String UserId,
1697 FreeRDP_Settings_Keys_String DomainId,
1698 FreeRDP_Settings_Keys_String PwdId)
1699{
1700 WINPR_ASSERT(identity);
1701 WINPR_ASSERT(settings);
1702
1703 size_t PwdLen = 0;
1704
1705 WCHAR* Password = freerdp_settings_get_string_as_utf16(settings, PwdId, &PwdLen);
1706
1707 const BOOL rc =
1708 identity_set_from_settings_with_pwd(identity, settings, UserId, DomainId, Password, PwdLen);
1709 zfree(Password, PwdLen);
1710 return rc;
1711}
1712
1713BOOL identity_set_from_smartcard_hash(SEC_WINNT_AUTH_IDENTITY_W* identity,
1714 const rdpSettings* settings,
1715 FreeRDP_Settings_Keys_String userId,
1716 FreeRDP_Settings_Keys_String domainId,
1717 FreeRDP_Settings_Keys_String pwdId,
1718 WINPR_ATTR_UNUSED const BYTE* certSha1,
1719 WINPR_ATTR_UNUSED size_t sha1len)
1720{
1721#ifdef _WIN32
1722 CERT_CREDENTIAL_INFO certInfo = { sizeof(CERT_CREDENTIAL_INFO), WINPR_C_ARRAY_INIT };
1723 LPWSTR marshalledCredentials = nullptr;
1724
1725 memcpy(certInfo.rgbHashOfCert, certSha1, MIN(sha1len, sizeof(certInfo.rgbHashOfCert)));
1726
1727 if (!CredMarshalCredentialW(CertCredential, &certInfo, &marshalledCredentials))
1728 {
1729 WLog_ERR(TAG, "error marshalling cert credentials");
1730 return FALSE;
1731 }
1732
1733 size_t pwdLen = 0;
1734 WCHAR* Password = freerdp_settings_get_string_as_utf16(settings, pwdId, &pwdLen);
1735 const int rc = sspi_SetAuthIdentityWithLengthW(identity, marshalledCredentials,
1736 _wcslen(marshalledCredentials), nullptr, 0,
1737 Password, pwdLen);
1738 zfree(Password, pwdLen);
1739 CredFree(marshalledCredentials);
1740 return (rc >= 0);
1741#else
1742 return identity_set_from_settings(identity, settings, userId, domainId, pwdId);
1743#endif /* _WIN32 */
1744}
1745
1746const char* freerdp_settings_glyph_level_string(UINT32 level, char* buffer, size_t size)
1747{
1748 const char* str = "GLYPH_SUPPORT_UNKNOWN";
1749 switch (level)
1750 {
1751 case GLYPH_SUPPORT_NONE:
1752 str = "GLYPH_SUPPORT_NONE";
1753 break;
1754 case GLYPH_SUPPORT_PARTIAL:
1755 str = "GLYPH_SUPPORT_PARTIAL";
1756 break;
1757 case GLYPH_SUPPORT_FULL:
1758 str = "GLYPH_SUPPORT_FULL";
1759 break;
1760 case GLYPH_SUPPORT_ENCODE:
1761 str = "GLYPH_SUPPORT_ENCODE";
1762 break;
1763 default:
1764 break;
1765 }
1766
1767 (void)_snprintf(buffer, size, "%s[0x%08" PRIx32 "]", str, level);
1768 return buffer;
1769}
1770
1771BOOL freerdp_target_net_adresses_reset(rdpSettings* settings, size_t size)
1772{
1773 freerdp_target_net_addresses_free(settings);
1774
1775 return freerdp_target_net_addresses_resize(settings, size);
1776}
1777
1778BOOL freerdp_settings_enforce_monitor_exists(rdpSettings* settings)
1779{
1780 const UINT32 count = freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount);
1781 const BOOL fullscreen = freerdp_settings_get_bool(settings, FreeRDP_Fullscreen);
1782 const BOOL multimon = freerdp_settings_get_bool(settings, FreeRDP_UseMultimon);
1783 const BOOL useMonitors = fullscreen || multimon;
1784
1785 const UINT32 size = freerdp_settings_get_uint32(settings, FreeRDP_MonitorDefArraySize);
1786 if (size == 0)
1787 {
1788 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorDefArray, nullptr, 16))
1789 return FALSE;
1790 }
1791
1792 if (!useMonitors || (count == 0))
1793 {
1794 const UINT32 width = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
1795 const UINT32 height = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
1796 const UINT32 pwidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopPhysicalWidth);
1797 const UINT32 pheight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopPhysicalHeight);
1798 const UINT16 orientation =
1799 freerdp_settings_get_uint16(settings, FreeRDP_DesktopOrientation);
1800 const UINT32 desktopScaleFactor =
1801 freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor);
1802 const UINT32 deviceScaleFactor =
1803 freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor);
1804
1805 if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorCount, 1))
1806 return FALSE;
1807
1808 rdpMonitor monitor = WINPR_C_ARRAY_INIT;
1809 monitor.x = 0;
1810 monitor.y = 0;
1811 monitor.width = WINPR_ASSERTING_INT_CAST(int32_t, width);
1812 monitor.height = WINPR_ASSERTING_INT_CAST(int32_t, height);
1813 monitor.is_primary = TRUE;
1814 monitor.orig_screen = 0;
1815 monitor.attributes.physicalWidth = pwidth;
1816 monitor.attributes.physicalHeight = pheight;
1817 monitor.attributes.orientation = orientation;
1818 monitor.attributes.desktopScaleFactor = desktopScaleFactor;
1819 monitor.attributes.deviceScaleFactor = deviceScaleFactor;
1820 if (!freerdp_settings_set_monitor_def_array_sorted(settings, &monitor, 1))
1821 return FALSE;
1822 }
1823
1824 return TRUE;
1825}
1826
1827BOOL freerdp_settings_enforce_consistency(rdpSettings* settings)
1828{
1829 if (freerdp_settings_get_bool(settings, FreeRDP_BitmapCacheV3Enabled))
1830 {
1831 settings->OrderSupportFlagsEx |= CACHE_BITMAP_V3_SUPPORT;
1832 settings->OrderSupportFlags |= ORDER_FLAGS_EXTRA_SUPPORT;
1833 }
1834
1835 if (settings->FrameMarkerCommandEnabled)
1836 {
1837 settings->OrderSupportFlagsEx |= ALTSEC_FRAME_MARKER_SUPPORT;
1838 settings->OrderSupportFlags |= ORDER_FLAGS_EXTRA_SUPPORT;
1839 }
1840 return TRUE;
1841}
WINPR_ATTR_NODISCARD FREERDP_API const void * freerdp_settings_get_pointer(const rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id)
Returns a immutable pointer settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_string_from_utf16N(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const WCHAR *param, size_t length)
Sets a string settings value. The param is converted to UTF-8 and the copy stored.
rdpSettings * freerdp_settings_new(DWORD flags)
creates a new setting struct
rdpSettings * freerdp_settings_clone(const rdpSettings *settings)
Creates a deep copy of settings.
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_string_len(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *val, size_t len)
Sets a string settings value. The val is copied.
char * freerdp_settings_get_config_path(void)
return the configuration directory for the library
WINPR_ATTR_NODISCARD FREERDP_API void * freerdp_settings_get_pointer_writable(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id)
Returns a mutable pointer settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT16 freerdp_settings_get_uint16(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt16 id)
Returns a UINT16 settings value.
BOOL freerdp_settings_copy(rdpSettings *dst, const rdpSettings *src)
Deep copies settings from src to dst.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_pointer_len(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id, const void *data, size_t len)
Set a pointer to value data.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_int32(rdpSettings *settings, FreeRDP_Settings_Keys_Int32 id, INT32 val)
Sets a INT32 settings value.
void freerdp_settings_free(rdpSettings *settings)
Free a settings struct with all data in it.
#define FREERDP_SETTINGS_SERVER_MODE
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API WCHAR * freerdp_settings_get_string_as_utf16(const rdpSettings *settings, FreeRDP_Settings_Keys_String id, size_t *pCharLen)
Return an allocated UTF16 string.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_uint16(rdpSettings *settings, FreeRDP_Settings_Keys_UInt16 id, UINT16 val)
Sets a UINT16 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_monitor_def_array_sorted(rdpSettings *settings, const rdpMonitor *monitors, size_t count)
Sort monitor array according to:
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *val)
Sets a string settings value. The param is copied.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
Definition wtypes.h:263