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