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