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