FreeRDP
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 
51 static 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 
59 struct bounds_t
60 {
61  INT32 x;
62  INT32 y;
63  INT32 width;
64  INT32 height;
65 };
66 
67 static 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 
75 static 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 
99 static 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 
112 static 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 
125 static 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 
139 static 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 
153 static 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 
163 static 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 
174 static 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 
185 static 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 
294 static 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 
313 static 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 
321 static 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 
334 void 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 
345 static 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 
379 static 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 
416 static void alloc_free(UINT32** ptr)
417 {
418  free((void*)ptr);
419 }
420 
421 WINPR_ATTR_MALLOC(alloc_free, 1)
422 static 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  */
442 static 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 
535 static 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 
555 fail:
556  alloc_free(graph);
557 
558  return rc;
559 }
560 
561 static 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 
575 static 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 
588 static 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  */
604 static 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 rc = TRUE;
610 
611  struct bounds_t bounds = { 0 };
612 
613  if (count == 0)
614  {
615  WLog_WARN(TAG, "Monitor configuration empty.");
616  return TRUE;
617  }
618 
619  for (UINT32 x = 0; x < count; x++)
620  {
621  const rdpMonitor* monitor =
622  freerdp_settings_get_pointer_array(settings, FreeRDP_MonitorDefArray, x);
623  struct bounds_t cur = {
624  .x = monitor->x, .y = monitor->y, .width = monitor->width, .height = monitor->height
625  };
626 
627  bounds = union_rect(&bounds, &cur);
628 
629  if (monitor->is_primary)
630  {
631  if (havePrimary)
632  {
633  WLog_ERR(TAG, "Monitor configuration contains multiple primary monitors!");
634  rc = FALSE;
635  }
636  havePrimary = TRUE;
637  }
638 
639  if ((monitor->x == 0) && (monitor->y == 0))
640  {
641  if (foundOrigin)
642  {
643  WLog_ERR(TAG, "Monitor configuration does have multiple origin 0/0");
644  rc = FALSE;
645  }
646  foundOrigin = TRUE;
647  }
648  }
649 
650  if ((bounds.width > 32766) || (bounds.width < 200))
651  {
652  WLog_ERR(TAG,
653  "Monitor configuration virtual desktop width must be 200 <= %" PRId32 " <= 32766",
654  bounds.width);
655  rc = FALSE;
656  }
657  if ((bounds.height > 32766) || (bounds.height < 200))
658  {
659  WLog_ERR(TAG,
660  "Monitor configuration virtual desktop height must be 200 <= %" PRId32 " <= 32766",
661  bounds.height);
662  rc = FALSE;
663  }
664 
665  if (!havePrimary)
666  {
667  WLog_ERR(TAG, "Monitor configuration does not contain a primary monitor!");
668  rc = FALSE;
669  }
670  if (!foundOrigin)
671  {
672  WLog_ERR(TAG, "Monitor configuration must start at 0/0 for first monitor!");
673  rc = FALSE;
674  }
675 
676  return rc;
677 }
678 
679 BOOL freerdp_settings_check_client_after_preconnect(const rdpSettings* settings)
680 {
681  wLog* log = WLog_Get(TAG);
682  BOOL rc = TRUE;
683  log_monitor_configuration(settings, log, WLOG_DEBUG);
684  if (freerdp_settings_client_monitors_overlap(settings))
685  rc = FALSE;
686  if (freerdp_settings_client_monitors_have_gaps(settings))
687  rc = FALSE;
688  if (!freerdp_settings_client_monitors_check_primary_and_origin(settings))
689  rc = FALSE;
690  if (!rc)
691  {
692  DWORD level = WLOG_ERROR;
693  WLog_Print(log, level, "Invalid or unsupported monitor configuration detected");
694  WLog_Print(log, level, "Check if the configuration is valid.");
695  WLog_Print(log, level,
696  "If you suspect a bug create a new issue at "
697  "https://github.com/FreeRDP/FreeRDP/issues/new");
698  WLog_Print(
699  log, level,
700  "Provide at least the following log lines detailing your monitor configuration:");
701  log_monitor_configuration(settings, log, level);
702  }
703 
704  return rc;
705 }
706 
707 BOOL freerdp_settings_set_default_order_support(rdpSettings* settings)
708 {
709  BYTE* OrderSupport = freerdp_settings_get_pointer_writable(settings, FreeRDP_OrderSupport);
710  if (!OrderSupport)
711  return FALSE;
712 
713  ZeroMemory(OrderSupport, 32);
714  OrderSupport[NEG_DSTBLT_INDEX] = TRUE;
715  OrderSupport[NEG_PATBLT_INDEX] = TRUE;
716  OrderSupport[NEG_SCRBLT_INDEX] = TRUE;
717  OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE;
718  OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE;
719  OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE;
720  OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE;
721  OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE;
722  OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE;
723  OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE;
724  OrderSupport[NEG_LINETO_INDEX] = TRUE;
725  OrderSupport[NEG_POLYLINE_INDEX] = TRUE;
726  OrderSupport[NEG_MEMBLT_INDEX] =
727  freerdp_settings_get_bool(settings, FreeRDP_BitmapCacheEnabled) ? 1 : 0;
728  OrderSupport[NEG_MEM3BLT_INDEX] =
729  freerdp_settings_get_bool(settings, FreeRDP_BitmapCacheEnabled) ? 1 : 0;
730  OrderSupport[NEG_MEMBLT_V2_INDEX] =
731  freerdp_settings_get_bool(settings, FreeRDP_BitmapCacheEnabled) ? 1 : 0;
732  OrderSupport[NEG_MEM3BLT_V2_INDEX] =
733  freerdp_settings_get_bool(settings, FreeRDP_BitmapCacheEnabled) ? 1 : 0;
734  OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE;
735  OrderSupport[NEG_GLYPH_INDEX_INDEX] =
736  freerdp_settings_get_uint32(settings, FreeRDP_GlyphSupportLevel) != GLYPH_SUPPORT_NONE;
737  OrderSupport[NEG_FAST_INDEX_INDEX] =
738  freerdp_settings_get_uint32(settings, FreeRDP_GlyphSupportLevel) != GLYPH_SUPPORT_NONE;
739  OrderSupport[NEG_FAST_GLYPH_INDEX] =
740  freerdp_settings_get_uint32(settings, FreeRDP_GlyphSupportLevel) != GLYPH_SUPPORT_NONE;
741  OrderSupport[NEG_POLYGON_SC_INDEX] = FALSE;
742  OrderSupport[NEG_POLYGON_CB_INDEX] = FALSE;
743  OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE;
744  OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE;
745  return TRUE;
746 }
747 
748 BOOL freerdp_capability_buffer_allocate(rdpSettings* settings, UINT32 count)
749 {
750  WINPR_ASSERT(settings);
751  WINPR_ASSERT(count > 0);
752  WINPR_ASSERT(count == 32);
753 
754  freerdp_capability_buffer_free(settings);
755  WINPR_ASSERT(settings->ReceivedCapabilitiesSize == 0);
756 
757  settings->ReceivedCapabilitiesSize = count;
758  void* tmp = realloc(settings->ReceivedCapabilities, count * sizeof(BYTE));
759  if (!tmp)
760  return FALSE;
761  memset(tmp, 0, count * sizeof(BYTE));
762  settings->ReceivedCapabilities = tmp;
763 
764  tmp = realloc((void*)settings->ReceivedCapabilityData, count * sizeof(BYTE*));
765  if (!tmp)
766  return FALSE;
767  memset(tmp, 0, count * sizeof(BYTE*));
768  settings->ReceivedCapabilityData = (BYTE**)tmp;
769 
770  tmp = realloc(settings->ReceivedCapabilityDataSizes, count * sizeof(UINT32));
771  if (!tmp)
772  return FALSE;
773  memset(tmp, 0, count * sizeof(UINT32));
774  settings->ReceivedCapabilityDataSizes = tmp;
775 
776  return (settings->ReceivedCapabilities && settings->ReceivedCapabilityData &&
777  settings->ReceivedCapabilityDataSizes);
778 }
779 
780 #if !defined(WITH_FULL_CONFIG_PATH)
781 static char* freerdp_settings_get_legacy_config_path(void)
782 {
783  char product[sizeof(FREERDP_PRODUCT_STRING)] = { 0 };
784 
785  for (size_t i = 0; i < sizeof(product); i++)
786  product[i] = (char)tolower(FREERDP_PRODUCT_STRING[i]);
787 
788  return GetKnownSubPath(KNOWN_PATH_XDG_CONFIG_HOME, product);
789 }
790 #endif
791 
793 {
794  char* path = NULL;
795  /* For default FreeRDP continue using same config directory
796  * as in old releases.
797  * Custom builds use <Vendor>/<Product> as config folder. */
798 #if !defined(WITH_FULL_CONFIG_PATH)
799  if (_stricmp(FREERDP_VENDOR_STRING, FREERDP_PRODUCT_STRING) == 0)
800  return freerdp_settings_get_legacy_config_path();
801 #endif
802 
803  char* base = GetKnownSubPath(KNOWN_PATH_XDG_CONFIG_HOME, FREERDP_VENDOR_STRING);
804  if (base)
805  path = GetCombinedPath(base, FREERDP_PRODUCT_STRING);
806  free(base);
807 
808  return path;
809 }
810 
811 rdpSettings* freerdp_settings_new(DWORD flags)
812 {
813  char* issuers[] = { "FreeRDP", "FreeRDP-licenser" };
814  const BOOL server = (flags & FREERDP_SETTINGS_SERVER_MODE) != 0 ? TRUE : FALSE;
815  const BOOL remote = (flags & FREERDP_SETTINGS_REMOTE_MODE) != 0 ? TRUE : FALSE;
816  rdpSettings* settings = (rdpSettings*)calloc(1, sizeof(rdpSettings));
817 
818  if (!settings)
819  return NULL;
820 
821  if (!server && !remote)
822  {
823  if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAvdClientID,
824  "a85cf173-4192-42f8-81fa-777a763e6e2c"))
825  goto out_fail;
826  if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAzureActiveDirectory,
827  "login.microsoftonline.com"))
828  goto out_fail;
829  if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAvdAadtenantid, "common"))
830  goto out_fail;
831  if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayAvdUseTenantid, FALSE))
832  goto out_fail;
833  if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopPhysicalWidth, 1000))
834  goto out_fail;
835  if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopPhysicalHeight, 1000))
836  goto out_fail;
837  if (!freerdp_settings_set_uint16(settings, FreeRDP_DesktopOrientation,
838  ORIENTATION_LANDSCAPE))
839  goto out_fail;
840  if (!freerdp_settings_set_uint32(settings, FreeRDP_DeviceScaleFactor, 100))
841  goto out_fail;
842  if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopScaleFactor, 100))
843  goto out_fail;
844  }
845  if (!freerdp_settings_set_uint32(settings, FreeRDP_SurfaceCommandsSupported,
846  SURFCMDS_SET_SURFACE_BITS | SURFCMDS_STREAM_SURFACE_BITS |
847  SURFCMDS_FRAME_MARKER))
848  goto out_fail;
849 
850  if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR3))
851  goto out_fail;
852 
853  if (!freerdp_settings_set_uint16(settings, FreeRDP_CapsProtocolVersion,
854  TS_CAPS_PROTOCOLVERSION))
855  goto out_fail;
856 
857  if (!freerdp_settings_set_uint32(settings, FreeRDP_ClipboardFeatureMask,
858  CLIPRDR_FLAG_DEFAULT_MASK))
859  goto out_fail;
860  if (!freerdp_settings_set_string(settings, FreeRDP_ServerLicenseCompanyName, "FreeRDP"))
861  goto out_fail;
862  if (!freerdp_settings_set_string(settings, FreeRDP_ServerLicenseProductName,
863  "FreeRDP-licensing-server"))
864  goto out_fail;
865  if (!freerdp_settings_set_uint32(settings, FreeRDP_ServerLicenseProductVersion, 1))
866  goto out_fail;
867  if (!freerdp_server_license_issuers_copy(settings, issuers, ARRAYSIZE(issuers)))
868  goto out_fail;
869 
870  if (!freerdp_settings_set_uint16(settings, FreeRDP_SupportedColorDepths,
871  RNS_UD_32BPP_SUPPORT | RNS_UD_24BPP_SUPPORT |
872  RNS_UD_16BPP_SUPPORT | RNS_UD_15BPP_SUPPORT))
873  goto out_fail;
874 
875  if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput, TRUE) ||
876  !freerdp_settings_set_bool(settings, FreeRDP_HasHorizontalWheel, TRUE) ||
877  !freerdp_settings_set_bool(settings, FreeRDP_HasExtendedMouseEvent, TRUE) ||
878  !freerdp_settings_set_bool(settings, FreeRDP_HasQoeEvent, TRUE) ||
879  !freerdp_settings_set_bool(settings, FreeRDP_HasRelativeMouseEvent, TRUE) ||
880  !freerdp_settings_set_bool(settings, FreeRDP_HiDefRemoteApp, TRUE) ||
882  settings, FreeRDP_RemoteApplicationSupportMask,
883  RAIL_LEVEL_SUPPORTED | RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED |
884  RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED | RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED |
885  RAIL_LEVEL_SERVER_TO_CLIENT_IME_SYNC_SUPPORTED |
886  RAIL_LEVEL_HIDE_MINIMIZED_APPS_SUPPORTED | RAIL_LEVEL_WINDOW_CLOAKING_SUPPORTED |
887  RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED) ||
888  !freerdp_settings_set_uint16(settings, FreeRDP_TextANSICodePage, CP_UTF8) ||
889  !freerdp_settings_set_uint16(settings, FreeRDP_OrderSupportFlags,
890  NEGOTIATE_ORDER_SUPPORT | ZERO_BOUNDS_DELTA_SUPPORT |
891  COLOR_INDEX_SUPPORT) ||
892  !freerdp_settings_set_bool(settings, FreeRDP_SupportHeartbeatPdu, TRUE) ||
893  !freerdp_settings_set_bool(settings, FreeRDP_ServerMode, server) ||
894  !freerdp_settings_set_bool(settings, FreeRDP_WaitForOutputBufferFlush, TRUE) ||
895  !freerdp_settings_set_uint32(settings, FreeRDP_ClusterInfoFlags, REDIRECTION_SUPPORTED) ||
896  !freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, 1024) ||
897  !freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, 768) ||
898  !freerdp_settings_set_bool(settings, FreeRDP_Workarea, FALSE) ||
899  !freerdp_settings_set_bool(settings, FreeRDP_Fullscreen, FALSE) ||
900  !freerdp_settings_set_bool(settings, FreeRDP_GrabKeyboard, TRUE) ||
901  !freerdp_settings_set_bool(settings, FreeRDP_Decorations, TRUE) ||
902  !freerdp_settings_set_uint32(settings, FreeRDP_RdpVersion, RDP_VERSION_10_12) ||
903  !freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, 32) ||
904  !freerdp_settings_set_bool(settings, FreeRDP_AadSecurity, FALSE) ||
905  !freerdp_settings_set_bool(settings, FreeRDP_ExtSecurity, FALSE) ||
906  !freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, TRUE) ||
907  !freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, TRUE) ||
908  !freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, TRUE) ||
909  !freerdp_settings_set_bool(settings, FreeRDP_RdstlsSecurity, FALSE) ||
910  !freerdp_settings_set_bool(settings, FreeRDP_NegotiateSecurityLayer, TRUE) ||
911  !freerdp_settings_set_bool(settings, FreeRDP_RestrictedAdminModeRequired, FALSE) ||
912  !freerdp_settings_set_bool(settings, FreeRDP_MstscCookieMode, FALSE) ||
913  !freerdp_settings_set_uint32(settings, FreeRDP_CookieMaxLength,
914  DEFAULT_COOKIE_MAX_LENGTH) ||
915  !freerdp_settings_set_uint32(settings, FreeRDP_ClientBuild,
916  18363) || /* Windows 10, Version 1909 */
917  !freerdp_settings_set_uint32(settings, FreeRDP_KeyboardType, 4) ||
918  !freerdp_settings_set_uint32(settings, FreeRDP_KeyboardSubType, 0) ||
919  !freerdp_settings_set_uint32(settings, FreeRDP_KeyboardFunctionKey, 12) ||
920  !freerdp_settings_set_uint32(settings, FreeRDP_KeyboardLayout, 0) ||
921  !freerdp_settings_set_uint32(settings, FreeRDP_KeyboardHook,
922  KEYBOARD_HOOK_FULLSCREEN_ONLY) ||
923  !freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, FALSE) ||
924  !freerdp_settings_set_bool(settings, FreeRDP_SaltedChecksum, TRUE) ||
925  !freerdp_settings_set_uint32(settings, FreeRDP_ServerPort, 3389) ||
926  !freerdp_settings_set_uint32(settings, FreeRDP_GatewayPort, 443) ||
927  !freerdp_settings_set_bool(settings, FreeRDP_DesktopResize, TRUE) ||
928  !freerdp_settings_set_bool(settings, FreeRDP_ToggleFullscreen, TRUE) ||
929  !freerdp_settings_set_uint32(settings, FreeRDP_DesktopPosX, UINT32_MAX) ||
930  !freerdp_settings_set_uint32(settings, FreeRDP_DesktopPosY, UINT32_MAX) ||
931  !freerdp_settings_set_bool(settings, FreeRDP_SoftwareGdi, TRUE) ||
932  !freerdp_settings_set_bool(settings, FreeRDP_UnmapButtons, FALSE) ||
933  !freerdp_settings_set_uint32(settings, FreeRDP_PerformanceFlags, PERF_FLAG_NONE) ||
934  !freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, TRUE) ||
935  !freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, FALSE) ||
936  !freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, FALSE) ||
937  !freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, TRUE) ||
938  !freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, TRUE) ||
939  !freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE) ||
940  !freerdp_settings_set_uint32(settings, FreeRDP_ConnectionType,
941  CONNECTION_TYPE_AUTODETECT) ||
942  !freerdp_settings_set_bool(settings, FreeRDP_NetworkAutoDetect, TRUE) ||
943  !freerdp_settings_set_uint32(settings, FreeRDP_EncryptionMethods, ENCRYPTION_METHOD_NONE) ||
944  !freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel, ENCRYPTION_LEVEL_NONE) ||
945  !freerdp_settings_set_bool(settings, FreeRDP_FIPSMode, FALSE) ||
946  !freerdp_settings_set_bool(settings, FreeRDP_CompressionEnabled, TRUE) ||
947  !freerdp_settings_set_bool(settings, FreeRDP_LogonNotify, TRUE) ||
948  !freerdp_settings_set_uint32(settings, FreeRDP_BrushSupportLevel, BRUSH_COLOR_FULL) ||
949  !freerdp_settings_set_uint32(settings, FreeRDP_CompressionLevel, PACKET_COMPR_TYPE_RDP61) ||
950  !freerdp_settings_set_bool(settings, FreeRDP_Authentication, TRUE) ||
951  !freerdp_settings_set_bool(settings, FreeRDP_AuthenticationOnly, FALSE) ||
952  !freerdp_settings_set_bool(settings, FreeRDP_CredentialsFromStdin, FALSE) ||
953  !freerdp_settings_set_bool(settings, FreeRDP_DisableCredentialsDelegation, FALSE) ||
954  !freerdp_settings_set_uint32(settings, FreeRDP_AuthenticationLevel, 2) ||
955  !freerdp_settings_set_uint32(settings, FreeRDP_ChannelCount, 0) ||
956  !freerdp_settings_set_bool(settings, FreeRDP_CertificateCallbackPreferPEM, FALSE) ||
957  !freerdp_settings_set_uint32(settings, FreeRDP_KeySpec, AT_KEYEXCHANGE))
958  goto out_fail;
959 
960  if (!freerdp_settings_set_pointer_len(settings, FreeRDP_ChannelDefArray, NULL,
961  CHANNEL_MAX_COUNT))
962  goto out_fail;
963 
964  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportMonitorLayoutPdu, FALSE))
965  goto out_fail;
966 
967  if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorCount, 0))
968  goto out_fail;
969 
970  if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorDefArray, NULL, 32))
971  goto out_fail;
972 
973  if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorLocalShiftX, 0))
974  goto out_fail;
975 
976  if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorLocalShiftY, 0))
977  goto out_fail;
978 
979  if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorIds, NULL, 0))
980  goto out_fail;
981 
982  if (!freerdp_settings_set_uint32(settings, FreeRDP_MultitransportFlags,
983  TRANSPORT_TYPE_UDP_FECR))
984  goto out_fail;
985  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportMultitransport, TRUE))
986  goto out_fail;
987 
988  if (!settings_init_computer_name(settings))
989  goto out_fail;
990 
991  if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerCertificate, NULL, 1))
992  goto out_fail;
993 
994  if (!freerdp_capability_buffer_allocate(settings, 32))
995  goto out_fail;
996 
997  {
998  char tmp[32] = { 0 };
999  if (!freerdp_settings_set_string_len(settings, FreeRDP_ClientProductId, tmp, sizeof(tmp)))
1000  goto out_fail;
1001  }
1002 
1003  /* [MS-RDPBCGR] 2.2.7.1.5 Pointer Capability Set (TS_POINTER_CAPABILITYSET)
1004  *
1005  * if we are in server mode send a reasonable large cache size,
1006  * if we are in client mode just set the value to the maximum we want to
1007  * support and during capability exchange that size will be limited to the
1008  * sizes the server supports
1009  *
1010  * We have chosen 128 cursors in cache which is at worst 128 * 576kB (384x384 pixel cursor with
1011  * 32bit color depth)
1012  * */
1013  if (freerdp_settings_get_bool(settings, FreeRDP_ServerMode))
1014  {
1015  if (!freerdp_settings_set_uint32(settings, FreeRDP_PointerCacheSize, 25) ||
1016  !freerdp_settings_set_uint32(settings, FreeRDP_ColorPointerCacheSize, 25))
1017  goto out_fail;
1018  }
1019  else
1020  {
1021  if (!freerdp_settings_set_uint32(settings, FreeRDP_PointerCacheSize, 128) ||
1022  !freerdp_settings_set_uint32(settings, FreeRDP_ColorPointerCacheSize, 128))
1023  goto out_fail;
1024  }
1025 
1026  if (!freerdp_settings_set_uint32(settings, FreeRDP_LargePointerFlag,
1027  (LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384)) ||
1028  !freerdp_settings_set_bool(settings, FreeRDP_SoundBeepsEnabled, TRUE) ||
1029  !freerdp_settings_set_bool(settings, FreeRDP_DrawGdiPlusEnabled, FALSE) ||
1030  !freerdp_settings_set_bool(settings, FreeRDP_DrawAllowSkipAlpha, TRUE) ||
1031  !freerdp_settings_set_bool(settings, FreeRDP_DrawAllowColorSubsampling, FALSE) ||
1032  !freerdp_settings_set_bool(settings, FreeRDP_DrawAllowDynamicColorFidelity, TRUE) ||
1033  !freerdp_settings_set_bool(settings, FreeRDP_FrameMarkerCommandEnabled, TRUE) ||
1034  !freerdp_settings_set_bool(settings, FreeRDP_SurfaceFrameMarkerEnabled, TRUE) ||
1035  !freerdp_settings_set_bool(settings, FreeRDP_AllowCacheWaitingList, TRUE) ||
1036  !freerdp_settings_set_uint32(settings, FreeRDP_BitmapCacheV2NumCells, 5))
1037  goto out_fail;
1038  settings->BitmapCacheV2CellInfo =
1040 
1041  if (!settings->BitmapCacheV2CellInfo)
1042  goto out_fail;
1043 
1044  {
1045  BITMAP_CACHE_V2_CELL_INFO cache = { 0 };
1046  cache.numEntries = 600;
1047  if (!freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, 0,
1048  &cache) ||
1049  !freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, 1, &cache))
1050  goto out_fail;
1051  cache.numEntries = 2048;
1052  if (!freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, 2,
1053  &cache) ||
1054  !freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, 4, &cache))
1055  goto out_fail;
1056  cache.numEntries = 4096;
1057  if (!freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, 3, &cache))
1058  goto out_fail;
1059  }
1060  if (!freerdp_settings_set_bool(settings, FreeRDP_NoBitmapCompressionHeader, TRUE) ||
1061  !freerdp_settings_set_bool(settings, FreeRDP_RefreshRect, TRUE) ||
1062  !freerdp_settings_set_bool(settings, FreeRDP_SuppressOutput, TRUE) ||
1063  !freerdp_settings_set_uint32(settings, FreeRDP_GlyphSupportLevel, GLYPH_SUPPORT_NONE))
1064  goto out_fail;
1065  settings->GlyphCache = calloc(10, sizeof(GLYPH_CACHE_DEFINITION));
1066 
1067  if (!settings->GlyphCache)
1068  goto out_fail;
1069 
1070  settings->FragCache = calloc(1, sizeof(GLYPH_CACHE_DEFINITION));
1071 
1072  if (!settings->FragCache)
1073  goto out_fail;
1074 
1075  for (size_t x = 0; x < 10; x++)
1076  {
1077  GLYPH_CACHE_DEFINITION cache = { 0 };
1078  cache.cacheEntries = 254;
1079  switch (x)
1080  {
1081  case 0:
1082  case 1:
1083  cache.cacheMaximumCellSize = 4;
1084  break;
1085  case 2:
1086  case 3:
1087  cache.cacheMaximumCellSize = 8;
1088  break;
1089  case 4:
1090  cache.cacheMaximumCellSize = 16;
1091  break;
1092  case 5:
1093  cache.cacheMaximumCellSize = 32;
1094  break;
1095  case 6:
1096  cache.cacheMaximumCellSize = 64;
1097  break;
1098  case 7:
1099  cache.cacheMaximumCellSize = 128;
1100  break;
1101  case 8:
1102  cache.cacheMaximumCellSize = 256;
1103  break;
1104  case 9:
1105  cache.cacheMaximumCellSize = 256;
1106  break;
1107  default:
1108  goto out_fail;
1109  }
1110 
1111  if (!freerdp_settings_set_pointer_array(settings, FreeRDP_GlyphCache, x, &cache))
1112  goto out_fail;
1113  }
1114  {
1115  GLYPH_CACHE_DEFINITION cache = { 0 };
1116  cache.cacheEntries = 256;
1117  cache.cacheMaximumCellSize = 256;
1118  if (!freerdp_settings_set_pointer_array(settings, FreeRDP_FragCache, 0, &cache))
1119  goto out_fail;
1120  }
1121  if (!freerdp_settings_set_uint32(settings, FreeRDP_OffscreenSupportLevel, 0) ||
1122  !freerdp_settings_set_uint32(settings, FreeRDP_OffscreenCacheSize, 7680) ||
1123  !freerdp_settings_set_uint32(settings, FreeRDP_OffscreenCacheEntries, 2000) ||
1124  !freerdp_settings_set_uint32(settings, FreeRDP_DrawNineGridCacheSize, 2560) ||
1125  !freerdp_settings_set_uint32(settings, FreeRDP_DrawNineGridCacheEntries, 256) ||
1126  !freerdp_settings_set_string(settings, FreeRDP_ClientDir, client_dll) ||
1127  !freerdp_settings_get_string(settings, FreeRDP_ClientDir) ||
1128  !freerdp_settings_set_uint32(settings, FreeRDP_RemoteWndSupportLevel,
1129  WINDOW_LEVEL_SUPPORTED | WINDOW_LEVEL_SUPPORTED_EX) ||
1130  !freerdp_settings_set_uint32(settings, FreeRDP_RemoteAppNumIconCaches, 3) ||
1131  !freerdp_settings_set_uint32(settings, FreeRDP_RemoteAppNumIconCacheEntries, 12) ||
1132  !freerdp_settings_set_uint32(settings, FreeRDP_VCChunkSize,
1133  (server && !remote) ? CHANNEL_CHUNK_MAX_LENGTH
1134  : CHANNEL_CHUNK_LENGTH) ||
1135  /* [MS-RDPBCGR] 2.2.7.2.7 Large Pointer Capability Set (TS_LARGE_POINTER_CAPABILITYSET)
1136  requires at least this size */
1137  !freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
1138  server ? 0 : 608299) ||
1139  !freerdp_settings_set_bool(settings, FreeRDP_GatewayUseSameCredentials, FALSE) ||
1140  !freerdp_settings_set_bool(settings, FreeRDP_GatewayBypassLocal, FALSE) ||
1141  !freerdp_settings_set_bool(settings, FreeRDP_GatewayRpcTransport, TRUE) ||
1142  !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpTransport, TRUE) ||
1143  !freerdp_settings_set_bool(settings, FreeRDP_GatewayUdpTransport, TRUE) ||
1144  !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpUseWebsockets, TRUE) ||
1145  !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpExtAuthSspiNtlm, FALSE) ||
1146  !freerdp_settings_set_bool(settings, FreeRDP_GatewayArmTransport, FALSE) ||
1147  !freerdp_settings_set_bool(settings, FreeRDP_FastPathInput, TRUE) ||
1148  !freerdp_settings_set_bool(settings, FreeRDP_FastPathOutput, TRUE) ||
1149  !freerdp_settings_set_bool(settings, FreeRDP_LongCredentialsSupported, TRUE) ||
1150  !freerdp_settings_set_uint32(settings, FreeRDP_FrameAcknowledge, 2) ||
1151  !freerdp_settings_set_bool(settings, FreeRDP_MouseMotion, TRUE) ||
1152  !freerdp_settings_set_uint32(settings, FreeRDP_NSCodecColorLossLevel, 3) ||
1153  !freerdp_settings_set_bool(settings, FreeRDP_NSCodecAllowSubsampling, TRUE) ||
1154  !freerdp_settings_set_bool(settings, FreeRDP_NSCodecAllowDynamicColorFidelity, TRUE) ||
1155  !freerdp_settings_set_bool(settings, FreeRDP_AutoReconnectionEnabled, FALSE) ||
1156  !freerdp_settings_set_uint32(settings, FreeRDP_AutoReconnectMaxRetries, 20) ||
1157  !freerdp_settings_set_bool(settings, FreeRDP_GfxThinClient, FALSE) ||
1158  !freerdp_settings_set_bool(settings, FreeRDP_GfxSmallCache, TRUE) ||
1159  !freerdp_settings_set_bool(settings, FreeRDP_GfxProgressive, FALSE) ||
1160  !freerdp_settings_set_bool(settings, FreeRDP_GfxProgressiveV2, FALSE) ||
1161  !freerdp_settings_set_bool(settings, FreeRDP_GfxPlanar, TRUE) ||
1162  !freerdp_settings_set_bool(settings, FreeRDP_GfxH264, FALSE) ||
1163  !freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444, FALSE) ||
1164  !freerdp_settings_set_bool(settings, FreeRDP_GfxSendQoeAck, FALSE))
1165  goto out_fail;
1166  {
1167  ARC_CS_PRIVATE_PACKET cookie = { 0 };
1168  if (!freerdp_settings_set_pointer_len(settings, FreeRDP_ClientAutoReconnectCookie, &cookie,
1169  1))
1170  goto out_fail;
1171  }
1172  {
1173  ARC_SC_PRIVATE_PACKET cookie = { 0 };
1174  if (!freerdp_settings_set_pointer_len(settings, FreeRDP_ServerAutoReconnectCookie, &cookie,
1175  1))
1176  goto out_fail;
1177  }
1178 
1179  settings->ClientTimeZone = (LPTIME_ZONE_INFORMATION)calloc(1, sizeof(TIME_ZONE_INFORMATION));
1180 
1181  if (!settings->ClientTimeZone)
1182  goto out_fail;
1183 
1184  if (!settings->ServerMode)
1185  {
1186  DYNAMIC_TIME_ZONE_INFORMATION dynamic = { 0 };
1187  TIME_ZONE_INFORMATION* tz =
1188  freerdp_settings_get_pointer_writable(settings, FreeRDP_ClientTimeZone);
1189  WINPR_ASSERT(tz);
1190 
1191  GetTimeZoneInformation(tz);
1192  GetDynamicTimeZoneInformation(&dynamic);
1193 
1194  if (!freerdp_settings_set_string_from_utf16N(settings, FreeRDP_DynamicDSTTimeZoneKeyName,
1195  dynamic.TimeZoneKeyName,
1196  ARRAYSIZE(dynamic.TimeZoneKeyName)))
1197  goto out_fail;
1198 
1199  if (!freerdp_settings_set_bool(settings, FreeRDP_DynamicDaylightTimeDisabled,
1200  dynamic.DynamicDaylightTimeDisabled))
1201  goto out_fail;
1202  }
1203 
1204  if (!freerdp_settings_set_bool(settings, FreeRDP_TcpKeepAlive, TRUE) ||
1205  !freerdp_settings_set_uint32(settings, FreeRDP_TcpKeepAliveRetries, 3) ||
1206  !freerdp_settings_set_uint32(settings, FreeRDP_TcpKeepAliveDelay, 5) ||
1207  !freerdp_settings_set_uint32(settings, FreeRDP_TcpKeepAliveInterval, 2) ||
1208  !freerdp_settings_set_uint32(settings, FreeRDP_TcpAckTimeout, 9000) ||
1209  !freerdp_settings_set_uint32(settings, FreeRDP_TcpConnectTimeout, 15000))
1210  goto out_fail;
1211 
1212  if (!freerdp_settings_get_bool(settings, FreeRDP_ServerMode))
1213  {
1214  BOOL rc = FALSE;
1215  char* path = NULL;
1216  if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectClipboard, TRUE))
1217  goto out_fail;
1218  /* these values are used only by the client part */
1219  path = GetKnownPath(KNOWN_PATH_HOME);
1220  rc = freerdp_settings_set_string(settings, FreeRDP_HomePath, path);
1221  free(path);
1222 
1223  if (!rc || !freerdp_settings_get_string(settings, FreeRDP_HomePath))
1224  goto out_fail;
1225 
1226  char* config = freerdp_settings_get_config_path();
1227  rc = freerdp_settings_set_string(settings, FreeRDP_ConfigPath, config);
1228  if (rc)
1229  {
1230  char* action = GetCombinedPath(config, "action.sh");
1231  rc = freerdp_settings_set_string(settings, FreeRDP_ActionScript, action);
1232  free(action);
1233  }
1234 
1235  free(config);
1236  if (!rc)
1237  goto out_fail;
1238  }
1239 
1240  settings_load_hkey_local_machine(settings);
1241 
1242  if (!freerdp_settings_set_bool(settings, FreeRDP_SmartcardLogon, FALSE))
1243  goto out_fail;
1244  if (!freerdp_settings_set_uint32(settings, FreeRDP_TlsSecLevel, 1))
1245  goto out_fail;
1246  settings->OrderSupport = calloc(1, 32);
1247 
1248  if (!freerdp_settings_set_uint16(settings, FreeRDP_TLSMinVersion, TLS1_VERSION))
1249  goto out_fail;
1250  if (!freerdp_settings_set_uint16(settings, FreeRDP_TLSMaxVersion, 0))
1251  goto out_fail;
1252 
1253  if (!settings->OrderSupport)
1254  goto out_fail;
1255 
1256  if (!freerdp_settings_set_default_order_support(settings))
1257  goto out_fail;
1258 
1259  const BOOL enable = freerdp_settings_get_bool(settings, FreeRDP_ServerMode);
1260 
1261  {
1262  const FreeRDP_Settings_Keys_Bool keys[] = { FreeRDP_SupportGraphicsPipeline,
1263  FreeRDP_SupportStatusInfoPdu,
1264  FreeRDP_SupportErrorInfoPdu,
1265  FreeRDP_SupportAsymetricKeys };
1266 
1267  for (size_t x = 0; x < ARRAYSIZE(keys); x++)
1268  {
1269  if (!freerdp_settings_set_bool(settings, keys[x], enable))
1270  goto out_fail;
1271  }
1272  }
1273 
1274  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportDynamicTimeZone, TRUE))
1275  goto out_fail;
1276  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportSkipChannelJoin, TRUE))
1277  goto out_fail;
1278 
1279  return settings;
1280 out_fail:
1281  WINPR_PRAGMA_DIAG_PUSH
1282  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1283  freerdp_settings_free(settings);
1284  WINPR_PRAGMA_DIAG_POP
1285  return NULL;
1286 }
1287 
1288 static void freerdp_settings_free_internal(rdpSettings* settings)
1289 {
1290  freerdp_server_license_issuers_free(settings);
1291  freerdp_target_net_addresses_free(settings);
1292  freerdp_device_collection_free(settings);
1293  freerdp_static_channel_collection_free(settings);
1294  freerdp_dynamic_channel_collection_free(settings);
1295 
1296  freerdp_capability_buffer_free(settings);
1297 
1298  /* Free all strings, set other pointers NULL */
1299  freerdp_settings_free_keys(settings, TRUE);
1300 }
1301 
1302 void freerdp_settings_free(rdpSettings* settings)
1303 {
1304  if (!settings)
1305  return;
1306 
1307  freerdp_settings_free_internal(settings);
1308  free(settings);
1309 }
1310 
1311 static BOOL freerdp_settings_int_buffer_copy(rdpSettings* _settings, const rdpSettings* settings)
1312 {
1313  BOOL rc = FALSE;
1314 
1315  if (!_settings || !settings)
1316  return FALSE;
1317 
1318  typedef struct
1319  {
1320  FreeRDP_Settings_Keys_UInt32 lenKey;
1321  FreeRDP_Settings_Keys_Pointer pointerKey;
1322  } PointerDefs;
1323 
1324  PointerDefs pointerDefs[] = {
1325  /* */
1326  { FreeRDP_LoadBalanceInfoLength, FreeRDP_LoadBalanceInfo },
1327  { FreeRDP_ServerRandomLength, FreeRDP_ServerRandom },
1328  { FreeRDP_ClientRandomLength, FreeRDP_ClientRandom },
1329  { FreeRDP_ServerCertificateLength, FreeRDP_ServerCertificate },
1330  { FreeRDP_ChannelDefArraySize, FreeRDP_ChannelDefArray },
1331  { FreeRDP_NumMonitorIds, FreeRDP_MonitorIds },
1332  { FreeRDP_BitmapCacheV2NumCells, FreeRDP_BitmapCacheV2CellInfo },
1333  { FreeRDP_RedirectionPasswordLength, FreeRDP_RedirectionPassword },
1334  { FreeRDP_RedirectionTsvUrlLength, FreeRDP_RedirectionTsvUrl },
1335  { FreeRDP_RedirectionGuidLength, FreeRDP_RedirectionGuid },
1336  { FreeRDP_MonitorDefArraySize, FreeRDP_MonitorDefArray }
1337  };
1338 
1339  for (size_t i = 0; i < ARRAYSIZE(pointerDefs); i++)
1340  {
1341  const PointerDefs* keys = &pointerDefs[i];
1342  UINT32 n = freerdp_settings_get_uint32(settings, keys->lenKey);
1343 
1344  const void* ptr = freerdp_settings_get_pointer(settings, keys->pointerKey);
1345  if (!freerdp_settings_set_pointer_len(_settings, keys->pointerKey, ptr, n))
1346  goto out_fail;
1347  }
1348 
1349  if (!freerdp_server_license_issuers_copy(_settings, settings->ServerLicenseProductIssuers,
1350  settings->ServerLicenseProductIssuersCount))
1351  return FALSE;
1352 
1353  if (settings->RdpServerCertificate)
1354  {
1355  rdpCertificate* cert = freerdp_certificate_clone(settings->RdpServerCertificate);
1356  if (!cert)
1357  goto out_fail;
1358  if (!freerdp_settings_set_pointer_len(_settings, FreeRDP_RdpServerCertificate, cert, 1))
1359  goto out_fail;
1360  }
1361  else
1362  {
1363  if (!freerdp_settings_set_pointer_len(_settings, FreeRDP_RdpServerCertificate, NULL, 0))
1364  goto out_fail;
1365  }
1366 
1367  if (settings->RdpServerRsaKey)
1368  {
1369  rdpPrivateKey* key = freerdp_key_clone(settings->RdpServerRsaKey);
1370  if (!key)
1371  goto out_fail;
1372  if (!freerdp_settings_set_pointer_len(_settings, FreeRDP_RdpServerRsaKey, key, 1))
1373  goto out_fail;
1374  }
1375  else
1376  {
1377  if (!freerdp_settings_set_pointer_len(_settings, FreeRDP_RdpServerRsaKey, NULL, 0))
1378  goto out_fail;
1379  }
1380 
1381  if (!freerdp_settings_set_uint32(_settings, FreeRDP_ChannelCount,
1382  freerdp_settings_get_uint32(settings, FreeRDP_ChannelCount)))
1383  goto out_fail;
1384 
1385  _settings->OrderSupport = malloc(32);
1386  if (!_settings->OrderSupport)
1387  goto out_fail;
1388 
1389  if (!freerdp_capability_buffer_copy(_settings, settings))
1390  goto out_fail;
1391  CopyMemory(_settings->OrderSupport, settings->OrderSupport, 32);
1392 
1393  const UINT32 glyphCacheCount = 10;
1394  const GLYPH_CACHE_DEFINITION* glyphCache =
1395  freerdp_settings_get_pointer(settings, FreeRDP_GlyphCache);
1396  if (!freerdp_settings_set_pointer_len(_settings, FreeRDP_GlyphCache, glyphCache,
1397  glyphCacheCount))
1398  goto out_fail;
1399 
1400  const UINT32 fragCacheCount = 1;
1401  const GLYPH_CACHE_DEFINITION* fragCache =
1402  freerdp_settings_get_pointer(settings, FreeRDP_FragCache);
1403  if (!freerdp_settings_set_pointer_len(_settings, FreeRDP_FragCache, fragCache, fragCacheCount))
1404  goto out_fail;
1405 
1407  _settings, FreeRDP_ClientAutoReconnectCookie,
1408  freerdp_settings_get_pointer(settings, FreeRDP_ClientAutoReconnectCookie), 1))
1409  goto out_fail;
1411  _settings, FreeRDP_ServerAutoReconnectCookie,
1412  freerdp_settings_get_pointer(settings, FreeRDP_ServerAutoReconnectCookie), 1))
1413  goto out_fail;
1414 
1415  const TIME_ZONE_INFORMATION* tz =
1416  freerdp_settings_get_pointer(settings, FreeRDP_ClientTimeZone);
1417  if (!freerdp_settings_set_pointer_len(_settings, FreeRDP_ClientTimeZone, tz, 1))
1418  goto out_fail;
1419 
1420  const UINT32 nrports = freerdp_settings_get_uint32(settings, FreeRDP_TargetNetAddressCount);
1421  if (!freerdp_target_net_adresses_reset(_settings, nrports))
1422  return FALSE;
1423 
1424  for (UINT32 i = 0; i < nrports; i++)
1425  {
1426  const char* address =
1427  freerdp_settings_get_pointer_array(settings, FreeRDP_TargetNetAddresses, i);
1428  const UINT32* port =
1429  freerdp_settings_get_pointer_array(settings, FreeRDP_TargetNetPorts, i);
1430  if (!freerdp_settings_set_pointer_array(_settings, FreeRDP_TargetNetAddresses, i, address))
1431  return FALSE;
1432  if (!freerdp_settings_set_pointer_array(_settings, FreeRDP_TargetNetPorts, i, port))
1433  return FALSE;
1434  }
1435 
1436  {
1437  const UINT32 len = freerdp_settings_get_uint32(_settings, FreeRDP_DeviceArraySize);
1438  const UINT32 count = freerdp_settings_get_uint32(settings, FreeRDP_DeviceCount);
1439 
1440  if (len < count)
1441  goto out_fail;
1442  if (!freerdp_settings_set_pointer_len(_settings, FreeRDP_DeviceArray, NULL, len))
1443  goto out_fail;
1444  if (!freerdp_settings_set_uint32(_settings, FreeRDP_DeviceCount, count))
1445  goto out_fail;
1446 
1447  for (size_t index = 0; index < count; index++)
1448  {
1449  const RDPDR_DEVICE* argv =
1450  freerdp_settings_get_pointer_array(settings, FreeRDP_DeviceArray, index);
1451  if (!freerdp_settings_set_pointer_array(_settings, FreeRDP_DeviceArray, index, argv))
1452  goto out_fail;
1453  }
1454  }
1455  {
1456  const UINT32 len = freerdp_settings_get_uint32(_settings, FreeRDP_StaticChannelArraySize);
1457  const UINT32 count = freerdp_settings_get_uint32(settings, FreeRDP_StaticChannelCount);
1458 
1459  if (len < count)
1460  goto out_fail;
1461  if (!freerdp_settings_set_pointer_len(_settings, FreeRDP_StaticChannelArray, NULL, len))
1462  goto out_fail;
1463  if (!freerdp_settings_set_uint32(_settings, FreeRDP_StaticChannelCount, count))
1464  goto out_fail;
1465 
1466  for (size_t index = 0; index < count; index++)
1467  {
1468  const ADDIN_ARGV* argv =
1469  freerdp_settings_get_pointer_array(settings, FreeRDP_StaticChannelArray, index);
1470  if (!freerdp_settings_set_pointer_array(_settings, FreeRDP_StaticChannelArray, index,
1471  argv))
1472  goto out_fail;
1473  }
1474  }
1475  {
1476  const UINT32 len = freerdp_settings_get_uint32(_settings, FreeRDP_DynamicChannelArraySize);
1477  const UINT32 count = freerdp_settings_get_uint32(settings, FreeRDP_DynamicChannelCount);
1478 
1479  if (len < count)
1480  goto out_fail;
1481  if (!freerdp_settings_set_pointer_len(_settings, FreeRDP_DynamicChannelArray, NULL, len))
1482  goto out_fail;
1483  if (!freerdp_settings_set_uint32(_settings, FreeRDP_DynamicChannelCount, count))
1484  goto out_fail;
1485 
1486  for (size_t index = 0; index < count; index++)
1487  {
1488  const ADDIN_ARGV* argv =
1489  freerdp_settings_get_pointer_array(settings, FreeRDP_DynamicChannelArray, index);
1490  if (!freerdp_settings_set_pointer_array(_settings, FreeRDP_DynamicChannelArray, index,
1491  argv))
1492  goto out_fail;
1493  }
1494  }
1495 
1496  rc = freerdp_settings_set_string(_settings, FreeRDP_ActionScript,
1497  freerdp_settings_get_string(settings, FreeRDP_ActionScript));
1498 
1499 out_fail:
1500  return rc;
1501 }
1502 
1503 BOOL freerdp_settings_copy(rdpSettings* _settings, const rdpSettings* settings)
1504 {
1505  BOOL rc = 0;
1506 
1507  if (!settings || !_settings)
1508  return FALSE;
1509 
1510  /* This is required to free all non string buffers */
1511  freerdp_settings_free_internal(_settings);
1512  /* This copies everything except allocated non string buffers. reset all allocated buffers to
1513  * NULL to fix issues during cleanup */
1514  rc = freerdp_settings_clone_keys(_settings, settings);
1515 
1516  _settings->LoadBalanceInfo = NULL;
1517  _settings->ServerRandom = NULL;
1518  _settings->ClientRandom = NULL;
1519  _settings->ServerCertificate = NULL;
1520  _settings->RdpServerCertificate = NULL;
1521  _settings->RdpServerRsaKey = NULL;
1522  _settings->ChannelDefArray = NULL;
1523  _settings->MonitorDefArray = NULL;
1524  _settings->MonitorIds = NULL;
1525  _settings->OrderSupport = NULL;
1526  _settings->BitmapCacheV2CellInfo = NULL;
1527  _settings->GlyphCache = NULL;
1528  _settings->FragCache = NULL;
1529  _settings->ClientAutoReconnectCookie = NULL;
1530  _settings->ServerAutoReconnectCookie = NULL;
1531  _settings->ClientTimeZone = NULL;
1532  _settings->RedirectionPassword = NULL;
1533  _settings->RedirectionTsvUrl = NULL;
1534  _settings->TargetNetAddresses = NULL;
1535  _settings->TargetNetPorts = NULL;
1536  _settings->RedirectionGuid = NULL;
1537  _settings->DeviceArray = NULL;
1538  _settings->StaticChannelArray = NULL;
1539  _settings->DynamicChannelArray = NULL;
1540  _settings->ReceivedCapabilities = NULL;
1541  _settings->ReceivedCapabilityData = NULL;
1542  _settings->ReceivedCapabilityDataSizes = NULL;
1543 
1544  _settings->ServerLicenseProductIssuersCount = 0;
1545  _settings->ServerLicenseProductIssuers = NULL;
1546 
1547  if (!rc)
1548  goto out_fail;
1549 
1550  /* Begin copying */
1551  if (!freerdp_settings_int_buffer_copy(_settings, settings))
1552  goto out_fail;
1553  return TRUE;
1554 out_fail:
1555  freerdp_settings_free_internal(_settings);
1556  return FALSE;
1557 }
1558 
1559 rdpSettings* freerdp_settings_clone(const rdpSettings* settings)
1560 {
1561  rdpSettings* _settings = (rdpSettings*)calloc(1, sizeof(rdpSettings));
1562 
1563  if (!freerdp_settings_copy(_settings, settings))
1564  goto out_fail;
1565 
1566  return _settings;
1567 out_fail:
1568  WINPR_PRAGMA_DIAG_PUSH
1569  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1570  freerdp_settings_free(_settings);
1571  WINPR_PRAGMA_DIAG_POP
1572  return NULL;
1573 }
1574 #ifdef _MSC_VER
1575 #pragma warning(pop)
1576 #endif
1577 
1578 static void zfree(WCHAR* str, size_t len)
1579 {
1580  if (str)
1581  memset(str, 0, len * sizeof(WCHAR));
1582  free(str);
1583 }
1584 
1585 BOOL identity_set_from_settings_with_pwd(SEC_WINNT_AUTH_IDENTITY* identity,
1586  const rdpSettings* settings,
1587  FreeRDP_Settings_Keys_String UserId,
1588  FreeRDP_Settings_Keys_String DomainId,
1589  const WCHAR* Password, size_t pwdLen)
1590 {
1591  WINPR_ASSERT(identity);
1592  WINPR_ASSERT(settings);
1593 
1594  size_t UserLen = 0;
1595  size_t DomainLen = 0;
1596 
1597  WCHAR* Username = freerdp_settings_get_string_as_utf16(settings, UserId, &UserLen);
1598  WCHAR* Domain = freerdp_settings_get_string_as_utf16(settings, DomainId, &DomainLen);
1599 
1600  const int rc = sspi_SetAuthIdentityWithLengthW(identity, Username, UserLen, Domain, DomainLen,
1601  Password, pwdLen);
1602  zfree(Username, UserLen);
1603  zfree(Domain, DomainLen);
1604  if (rc < 0)
1605  return FALSE;
1606  return TRUE;
1607 }
1608 
1609 BOOL identity_set_from_settings(SEC_WINNT_AUTH_IDENTITY_W* identity, const rdpSettings* settings,
1610  FreeRDP_Settings_Keys_String UserId,
1611  FreeRDP_Settings_Keys_String DomainId,
1612  FreeRDP_Settings_Keys_String PwdId)
1613 {
1614  WINPR_ASSERT(identity);
1615  WINPR_ASSERT(settings);
1616 
1617  size_t PwdLen = 0;
1618 
1619  WCHAR* Password = freerdp_settings_get_string_as_utf16(settings, PwdId, &PwdLen);
1620 
1621  const BOOL rc =
1622  identity_set_from_settings_with_pwd(identity, settings, UserId, DomainId, Password, PwdLen);
1623  zfree(Password, PwdLen);
1624  return rc;
1625 }
1626 
1627 BOOL identity_set_from_smartcard_hash(SEC_WINNT_AUTH_IDENTITY_W* identity,
1628  const rdpSettings* settings,
1629  FreeRDP_Settings_Keys_String userId,
1630  FreeRDP_Settings_Keys_String domainId,
1631  FreeRDP_Settings_Keys_String pwdId, const BYTE* certSha1,
1632  size_t sha1len)
1633 {
1634 #ifdef _WIN32
1635  CERT_CREDENTIAL_INFO certInfo = { sizeof(CERT_CREDENTIAL_INFO), { 0 } };
1636  LPWSTR marshalledCredentials = NULL;
1637 
1638  memcpy(certInfo.rgbHashOfCert, certSha1, MIN(sha1len, sizeof(certInfo.rgbHashOfCert)));
1639 
1640  if (!CredMarshalCredentialW(CertCredential, &certInfo, &marshalledCredentials))
1641  {
1642  WLog_ERR(TAG, "error marshalling cert credentials");
1643  return FALSE;
1644  }
1645 
1646  size_t pwdLen = 0;
1647  WCHAR* Password = freerdp_settings_get_string_as_utf16(settings, pwdId, &pwdLen);
1648  const int rc = sspi_SetAuthIdentityWithLengthW(
1649  identity, marshalledCredentials, _wcslen(marshalledCredentials), NULL, 0, Password, pwdLen);
1650  zfree(Password, pwdLen);
1651  CredFree(marshalledCredentials);
1652  if (rc < 0)
1653  return FALSE;
1654 
1655 #else
1656  if (!identity_set_from_settings(identity, settings, userId, domainId, pwdId))
1657  return FALSE;
1658 #endif /* _WIN32 */
1659  return TRUE;
1660 }
1661 
1662 const char* freerdp_settings_glyph_level_string(UINT32 level, char* buffer, size_t size)
1663 {
1664  const char* str = "GLYPH_SUPPORT_UNKNOWN";
1665  switch (level)
1666  {
1667  case GLYPH_SUPPORT_NONE:
1668  str = "GLYPH_SUPPORT_NONE";
1669  break;
1670  case GLYPH_SUPPORT_PARTIAL:
1671  str = "GLYPH_SUPPORT_PARTIAL";
1672  break;
1673  case GLYPH_SUPPORT_FULL:
1674  str = "GLYPH_SUPPORT_FULL";
1675  break;
1676  case GLYPH_SUPPORT_ENCODE:
1677  str = "GLYPH_SUPPORT_ENCODE";
1678  break;
1679  default:
1680  break;
1681  }
1682 
1683  (void)_snprintf(buffer, size, "%s[0x%08" PRIx32 "]", str, level);
1684  return buffer;
1685 }
1686 
1687 BOOL freerdp_target_net_adresses_reset(rdpSettings* settings, size_t size)
1688 {
1689  freerdp_target_net_addresses_free(settings);
1690 
1691  if (size > 0)
1692  {
1693  if (!freerdp_settings_set_pointer_len_(settings, FreeRDP_TargetNetPorts,
1694  FreeRDP_UINT32_UNUSED, NULL, size, sizeof(UINT32)))
1695  return FALSE;
1696  if (!freerdp_settings_set_pointer_len_(settings, FreeRDP_TargetNetAddresses,
1697  FreeRDP_TargetNetAddressCount, NULL, size,
1698  sizeof(char*)))
1699  return FALSE;
1700  }
1701  return TRUE;
1702 }
1703 
1704 BOOL freerdp_settings_enforce_monitor_exists(rdpSettings* settings)
1705 {
1706  const UINT32 nrIds = freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds);
1707  const UINT32 count = freerdp_settings_get_uint32(settings, FreeRDP_MonitorCount);
1708  const BOOL fullscreen = freerdp_settings_get_bool(settings, FreeRDP_Fullscreen);
1709  const BOOL multimon = freerdp_settings_get_bool(settings, FreeRDP_UseMultimon);
1710  const BOOL useMonitors = fullscreen || multimon;
1711 
1712  const UINT32 size = freerdp_settings_get_uint32(settings, FreeRDP_MonitorDefArraySize);
1713  if (size == 0)
1714  {
1715  if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorDefArray, NULL, 16))
1716  return FALSE;
1717  }
1718 
1719  if (nrIds == 0)
1720  {
1721  if (!freerdp_settings_set_uint32(settings, FreeRDP_NumMonitorIds, 1))
1722  return FALSE;
1723  }
1724  if (!useMonitors || (count == 0))
1725  {
1726  const UINT32 width = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
1727  const UINT32 height = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
1728  const UINT32 pwidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopPhysicalWidth);
1729  const UINT32 pheight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopPhysicalHeight);
1730  const UINT16 orientation =
1731  freerdp_settings_get_uint16(settings, FreeRDP_DesktopOrientation);
1732  const UINT32 desktopScaleFactor =
1733  freerdp_settings_get_uint32(settings, FreeRDP_DeviceScaleFactor);
1734  const UINT32 deviceScaleFactor =
1735  freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor);
1736 
1737  if (!freerdp_settings_set_uint32(settings, FreeRDP_MonitorCount, 1))
1738  return FALSE;
1739 
1740  rdpMonitor* monitor =
1741  freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, 0);
1742  if (!monitor)
1743  return FALSE;
1744  monitor->x = 0;
1745  monitor->y = 0;
1746  WINPR_ASSERT(width <= INT32_MAX);
1747  monitor->width = (INT32)width;
1748  WINPR_ASSERT(height <= INT32_MAX);
1749  monitor->height = (INT32)height;
1750  monitor->is_primary = TRUE;
1751  monitor->orig_screen = 0;
1752  monitor->attributes.physicalWidth = pwidth;
1753  monitor->attributes.physicalHeight = pheight;
1754  monitor->attributes.orientation = orientation;
1755  monitor->attributes.desktopScaleFactor = desktopScaleFactor;
1756  monitor->attributes.deviceScaleFactor = deviceScaleFactor;
1757  }
1758  else if (fullscreen || (multimon && (count == 1)))
1759  {
1760  /* not all platforms start primary monitor at 0/0, so enforce this to avoid issues with
1761  * fullscreen mode */
1762  rdpMonitor* monitor =
1763  freerdp_settings_get_pointer_array_writable(settings, FreeRDP_MonitorDefArray, 0);
1764  if (!monitor)
1765  return FALSE;
1766  monitor->x = 0;
1767  monitor->y = 0;
1768  monitor->is_primary = TRUE;
1769  }
1770 
1771  return TRUE;
1772 }
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.
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_from_utf16N(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const WCHAR *param, size_t length)
Sets a string settings value. The param is converted to UTF-8 and the copy stored.
rdpSettings * freerdp_settings_new(DWORD flags)
creates a new setting struct
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_pointer_len(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id, const void *data, size_t len)
Set a pointer to value data.
char * freerdp_settings_get_config_path(void)
return the configuration directory for the library
void freerdp_settings_free(rdpSettings *settings)
Free a settings struct with all data in it.
#define FREERDP_SETTINGS_SERVER_MODE
FREERDP_API UINT16 freerdp_settings_get_uint16(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt16 id)
Returns a UINT16 settings value.
BOOL freerdp_settings_copy(rdpSettings *_settings, const rdpSettings *settings)
Deep copies settings from src to dst.
rdpSettings * freerdp_settings_clone(const rdpSettings *settings)
Creates a deep copy of settings.
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.
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.
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL param)
Sets a BOOL settings value.
FREERDP_API void * freerdp_settings_get_pointer_writable(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id)
Returns a mutable pointer settings value.