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