Coverage Report

Created: 2026-10-15 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/client/common/file.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * .rdp file
4
 *
5
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include <freerdp/config.h>
21
22
#include <errno.h>
23
#include <ctype.h>
24
#include <stdlib.h>
25
26
#include <winpr/string.h>
27
#include <winpr/file.h>
28
#include <winpr/cast.h>
29
30
#include <freerdp/utils/warnings.h>
31
32
#include <freerdp/client.h>
33
#include <freerdp/client/file.h>
34
#include <freerdp/client/cmdline.h>
35
36
#include <freerdp/channels/urbdrc.h>
37
#include <freerdp/channels/rdpecam.h>
38
#include <freerdp/channels/location.h>
39
40
/**
41
 * Remote Desktop Plus - Overview of .rdp file settings:
42
 * http://www.donkz.nl/files/rdpsettings.html
43
 *
44
 * RDP Settings for Remote Desktop Services in Windows Server 2008 R2:
45
 * http://technet.microsoft.com/en-us/library/ff393699/
46
 *
47
 * https://docs.microsoft.com/en-us/windows-server/remote/remote-desktop-services/clients/rdp-files
48
 */
49
50
#include <stdio.h>
51
#include <string.h>
52
53
#include <winpr/wtypes.h>
54
#include <winpr/crt.h>
55
#include <winpr/path.h>
56
#include <freerdp/log.h>
57
#define TAG CLIENT_TAG("common")
58
59
/*#define DEBUG_CLIENT_FILE 1*/
60
61
static const BYTE BOM_UTF16_LE[2] = { 0xFF, 0xFE };
62
63
// #define INVALID_INTEGER_VALUE 0xFFFFFFFF
64
65
3.99M
#define RDP_FILE_LINE_FLAG_FORMATTED 0x00000001
66
// #define RDP_FILE_LINE_FLAG_STANDARD 0x00000002
67
1.91M
#define RDP_FILE_LINE_FLAG_TYPE_STRING 0x00000010
68
540k
#define RDP_FILE_LINE_FLAG_TYPE_INTEGER 0x00000020
69
// #define RDP_FILE_LINE_FLAG_TYPE_BINARY 0x00000040
70
71
struct rdp_file_line
72
{
73
  char* name;
74
  LPSTR sValue;
75
  PBYTE bValue;
76
77
  size_t index;
78
79
  long iValue;
80
  DWORD flags;
81
  int valueLength;
82
};
83
typedef struct rdp_file_line rdpFileLine;
84
85
struct rdp_file
86
{
87
  DWORD UseMultiMon;                 /* use multimon */
88
  LPSTR SelectedMonitors;            /* selectedmonitors */
89
  DWORD MaximizeToCurrentDisplays;   /* maximizetocurrentdisplays */
90
  DWORD SingleMonInWindowedMode;     /* singlemoninwindowedmode */
91
  DWORD ScreenModeId;                /* screen mode id */
92
  DWORD SpanMonitors;                /* span monitors */
93
  DWORD SmartSizing;                 /* smartsizing */
94
  DWORD DynamicResolution;           /* dynamic resolution */
95
  DWORD EnableSuperSpan;             /* enablesuperpan */
96
  DWORD SuperSpanAccelerationFactor; /* superpanaccelerationfactor */
97
98
  DWORD DesktopWidth;       /* desktopwidth */
99
  DWORD DesktopHeight;      /* desktopheight */
100
  DWORD DesktopSizeId;      /* desktop size id */
101
  DWORD SessionBpp;         /* session bpp */
102
  DWORD DesktopScaleFactor; /* desktopscalefactor */
103
104
  DWORD Compression;       /* compression */
105
  DWORD KeyboardHook;      /* keyboardhook */
106
  DWORD DisableCtrlAltDel; /* disable ctrl+alt+del */
107
108
  DWORD AudioMode;                             /* audiomode */
109
  DWORD AudioQualityMode;                      /* audioqualitymode */
110
  DWORD AudioCaptureMode;                      /* audiocapturemode */
111
  DWORD EncodeRedirectedVideoCapture;          /* encode redirected video capture */
112
  DWORD RedirectedVideoCaptureEncodingQuality; /* redirected video capture encoding quality */
113
  DWORD VideoPlaybackMode;                     /* videoplaybackmode */
114
115
  DWORD ConnectionType; /* connection type */
116
117
  DWORD NetworkAutoDetect;   /* networkautodetect */
118
  DWORD BandwidthAutoDetect; /* bandwidthautodetect */
119
120
  DWORD PinConnectionBar;     /* pinconnectionbar */
121
  DWORD DisplayConnectionBar; /* displayconnectionbar */
122
123
  DWORD WorkspaceId;              /* workspaceid */
124
  DWORD EnableWorkspaceReconnect; /* enableworkspacereconnect */
125
126
  DWORD DisableWallpaper;        /* disable wallpaper */
127
  DWORD AllowFontSmoothing;      /* allow font smoothing */
128
  DWORD AllowDesktopComposition; /* allow desktop composition */
129
  DWORD DisableFullWindowDrag;   /* disable full window drag */
130
  DWORD DisableMenuAnims;        /* disable menu anims */
131
  DWORD DisableThemes;           /* disable themes */
132
  DWORD DisableCursorSetting;    /* disable cursor setting */
133
134
  DWORD BitmapCacheSize;          /* bitmapcachesize */
135
  DWORD BitmapCachePersistEnable; /* bitmapcachepersistenable */
136
137
  DWORD ServerPort; /* server port */
138
139
  LPSTR Username;   /* username */
140
  LPSTR Domain;     /* domain */
141
  LPSTR Password;   /*password*/
142
143
  LPSTR FullAddress;          /* full address */
144
  LPSTR AlternateFullAddress; /* alternate full address */
145
146
  LPSTR UsbDevicesToRedirect;        /* usbdevicestoredirect */
147
  DWORD RedirectDrives;              /* redirectdrives */
148
  DWORD RedirectPrinters;            /* redirectprinters */
149
  DWORD RedirectComPorts;            /* redirectcomports */
150
  DWORD RedirectLocation;            /* redirectlocation */
151
  DWORD RedirectSmartCards;          /* redirectsmartcards */
152
  DWORD RedirectWebauthN;            /* redirectwebauthn */
153
  LPSTR RedirectCameras;             /* camerastoredirect */
154
  DWORD RedirectClipboard;           /* redirectclipboard */
155
  DWORD RedirectPosDevices;          /* redirectposdevices */
156
  DWORD RedirectDirectX;             /* redirectdirectx */
157
  DWORD DisablePrinterRedirection;   /* disableprinterredirection */
158
  DWORD DisableClipboardRedirection; /* disableclipboardredirection */
159
160
  DWORD ConnectToConsole;        /* connect to console */
161
  DWORD AdministrativeSession;   /* administrative session */
162
  DWORD AutoReconnectionEnabled; /* autoreconnection enabled */
163
  DWORD AutoReconnectMaxRetries; /* autoreconnect max retries */
164
165
  DWORD PublicMode;             /* public mode */
166
  DWORD AuthenticationLevel;    /* authentication level */
167
  DWORD PromptCredentialOnce;   /* promptcredentialonce */
168
  DWORD PromptForCredentials;   /* prompt for credentials */
169
  DWORD NegotiateSecurityLayer; /* negotiate security layer */
170
  DWORD EnableCredSSPSupport;   /* enablecredsspsupport */
171
  DWORD EnableRdsAadAuth;       /* enablerdsaadauth */
172
173
  DWORD RemoteApplicationMode; /* remoteapplicationmode */
174
  LPSTR LoadBalanceInfo;       /* loadbalanceinfo */
175
176
  LPSTR RemoteApplicationName;             /* remoteapplicationname */
177
  LPSTR RemoteApplicationIcon;             /* remoteapplicationicon */
178
  LPSTR RemoteApplicationProgram;          /* remoteapplicationprogram */
179
  LPSTR RemoteApplicationFile;             /* remoteapplicationfile */
180
  LPSTR RemoteApplicationGuid;             /* remoteapplicationguid */
181
  LPSTR RemoteApplicationCmdLine;          /* remoteapplicationcmdline */
182
  DWORD RemoteApplicationExpandCmdLine;    /* remoteapplicationexpandcmdline */
183
  DWORD RemoteApplicationExpandWorkingDir; /* remoteapplicationexpandworkingdir */
184
  DWORD DisableConnectionSharing;          /* disableconnectionsharing */
185
  DWORD DisableRemoteAppCapsCheck;         /* disableremoteappcapscheck */
186
187
  LPSTR AlternateShell;        /* alternate shell */
188
  LPSTR ShellWorkingDirectory; /* shell working directory */
189
190
  LPSTR GatewayHostname;           /* gatewayhostname */
191
  DWORD GatewayUsageMethod;        /* gatewayusagemethod */
192
  DWORD GatewayProfileUsageMethod; /* gatewayprofileusagemethod */
193
  DWORD GatewayCredentialsSource;  /* gatewaycredentialssource */
194
195
  LPSTR ResourceProvider; /* resourceprovider */
196
197
  LPSTR WvdEndpointPool;      /* wvd endpoint pool */
198
  LPSTR geo;                  /* geo */
199
  LPSTR armpath;              /* armpath */
200
  LPSTR aadtenantid;          /* aadtenantid" */
201
  LPSTR diagnosticserviceurl; /* diagnosticserviceurl */
202
  LPSTR hubdiscoverygeourl;   /* hubdiscoverygeourl" */
203
  LPSTR activityhint;         /* activityhint */
204
205
  DWORD UseRedirectionServerName; /* use redirection server name */
206
207
  LPSTR GatewayAccessToken; /* gatewayaccesstoken */
208
209
  LPSTR EndpointFedAuthToken; /* endpointfedauth */
210
211
  LPSTR DrivesToRedirect;  /* drivestoredirect */
212
  LPSTR DevicesToRedirect; /* devicestoredirect */
213
  LPSTR WinPosStr;         /* winposstr */
214
215
  LPSTR PreconnectionBlob; /* pcb */
216
217
  LPSTR KdcProxyName;  /* kdcproxyname */
218
  DWORD RdgIsKdcProxy; /* rdgiskdcproxy */
219
220
  DWORD align1;
221
222
  size_t lineCount;
223
  size_t lineSize;
224
  rdpFileLine* lines;
225
226
  ADDIN_ARGV* args;
227
  void* context;
228
229
  DWORD flags;
230
};
231
232
static const char key_str_username[] = "username";
233
static const char key_str_domain[] = "domain";
234
static const char key_str_password[] = "password";
235
static const char key_str_full_address[] = "full address";
236
static const char key_str_alternate_full_address[] = "alternate full address";
237
static const char key_str_usbdevicestoredirect[] = "usbdevicestoredirect";
238
static const char key_str_camerastoredirect[] = "camerastoredirect";
239
static const char key_str_loadbalanceinfo[] = "loadbalanceinfo";
240
static const char key_str_remoteapplicationname[] = "remoteapplicationname";
241
static const char key_str_remoteapplicationicon[] = "remoteapplicationicon";
242
static const char key_str_remoteapplicationprogram[] = "remoteapplicationprogram";
243
static const char key_str_remoteapplicationfile[] = "remoteapplicationfile";
244
static const char key_str_remoteapplicationguid[] = "remoteapplicationguid";
245
static const char key_str_remoteapplicationcmdline[] = "remoteapplicationcmdline";
246
static const char key_str_alternate_shell[] = "alternate shell";
247
static const char key_str_shell_working_directory[] = "shell working directory";
248
static const char key_str_gatewayhostname[] = "gatewayhostname";
249
static const char key_str_gatewayaccesstoken[] = "gatewayaccesstoken";
250
static const char key_str_endpointfedauth[] = "endpointfedauth";
251
static const char key_str_resourceprovider[] = "resourceprovider";
252
static const char str_resourceprovider_arm[] = "arm";
253
static const char key_str_kdcproxyname[] = "kdcproxyname";
254
static const char key_str_drivestoredirect[] = "drivestoredirect";
255
static const char key_str_devicestoredirect[] = "devicestoredirect";
256
static const char key_str_winposstr[] = "winposstr";
257
static const char key_str_pcb[] = "pcb";
258
static const char key_str_selectedmonitors[] = "selectedmonitors";
259
260
static const char key_str_wvd[] = "wvd endpoint pool";
261
static const char key_str_geo[] = "geo";
262
static const char key_str_armpath[] = "armpath";
263
static const char key_str_aadtenantid[] = "aadtenantid";
264
265
static const char key_str_diagnosticserviceurl[] = "diagnosticserviceurl";
266
static const char key_str_hubdiscoverygeourl[] = "hubdiscoverygeourl";
267
268
static const char key_str_activityhint[] = "activityhint";
269
270
static const char key_int_rdgiskdcproxy[] = "rdgiskdcproxy";
271
static const char key_int_use_redirection_server_name[] = "use redirection server name";
272
static const char key_int_gatewaycredentialssource[] = "gatewaycredentialssource";
273
static const char key_int_gatewayprofileusagemethod[] = "gatewayprofileusagemethod";
274
static const char key_int_gatewayusagemethod[] = "gatewayusagemethod";
275
static const char key_int_disableremoteappcapscheck[] = "disableremoteappcapscheck";
276
static const char key_int_disableconnectionsharing[] = "disableconnectionsharing";
277
static const char key_int_remoteapplicationexpandworkingdir[] = "remoteapplicationexpandworkingdir";
278
static const char key_int_remoteapplicationexpandcmdline[] = "remoteapplicationexpandcmdline";
279
static const char key_int_remoteapplicationmode[] = "remoteapplicationmode";
280
static const char key_int_enablecredsspsupport[] = "enablecredsspsupport";
281
static const char key_int_enablerdsaadauth[] = "enablerdsaadauth";
282
static const char key_int_negotiate_security_layer[] = "negotiate security layer";
283
static const char key_int_prompt_for_credentials[] = "prompt for credentials";
284
static const char key_int_promptcredentialonce[] = "promptcredentialonce";
285
static const char key_int_authentication_level[] = "authentication level";
286
static const char key_int_public_mode[] = "public mode";
287
static const char key_int_autoreconnect_max_retries[] = "autoreconnect max retries";
288
static const char key_int_autoreconnection_enabled[] = "autoreconnection enabled";
289
static const char key_int_administrative_session[] = "administrative session";
290
static const char key_int_connect_to_console[] = "connect to console";
291
static const char key_int_disableclipboardredirection[] = "disableclipboardredirection";
292
static const char key_int_disableprinterredirection[] = "disableprinterredirection";
293
static const char key_int_redirectdirectx[] = "redirectdirectx";
294
static const char key_int_redirectposdevices[] = "redirectposdevices";
295
static const char key_int_redirectclipboard[] = "redirectclipboard";
296
static const char key_int_redirectsmartcards[] = "redirectsmartcards";
297
static const char key_int_redirectcomports[] = "redirectcomports";
298
static const char key_int_redirectlocation[] = "redirectlocation";
299
static const char key_int_redirectprinters[] = "redirectprinters";
300
static const char key_int_redirectdrives[] = "redirectdrives";
301
static const char key_int_server_port[] = "server port";
302
static const char key_int_bitmapcachepersistenable[] = "bitmapcachepersistenable";
303
static const char key_int_bitmapcachesize[] = "bitmapcachesize";
304
static const char key_int_disable_cursor_setting[] = "disable cursor setting";
305
static const char key_int_disable_themes[] = "disable themes";
306
static const char key_int_disable_menu_anims[] = "disable menu anims";
307
static const char key_int_disable_full_window_drag[] = "disable full window drag";
308
static const char key_int_allow_desktop_composition[] = "allow desktop composition";
309
static const char key_int_allow_font_smoothing[] = "allow font smoothing";
310
static const char key_int_disable_wallpaper[] = "disable wallpaper";
311
static const char key_int_enableworkspacereconnect[] = "enableworkspacereconnect";
312
static const char key_int_workspaceid[] = "workspaceid";
313
static const char key_int_displayconnectionbar[] = "displayconnectionbar";
314
static const char key_int_pinconnectionbar[] = "pinconnectionbar";
315
static const char key_int_bandwidthautodetect[] = "bandwidthautodetect";
316
static const char key_int_networkautodetect[] = "networkautodetect";
317
static const char key_int_connection_type[] = "connection type";
318
static const char key_int_videoplaybackmode[] = "videoplaybackmode";
319
static const char key_int_redirected_video_capture_encoding_quality[] =
320
    "redirected video capture encoding quality";
321
static const char key_int_encode_redirected_video_capture[] = "encode redirected video capture";
322
static const char key_int_audiocapturemode[] = "audiocapturemode";
323
static const char key_int_audioqualitymode[] = "audioqualitymode";
324
static const char key_int_audiomode[] = "audiomode";
325
static const char key_int_disable_ctrl_alt_del[] = "disable ctrl+alt+del";
326
static const char key_int_keyboardhook[] = "keyboardhook";
327
static const char key_int_compression[] = "compression";
328
static const char key_int_desktopscalefactor[] = "desktopscalefactor";
329
static const char key_int_session_bpp[] = "session bpp";
330
static const char key_int_desktop_size_id[] = "desktop size id";
331
static const char key_int_desktopheight[] = "desktopheight";
332
static const char key_int_desktopwidth[] = "desktopwidth";
333
static const char key_int_superpanaccelerationfactor[] = "superpanaccelerationfactor";
334
static const char key_int_enablesuperpan[] = "enablesuperpan";
335
static const char key_int_dynamic_resolution[] = "dynamic resolution";
336
static const char key_int_smart_sizing[] = "smart sizing";
337
static const char key_int_span_monitors[] = "span monitors";
338
static const char key_int_screen_mode_id[] = "screen mode id";
339
static const char key_int_singlemoninwindowedmode[] = "singlemoninwindowedmode";
340
static const char key_int_maximizetocurrentdisplays[] = "maximizetocurrentdisplays";
341
static const char key_int_use_multimon[] = "use multimon";
342
static const char key_int_redirectwebauthn[] = "redirectwebauthn";
343
344
WINPR_ATTR_NODISCARD
345
static BOOL is_pointer_used(void* ptr)
346
1.96M
{
347
1.96M
  return ~((size_t)ptr) != 0;
348
1.96M
}
349
350
WINPR_ATTR_NODISCARD
351
static BOOL utils_str_is_empty(const char* str)
352
154
{
353
154
  if (!str)
354
0
    return TRUE;
355
154
  if (strlen(str) == 0)
356
30
    return TRUE;
357
124
  return FALSE;
358
154
}
359
360
WINPR_ATTR_NODISCARD
361
static SSIZE_T freerdp_client_rdp_file_add_line(rdpFile* file);
362
363
WINPR_ATTR_NODISCARD
364
static rdpFileLine* freerdp_client_rdp_file_find_line_by_name(const rdpFile* file,
365
                                                              const char* name);
366
static void freerdp_client_file_string_check_free(LPSTR str);
367
368
WINPR_ATTR_NODISCARD
369
static BOOL freerdp_client_rdp_file_find_integer_entry(rdpFile* file, const char* name,
370
                                                       DWORD** outValue, rdpFileLine** outLine)
371
295k
{
372
295k
  WINPR_ASSERT(file);
373
295k
  WINPR_ASSERT(name);
374
295k
  WINPR_ASSERT(outValue);
375
295k
  WINPR_ASSERT(outLine);
376
377
295k
  *outValue = nullptr;
378
295k
  *outLine = nullptr;
379
380
295k
  if (_stricmp(name, key_int_use_multimon) == 0)
381
220
    *outValue = &file->UseMultiMon;
382
294k
  else if (_stricmp(name, key_int_maximizetocurrentdisplays) == 0)
383
196
    *outValue = &file->MaximizeToCurrentDisplays;
384
294k
  else if (_stricmp(name, key_int_singlemoninwindowedmode) == 0)
385
201
    *outValue = &file->SingleMonInWindowedMode;
386
294k
  else if (_stricmp(name, key_int_screen_mode_id) == 0)
387
225
    *outValue = &file->ScreenModeId;
388
294k
  else if (_stricmp(name, key_int_span_monitors) == 0)
389
223
    *outValue = &file->SpanMonitors;
390
294k
  else if (_stricmp(name, key_int_smart_sizing) == 0)
391
298
    *outValue = &file->SmartSizing;
392
293k
  else if (_stricmp(name, key_int_dynamic_resolution) == 0)
393
227
    *outValue = &file->DynamicResolution;
394
293k
  else if (_stricmp(name, key_int_enablesuperpan) == 0)
395
313
    *outValue = &file->EnableSuperSpan;
396
293k
  else if (_stricmp(name, key_int_superpanaccelerationfactor) == 0)
397
203
    *outValue = &file->SuperSpanAccelerationFactor;
398
293k
  else if (_stricmp(name, key_int_desktopwidth) == 0)
399
240
    *outValue = &file->DesktopWidth;
400
292k
  else if (_stricmp(name, key_int_desktopheight) == 0)
401
226
    *outValue = &file->DesktopHeight;
402
292k
  else if (_stricmp(name, key_int_desktop_size_id) == 0)
403
276
    *outValue = &file->DesktopSizeId;
404
292k
  else if (_stricmp(name, key_int_session_bpp) == 0)
405
207
    *outValue = &file->SessionBpp;
406
292k
  else if (_stricmp(name, key_int_desktopscalefactor) == 0)
407
221
    *outValue = &file->DesktopScaleFactor;
408
291k
  else if (_stricmp(name, key_int_compression) == 0)
409
304
    *outValue = &file->Compression;
410
291k
  else if (_stricmp(name, key_int_keyboardhook) == 0)
411
243
    *outValue = &file->KeyboardHook;
412
291k
  else if (_stricmp(name, key_int_disable_ctrl_alt_del) == 0)
413
194
    *outValue = &file->DisableCtrlAltDel;
414
291k
  else if (_stricmp(name, key_int_audiomode) == 0)
415
237
    *outValue = &file->AudioMode;
416
290k
  else if (_stricmp(name, key_int_audioqualitymode) == 0)
417
198
    *outValue = &file->AudioQualityMode;
418
290k
  else if (_stricmp(name, key_int_audiocapturemode) == 0)
419
249
    *outValue = &file->AudioCaptureMode;
420
290k
  else if (_stricmp(name, key_int_encode_redirected_video_capture) == 0)
421
194
    *outValue = &file->EncodeRedirectedVideoCapture;
422
290k
  else if (_stricmp(name, key_int_redirected_video_capture_encoding_quality) == 0)
423
194
    *outValue = &file->RedirectedVideoCaptureEncodingQuality;
424
290k
  else if (_stricmp(name, key_int_videoplaybackmode) == 0)
425
221
    *outValue = &file->VideoPlaybackMode;
426
289k
  else if (_stricmp(name, key_int_connection_type) == 0)
427
229
    *outValue = &file->ConnectionType;
428
289k
  else if (_stricmp(name, key_int_networkautodetect) == 0)
429
279
    *outValue = &file->NetworkAutoDetect;
430
289k
  else if (_stricmp(name, key_int_bandwidthautodetect) == 0)
431
272
    *outValue = &file->BandwidthAutoDetect;
432
289k
  else if (_stricmp(name, key_int_pinconnectionbar) == 0)
433
297
    *outValue = &file->PinConnectionBar;
434
288k
  else if (_stricmp(name, key_int_displayconnectionbar) == 0)
435
206
    *outValue = &file->DisplayConnectionBar;
436
288k
  else if (_stricmp(name, key_int_workspaceid) == 0)
437
194
    *outValue = &file->WorkspaceId;
438
288k
  else if (_stricmp(name, key_int_enableworkspacereconnect) == 0)
439
194
    *outValue = &file->EnableWorkspaceReconnect;
440
288k
  else if (_stricmp(name, key_int_disable_wallpaper) == 0)
441
236
    *outValue = &file->DisableWallpaper;
442
287k
  else if (_stricmp(name, key_int_allow_font_smoothing) == 0)
443
266
    *outValue = &file->AllowFontSmoothing;
444
287k
  else if (_stricmp(name, key_int_allow_desktop_composition) == 0)
445
215
    *outValue = &file->AllowDesktopComposition;
446
287k
  else if (_stricmp(name, key_int_disable_full_window_drag) == 0)
447
244
    *outValue = &file->DisableFullWindowDrag;
448
287k
  else if (_stricmp(name, key_int_disable_menu_anims) == 0)
449
233
    *outValue = &file->DisableMenuAnims;
450
286k
  else if (_stricmp(name, key_int_disable_themes) == 0)
451
230
    *outValue = &file->DisableThemes;
452
286k
  else if (_stricmp(name, key_int_disable_cursor_setting) == 0)
453
196
    *outValue = &file->DisableCursorSetting;
454
286k
  else if (_stricmp(name, key_int_bitmapcachesize) == 0)
455
194
    *outValue = &file->BitmapCacheSize;
456
286k
  else if (_stricmp(name, key_int_bitmapcachepersistenable) == 0)
457
203
    *outValue = &file->BitmapCachePersistEnable;
458
286k
  else if (_stricmp(name, key_int_server_port) == 0)
459
479
    *outValue = &file->ServerPort;
460
285k
  else if (_stricmp(name, key_int_redirectdrives) == 0)
461
237
    *outValue = &file->RedirectDrives;
462
285k
  else if (_stricmp(name, key_int_redirectprinters) == 0)
463
230
    *outValue = &file->RedirectPrinters;
464
285k
  else if (_stricmp(name, key_int_redirectcomports) == 0)
465
242
    *outValue = &file->RedirectComPorts;
466
284k
  else if (_stricmp(name, key_int_redirectlocation) == 0)
467
225
    *outValue = &file->RedirectLocation;
468
284k
  else if (_stricmp(name, key_int_redirectsmartcards) == 0)
469
243
    *outValue = &file->RedirectSmartCards;
470
284k
  else if (_stricmp(name, key_int_redirectclipboard) == 0)
471
225
    *outValue = &file->RedirectClipboard;
472
284k
  else if (_stricmp(name, key_int_redirectposdevices) == 0)
473
231
    *outValue = &file->RedirectPosDevices;
474
284k
  else if (_stricmp(name, key_int_redirectdirectx) == 0)
475
223
    *outValue = &file->RedirectDirectX;
476
283k
  else if (_stricmp(name, key_int_disableprinterredirection) == 0)
477
194
    *outValue = &file->DisablePrinterRedirection;
478
283k
  else if (_stricmp(name, key_int_disableclipboardredirection) == 0)
479
194
    *outValue = &file->DisableClipboardRedirection;
480
283k
  else if (_stricmp(name, key_int_connect_to_console) == 0)
481
236
    *outValue = &file->ConnectToConsole;
482
283k
  else if (_stricmp(name, key_int_administrative_session) == 0)
483
232
    *outValue = &file->AdministrativeSession;
484
282k
  else if (_stricmp(name, key_int_autoreconnection_enabled) == 0)
485
210
    *outValue = &file->AutoReconnectionEnabled;
486
282k
  else if (_stricmp(name, key_int_autoreconnect_max_retries) == 0)
487
194
    *outValue = &file->AutoReconnectMaxRetries;
488
282k
  else if (_stricmp(name, key_int_public_mode) == 0)
489
4.60k
    *outValue = &file->PublicMode;
490
277k
  else if (_stricmp(name, key_int_authentication_level) == 0)
491
284
    *outValue = &file->AuthenticationLevel;
492
277k
  else if (_stricmp(name, key_int_promptcredentialonce) == 0)
493
217
    *outValue = &file->PromptCredentialOnce;
494
277k
  else if ((_stricmp(name, key_int_prompt_for_credentials) == 0))
495
209
    *outValue = &file->PromptForCredentials;
496
277k
  else if (_stricmp(name, key_int_negotiate_security_layer) == 0)
497
216
    *outValue = &file->NegotiateSecurityLayer;
498
276k
  else if (_stricmp(name, key_int_enablecredsspsupport) == 0)
499
233
    *outValue = &file->EnableCredSSPSupport;
500
276k
  else if (_stricmp(name, key_int_enablerdsaadauth) == 0)
501
221
    *outValue = &file->EnableRdsAadAuth;
502
276k
  else if (_stricmp(name, key_int_remoteapplicationmode) == 0)
503
242
    *outValue = &file->RemoteApplicationMode;
504
276k
  else if (_stricmp(name, key_int_remoteapplicationexpandcmdline) == 0)
505
194
    *outValue = &file->RemoteApplicationExpandCmdLine;
506
276k
  else if (_stricmp(name, key_int_remoteapplicationexpandworkingdir) == 0)
507
194
    *outValue = &file->RemoteApplicationExpandWorkingDir;
508
275k
  else if (_stricmp(name, key_int_disableconnectionsharing) == 0)
509
194
    *outValue = &file->DisableConnectionSharing;
510
275k
  else if (_stricmp(name, key_int_disableremoteappcapscheck) == 0)
511
225
    *outValue = &file->DisableRemoteAppCapsCheck;
512
275k
  else if (_stricmp(name, key_int_gatewayusagemethod) == 0)
513
267
    *outValue = &file->GatewayUsageMethod;
514
275k
  else if (_stricmp(name, key_int_gatewayprofileusagemethod) == 0)
515
196
    *outValue = &file->GatewayProfileUsageMethod;
516
275k
  else if (_stricmp(name, key_int_gatewaycredentialssource) == 0)
517
221
    *outValue = &file->GatewayCredentialsSource;
518
274k
  else if (_stricmp(name, key_int_use_redirection_server_name) == 0)
519
201
    *outValue = &file->UseRedirectionServerName;
520
274k
  else if (_stricmp(name, key_int_rdgiskdcproxy) == 0)
521
224
    *outValue = &file->RdgIsKdcProxy;
522
274k
  else if (_stricmp(name, key_int_redirectwebauthn) == 0)
523
317
    *outValue = &file->RedirectWebauthN;
524
274k
  else
525
274k
  {
526
274k
    rdpFileLine* line = freerdp_client_rdp_file_find_line_by_name(file, name);
527
274k
    if (!line)
528
7.52k
      return FALSE;
529
266k
    if (!(line->flags & RDP_FILE_LINE_FLAG_TYPE_INTEGER))
530
246k
      return FALSE;
531
532
19.5k
    *outLine = line;
533
19.5k
  }
534
535
40.6k
  return TRUE;
536
295k
}
537
538
WINPR_ATTR_NODISCARD
539
static BOOL freerdp_client_rdp_file_find_string_entry(rdpFile* file, const char* name,
540
                                                      LPSTR** outValue, rdpFileLine** outLine)
541
573k
{
542
573k
  WINPR_ASSERT(file);
543
573k
  WINPR_ASSERT(name);
544
573k
  WINPR_ASSERT(outValue);
545
573k
  WINPR_ASSERT(outLine);
546
547
573k
  *outValue = nullptr;
548
573k
  *outLine = nullptr;
549
550
573k
  if (_stricmp(name, key_str_username) == 0)
551
229
    *outValue = &file->Username;
552
573k
  else if (_stricmp(name, key_str_domain) == 0)
553
251
    *outValue = &file->Domain;
554
573k
  else if (_stricmp(name, key_str_password) == 0)
555
194
    *outValue = &file->Password;
556
573k
  else if (_stricmp(name, key_str_full_address) == 0)
557
295
    *outValue = &file->FullAddress;
558
572k
  else if (_stricmp(name, key_str_alternate_full_address) == 0)
559
199
    *outValue = &file->AlternateFullAddress;
560
572k
  else if (_stricmp(name, key_str_usbdevicestoredirect) == 0)
561
209
    *outValue = &file->UsbDevicesToRedirect;
562
572k
  else if (_stricmp(name, key_str_camerastoredirect) == 0)
563
216
    *outValue = &file->RedirectCameras;
564
572k
  else if (_stricmp(name, key_str_loadbalanceinfo) == 0)
565
210
    *outValue = &file->LoadBalanceInfo;
566
571k
  else if (_stricmp(name, key_str_remoteapplicationname) == 0)
567
202
    *outValue = &file->RemoteApplicationName;
568
571k
  else if (_stricmp(name, key_str_remoteapplicationicon) == 0)
569
203
    *outValue = &file->RemoteApplicationIcon;
570
571k
  else if (_stricmp(name, key_str_remoteapplicationprogram) == 0)
571
202
    *outValue = &file->RemoteApplicationProgram;
572
571k
  else if (_stricmp(name, key_str_remoteapplicationfile) == 0)
573
195
    *outValue = &file->RemoteApplicationFile;
574
571k
  else if (_stricmp(name, key_str_remoteapplicationguid) == 0)
575
233
    *outValue = &file->RemoteApplicationGuid;
576
570k
  else if (_stricmp(name, key_str_remoteapplicationcmdline) == 0)
577
331
    *outValue = &file->RemoteApplicationCmdLine;
578
570k
  else if (_stricmp(name, key_str_alternate_shell) == 0)
579
206
    *outValue = &file->AlternateShell;
580
570k
  else if (_stricmp(name, key_str_shell_working_directory) == 0)
581
215
    *outValue = &file->ShellWorkingDirectory;
582
570k
  else if (_stricmp(name, key_str_gatewayhostname) == 0)
583
248
    *outValue = &file->GatewayHostname;
584
569k
  else if (_stricmp(name, key_str_resourceprovider) == 0)
585
221
    *outValue = &file->ResourceProvider;
586
569k
  else if (_stricmp(name, key_str_wvd) == 0)
587
201
    *outValue = &file->WvdEndpointPool;
588
569k
  else if (_stricmp(name, key_str_geo) == 0)
589
259
    *outValue = &file->geo;
590
569k
  else if (_stricmp(name, key_str_armpath) == 0)
591
201
    *outValue = &file->armpath;
592
569k
  else if (_stricmp(name, key_str_aadtenantid) == 0)
593
206
    *outValue = &file->aadtenantid;
594
568k
  else if (_stricmp(name, key_str_diagnosticserviceurl) == 0)
595
196
    *outValue = &file->diagnosticserviceurl;
596
568k
  else if (_stricmp(name, key_str_hubdiscoverygeourl) == 0)
597
198
    *outValue = &file->hubdiscoverygeourl;
598
568k
  else if (_stricmp(name, key_str_activityhint) == 0)
599
197
    *outValue = &file->activityhint;
600
568k
  else if (_stricmp(name, key_str_gatewayaccesstoken) == 0)
601
198
    *outValue = &file->GatewayAccessToken;
602
568k
  else if (_stricmp(name, key_str_endpointfedauth) == 0)
603
212
    *outValue = &file->EndpointFedAuthToken;
604
567k
  else if (_stricmp(name, key_str_kdcproxyname) == 0)
605
354
    *outValue = &file->KdcProxyName;
606
567k
  else if (_stricmp(name, key_str_drivestoredirect) == 0)
607
204
    *outValue = &file->DrivesToRedirect;
608
567k
  else if (_stricmp(name, key_str_devicestoredirect) == 0)
609
210
    *outValue = &file->DevicesToRedirect;
610
567k
  else if (_stricmp(name, key_str_winposstr) == 0)
611
205
    *outValue = &file->WinPosStr;
612
566k
  else if (_stricmp(name, key_str_pcb) == 0)
613
227
    *outValue = &file->PreconnectionBlob;
614
566k
  else if (_stricmp(name, key_str_selectedmonitors) == 0)
615
497
    *outValue = &file->SelectedMonitors;
616
566k
  else
617
566k
  {
618
566k
    rdpFileLine* line = freerdp_client_rdp_file_find_line_by_name(file, name);
619
566k
    if (!line)
620
3.94k
      return FALSE;
621
562k
    if (!(line->flags & RDP_FILE_LINE_FLAG_TYPE_STRING))
622
525k
      return FALSE;
623
624
36.2k
    *outLine = line;
625
36.2k
  }
626
627
43.8k
  return TRUE;
628
573k
}
629
630
/*
631
 * Set an integer in a rdpFile
632
 *
633
 * @return FALSE if a standard name was set, TRUE for a non-standard name, FALSE on error
634
 *
635
 */
636
WINPR_ATTR_NODISCARD
637
static BOOL freerdp_client_rdp_file_set_integer(rdpFile* file, const char* name, long value)
638
295k
{
639
295k
  DWORD* targetValue = nullptr;
640
295k
  rdpFileLine* line = nullptr;
641
#ifdef DEBUG_CLIENT_FILE
642
  WLog_DBG(TAG, "%s:i:%ld", name, value);
643
#endif
644
645
295k
  if (value < 0)
646
55
    return FALSE;
647
648
295k
  if (!freerdp_client_rdp_file_find_integer_entry(file, name, &targetValue, &line))
649
254k
  {
650
254k
    SSIZE_T index = freerdp_client_rdp_file_add_line(file);
651
254k
    if (index == -1)
652
0
      return FALSE;
653
254k
    line = &file->lines[index];
654
254k
  }
655
656
295k
  if (targetValue)
657
21.0k
  {
658
21.0k
    *targetValue = (DWORD)value;
659
21.0k
    return TRUE;
660
21.0k
  }
661
662
274k
  if (line)
663
274k
  {
664
274k
    free(line->name);
665
274k
    line->name = _strdup(name);
666
274k
    if (!line->name)
667
0
    {
668
0
      free(line->name);
669
0
      line->name = nullptr;
670
0
      return FALSE;
671
0
    }
672
673
274k
    line->iValue = value;
674
274k
    line->flags = RDP_FILE_LINE_FLAG_FORMATTED;
675
274k
    line->flags |= RDP_FILE_LINE_FLAG_TYPE_INTEGER;
676
274k
    line->valueLength = 0;
677
274k
    return TRUE;
678
274k
  }
679
680
0
  return FALSE;
681
274k
}
682
683
WINPR_ATTR_NODISCARD
684
static BOOL freerdp_client_parse_rdp_file_integer(rdpFile* file, const char* name,
685
                                                  const char* value)
686
313k
{
687
313k
  char* endptr = nullptr;
688
313k
  long ivalue = 0;
689
313k
  errno = 0;
690
313k
  ivalue = strtol(value, &endptr, 0);
691
692
313k
  if ((endptr == nullptr) || (errno != 0) || (endptr == value) || (ivalue > INT32_MAX) ||
693
296k
      (ivalue < INT32_MIN))
694
18.6k
  {
695
18.6k
    if (file->flags & RDP_FILE_FLAG_PARSE_INT_RELAXED)
696
18.6k
    {
697
18.6k
      WLog_WARN(TAG, "Integer option %s has invalid value %s, using default", name, value);
698
18.6k
      return TRUE;
699
18.6k
    }
700
0
    else
701
0
    {
702
0
      WLog_ERR(TAG, "Failed to convert RDP file integer option %s [value=%s]", name, value);
703
0
      return FALSE;
704
0
    }
705
18.6k
  }
706
707
295k
  return freerdp_client_rdp_file_set_integer(file, name, ivalue);
708
313k
}
709
710
/** set a string value in the provided rdp file context
711
 *
712
 * @param file rdpFile
713
 * @param name name of the string
714
 * @param value value of the string to set
715
 * @return 0 on success, 1 if the key wasn't found (not a standard key), -1 on error
716
 */
717
WINPR_ATTR_NODISCARD
718
static BOOL freerdp_client_rdp_file_set_string(rdpFile* file, const char* name, const char* value)
719
573k
{
720
573k
  LPSTR* targetValue = nullptr;
721
573k
  rdpFileLine* line = nullptr;
722
#ifdef DEBUG_CLIENT_FILE
723
  WLog_DBG(TAG, "%s:s:%s", name, value);
724
#endif
725
726
573k
  if (!name || !value)
727
0
    return FALSE;
728
729
573k
  if (!freerdp_client_rdp_file_find_string_entry(file, name, &targetValue, &line))
730
529k
  {
731
529k
    SSIZE_T index = freerdp_client_rdp_file_add_line(file);
732
529k
    if (index == -1)
733
0
      return FALSE;
734
529k
    line = &file->lines[index];
735
529k
  }
736
737
573k
  if (targetValue)
738
7.62k
  {
739
7.62k
    if ((uintptr_t)(*targetValue) != UINTPTR_MAX)
740
6.60k
      free(*targetValue);
741
742
7.62k
    *targetValue = _strdup(value);
743
7.62k
    return ((*targetValue) != nullptr);
744
7.62k
  }
745
746
566k
  if (line)
747
566k
  {
748
566k
    free(line->name);
749
566k
    free(line->sValue);
750
566k
    line->name = _strdup(name);
751
566k
    line->sValue = _strdup(value);
752
566k
    if (!line->name || !line->sValue)
753
0
    {
754
0
      free(line->name);
755
0
      free(line->sValue);
756
0
      line->name = nullptr;
757
0
      line->sValue = nullptr;
758
0
      return FALSE;
759
0
    }
760
761
566k
    line->flags = RDP_FILE_LINE_FLAG_FORMATTED;
762
566k
    line->flags |= RDP_FILE_LINE_FLAG_TYPE_STRING;
763
566k
    line->valueLength = 0;
764
566k
    return TRUE;
765
566k
  }
766
767
0
  return FALSE;
768
566k
}
769
770
WINPR_ATTR_NODISCARD
771
static BOOL freerdp_client_add_option(rdpFile* file, const char* option)
772
12.1k
{
773
12.1k
  return freerdp_addin_argv_add_argument(file->args, option);
774
12.1k
}
775
776
WINPR_ATTR_NODISCARD
777
static SSIZE_T freerdp_client_rdp_file_add_line(rdpFile* file)
778
784k
{
779
784k
  SSIZE_T index = (SSIZE_T)file->lineCount;
780
781
784k
  while ((file->lineCount + 1) > file->lineSize)
782
420
  {
783
420
    size_t new_size = file->lineCount + 2048;
784
420
    rdpFileLine* new_line = (rdpFileLine*)realloc(file->lines, new_size * sizeof(rdpFileLine));
785
786
420
    if (!new_line)
787
0
      return -1;
788
789
420
    file->lines = new_line;
790
420
    file->lineSize = new_size;
791
420
  }
792
793
784k
  ZeroMemory(&(file->lines[file->lineCount]), sizeof(rdpFileLine));
794
784k
  file->lines[file->lineCount].index = (size_t)index;
795
784k
  (file->lineCount)++;
796
784k
  return index;
797
784k
}
798
799
BOOL freerdp_client_parse_rdp_file_buffer(rdpFile* file, const BYTE* buffer, size_t size)
800
12.1k
{
801
12.1k
  return freerdp_client_parse_rdp_file_buffer_ex(file, buffer, size, nullptr);
802
12.1k
}
803
804
WINPR_ATTR_NODISCARD
805
static BOOL trim(char** strptr)
806
819k
{
807
819k
  char* start = nullptr;
808
819k
  char* str = nullptr;
809
819k
  char* end = nullptr;
810
811
819k
  start = str = *strptr;
812
819k
  if (!str)
813
0
    return TRUE;
814
819k
  if (!(is_pointer_used(str)))
815
288k
    return TRUE;
816
530k
  end = str + strlen(str) - 1;
817
818
530k
  while (isspace(*str))
819
441
    str++;
820
821
530k
  while ((end > str) && isspace(*end))
822
221
    end--;
823
530k
  end[1] = '\0';
824
530k
  if (start == str)
825
530k
    *strptr = str;
826
244
  else
827
244
  {
828
244
    *strptr = _strdup(str);
829
244
    free(start);
830
244
    return *strptr != nullptr;
831
244
  }
832
833
530k
  return TRUE;
834
530k
}
835
836
WINPR_ATTR_NODISCARD
837
static BOOL trim_strings(rdpFile* file)
838
12.0k
{
839
12.0k
  if (!trim(&file->Username))
840
0
    return FALSE;
841
12.0k
  if (!trim(&file->Domain))
842
0
    return FALSE;
843
12.0k
  if (!trim(&file->AlternateFullAddress))
844
0
    return FALSE;
845
12.0k
  if (!trim(&file->FullAddress))
846
0
    return FALSE;
847
12.0k
  if (!trim(&file->UsbDevicesToRedirect))
848
0
    return FALSE;
849
12.0k
  if (!trim(&file->RedirectCameras))
850
0
    return FALSE;
851
12.0k
  if (!trim(&file->LoadBalanceInfo))
852
0
    return FALSE;
853
12.0k
  if (!trim(&file->GatewayHostname))
854
0
    return FALSE;
855
12.0k
  if (!trim(&file->GatewayAccessToken))
856
0
    return FALSE;
857
12.0k
  if (!trim(&file->EndpointFedAuthToken))
858
0
    return FALSE;
859
12.0k
  if (!trim(&file->RemoteApplicationName))
860
0
    return FALSE;
861
12.0k
  if (!trim(&file->RemoteApplicationIcon))
862
0
    return FALSE;
863
12.0k
  if (!trim(&file->RemoteApplicationProgram))
864
0
    return FALSE;
865
12.0k
  if (!trim(&file->RemoteApplicationFile))
866
0
    return FALSE;
867
12.0k
  if (!trim(&file->RemoteApplicationGuid))
868
0
    return FALSE;
869
12.0k
  if (!trim(&file->RemoteApplicationCmdLine))
870
0
    return FALSE;
871
12.0k
  if (!trim(&file->AlternateShell))
872
0
    return FALSE;
873
12.0k
  if (!trim(&file->ShellWorkingDirectory))
874
0
    return FALSE;
875
12.0k
  if (!trim(&file->DrivesToRedirect))
876
0
    return FALSE;
877
12.0k
  if (!trim(&file->DevicesToRedirect))
878
0
    return FALSE;
879
12.0k
  if (!trim(&file->WinPosStr))
880
0
    return FALSE;
881
12.0k
  if (!trim(&file->PreconnectionBlob))
882
0
    return FALSE;
883
12.0k
  if (!trim(&file->KdcProxyName))
884
0
    return FALSE;
885
12.0k
  if (!trim(&file->SelectedMonitors))
886
0
    return FALSE;
887
888
796k
  for (size_t i = 0; i < file->lineCount; ++i)
889
784k
  {
890
784k
    rdpFileLine* curLine = &file->lines[i];
891
784k
    if (curLine->flags & RDP_FILE_LINE_FLAG_TYPE_STRING)
892
529k
    {
893
529k
      if (!trim(&curLine->sValue))
894
0
        return FALSE;
895
529k
    }
896
784k
  }
897
898
12.0k
  return TRUE;
899
12.0k
}
900
901
WINPR_ATTR_NODISCARD
902
static BOOL parse_line(rdpFile* file, char* line, size_t length, rdp_file_fkt_parse parse)
903
1.07M
{
904
1.07M
  if (length <= 1)
905
12.3k
    return TRUE;
906
907
1.06M
  const char* beg = line;
908
1.06M
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
909
#if defined(WITH_EMBEDDED_CLI_IN_RDP_FILES)
910
  if (beg[0] == '/')
911
  {
912
    freerdp_warn_deprecated(WLog_Get(TAG), "Parsing CLI options within an RDP file",
913
                            "Will be removed in FreeRDP 4.0");
914
    if (!freerdp_client_add_option(file, line))
915
      return FALSE;
916
917
    return TRUE; /* FreeRDP option */
918
  }
919
#endif
920
1.06M
#endif
921
922
1.06M
  char* d1 = strchr(line, ':');
923
924
1.06M
  if (!d1)
925
8.27k
    return TRUE; /* not first delimiter */
926
927
1.05M
  const char* type = &d1[1];
928
1.05M
  char* d2 = strchr(type, ':');
929
930
1.05M
  if (!d2)
931
123k
    return TRUE; /* no second delimiter */
932
933
931k
  if ((d2 - d1) != 2)
934
39.9k
    return TRUE; /* improper type length */
935
936
891k
  *d1 = 0;
937
891k
  *d2 = 0;
938
891k
  const char* name = beg;
939
891k
  const char* value = &d2[1];
940
941
891k
  if (parse && parse(file->context, name, *type, value))
942
0
    return TRUE;
943
944
891k
  if (*type == 'i')
945
313k
  {
946
    /* integer type */
947
313k
    return freerdp_client_parse_rdp_file_integer(file, name, value);
948
313k
  }
949
578k
  if (*type == 's')
950
573k
  {
951
    /* string type */
952
573k
    return freerdp_client_rdp_file_set_string(file, name, value);
953
573k
  }
954
4.33k
  if (*type == 'b')
955
250
  {
956
    /* binary type */
957
250
    WLog_ERR(TAG, "Unsupported RDP file binary option %s [value=%s]", name, value);
958
250
  }
959
960
4.33k
  return TRUE;
961
578k
}
962
963
BOOL freerdp_client_parse_rdp_file_buffer_ex(rdpFile* file, const BYTE* buffer, size_t size,
964
                                             rdp_file_fkt_parse parse)
965
12.1k
{
966
12.1k
  BOOL rc = FALSE;
967
12.1k
  char* copy = nullptr;
968
969
12.1k
  if (!file)
970
0
    return FALSE;
971
12.1k
  if (size < 2)
972
0
    return FALSE;
973
974
12.1k
  if ((buffer[0] == BOM_UTF16_LE[0]) && (buffer[1] == BOM_UTF16_LE[1]))
975
247
  {
976
    /* algignment unknown, so create a copy. */
977
247
    const size_t nobomsize = size - 2;
978
247
    WCHAR* uc = calloc(nobomsize + 2, 1);
979
247
    if (!uc)
980
0
      return FALSE;
981
247
    memcpy(uc, &buffer[2], nobomsize);
982
247
    const size_t charlen = nobomsize / sizeof(WCHAR);
983
247
    copy = ConvertWCharNToUtf8Alloc(uc, charlen, &size);
984
247
    winpr_znfree(uc, nobomsize);
985
247
    if (!copy)
986
61
    {
987
61
      WLog_ERR(TAG, "Failed to convert RDP file from UCS2 to UTF8");
988
61
      return FALSE;
989
61
    }
990
247
  }
991
11.9k
  else
992
11.9k
  {
993
11.9k
    copy = calloc(1, size + sizeof(BYTE));
994
995
11.9k
    if (!copy)
996
0
      return FALSE;
997
998
11.9k
    memcpy(copy, buffer, size);
999
11.9k
  }
1000
1001
12.1k
  char* context = nullptr;
1002
12.1k
  char* line = strtok_s(copy, "\r\n", &context);
1003
1004
1.08M
  while (line)
1005
1.07M
  {
1006
1.07M
    const size_t length = strnlen(line, size);
1007
1008
1.07M
    if (!parse_line(file, line, length, parse))
1009
55
      goto fail;
1010
1011
1.07M
    line = strtok_s(nullptr, "\r\n", &context);
1012
1.07M
  }
1013
1014
12.0k
  rc = trim_strings(file);
1015
12.1k
fail:
1016
12.1k
  free(copy);
1017
12.1k
  return rc;
1018
12.0k
}
1019
1020
BOOL freerdp_client_parse_rdp_file(rdpFile* file, const char* name)
1021
0
{
1022
0
  return freerdp_client_parse_rdp_file_ex(file, name, nullptr);
1023
0
}
1024
1025
BOOL freerdp_client_parse_rdp_file_ex(rdpFile* file, const char* name, rdp_file_fkt_parse parse)
1026
0
{
1027
0
  BOOL status = 0;
1028
0
  BYTE* buffer = nullptr;
1029
0
  FILE* fp = nullptr;
1030
0
  size_t read_size = 0;
1031
0
  INT64 file_size = 0;
1032
0
  const char* fname = name;
1033
1034
0
  if (!file || !name)
1035
0
    return FALSE;
1036
1037
0
  if (_strnicmp(fname, "file://", 7) == 0)
1038
0
    fname = &name[7];
1039
1040
0
  fp = winpr_fopen(fname, "r");
1041
0
  if (!fp)
1042
0
  {
1043
0
    WLog_ERR(TAG, "Failed to open RDP file %s", name);
1044
0
    return FALSE;
1045
0
  }
1046
1047
0
  if (_fseeki64(fp, 0, SEEK_END) < 0)
1048
0
    goto fail;
1049
0
  file_size = _ftelli64(fp);
1050
0
  if (_fseeki64(fp, 0, SEEK_SET) < 0)
1051
0
    goto fail;
1052
1053
0
  if (file_size < 1)
1054
0
  {
1055
0
    WLog_ERR(TAG, "RDP file %s is empty", name);
1056
0
    goto fail;
1057
0
  }
1058
1059
0
  buffer = (BYTE*)malloc((size_t)file_size + 2);
1060
1061
0
  if (!buffer)
1062
0
    goto fail;
1063
1064
0
  read_size = fread(buffer, (size_t)file_size, 1, fp);
1065
1066
0
  if (!read_size)
1067
0
  {
1068
0
    if (!ferror(fp))
1069
0
      read_size = (size_t)file_size;
1070
0
  }
1071
1072
0
  if (read_size < 1)
1073
0
  {
1074
0
    WLog_ERR(TAG, "Could not read from RDP file %s", name);
1075
0
    goto fail;
1076
0
  }
1077
1078
0
  buffer[file_size] = '\0';
1079
0
  buffer[file_size + 1] = '\0';
1080
0
  status = freerdp_client_parse_rdp_file_buffer_ex(file, buffer, (size_t)file_size, parse);
1081
1082
0
fail:
1083
0
  (void)fclose(fp);
1084
0
  free(buffer);
1085
0
  return status;
1086
0
}
1087
1088
static inline void freerdp_client_file_string_reset(char** target)
1089
0
{
1090
0
  WINPR_ASSERT(target);
1091
0
  freerdp_client_file_string_check_free(*target);
1092
0
  *target = (char*)UINTPTR_MAX;
1093
0
}
1094
1095
WINPR_ATTR_NODISCARD
1096
static inline BOOL FILE_POPULATE_STRING(char** _target, const rdpSettings* _settings,
1097
                                        FreeRDP_Settings_Keys_String _option)
1098
0
{
1099
0
  WINPR_ASSERT(_target);
1100
0
  WINPR_ASSERT(_settings);
1101
1102
0
  const char* str = freerdp_settings_get_string(_settings, _option);
1103
0
  freerdp_client_file_string_reset(_target);
1104
0
  if (str)
1105
0
  {
1106
0
    char* copy = _strdup(str);
1107
0
    if (!copy)
1108
0
      return FALSE;
1109
0
    *_target = copy;
1110
0
  }
1111
0
  return TRUE;
1112
0
}
1113
1114
WINPR_ATTR_NODISCARD
1115
static char* freerdp_client_channel_args_to_string(const rdpSettings* settings, const char* channel,
1116
                                                   const char* option)
1117
0
{
1118
0
  ADDIN_ARGV* args = freerdp_dynamic_channel_collection_find(settings, channel);
1119
0
  const char* filters[] = { option };
1120
0
  if (!args || (args->argc < 2))
1121
0
    return nullptr;
1122
1123
0
  return CommandLineToCommaSeparatedValuesEx(args->argc - 1, args->argv + 1, filters,
1124
0
                                             ARRAYSIZE(filters));
1125
0
}
1126
1127
WINPR_ATTR_NODISCARD
1128
static BOOL rdp_opt_duplicate(const rdpSettings* _settings, FreeRDP_Settings_Keys_String _id,
1129
                              char** _key)
1130
0
{
1131
0
  WINPR_ASSERT(_settings);
1132
0
  WINPR_ASSERT(_key);
1133
0
  const char* tmp = freerdp_settings_get_string(_settings, _id);
1134
1135
0
  if (tmp)
1136
0
  {
1137
0
    *_key = _strdup(tmp);
1138
0
    if (!*_key)
1139
0
      return FALSE;
1140
0
  }
1141
1142
0
  return TRUE;
1143
0
}
1144
1145
BOOL freerdp_client_populate_rdp_file_from_settings(rdpFile* file, const rdpSettings* settings)
1146
0
{
1147
0
  FreeRDP_Settings_Keys_String index = FreeRDP_STRING_UNUSED;
1148
0
  UINT32 LoadBalanceInfoLength = 0;
1149
0
  const char* GatewayHostname = nullptr;
1150
0
  char* redirectCameras = nullptr;
1151
1152
0
  if (!file || !settings)
1153
0
    return FALSE;
1154
1155
0
  if (!FILE_POPULATE_STRING(&file->Domain, settings, FreeRDP_Domain) ||
1156
0
      !FILE_POPULATE_STRING(&file->Username, settings, FreeRDP_Username) ||
1157
0
      !FILE_POPULATE_STRING(&file->Password, settings, FreeRDP_Password) ||
1158
0
      !FILE_POPULATE_STRING(&file->FullAddress, settings, FreeRDP_ServerHostname) ||
1159
0
      !FILE_POPULATE_STRING(&file->AlternateFullAddress, settings, FreeRDP_ServerHostname) ||
1160
0
      !FILE_POPULATE_STRING(&file->AlternateShell, settings, FreeRDP_AlternateShell) ||
1161
0
      !FILE_POPULATE_STRING(&file->DrivesToRedirect, settings, FreeRDP_DrivesToRedirect))
1162
1163
0
    return FALSE;
1164
0
  file->ServerPort = freerdp_settings_get_uint32(settings, FreeRDP_ServerPort);
1165
1166
0
  file->DesktopWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
1167
0
  file->DesktopHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
1168
0
  file->SessionBpp = freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth);
1169
0
  file->DesktopScaleFactor = freerdp_settings_get_uint32(settings, FreeRDP_DesktopScaleFactor);
1170
0
  file->DynamicResolution = WINPR_ASSERTING_INT_CAST(
1171
0
      UINT32, freerdp_settings_get_bool(settings, FreeRDP_SupportDisplayControl));
1172
0
  file->VideoPlaybackMode = WINPR_ASSERTING_INT_CAST(
1173
0
      UINT32, freerdp_settings_get_bool(settings, FreeRDP_SupportVideoOptimized));
1174
1175
  // TODO file->MaximizeToCurrentDisplays;
1176
  // TODO file->SingleMonInWindowedMode;
1177
  // TODO file->EncodeRedirectedVideoCapture;
1178
  // TODO file->RedirectedVideoCaptureEncodingQuality;
1179
0
  file->ConnectToConsole = WINPR_ASSERTING_INT_CAST(
1180
0
      UINT32, freerdp_settings_get_bool(settings, FreeRDP_ConsoleSession));
1181
0
  file->NegotiateSecurityLayer = WINPR_ASSERTING_INT_CAST(
1182
0
      UINT32, freerdp_settings_get_bool(settings, FreeRDP_NegotiateSecurityLayer));
1183
1184
0
  const BOOL nla = freerdp_settings_get_bool(settings, FreeRDP_NlaSecurity) ||
1185
0
                   freerdp_settings_get_bool(settings, FreeRDP_ExtSecurity);
1186
0
  file->EnableCredSSPSupport = WINPR_ASSERTING_INT_CAST(UINT32, nla);
1187
0
  file->EnableRdsAadAuth =
1188
0
      WINPR_ASSERTING_INT_CAST(UINT32, freerdp_settings_get_bool(settings, FreeRDP_AadSecurity));
1189
1190
0
  if (freerdp_settings_get_bool(settings, FreeRDP_RemoteApplicationMode))
1191
0
    index = FreeRDP_RemoteApplicationWorkingDir;
1192
0
  else
1193
0
    index = FreeRDP_ShellWorkingDirectory;
1194
0
  if (!FILE_POPULATE_STRING(&file->ShellWorkingDirectory, settings, index))
1195
0
    return FALSE;
1196
0
  file->ConnectionType = freerdp_settings_get_uint32(settings, FreeRDP_ConnectionType);
1197
1198
0
  file->ScreenModeId = freerdp_settings_get_bool(settings, FreeRDP_Fullscreen) ? 2 : 1;
1199
0
  file->SmartSizing = freerdp_settings_get_bool(settings, FreeRDP_SmartSizing) ? 1 : 0;
1200
1201
0
  LoadBalanceInfoLength = freerdp_settings_get_uint32(settings, FreeRDP_LoadBalanceInfoLength);
1202
0
  if (LoadBalanceInfoLength > 0)
1203
0
  {
1204
0
    const BYTE* LoadBalanceInfo =
1205
0
        freerdp_settings_get_pointer(settings, FreeRDP_LoadBalanceInfo);
1206
0
    file->LoadBalanceInfo = calloc(LoadBalanceInfoLength + 1, 1);
1207
0
    if (!file->LoadBalanceInfo)
1208
0
      return FALSE;
1209
0
    memcpy(file->LoadBalanceInfo, LoadBalanceInfo, LoadBalanceInfoLength);
1210
0
  }
1211
1212
0
  if (freerdp_settings_get_bool(settings, FreeRDP_AudioPlayback))
1213
0
    file->AudioMode = AUDIO_MODE_REDIRECT;
1214
0
  else if (freerdp_settings_get_bool(settings, FreeRDP_RemoteConsoleAudio))
1215
0
    file->AudioMode = AUDIO_MODE_PLAY_ON_SERVER;
1216
0
  else
1217
0
    file->AudioMode = AUDIO_MODE_NONE;
1218
1219
  /* The gateway hostname should also contain a port specifier unless it is the default port 443
1220
   */
1221
0
  GatewayHostname = freerdp_settings_get_string(settings, FreeRDP_GatewayHostname);
1222
0
  if (GatewayHostname)
1223
0
  {
1224
0
    const UINT32 GatewayPort = freerdp_settings_get_uint32(settings, FreeRDP_GatewayPort);
1225
0
    freerdp_client_file_string_check_free(file->GatewayHostname);
1226
0
    if (GatewayPort == 443)
1227
0
      file->GatewayHostname = _strdup(GatewayHostname);
1228
0
    else
1229
0
    {
1230
0
      int length = _scprintf("%s:%" PRIu32, GatewayHostname, GatewayPort);
1231
0
      if (length < 0)
1232
0
        return FALSE;
1233
1234
0
      file->GatewayHostname = (char*)malloc((size_t)length + 1);
1235
0
      if (!file->GatewayHostname)
1236
0
        return FALSE;
1237
1238
0
      if (sprintf_s(file->GatewayHostname, (size_t)length + 1, "%s:%" PRIu32, GatewayHostname,
1239
0
                    GatewayPort) < 0)
1240
0
        return FALSE;
1241
0
    }
1242
0
    if (!file->GatewayHostname)
1243
0
      return FALSE;
1244
0
  }
1245
1246
0
  if (freerdp_settings_get_bool(settings, FreeRDP_GatewayArmTransport))
1247
0
    file->ResourceProvider = _strdup(str_resourceprovider_arm);
1248
1249
0
  if (!rdp_opt_duplicate(settings, FreeRDP_GatewayAvdWvdEndpointPool, &file->WvdEndpointPool))
1250
0
    return FALSE;
1251
0
  if (!rdp_opt_duplicate(settings, FreeRDP_GatewayAvdGeo, &file->geo))
1252
0
    return FALSE;
1253
0
  if (!rdp_opt_duplicate(settings, FreeRDP_GatewayAvdArmpath, &file->armpath))
1254
0
    return FALSE;
1255
0
  if (!rdp_opt_duplicate(settings, FreeRDP_GatewayAvdAadtenantid, &file->aadtenantid))
1256
0
    return FALSE;
1257
0
  if (!rdp_opt_duplicate(settings, FreeRDP_GatewayAvdDiagnosticserviceurl,
1258
0
                         &file->diagnosticserviceurl))
1259
0
    return FALSE;
1260
0
  if (!rdp_opt_duplicate(settings, FreeRDP_GatewayAvdHubdiscoverygeourl,
1261
0
                         &file->hubdiscoverygeourl))
1262
0
    return FALSE;
1263
0
  if (!rdp_opt_duplicate(settings, FreeRDP_GatewayAvdActivityhint, &file->activityhint))
1264
0
    return FALSE;
1265
1266
0
  file->AudioCaptureMode =
1267
0
      WINPR_ASSERTING_INT_CAST(UINT32, freerdp_settings_get_bool(settings, FreeRDP_AudioCapture));
1268
0
  file->BitmapCachePersistEnable = WINPR_ASSERTING_INT_CAST(
1269
0
      UINT32, freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled));
1270
0
  file->Compression = WINPR_ASSERTING_INT_CAST(
1271
0
      UINT32, freerdp_settings_get_bool(settings, FreeRDP_CompressionEnabled));
1272
0
  file->AuthenticationLevel = freerdp_settings_get_uint32(settings, FreeRDP_AuthenticationLevel);
1273
0
  file->GatewayUsageMethod = freerdp_get_gateway_usage_method(settings);
1274
0
  file->GatewayCredentialsSource =
1275
0
      freerdp_settings_get_uint32(settings, FreeRDP_GatewayCredentialsSource);
1276
0
  file->PromptCredentialOnce = WINPR_ASSERTING_INT_CAST(
1277
0
      UINT32, freerdp_settings_get_bool(settings, FreeRDP_GatewayUseSameCredentials));
1278
0
  file->PromptForCredentials = WINPR_ASSERTING_INT_CAST(
1279
0
      UINT32, freerdp_settings_get_bool(settings, FreeRDP_PromptForCredentials));
1280
0
  file->RemoteApplicationMode = WINPR_ASSERTING_INT_CAST(
1281
0
      UINT32, freerdp_settings_get_bool(settings, FreeRDP_RemoteApplicationMode));
1282
0
  if (!FILE_POPULATE_STRING(&file->GatewayAccessToken, settings, FreeRDP_GatewayAccessToken) ||
1283
0
      !FILE_POPULATE_STRING(&file->EndpointFedAuthToken, settings,
1284
0
                            FreeRDP_EndpointFedAuthToken) ||
1285
0
      !FILE_POPULATE_STRING(&file->RemoteApplicationProgram, settings,
1286
0
                            FreeRDP_RemoteApplicationProgram) ||
1287
0
      !FILE_POPULATE_STRING(&file->RemoteApplicationName, settings,
1288
0
                            FreeRDP_RemoteApplicationName) ||
1289
0
      !FILE_POPULATE_STRING(&file->RemoteApplicationIcon, settings,
1290
0
                            FreeRDP_RemoteApplicationIcon) ||
1291
0
      !FILE_POPULATE_STRING(&file->RemoteApplicationFile, settings,
1292
0
                            FreeRDP_RemoteApplicationFile) ||
1293
0
      !FILE_POPULATE_STRING(&file->RemoteApplicationGuid, settings,
1294
0
                            FreeRDP_RemoteApplicationGuid) ||
1295
0
      !FILE_POPULATE_STRING(&file->RemoteApplicationCmdLine, settings,
1296
0
                            FreeRDP_RemoteApplicationCmdLine))
1297
0
    return FALSE;
1298
0
  file->SpanMonitors =
1299
0
      WINPR_ASSERTING_INT_CAST(UINT32, freerdp_settings_get_bool(settings, FreeRDP_SpanMonitors));
1300
0
  file->UseMultiMon =
1301
0
      WINPR_ASSERTING_INT_CAST(UINT32, freerdp_settings_get_bool(settings, FreeRDP_UseMultimon));
1302
0
  file->AllowDesktopComposition = WINPR_ASSERTING_INT_CAST(
1303
0
      UINT32, freerdp_settings_get_bool(settings, FreeRDP_AllowDesktopComposition));
1304
0
  file->AllowFontSmoothing = WINPR_ASSERTING_INT_CAST(
1305
0
      UINT32, freerdp_settings_get_bool(settings, FreeRDP_AllowFontSmoothing));
1306
0
  file->DisableWallpaper = WINPR_ASSERTING_INT_CAST(
1307
0
      UINT32, freerdp_settings_get_bool(settings, FreeRDP_DisableWallpaper));
1308
0
  file->DisableFullWindowDrag = WINPR_ASSERTING_INT_CAST(
1309
0
      UINT32, freerdp_settings_get_bool(settings, FreeRDP_DisableFullWindowDrag));
1310
0
  file->DisableMenuAnims = WINPR_ASSERTING_INT_CAST(
1311
0
      UINT32, freerdp_settings_get_bool(settings, FreeRDP_DisableMenuAnims));
1312
0
  file->DisableThemes = WINPR_ASSERTING_INT_CAST(
1313
0
      UINT32, freerdp_settings_get_bool(settings, FreeRDP_DisableThemes));
1314
0
  file->BandwidthAutoDetect = (freerdp_settings_get_uint32(settings, FreeRDP_ConnectionType) >=
1315
0
                               CONNECTION_TYPE_AUTODETECT);
1316
0
  file->NetworkAutoDetect =
1317
0
      freerdp_settings_get_bool(settings, FreeRDP_NetworkAutoDetect) ? 1 : 0;
1318
0
  file->AutoReconnectionEnabled = WINPR_ASSERTING_INT_CAST(
1319
0
      UINT32, freerdp_settings_get_bool(settings, FreeRDP_AutoReconnectionEnabled));
1320
0
  file->RedirectSmartCards = WINPR_ASSERTING_INT_CAST(
1321
0
      UINT32, freerdp_settings_get_bool(settings, FreeRDP_RedirectSmartCards));
1322
0
  file->RedirectWebauthN = WINPR_ASSERTING_INT_CAST(
1323
0
      UINT32, freerdp_settings_get_bool(settings, FreeRDP_RedirectWebAuthN));
1324
1325
0
  redirectCameras =
1326
0
      freerdp_client_channel_args_to_string(settings, RDPECAM_DVC_CHANNEL_NAME, "device:");
1327
0
  if (redirectCameras)
1328
0
  {
1329
0
    char* str =
1330
0
        freerdp_client_channel_args_to_string(settings, RDPECAM_DVC_CHANNEL_NAME, "encode:");
1331
0
    file->EncodeRedirectedVideoCapture = 0;
1332
0
    if (str)
1333
0
    {
1334
0
      unsigned long val = 0;
1335
0
      errno = 0;
1336
0
      val = strtoul(str, nullptr, 0);
1337
0
      if ((val < UINT32_MAX) && (errno == 0))
1338
0
        file->EncodeRedirectedVideoCapture = (UINT32)val;
1339
0
    }
1340
0
    free(str);
1341
1342
0
    str = freerdp_client_channel_args_to_string(settings, RDPECAM_DVC_CHANNEL_NAME, "quality:");
1343
0
    file->RedirectedVideoCaptureEncodingQuality = 0;
1344
0
    if (str)
1345
0
    {
1346
0
      unsigned long val = 0;
1347
0
      errno = 0;
1348
0
      val = strtoul(str, nullptr, 0);
1349
0
      if ((val <= 2) && (errno == 0))
1350
0
      {
1351
0
        file->RedirectedVideoCaptureEncodingQuality = (UINT32)val;
1352
0
      }
1353
0
    }
1354
0
    free(str);
1355
1356
0
    file->RedirectCameras = redirectCameras;
1357
0
  }
1358
0
  else
1359
0
    freerdp_client_file_string_reset(&file->RedirectCameras);
1360
1361
#ifdef CHANNEL_URBDRC_CLIENT
1362
  char* redirectUsb =
1363
      freerdp_client_channel_args_to_string(settings, URBDRC_CHANNEL_NAME, "device:");
1364
  if (redirectUsb)
1365
    file->UsbDevicesToRedirect = redirectUsb;
1366
  else
1367
    freerdp_client_file_string_reset(&file->UsbDevicesToRedirect);
1368
#endif
1369
1370
0
  file->RedirectClipboard =
1371
0
      freerdp_settings_get_bool(settings, FreeRDP_RedirectClipboard) ? 1 : 0;
1372
0
  file->RedirectPrinters = freerdp_settings_get_bool(settings, FreeRDP_RedirectPrinters) ? 1 : 0;
1373
0
  file->RedirectDrives = freerdp_settings_get_bool(settings, FreeRDP_RedirectDrives) ? 1 : 0;
1374
0
  file->RdgIsKdcProxy = freerdp_settings_get_bool(settings, FreeRDP_KerberosRdgIsProxy) ? 1 : 0;
1375
0
  file->RedirectComPorts = (freerdp_settings_get_bool(settings, FreeRDP_RedirectSerialPorts) ||
1376
0
                            freerdp_settings_get_bool(settings, FreeRDP_RedirectParallelPorts));
1377
0
  file->RedirectLocation =
1378
0
      (freerdp_dynamic_channel_collection_find(settings, LOCATION_CHANNEL_NAME) != nullptr);
1379
0
  if (!FILE_POPULATE_STRING(&file->DrivesToRedirect, settings, FreeRDP_DrivesToRedirect) ||
1380
0
      !FILE_POPULATE_STRING(&file->PreconnectionBlob, settings, FreeRDP_PreconnectionBlob) ||
1381
0
      !FILE_POPULATE_STRING(&file->KdcProxyName, settings, FreeRDP_KerberosKdcUrl))
1382
0
    return FALSE;
1383
1384
0
  {
1385
0
    size_t offset = 0;
1386
0
    UINT32 count = freerdp_settings_get_uint32(settings, FreeRDP_NumMonitorIds);
1387
0
    const UINT32* MonitorIds = freerdp_settings_get_pointer(settings, FreeRDP_MonitorIds);
1388
    /* String size: 10 char UINT32 max string length, 1 char separator, one element nullptr */
1389
0
    size_t size = count * (10 + 1) + 1;
1390
1391
0
    char* str = calloc(size, sizeof(char));
1392
0
    for (UINT32 x = 0; x < count; x++)
1393
0
    {
1394
0
      int rc = _snprintf(&str[offset], size - offset, "%" PRIu32 ",", MonitorIds[x]);
1395
0
      if (rc <= 0)
1396
0
      {
1397
0
        free(str);
1398
0
        return FALSE;
1399
0
      }
1400
0
      offset += (size_t)rc;
1401
0
    }
1402
0
    if (offset > 0)
1403
0
      str[offset - 1] = '\0';
1404
0
    freerdp_client_file_string_check_free(file->SelectedMonitors);
1405
0
    file->SelectedMonitors = str;
1406
0
  }
1407
1408
0
  file->KeyboardHook = freerdp_settings_get_uint32(settings, FreeRDP_KeyboardHook);
1409
1410
0
  return TRUE;
1411
0
}
1412
1413
BOOL freerdp_client_write_rdp_file(const rdpFile* file, const char* name, BOOL unicode)
1414
0
{
1415
0
  int status = 0;
1416
0
  WCHAR* unicodestr = nullptr;
1417
1418
0
  if (!file || !name)
1419
0
    return FALSE;
1420
1421
0
  const size_t size = freerdp_client_write_rdp_file_buffer(file, nullptr, 0);
1422
0
  if (size == 0)
1423
0
    return FALSE;
1424
0
  char* buffer = calloc(size + 1ULL, sizeof(char));
1425
0
  if (!buffer)
1426
0
    return FALSE;
1427
1428
0
  if (freerdp_client_write_rdp_file_buffer(file, buffer, size + 1) != size)
1429
0
  {
1430
0
    WLog_ERR(TAG, "freerdp_client_write_rdp_file: error writing to output buffer");
1431
0
    free(buffer);
1432
0
    return FALSE;
1433
0
  }
1434
1435
0
  FILE* fp = winpr_fopen(name, "w+b");
1436
1437
0
  if (fp)
1438
0
  {
1439
0
    if (unicode)
1440
0
    {
1441
0
      size_t len = 0;
1442
0
      unicodestr = ConvertUtf8NToWCharAlloc(buffer, size, &len);
1443
1444
0
      if (!unicodestr)
1445
0
      {
1446
0
        free(buffer);
1447
0
        (void)fclose(fp);
1448
0
        return FALSE;
1449
0
      }
1450
1451
      /* Write multi-byte header */
1452
0
      if ((fwrite(BOM_UTF16_LE, sizeof(BYTE), 2, fp) != 2) ||
1453
0
          (fwrite(unicodestr, sizeof(WCHAR), len, fp) != len))
1454
0
      {
1455
0
        free(buffer);
1456
0
        free(unicodestr);
1457
0
        (void)fclose(fp);
1458
0
        return FALSE;
1459
0
      }
1460
1461
0
      free(unicodestr);
1462
0
    }
1463
0
    else
1464
0
    {
1465
0
      if (fwrite(buffer, 1, size, fp) != size)
1466
0
      {
1467
0
        free(buffer);
1468
0
        (void)fclose(fp);
1469
0
        return FALSE;
1470
0
      }
1471
0
    }
1472
1473
0
    (void)fflush(fp);
1474
0
    status = fclose(fp);
1475
0
  }
1476
1477
0
  free(buffer);
1478
0
  return (status == 0);
1479
0
}
1480
1481
WINPR_ATTR_FORMAT_ARG(3, 4)
1482
static SSIZE_T freerdp_client_write_setting_to_buffer(char** buffer, size_t* bufferSize,
1483
                                                      WINPR_FORMAT_ARG const char* fmt, ...)
1484
0
{
1485
0
  va_list ap = WINPR_C_ARRAY_INIT;
1486
0
  SSIZE_T len = 0;
1487
0
  char* buf = nullptr;
1488
0
  size_t bufSize = 0;
1489
1490
0
  if (!buffer || !bufferSize || !fmt)
1491
0
    return -1;
1492
1493
0
  buf = *buffer;
1494
0
  bufSize = *bufferSize;
1495
1496
0
  va_start(ap, fmt);
1497
0
  len = vsnprintf(buf, bufSize, fmt, ap);
1498
0
  va_end(ap);
1499
0
  if (len < 0)
1500
0
    return -1;
1501
1502
  /* _snprintf doesn't add the ending \0 to its return value */
1503
0
  ++len;
1504
1505
  /* we just want to know the size - return it */
1506
0
  if (!buf && !bufSize)
1507
0
    return len;
1508
1509
0
  if (!buf)
1510
0
    return -1;
1511
1512
  /* update buffer size and buffer position and replace \0 with \n */
1513
0
  if (bufSize >= (size_t)len)
1514
0
  {
1515
0
    *bufferSize -= (size_t)len;
1516
0
    buf[len - 1] = '\n';
1517
0
    *buffer = buf + len;
1518
0
  }
1519
0
  else
1520
0
    return -1;
1521
1522
0
  return len;
1523
0
}
1524
1525
WINPR_ATTR_NODISCARD
1526
static SSIZE_T write_int_parameters(const rdpFile* file, char* buffer, size_t size)
1527
0
{
1528
0
  WINPR_ASSERT(file);
1529
1530
0
  struct intentry_t
1531
0
  {
1532
0
    const char* key;
1533
0
    DWORD val;
1534
0
  };
1535
0
  const struct intentry_t settings[] = {
1536
0
    { key_int_use_multimon, file->UseMultiMon },
1537
0
    { key_int_maximizetocurrentdisplays, file->MaximizeToCurrentDisplays },
1538
0
    { key_int_singlemoninwindowedmode, file->SingleMonInWindowedMode },
1539
0
    { key_int_screen_mode_id, file->ScreenModeId },
1540
0
    { key_int_span_monitors, file->SpanMonitors },
1541
0
    { key_int_smart_sizing, file->SmartSizing },
1542
0
    { key_int_dynamic_resolution, file->DynamicResolution },
1543
0
    { key_int_enablesuperpan, file->EnableSuperSpan },
1544
0
    { key_int_superpanaccelerationfactor, file->SuperSpanAccelerationFactor },
1545
0
    { key_int_desktopwidth, file->DesktopWidth },
1546
0
    { key_int_desktopheight, file->DesktopHeight },
1547
0
    { key_int_desktop_size_id, file->DesktopSizeId },
1548
0
    { key_int_session_bpp, file->SessionBpp },
1549
0
    { key_int_desktopscalefactor, file->DesktopScaleFactor },
1550
0
    { key_int_compression, file->Compression },
1551
0
    { key_int_keyboardhook, file->KeyboardHook },
1552
0
    { key_int_disable_ctrl_alt_del, file->DisableCtrlAltDel },
1553
0
    { key_int_audiomode, file->AudioMode },
1554
0
    { key_int_audioqualitymode, file->AudioQualityMode },
1555
0
    { key_int_audiocapturemode, file->AudioCaptureMode },
1556
0
    { key_int_encode_redirected_video_capture, file->EncodeRedirectedVideoCapture },
1557
0
    { key_int_redirected_video_capture_encoding_quality,
1558
0
      file->RedirectedVideoCaptureEncodingQuality },
1559
0
    { key_int_videoplaybackmode, file->VideoPlaybackMode },
1560
0
    { key_int_connection_type, file->ConnectionType },
1561
0
    { key_int_networkautodetect, file->NetworkAutoDetect },
1562
0
    { key_int_bandwidthautodetect, file->BandwidthAutoDetect },
1563
0
    { key_int_pinconnectionbar, file->PinConnectionBar },
1564
0
    { key_int_displayconnectionbar, file->DisplayConnectionBar },
1565
0
    { key_int_workspaceid, file->WorkspaceId },
1566
0
    { key_int_enableworkspacereconnect, file->EnableWorkspaceReconnect },
1567
0
    { key_int_disable_wallpaper, file->DisableWallpaper },
1568
0
    { key_int_allow_font_smoothing, file->AllowFontSmoothing },
1569
0
    { key_int_allow_desktop_composition, file->AllowDesktopComposition },
1570
0
    { key_int_disable_full_window_drag, file->DisableFullWindowDrag },
1571
0
    { key_int_disable_menu_anims, file->DisableMenuAnims },
1572
0
    { key_int_disable_themes, file->DisableThemes },
1573
0
    { key_int_disable_cursor_setting, file->DisableCursorSetting },
1574
0
    { key_int_bitmapcachesize, file->BitmapCacheSize },
1575
0
    { key_int_bitmapcachepersistenable, file->BitmapCachePersistEnable },
1576
0
    { key_int_server_port, file->ServerPort },
1577
0
    { key_int_redirectdrives, file->RedirectDrives },
1578
0
    { key_int_redirectprinters, file->RedirectPrinters },
1579
0
    { key_int_redirectcomports, file->RedirectComPorts },
1580
0
    { key_int_redirectlocation, file->RedirectLocation },
1581
0
    { key_int_redirectsmartcards, file->RedirectSmartCards },
1582
0
    { key_int_redirectclipboard, file->RedirectClipboard },
1583
0
    { key_int_redirectposdevices, file->RedirectPosDevices },
1584
0
    { key_int_redirectdirectx, file->RedirectDirectX },
1585
0
    { key_int_disableprinterredirection, file->DisablePrinterRedirection },
1586
0
    { key_int_disableclipboardredirection, file->DisableClipboardRedirection },
1587
0
    { key_int_connect_to_console, file->ConnectToConsole },
1588
0
    { key_int_administrative_session, file->AdministrativeSession },
1589
0
    { key_int_autoreconnection_enabled, file->AutoReconnectionEnabled },
1590
0
    { key_int_autoreconnect_max_retries, file->AutoReconnectMaxRetries },
1591
0
    { key_int_public_mode, file->PublicMode },
1592
0
    { key_int_authentication_level, file->AuthenticationLevel },
1593
0
    { key_int_promptcredentialonce, file->PromptCredentialOnce },
1594
0
    { key_int_prompt_for_credentials, file->PromptForCredentials },
1595
0
    { key_int_negotiate_security_layer, file->NegotiateSecurityLayer },
1596
0
    { key_int_enablecredsspsupport, file->EnableCredSSPSupport },
1597
0
    { key_int_enablerdsaadauth, file->EnableRdsAadAuth },
1598
0
    { key_int_remoteapplicationmode, file->RemoteApplicationMode },
1599
0
    { key_int_remoteapplicationexpandcmdline, file->RemoteApplicationExpandCmdLine },
1600
0
    { key_int_remoteapplicationexpandworkingdir, file->RemoteApplicationExpandWorkingDir },
1601
0
    { key_int_disableconnectionsharing, file->DisableConnectionSharing },
1602
0
    { key_int_disableremoteappcapscheck, file->DisableRemoteAppCapsCheck },
1603
0
    { key_int_gatewayusagemethod, file->GatewayUsageMethod },
1604
0
    { key_int_gatewayprofileusagemethod, file->GatewayProfileUsageMethod },
1605
0
    { key_int_gatewaycredentialssource, file->GatewayCredentialsSource },
1606
0
    { key_int_use_redirection_server_name, file->UseRedirectionServerName },
1607
0
    { key_int_rdgiskdcproxy, file->RdgIsKdcProxy },
1608
0
    { key_int_redirectwebauthn, file->RedirectWebauthN }
1609
0
  };
1610
1611
0
  SSIZE_T totalSize = 0;
1612
0
  for (size_t x = 0; x < ARRAYSIZE(settings); x++)
1613
0
  {
1614
0
    const struct intentry_t* cur = &settings[x];
1615
0
    if (~cur->val)
1616
0
    {
1617
0
      const SSIZE_T res = freerdp_client_write_setting_to_buffer(
1618
0
          &buffer, &size, "%s:i:%" PRIu32, cur->key, cur->val);
1619
0
      if (res < 0)
1620
0
        return res;
1621
0
      totalSize += res;
1622
0
    }
1623
0
  }
1624
1625
0
  return totalSize;
1626
0
}
1627
1628
WINPR_ATTR_NODISCARD
1629
static SSIZE_T write_string_parameters(const rdpFile* file, char* buffer, size_t size)
1630
0
{
1631
0
  WINPR_ASSERT(file);
1632
1633
0
  struct strentry_t
1634
0
  {
1635
0
    const char* key;
1636
0
    const char* val;
1637
0
  };
1638
0
  const struct strentry_t settings[] = {
1639
0
    { key_str_username, file->Username },
1640
0
    { key_str_domain, file->Domain },
1641
0
    { key_str_password, file->Password },
1642
0
    { key_str_full_address, file->FullAddress },
1643
0
    { key_str_alternate_full_address, file->AlternateFullAddress },
1644
0
    { key_str_usbdevicestoredirect, file->UsbDevicesToRedirect },
1645
0
    { key_str_camerastoredirect, file->RedirectCameras },
1646
0
    { key_str_loadbalanceinfo, file->LoadBalanceInfo },
1647
0
    { key_str_remoteapplicationname, file->RemoteApplicationName },
1648
0
    { key_str_remoteapplicationicon, file->RemoteApplicationIcon },
1649
0
    { key_str_remoteapplicationprogram, file->RemoteApplicationProgram },
1650
0
    { key_str_remoteapplicationfile, file->RemoteApplicationFile },
1651
0
    { key_str_remoteapplicationguid, file->RemoteApplicationGuid },
1652
0
    { key_str_remoteapplicationcmdline, file->RemoteApplicationCmdLine },
1653
0
    { key_str_alternate_shell, file->AlternateShell },
1654
0
    { key_str_shell_working_directory, file->ShellWorkingDirectory },
1655
0
    { key_str_gatewayhostname, file->GatewayHostname },
1656
0
    { key_str_resourceprovider, file->ResourceProvider },
1657
0
    { key_str_wvd, file->WvdEndpointPool },
1658
0
    { key_str_geo, file->geo },
1659
0
    { key_str_armpath, file->armpath },
1660
0
    { key_str_aadtenantid, file->aadtenantid },
1661
0
    { key_str_diagnosticserviceurl, file->diagnosticserviceurl },
1662
0
    { key_str_hubdiscoverygeourl, file->hubdiscoverygeourl },
1663
0
    { key_str_activityhint, file->activityhint },
1664
0
    { key_str_gatewayaccesstoken, file->GatewayAccessToken },
1665
0
    { key_str_endpointfedauth, file->EndpointFedAuthToken },
1666
0
    { key_str_kdcproxyname, file->KdcProxyName },
1667
0
    { key_str_drivestoredirect, file->DrivesToRedirect },
1668
0
    { key_str_devicestoredirect, file->DevicesToRedirect },
1669
0
    { key_str_winposstr, file->WinPosStr },
1670
0
    { key_str_pcb, file->PreconnectionBlob },
1671
0
    { key_str_selectedmonitors, file->SelectedMonitors }
1672
0
  };
1673
1674
0
  SSIZE_T totalSize = 0;
1675
0
  for (size_t x = 0; x < ARRAYSIZE(settings); x++)
1676
0
  {
1677
0
    const struct strentry_t* cur = &settings[x];
1678
0
    if (~(size_t)(cur->val))
1679
0
    {
1680
0
      const SSIZE_T res = freerdp_client_write_setting_to_buffer(&buffer, &size, "%s:s:%s",
1681
0
                                                                 cur->key, cur->val);
1682
0
      if (res < 0)
1683
0
        return res;
1684
0
      totalSize += res;
1685
0
    }
1686
0
  }
1687
1688
0
  return totalSize;
1689
0
}
1690
1691
WINPR_ATTR_NODISCARD
1692
static SSIZE_T write_custom_parameters(const rdpFile* file, char* buffer, size_t size)
1693
0
{
1694
0
  WINPR_ASSERT(file);
1695
1696
0
  SSIZE_T totalSize = 0;
1697
  /* custom parameters */
1698
0
  for (size_t i = 0; i < file->lineCount; ++i)
1699
0
  {
1700
0
    SSIZE_T res = -1;
1701
0
    const rdpFileLine* curLine = &file->lines[i];
1702
1703
0
    if (curLine->flags & RDP_FILE_LINE_FLAG_TYPE_INTEGER)
1704
0
      res = freerdp_client_write_setting_to_buffer(&buffer, &size, "%s:i:%" PRIu32,
1705
0
                                                   curLine->name, (UINT32)curLine->iValue);
1706
0
    else if (curLine->flags & RDP_FILE_LINE_FLAG_TYPE_STRING)
1707
0
      res = freerdp_client_write_setting_to_buffer(&buffer, &size, "%s:s:%s", curLine->name,
1708
0
                                                   curLine->sValue);
1709
0
    if (res < 0)
1710
0
      return res;
1711
1712
0
    totalSize += res;
1713
0
  }
1714
0
  return totalSize;
1715
0
}
1716
1717
size_t freerdp_client_write_rdp_file_buffer(const rdpFile* file, char* buffer, size_t size)
1718
0
{
1719
0
  size_t totalSize = 0;
1720
1721
0
  if (!file)
1722
0
    return 0;
1723
1724
  /* either buffer and size are null or non-null */
1725
0
  if ((!buffer || !size) && (buffer || size))
1726
0
    return 0;
1727
1728
  /* integer parameters */
1729
0
  const SSIZE_T intsize = write_int_parameters(file, buffer, size);
1730
0
  if (intsize < 0)
1731
0
    return 0;
1732
0
  totalSize += (size_t)intsize;
1733
0
  if (buffer)
1734
0
    buffer += intsize;
1735
1736
  /* string parameters */
1737
0
  const SSIZE_T stringsize = write_string_parameters(file, buffer, size);
1738
0
  if (stringsize < 0)
1739
0
    return 0;
1740
0
  totalSize += (size_t)stringsize;
1741
0
  if (buffer)
1742
0
    buffer += stringsize;
1743
1744
  /* custom parameters */
1745
0
  const SSIZE_T customsize = write_custom_parameters(file, buffer, size);
1746
0
  if (customsize < 0)
1747
0
    return 0;
1748
0
  totalSize += (size_t)customsize;
1749
0
  return totalSize;
1750
0
}
1751
1752
WINPR_ATTR_MALLOC(freerdp_addin_argv_free, 1)
1753
static ADDIN_ARGV* rdp_file_to_args(const char* channel, const char* values)
1754
0
{
1755
0
  size_t count = 0;
1756
0
  char** p = nullptr;
1757
0
  ADDIN_ARGV* args = freerdp_addin_argv_new(0, nullptr);
1758
0
  if (!args)
1759
0
    return nullptr;
1760
0
  if (!freerdp_addin_argv_add_argument(args, channel))
1761
0
    goto fail;
1762
0
1763
0
  p = CommandLineParseCommaSeparatedValues(values, &count);
1764
0
  for (size_t x = 0; x < count; x++)
1765
0
  {
1766
0
    BOOL rc = 0;
1767
0
    const char* val = p[x];
1768
0
    const size_t len = strlen(val) + 8;
1769
0
    char* str = calloc(len, sizeof(char));
1770
0
    if (!str)
1771
0
      goto fail;
1772
0
1773
0
    (void)_snprintf(str, len, "device:%s", val);
1774
0
    rc = freerdp_addin_argv_add_argument(args, str);
1775
0
    free(str);
1776
0
    if (!rc)
1777
0
      goto fail;
1778
0
  }
1779
0
  CommandLineParserFree(p);
1780
0
  return args;
1781
0
1782
0
fail:
1783
0
  CommandLineParserFree(p);
1784
0
  freerdp_addin_argv_free(args);
1785
0
  return nullptr;
1786
0
}
1787
1788
BOOL freerdp_client_populate_settings_from_rdp_file_unchecked(const rdpFile* file,
1789
                                                              rdpSettings* settings)
1790
24.1k
{
1791
24.1k
  if (!file || !settings)
1792
0
    return FALSE;
1793
1794
  /* Start with connection type.
1795
   * This setting initializes certain defaults which might be overridden by later options.
1796
   */
1797
24.1k
  if (~file->BandwidthAutoDetect)
1798
154
  {
1799
154
    if (file->BandwidthAutoDetect != 0)
1800
102
    {
1801
102
      if ((~file->NetworkAutoDetect) && (file->NetworkAutoDetect == 0))
1802
2
      {
1803
2
        WLog_WARN(TAG,
1804
2
                  "Got networkautodetect:i:%" PRIu32 " and bandwidthautodetect:i:%" PRIu32
1805
2
                  ". Correcting to networkautodetect:i:1",
1806
2
                  file->NetworkAutoDetect, file->BandwidthAutoDetect);
1807
2
        WLog_WARN(TAG,
1808
2
                  "Add networkautodetect:i:1 to your RDP file to eliminate this warning.");
1809
2
      }
1810
102
    }
1811
154
    if (!freerdp_settings_set_bool(settings, FreeRDP_NetworkAutoDetect,
1812
154
                                   (file->BandwidthAutoDetect != 0) ||
1813
52
                                       (file->NetworkAutoDetect != 0)))
1814
0
      return FALSE;
1815
154
  }
1816
1817
24.1k
  if (~file->NetworkAutoDetect)
1818
184
  {
1819
184
    if (file->NetworkAutoDetect != 0)
1820
174
    {
1821
174
      if ((~file->BandwidthAutoDetect) && (file->BandwidthAutoDetect == 0))
1822
30
      {
1823
30
        WLog_WARN(TAG,
1824
30
                  "Got networkautodetect:i:%" PRIu32 " and bandwidthautodetect:i:%" PRIu32
1825
30
                  ". Correcting to bandwidthautodetect:i:1",
1826
30
                  file->NetworkAutoDetect, file->BandwidthAutoDetect);
1827
30
        WLog_WARN(
1828
30
            TAG, "Add bandwidthautodetect:i:1 to your RDP file to eliminate this warning.");
1829
30
      }
1830
174
    }
1831
184
    if (!freerdp_settings_set_bool(settings, FreeRDP_NetworkAutoDetect,
1832
184
                                   (file->BandwidthAutoDetect != 0) ||
1833
34
                                       (file->NetworkAutoDetect != 0)))
1834
0
      return FALSE;
1835
184
  }
1836
1837
24.1k
  if (is_pointer_used(file->Domain))
1838
44
  {
1839
44
    if (!freerdp_settings_set_string(settings, FreeRDP_Domain, file->Domain))
1840
0
      return FALSE;
1841
44
  }
1842
1843
24.1k
  if (is_pointer_used(file->Username))
1844
74
  {
1845
74
    char* user = nullptr;
1846
74
    char* domain = nullptr;
1847
1848
74
    if (!freerdp_parse_username(file->Username, &user, &domain))
1849
0
      return FALSE;
1850
1851
74
    if (!freerdp_settings_set_string(settings, FreeRDP_Username, user))
1852
0
      return FALSE;
1853
1854
74
    if (!(is_pointer_used(file->Domain)) && domain)
1855
16
    {
1856
16
      if (!freerdp_settings_set_string(settings, FreeRDP_Domain, domain))
1857
0
        return FALSE;
1858
16
    }
1859
1860
74
    free(user);
1861
74
    free(domain);
1862
74
  }
1863
1864
24.1k
  if (is_pointer_used(file->Password))
1865
16
  {
1866
16
    if (!freerdp_settings_set_string(settings, FreeRDP_Password, file->Password))
1867
0
      return FALSE;
1868
16
  }
1869
1870
24.1k
  {
1871
24.1k
    const char* address = nullptr;
1872
1873
    /* With MSTSC alternate full address always wins,
1874
     * so mimic this. */
1875
24.1k
    if (is_pointer_used(file->AlternateFullAddress))
1876
26
      address = file->AlternateFullAddress;
1877
24.0k
    else if (is_pointer_used(file->FullAddress))
1878
210
      address = file->FullAddress;
1879
1880
24.1k
    if (address)
1881
236
    {
1882
236
      int port = -1;
1883
236
      char* host = nullptr;
1884
1885
236
      if (!freerdp_parse_hostname(address, &host, &port))
1886
148
        return FALSE;
1887
1888
88
      const BOOL rc = freerdp_settings_set_string(settings, FreeRDP_ServerHostname, host);
1889
88
      free(host);
1890
88
      if (!rc)
1891
0
        return FALSE;
1892
1893
88
      if (port > 0)
1894
40
      {
1895
40
        if (!freerdp_settings_set_uint32(settings, FreeRDP_ServerPort, (UINT32)port))
1896
0
          return FALSE;
1897
40
      }
1898
88
    }
1899
24.1k
  }
1900
1901
23.9k
  if (~file->ServerPort)
1902
68
  {
1903
68
    if (!freerdp_settings_set_uint32(settings, FreeRDP_ServerPort, file->ServerPort))
1904
0
      return FALSE;
1905
68
  }
1906
1907
23.9k
  if (~file->DesktopSizeId)
1908
180
  {
1909
180
    switch (file->DesktopSizeId)
1910
180
    {
1911
28
      case 0:
1912
28
        if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, 640))
1913
0
          return FALSE;
1914
28
        if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, 480))
1915
0
          return FALSE;
1916
28
        break;
1917
28
      case 1:
1918
16
        if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, 800))
1919
0
          return FALSE;
1920
16
        if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, 600))
1921
0
          return FALSE;
1922
16
        break;
1923
16
      case 2:
1924
6
        if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, 1024))
1925
0
          return FALSE;
1926
6
        if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, 768))
1927
0
          return FALSE;
1928
6
        break;
1929
6
      case 3:
1930
6
        if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, 1280))
1931
0
          return FALSE;
1932
6
        if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, 1024))
1933
0
          return FALSE;
1934
6
        break;
1935
6
      case 4:
1936
4
        if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, 1600))
1937
0
          return FALSE;
1938
4
        if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, 1200))
1939
0
          return FALSE;
1940
4
        break;
1941
120
      default:
1942
120
        WLog_WARN(TAG, "Unsupported 'desktop size id' value %" PRIu32, file->DesktopSizeId);
1943
120
        break;
1944
180
    }
1945
180
  }
1946
1947
23.9k
  if (~file->DesktopWidth)
1948
108
  {
1949
108
    if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, file->DesktopWidth))
1950
0
      return FALSE;
1951
108
  }
1952
1953
23.9k
  if (~file->DesktopHeight)
1954
80
  {
1955
80
    if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, file->DesktopHeight))
1956
0
      return FALSE;
1957
80
  }
1958
1959
23.9k
  if (~file->SessionBpp)
1960
42
  {
1961
42
    if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, file->SessionBpp))
1962
0
      return FALSE;
1963
42
  }
1964
1965
23.9k
  if (~file->ConnectToConsole)
1966
82
  {
1967
82
    if (!freerdp_settings_set_bool(settings, FreeRDP_ConsoleSession,
1968
82
                                   file->ConnectToConsole != 0))
1969
0
      return FALSE;
1970
82
  }
1971
1972
23.9k
  if (~file->AdministrativeSession)
1973
88
  {
1974
88
    if (!freerdp_settings_set_bool(settings, FreeRDP_ConsoleSession,
1975
88
                                   file->AdministrativeSession != 0))
1976
0
      return FALSE;
1977
88
  }
1978
1979
23.9k
  if (~file->NegotiateSecurityLayer)
1980
58
  {
1981
58
    if (!freerdp_settings_set_bool(settings, FreeRDP_NegotiateSecurityLayer,
1982
58
                                   file->NegotiateSecurityLayer != 0))
1983
0
      return FALSE;
1984
58
  }
1985
1986
23.9k
  if (~file->EnableCredSSPSupport)
1987
94
  {
1988
94
    if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity,
1989
94
                                   file->EnableCredSSPSupport != 0))
1990
0
      return FALSE;
1991
94
    if (!freerdp_settings_set_bool(settings, FreeRDP_ExtSecurity,
1992
94
                                   file->EnableCredSSPSupport != 0))
1993
0
      return FALSE;
1994
94
  }
1995
1996
23.9k
  if (~file->EnableRdsAadAuth)
1997
70
  {
1998
70
    const BOOL val = file->EnableRdsAadAuth != 0;
1999
70
    if (!freerdp_settings_set_bool(settings, FreeRDP_AadSecurity, val))
2000
0
      return FALSE;
2001
70
  }
2002
2003
23.9k
  if (is_pointer_used(file->AlternateShell))
2004
36
  {
2005
36
    if (!freerdp_settings_set_string(settings, FreeRDP_AlternateShell, file->AlternateShell))
2006
0
      return FALSE;
2007
36
  }
2008
2009
23.9k
  if (is_pointer_used(file->ShellWorkingDirectory))
2010
54
  {
2011
    /* ShellWorkingDir is used for either, shell working dir or remote app working dir */
2012
54
    FreeRDP_Settings_Keys_String targetId =
2013
54
        (~file->RemoteApplicationMode && file->RemoteApplicationMode != 0)
2014
54
            ? FreeRDP_RemoteApplicationWorkingDir
2015
54
            : FreeRDP_ShellWorkingDirectory;
2016
2017
54
    if (!freerdp_settings_set_string(settings, targetId, file->ShellWorkingDirectory))
2018
0
      return FALSE;
2019
54
  }
2020
2021
23.9k
  if (~file->ScreenModeId)
2022
76
  {
2023
    /**
2024
     * Screen Mode Id:
2025
     * http://technet.microsoft.com/en-us/library/ff393692/
2026
     *
2027
     * This setting corresponds to the selection in the Display
2028
     * configuration slider on the Display tab under Options in RDC.
2029
     *
2030
     * Values:
2031
     *
2032
     * 1: The remote session will appear in a window.
2033
     * 2: The remote session will appear full screen.
2034
     */
2035
76
    if (!freerdp_settings_set_bool(settings, FreeRDP_Fullscreen, (file->ScreenModeId == 2)))
2036
0
      return FALSE;
2037
76
  }
2038
2039
23.9k
  if (~(file->SmartSizing))
2040
222
  {
2041
222
    if (!freerdp_settings_set_bool(settings, FreeRDP_SmartSizing, (file->SmartSizing == 1)))
2042
0
      return FALSE;
2043
    /**
2044
     *  SmartSizingWidth and SmartSizingHeight:
2045
     *
2046
     *  Adding this option to use the DesktopHeight and DesktopWidth as
2047
     *  parameters for the SmartSizingWidth and SmartSizingHeight, as there
2048
     *  are no options for that in standard RDP files.
2049
     *
2050
     *  Equivalent of doing /smart-sizing:WxH
2051
     */
2052
222
    if (((~(file->DesktopWidth) && ~(file->DesktopHeight)) || ~(file->DesktopSizeId)) &&
2053
110
        (file->SmartSizing == 1))
2054
14
    {
2055
14
      if (!freerdp_settings_set_uint32(settings, FreeRDP_SmartSizingWidth,
2056
14
                                       file->DesktopWidth))
2057
0
        return FALSE;
2058
14
      if (!freerdp_settings_set_uint32(settings, FreeRDP_SmartSizingHeight,
2059
14
                                       file->DesktopHeight))
2060
0
        return FALSE;
2061
14
    }
2062
222
  }
2063
2064
23.9k
  if (is_pointer_used(file->LoadBalanceInfo))
2065
44
  {
2066
44
    const size_t len = strlen(file->LoadBalanceInfo);
2067
44
    if (!freerdp_settings_set_pointer_len(settings, FreeRDP_LoadBalanceInfo,
2068
44
                                          file->LoadBalanceInfo, len))
2069
0
      return FALSE;
2070
44
  }
2071
2072
23.9k
  if (~file->AuthenticationLevel)
2073
68
  {
2074
    /**
2075
     * Authentication Level:
2076
     * http://technet.microsoft.com/en-us/library/ff393709/
2077
     *
2078
     * This setting corresponds to the selection in the If server authentication
2079
     * fails drop-down list on the Advanced tab under Options in RDC.
2080
     *
2081
     * Values:
2082
     *
2083
     * 0: If server authentication fails, connect to the computer without warning (Connect and
2084
     * don’t warn me). 1: If server authentication fails, do not establish a connection (Do not
2085
     * connect). 2: If server authentication fails, show a warning and allow me to connect or
2086
     * refuse the connection (Warn me). 3: No authentication requirement is specified.
2087
     */
2088
68
    if (!freerdp_settings_set_uint32(settings, FreeRDP_AuthenticationLevel,
2089
68
                                     file->AuthenticationLevel))
2090
0
      return FALSE;
2091
68
  }
2092
2093
23.9k
  if (~file->ConnectionType)
2094
86
  {
2095
86
    if (!freerdp_settings_set_uint32(settings, FreeRDP_ConnectionType, file->ConnectionType))
2096
0
      return FALSE;
2097
86
  }
2098
2099
23.9k
  if (~file->AudioMode)
2100
102
  {
2101
102
    switch (file->AudioMode)
2102
102
    {
2103
4
      case AUDIO_MODE_REDIRECT:
2104
4
        if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteConsoleAudio, FALSE))
2105
0
          return FALSE;
2106
4
        if (!freerdp_settings_set_bool(settings, FreeRDP_AudioPlayback, TRUE))
2107
0
          return FALSE;
2108
4
        break;
2109
10
      case AUDIO_MODE_PLAY_ON_SERVER:
2110
10
        if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteConsoleAudio, TRUE))
2111
0
          return FALSE;
2112
10
        if (!freerdp_settings_set_bool(settings, FreeRDP_AudioPlayback, FALSE))
2113
0
          return FALSE;
2114
10
        break;
2115
14
      case AUDIO_MODE_NONE:
2116
88
      default:
2117
88
        if (!freerdp_settings_set_bool(settings, FreeRDP_AudioPlayback, FALSE))
2118
0
          return FALSE;
2119
88
        if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteConsoleAudio, FALSE))
2120
0
          return FALSE;
2121
88
        break;
2122
102
    }
2123
102
  }
2124
2125
23.9k
  if (~file->AudioCaptureMode)
2126
92
  {
2127
92
    if (!freerdp_settings_set_bool(settings, FreeRDP_AudioCapture, file->AudioCaptureMode != 0))
2128
0
      return FALSE;
2129
92
  }
2130
2131
23.9k
  if (~file->Compression)
2132
86
  {
2133
86
    if (!freerdp_settings_set_bool(settings, FreeRDP_CompressionEnabled,
2134
86
                                   file->Compression != 0))
2135
0
      return FALSE;
2136
86
  }
2137
2138
23.9k
  if (is_pointer_used(file->GatewayHostname))
2139
82
  {
2140
82
    int port = -1;
2141
82
    char* host = nullptr;
2142
2143
82
    if (!freerdp_parse_hostname(file->GatewayHostname, &host, &port))
2144
14
      return FALSE;
2145
2146
68
    const BOOL rc = freerdp_settings_set_string(settings, FreeRDP_GatewayHostname, host);
2147
68
    free(host);
2148
68
    if (!rc)
2149
0
      return FALSE;
2150
2151
68
    if (port > 0)
2152
32
    {
2153
32
      if (!freerdp_settings_set_uint32(settings, FreeRDP_GatewayPort, (UINT32)port))
2154
0
        return FALSE;
2155
32
    }
2156
68
  }
2157
2158
23.9k
  if (is_pointer_used(file->ResourceProvider))
2159
68
  {
2160
68
    if (_stricmp(file->ResourceProvider, str_resourceprovider_arm) == 0)
2161
18
    {
2162
18
      if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayArmTransport, TRUE))
2163
0
        return FALSE;
2164
18
    }
2165
68
  }
2166
2167
23.9k
  if (is_pointer_used(file->WvdEndpointPool))
2168
30
  {
2169
30
    if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAvdWvdEndpointPool,
2170
30
                                     file->WvdEndpointPool))
2171
0
      return FALSE;
2172
30
  }
2173
2174
23.9k
  if (is_pointer_used(file->geo))
2175
40
  {
2176
40
    if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAvdGeo, file->geo))
2177
0
      return FALSE;
2178
40
  }
2179
2180
23.9k
  if (is_pointer_used(file->armpath))
2181
30
  {
2182
30
    if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAvdArmpath, file->armpath))
2183
0
      return FALSE;
2184
30
  }
2185
2186
23.9k
  if (is_pointer_used(file->aadtenantid))
2187
22
  {
2188
22
    if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAvdAadtenantid,
2189
22
                                     file->aadtenantid))
2190
0
      return FALSE;
2191
22
  }
2192
2193
23.9k
  if (is_pointer_used(file->diagnosticserviceurl))
2194
20
  {
2195
20
    if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAvdDiagnosticserviceurl,
2196
20
                                     file->diagnosticserviceurl))
2197
0
      return FALSE;
2198
20
  }
2199
2200
23.9k
  if (is_pointer_used(file->hubdiscoverygeourl))
2201
24
  {
2202
24
    if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAvdHubdiscoverygeourl,
2203
24
                                     file->hubdiscoverygeourl))
2204
0
      return FALSE;
2205
24
  }
2206
2207
23.9k
  if (is_pointer_used(file->activityhint))
2208
22
  {
2209
22
    if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAvdActivityhint,
2210
22
                                     file->activityhint))
2211
0
      return FALSE;
2212
22
  }
2213
2214
23.9k
  if (is_pointer_used(file->GatewayAccessToken))
2215
20
  {
2216
20
    if (!freerdp_settings_set_string(settings, FreeRDP_GatewayAccessToken,
2217
20
                                     file->GatewayAccessToken))
2218
0
      return FALSE;
2219
20
  }
2220
2221
23.9k
  if (is_pointer_used(file->EndpointFedAuthToken))
2222
38
  {
2223
38
    if (!freerdp_settings_set_string(settings, FreeRDP_EndpointFedAuthToken,
2224
38
                                     file->EndpointFedAuthToken))
2225
0
      return FALSE;
2226
38
  }
2227
2228
23.9k
  if (~file->GatewayUsageMethod)
2229
118
  {
2230
118
    if (!freerdp_set_gateway_usage_method(settings, file->GatewayUsageMethod))
2231
0
      return FALSE;
2232
118
  }
2233
2234
23.9k
  if (~file->GatewayCredentialsSource)
2235
66
  {
2236
66
    if (file->GatewayCredentialsSource > 5)
2237
46
    {
2238
46
      WLog_WARN(TAG, "ignoring gatewaycredentialssource value outside range 0..5");
2239
46
    }
2240
20
    else if (!freerdp_settings_set_uint32(settings, FreeRDP_GatewayCredentialsSource,
2241
20
                                          file->GatewayCredentialsSource))
2242
0
      return FALSE;
2243
66
  }
2244
2245
23.9k
  if (~file->PromptCredentialOnce)
2246
58
  {
2247
58
    if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayUseSameCredentials,
2248
58
                                   file->PromptCredentialOnce != 0))
2249
0
      return FALSE;
2250
58
  }
2251
2252
23.9k
  if (~file->PromptForCredentials)
2253
46
  {
2254
46
    if (!freerdp_settings_set_bool(settings, FreeRDP_PromptForCredentials,
2255
46
                                   file->PromptForCredentials != 0))
2256
0
      return FALSE;
2257
46
  }
2258
2259
23.9k
  if (~file->RemoteApplicationMode)
2260
92
  {
2261
92
    if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteApplicationMode,
2262
92
                                   file->RemoteApplicationMode != 0))
2263
0
      return FALSE;
2264
92
  }
2265
2266
23.9k
  if (is_pointer_used(file->RemoteApplicationProgram))
2267
28
  {
2268
28
    if (!freerdp_settings_set_string(settings, FreeRDP_RemoteApplicationProgram,
2269
28
                                     file->RemoteApplicationProgram))
2270
0
      return FALSE;
2271
28
  }
2272
2273
23.9k
  if (is_pointer_used(file->RemoteApplicationName))
2274
28
  {
2275
28
    if (!freerdp_settings_set_string(settings, FreeRDP_RemoteApplicationName,
2276
28
                                     file->RemoteApplicationName))
2277
0
      return FALSE;
2278
28
  }
2279
2280
23.9k
  if (is_pointer_used(file->RemoteApplicationIcon))
2281
28
  {
2282
28
    if (!freerdp_settings_set_string(settings, FreeRDP_RemoteApplicationIcon,
2283
28
                                     file->RemoteApplicationIcon))
2284
0
      return FALSE;
2285
28
  }
2286
2287
23.9k
  if (is_pointer_used(file->RemoteApplicationFile))
2288
18
  {
2289
18
    if (!freerdp_settings_set_string(settings, FreeRDP_RemoteApplicationFile,
2290
18
                                     file->RemoteApplicationFile))
2291
0
      return FALSE;
2292
18
  }
2293
2294
23.9k
  if (is_pointer_used(file->RemoteApplicationGuid))
2295
38
  {
2296
38
    if (!freerdp_settings_set_string(settings, FreeRDP_RemoteApplicationGuid,
2297
38
                                     file->RemoteApplicationGuid))
2298
0
      return FALSE;
2299
38
  }
2300
2301
23.9k
  if (is_pointer_used(file->RemoteApplicationCmdLine))
2302
32
  {
2303
32
    if (!freerdp_settings_set_string(settings, FreeRDP_RemoteApplicationCmdLine,
2304
32
                                     file->RemoteApplicationCmdLine))
2305
0
      return FALSE;
2306
32
  }
2307
2308
23.9k
  if (~file->SpanMonitors)
2309
74
  {
2310
74
    if (!freerdp_settings_set_bool(settings, FreeRDP_SpanMonitors, file->SpanMonitors != 0))
2311
0
      return FALSE;
2312
74
  }
2313
2314
23.9k
  if (~file->UseMultiMon)
2315
68
  {
2316
68
    if (!freerdp_settings_set_bool(settings, FreeRDP_UseMultimon, file->UseMultiMon != 0))
2317
0
      return FALSE;
2318
68
  }
2319
2320
23.9k
  if (~file->AllowFontSmoothing)
2321
108
  {
2322
108
    if (!freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing,
2323
108
                                   file->AllowFontSmoothing != 0))
2324
0
      return FALSE;
2325
108
  }
2326
2327
23.9k
  if (~file->DisableWallpaper)
2328
100
  {
2329
100
    if (!freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper,
2330
100
                                   file->DisableWallpaper != 0))
2331
0
      return FALSE;
2332
100
  }
2333
2334
23.9k
  if (~file->DisableFullWindowDrag)
2335
90
  {
2336
90
    if (!freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag,
2337
90
                                   file->DisableFullWindowDrag != 0))
2338
0
      return FALSE;
2339
90
  }
2340
2341
23.9k
  if (~file->DisableMenuAnims)
2342
92
  {
2343
92
    if (!freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims,
2344
92
                                   file->DisableMenuAnims != 0))
2345
0
      return FALSE;
2346
92
  }
2347
2348
23.9k
  if (~file->DisableThemes)
2349
78
  {
2350
78
    if (!freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, file->DisableThemes != 0))
2351
0
      return FALSE;
2352
78
  }
2353
2354
23.9k
  if (~file->AllowDesktopComposition)
2355
58
  {
2356
58
    if (!freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition,
2357
58
                                   file->AllowDesktopComposition != 0))
2358
0
      return FALSE;
2359
58
  }
2360
2361
23.9k
  if (~file->BitmapCachePersistEnable)
2362
32
  {
2363
32
    if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled,
2364
32
                                   file->BitmapCachePersistEnable != 0))
2365
0
      return FALSE;
2366
32
  }
2367
2368
23.9k
  if (~file->DisableRemoteAppCapsCheck)
2369
78
  {
2370
78
    if (!freerdp_settings_set_bool(settings, FreeRDP_DisableRemoteAppCapsCheck,
2371
78
                                   file->DisableRemoteAppCapsCheck != 0))
2372
0
      return FALSE;
2373
78
  }
2374
2375
23.9k
  if (~file->AutoReconnectionEnabled)
2376
48
  {
2377
48
    if (!freerdp_settings_set_bool(settings, FreeRDP_AutoReconnectionEnabled,
2378
48
                                   file->AutoReconnectionEnabled != 0))
2379
0
      return FALSE;
2380
48
  }
2381
2382
23.9k
  if (~file->AutoReconnectMaxRetries)
2383
16
  {
2384
16
    if (!freerdp_settings_set_uint32(settings, FreeRDP_AutoReconnectMaxRetries,
2385
16
                                     file->AutoReconnectMaxRetries))
2386
0
      return FALSE;
2387
16
  }
2388
2389
23.9k
  if (~file->RedirectSmartCards)
2390
78
  {
2391
78
    if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectSmartCards,
2392
78
                                   file->RedirectSmartCards != 0))
2393
0
      return FALSE;
2394
78
  }
2395
2396
23.9k
  if (~file->RedirectWebauthN)
2397
88
  {
2398
88
    if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectWebAuthN,
2399
88
                                   file->RedirectWebauthN != 0))
2400
0
      return FALSE;
2401
88
  }
2402
2403
23.9k
  if (~file->RedirectClipboard)
2404
66
  {
2405
66
    if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectClipboard,
2406
66
                                   file->RedirectClipboard != 0))
2407
0
      return FALSE;
2408
66
  }
2409
2410
23.9k
  if (~file->RedirectPrinters)
2411
86
  {
2412
86
    if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectPrinters,
2413
86
                                   file->RedirectPrinters != 0))
2414
0
      return FALSE;
2415
86
  }
2416
2417
23.9k
  if (~file->RedirectDrives)
2418
80
  {
2419
80
    if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectDrives, file->RedirectDrives != 0))
2420
0
      return FALSE;
2421
80
  }
2422
2423
23.9k
  if (~file->RedirectPosDevices)
2424
90
  {
2425
90
    if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectSerialPorts,
2426
90
                                   file->RedirectComPorts != 0) ||
2427
90
        !freerdp_settings_set_bool(settings, FreeRDP_RedirectParallelPorts,
2428
90
                                   file->RedirectComPorts != 0))
2429
0
      return FALSE;
2430
90
  }
2431
2432
23.9k
  if (~file->RedirectComPorts)
2433
112
  {
2434
112
    if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectSerialPorts,
2435
112
                                   file->RedirectComPorts != 0) ||
2436
112
        !freerdp_settings_set_bool(settings, FreeRDP_RedirectParallelPorts,
2437
112
                                   file->RedirectComPorts != 0))
2438
0
      return FALSE;
2439
112
  }
2440
2441
23.9k
  if (~file->RedirectLocation && (file->RedirectLocation != 0))
2442
68
  {
2443
68
    size_t count = 0;
2444
2445
68
    char** ptr = CommandLineParseCommaSeparatedValuesEx(LOCATION_CHANNEL_NAME, nullptr, &count);
2446
68
    const BOOL rc =
2447
68
        freerdp_client_add_dynamic_channel(settings, count, (const char* const*)ptr);
2448
68
    CommandLineParserFree(ptr);
2449
68
    if (!rc)
2450
0
      return FALSE;
2451
68
  }
2452
2453
23.9k
  if (~file->RedirectDirectX)
2454
20
  {
2455
    /* What is this?! */
2456
20
  }
2457
2458
23.9k
  if ((is_pointer_used(file->DevicesToRedirect)) && !utils_str_is_empty(file->DevicesToRedirect))
2459
38
  {
2460
    /**
2461
     * Devices to redirect:
2462
     * http://technet.microsoft.com/en-us/library/ff393728/
2463
     *
2464
     * This setting corresponds to the selections for Other supported Plug and Play
2465
     * (PnP) devices under More on the Local Resources tab under Options in RDC.
2466
     *
2467
     * Values:
2468
     *
2469
     * '*':
2470
     *  Redirect all supported Plug and Play devices.
2471
     *
2472
     * 'DynamicDevices':
2473
     *  Redirect any supported Plug and Play devices that are connected later.
2474
     *
2475
     * The hardware ID for the supported Plug and Play device:
2476
     *  Redirect the specified supported Plug and Play device.
2477
     *
2478
     * Examples:
2479
     *  devicestoredirect:s:*
2480
     *  devicestoredirect:s:DynamicDevices
2481
     *  devicestoredirect:s:USB\VID_04A9&PID_30C1\6&4BD985D&0&2;,DynamicDevices
2482
     *
2483
     */
2484
38
    if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))
2485
0
      return FALSE;
2486
38
  }
2487
2488
23.9k
  if ((is_pointer_used(file->DrivesToRedirect)) && !utils_str_is_empty(file->DrivesToRedirect))
2489
24
  {
2490
24
    if (!freerdp_settings_set_string(settings, FreeRDP_DrivesToRedirect,
2491
24
                                     file->DrivesToRedirect))
2492
0
      return FALSE;
2493
24
  }
2494
2495
23.9k
  if ((is_pointer_used(file->RedirectCameras)) && !utils_str_is_empty(file->RedirectCameras))
2496
28
  {
2497
#if defined(CHANNEL_RDPECAM_CLIENT)
2498
    union
2499
    {
2500
      char** c;
2501
      const char* const* cc;
2502
    } cnv;
2503
    ADDIN_ARGV* args = rdp_file_to_args(RDPECAM_DVC_CHANNEL_NAME, file->RedirectCameras);
2504
    if (!args)
2505
      return FALSE;
2506
2507
    BOOL status = TRUE;
2508
    if (~file->EncodeRedirectedVideoCapture)
2509
    {
2510
      char encode[64] = WINPR_C_ARRAY_INIT;
2511
      (void)_snprintf(encode, sizeof(encode), "encode:%" PRIu32,
2512
                      file->EncodeRedirectedVideoCapture);
2513
      if (!freerdp_addin_argv_add_argument(args, encode))
2514
        status = FALSE;
2515
    }
2516
    if (~file->RedirectedVideoCaptureEncodingQuality)
2517
    {
2518
      char quality[64] = WINPR_C_ARRAY_INIT;
2519
      (void)_snprintf(quality, sizeof(quality), "quality:%" PRIu32,
2520
                      file->RedirectedVideoCaptureEncodingQuality);
2521
      if (!freerdp_addin_argv_add_argument(args, quality))
2522
        status = FALSE;
2523
    }
2524
2525
    cnv.c = args->argv;
2526
    if (status)
2527
      status = freerdp_client_add_dynamic_channel(
2528
          settings, WINPR_ASSERTING_INT_CAST(size_t, args->argc), cnv.cc);
2529
    freerdp_addin_argv_free(args);
2530
    if (!status)
2531
      return FALSE;
2532
#else
2533
28
    WLog_WARN(
2534
28
        TAG,
2535
28
        "This build does not support [MS-RDPECAM] camera redirection channel. Ignoring '%s'",
2536
28
        key_str_camerastoredirect);
2537
28
#endif
2538
28
  }
2539
2540
23.9k
  if ((is_pointer_used(file->UsbDevicesToRedirect)) &&
2541
38
      !utils_str_is_empty(file->UsbDevicesToRedirect))
2542
34
  {
2543
#ifdef CHANNEL_URBDRC_CLIENT
2544
    union
2545
    {
2546
      char** c;
2547
      const char* const* cc;
2548
    } cnv;
2549
    ADDIN_ARGV* args = rdp_file_to_args(URBDRC_CHANNEL_NAME, file->UsbDevicesToRedirect);
2550
    if (!args)
2551
      return FALSE;
2552
    cnv.c = args->argv;
2553
    const BOOL status = freerdp_client_add_dynamic_channel(
2554
        settings, WINPR_ASSERTING_INT_CAST(size_t, args->argc), cnv.cc);
2555
    freerdp_addin_argv_free(args);
2556
    if (!status)
2557
      return FALSE;
2558
#else
2559
34
    WLog_WARN(TAG,
2560
34
              "This build does not support [MS-RDPEUSB] usb redirection channel. Ignoring '%s'",
2561
34
              key_str_usbdevicestoredirect);
2562
34
#endif
2563
34
  }
2564
2565
23.9k
  if (~file->KeyboardHook)
2566
78
  {
2567
78
    if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardHook, file->KeyboardHook))
2568
0
      return FALSE;
2569
78
  }
2570
2571
23.9k
  if (~(size_t)file->SelectedMonitors)
2572
606
  {
2573
606
    size_t count = 0;
2574
606
    char** ptr = CommandLineParseCommaSeparatedValues(file->SelectedMonitors, &count);
2575
606
    UINT32* list = nullptr;
2576
2577
606
    if (!freerdp_settings_set_pointer_len(settings, FreeRDP_MonitorIds, nullptr, count))
2578
0
    {
2579
0
      CommandLineParserFree(ptr);
2580
0
      return FALSE;
2581
0
    }
2582
606
    list = freerdp_settings_get_pointer_writable(settings, FreeRDP_MonitorIds);
2583
606
    if (!list && (count > 0))
2584
0
    {
2585
0
      CommandLineParserFree(ptr);
2586
0
      return FALSE;
2587
0
    }
2588
317k
    for (size_t x = 0; x < count; x++)
2589
317k
    {
2590
317k
      unsigned long val = 0;
2591
317k
      errno = 0;
2592
317k
      val = strtoul(ptr[x], nullptr, 0);
2593
317k
      if ((val >= UINT32_MAX) && (errno != 0))
2594
2
      {
2595
2
        CommandLineParserFree(ptr);
2596
2
        return FALSE;
2597
2
      }
2598
317k
      list[x] = (UINT32)val;
2599
317k
    }
2600
604
    CommandLineParserFree(ptr);
2601
604
  }
2602
2603
23.9k
  if (~file->DynamicResolution)
2604
82
  {
2605
82
    const BOOL val = file->DynamicResolution != 0;
2606
82
    if (!freerdp_settings_set_bool(settings, FreeRDP_SupportDisplayControl, val))
2607
0
      return FALSE;
2608
82
    if (!freerdp_settings_set_bool(settings, FreeRDP_DynamicResolutionUpdate, val))
2609
0
      return FALSE;
2610
82
  }
2611
2612
23.9k
  if (~file->DesktopScaleFactor)
2613
70
  {
2614
70
    if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopScaleFactor,
2615
70
                                     file->DesktopScaleFactor))
2616
0
      return FALSE;
2617
70
  }
2618
2619
23.9k
  if (~file->VideoPlaybackMode)
2620
66
  {
2621
66
    if (file->VideoPlaybackMode != 0)
2622
54
    {
2623
54
      if (!freerdp_settings_set_bool(settings, FreeRDP_SupportGeometryTracking, TRUE) ||
2624
54
          !freerdp_settings_set_bool(settings, FreeRDP_SupportVideoOptimized, TRUE))
2625
0
        return FALSE;
2626
54
    }
2627
12
    else
2628
12
    {
2629
12
      if (!freerdp_settings_set_bool(settings, FreeRDP_SupportVideoOptimized, FALSE))
2630
0
        return FALSE;
2631
12
    }
2632
66
  }
2633
  // TODO file->MaximizeToCurrentDisplays;
2634
  // TODO file->SingleMonInWindowedMode;
2635
  // TODO file->EncodeRedirectedVideoCapture;
2636
  // TODO file->RedirectedVideoCaptureEncodingQuality;
2637
2638
23.9k
  if (is_pointer_used(file->PreconnectionBlob))
2639
60
  {
2640
60
    if (!freerdp_settings_set_string(settings, FreeRDP_PreconnectionBlob,
2641
60
                                     file->PreconnectionBlob) ||
2642
60
        !freerdp_settings_set_bool(settings, FreeRDP_SendPreconnectionPdu, TRUE))
2643
0
      return FALSE;
2644
60
  }
2645
2646
23.9k
  if (is_pointer_used(file->KdcProxyName))
2647
32
  {
2648
32
    if (!freerdp_settings_set_string(settings, FreeRDP_KerberosKdcUrl, file->KdcProxyName))
2649
0
      return FALSE;
2650
32
  }
2651
2652
23.9k
  if (~file->RdgIsKdcProxy)
2653
76
  {
2654
76
    if (!freerdp_settings_set_bool(settings, FreeRDP_KerberosRdgIsProxy,
2655
76
                                   file->RdgIsKdcProxy != 0))
2656
0
      return FALSE;
2657
76
  }
2658
2659
23.9k
  if (file->args->argc > 1)
2660
0
  {
2661
0
    WCHAR* ConnectionFile =
2662
0
        freerdp_settings_get_string_as_utf16(settings, FreeRDP_ConnectionFile, nullptr);
2663
2664
0
    if (freerdp_client_settings_parse_command_line(settings, file->args->argc, file->args->argv,
2665
0
                                                   FALSE) < 0)
2666
0
    {
2667
0
      free(ConnectionFile);
2668
0
      return FALSE;
2669
0
    }
2670
2671
0
    BOOL rc = freerdp_settings_set_string_from_utf16(settings, FreeRDP_ConnectionFile,
2672
0
                                                     ConnectionFile);
2673
0
    free(ConnectionFile);
2674
0
    if (!rc)
2675
0
      return FALSE;
2676
0
  }
2677
2678
23.9k
  return TRUE;
2679
23.9k
}
2680
2681
WINPR_ATTR_NODISCARD
2682
static BOOL freerdp_apply_connection_type_from_file(const rdpFile* file, rdpSettings* settings,
2683
                                                    UINT32 type)
2684
11.9k
{
2685
11.9k
  struct network_settings
2686
11.9k
  {
2687
11.9k
    FreeRDP_Settings_Keys_Bool id;
2688
11.9k
    BOOL apply;
2689
11.9k
    BOOL value[7];
2690
11.9k
  };
2691
11.9k
  WINPR_ASSERT(file);
2692
2693
11.9k
  const struct network_settings config[] = { { FreeRDP_DisableWallpaper,
2694
11.9k
                                             (~file->DisableWallpaper) == 0,
2695
11.9k
                                             { TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE } },
2696
11.9k
                                           { FreeRDP_AllowFontSmoothing,
2697
11.9k
                                             (~file->AllowFontSmoothing) == 0,
2698
11.9k
                                             { FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE } },
2699
11.9k
                                           { FreeRDP_AllowDesktopComposition,
2700
11.9k
                                             (~file->AllowDesktopComposition) == 0,
2701
11.9k
                                             { FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE } },
2702
11.9k
                                           { FreeRDP_DisableFullWindowDrag,
2703
11.9k
                                             (~file->DisableFullWindowDrag) == 0,
2704
11.9k
                                             { TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE } },
2705
11.9k
                                           { FreeRDP_DisableMenuAnims,
2706
11.9k
                                             (~file->DisableMenuAnims) == 0,
2707
11.9k
                                             { TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE } },
2708
11.9k
                                           { FreeRDP_DisableThemes,
2709
11.9k
                                             (~file->DisableThemes) == 0,
2710
11.9k
                                             { TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,
2711
11.9k
                                               FALSE } } };
2712
2713
11.9k
  switch (type)
2714
11.9k
  {
2715
6
    case CONNECTION_TYPE_INVALID:
2716
6
      return TRUE;
2717
2718
1
    case CONNECTION_TYPE_MODEM:
2719
2
    case CONNECTION_TYPE_BROADBAND_LOW:
2720
6
    case CONNECTION_TYPE_BROADBAND_HIGH:
2721
7
    case CONNECTION_TYPE_SATELLITE:
2722
8
    case CONNECTION_TYPE_WAN:
2723
9
    case CONNECTION_TYPE_LAN:
2724
11.9k
    case CONNECTION_TYPE_AUTODETECT:
2725
11.9k
      break;
2726
0
    default:
2727
0
      WLog_WARN(TAG, "Unknown ConnectionType %" PRIu32 ", aborting", type);
2728
0
      return FALSE;
2729
11.9k
  }
2730
2731
83.5k
  for (size_t x = 0; x < ARRAYSIZE(config); x++)
2732
71.6k
  {
2733
71.6k
    const struct network_settings* cur = &config[x];
2734
71.6k
    if (!cur->apply)
2735
263
      continue;
2736
2737
71.3k
    if (!freerdp_settings_set_bool(settings, cur->id, cur->value[type - 1]))
2738
0
      return FALSE;
2739
71.3k
  }
2740
11.9k
  return TRUE;
2741
11.9k
}
2742
2743
WINPR_ATTR_NODISCARD
2744
static BOOL freerdp_set_connection_type_from_file(const rdpFile* file, rdpSettings* settings,
2745
                                                  UINT32 type)
2746
11.9k
{
2747
11.9k
  WINPR_ASSERT(file);
2748
11.9k
  if (!freerdp_settings_set_uint32(settings, FreeRDP_ConnectionType, type))
2749
0
    return FALSE;
2750
2751
11.9k
  switch (type)
2752
11.9k
  {
2753
6
    case CONNECTION_TYPE_INVALID:
2754
7
    case CONNECTION_TYPE_MODEM:
2755
8
    case CONNECTION_TYPE_BROADBAND_LOW:
2756
9
    case CONNECTION_TYPE_SATELLITE:
2757
13
    case CONNECTION_TYPE_BROADBAND_HIGH:
2758
14
    case CONNECTION_TYPE_WAN:
2759
15
    case CONNECTION_TYPE_LAN:
2760
15
      if (!freerdp_apply_connection_type_from_file(file, settings, type))
2761
0
        return FALSE;
2762
15
      break;
2763
11.9k
    case CONNECTION_TYPE_AUTODETECT:
2764
11.9k
      if (!freerdp_apply_connection_type_from_file(file, settings, type))
2765
0
        return FALSE;
2766
      /* Automatically activate GFX and RFX codec support */
2767
#ifdef WITH_GFX_H264
2768
      if (!freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444v2, TRUE) ||
2769
          !freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444, TRUE) ||
2770
          !freerdp_settings_set_bool(settings, FreeRDP_GfxH264, TRUE))
2771
        return FALSE;
2772
#endif
2773
11.9k
      if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE) ||
2774
11.9k
          !freerdp_settings_set_bool(settings, FreeRDP_SupportGraphicsPipeline, TRUE))
2775
0
        return FALSE;
2776
11.9k
      break;
2777
11.9k
    default:
2778
22
      WLog_WARN(TAG, "Unknown ConnectionType %" PRIu32 ", aborting", type);
2779
22
      return FALSE;
2780
11.9k
  }
2781
2782
11.9k
  return TRUE;
2783
11.9k
}
2784
2785
BOOL freerdp_client_populate_settings_from_rdp_file(const rdpFile* file, rdpSettings* settings)
2786
12.0k
{
2787
12.0k
  if (!freerdp_client_populate_settings_from_rdp_file_unchecked(file, settings))
2788
82
    return FALSE;
2789
2790
11.9k
  DWORD type = freerdp_settings_get_uint32(settings, FreeRDP_ConnectionType);
2791
11.9k
  if ((~file->ConnectionType) == 0)
2792
11.9k
  {
2793
11.9k
    if (freerdp_settings_get_bool(settings, FreeRDP_NetworkAutoDetect))
2794
11.9k
      type = CONNECTION_TYPE_AUTODETECT;
2795
11.9k
  }
2796
11.9k
  return freerdp_set_connection_type_from_file(file, settings, type);
2797
12.0k
}
2798
2799
WINPR_ATTR_NODISCARD
2800
static rdpFileLine* freerdp_client_rdp_file_find_line_by_name(const rdpFile* file, const char* name)
2801
840k
{
2802
840k
  BOOL bFound = FALSE;
2803
840k
  rdpFileLine* line = nullptr;
2804
2805
3.17M
  for (size_t index = 0; index < file->lineCount; index++)
2806
3.15M
  {
2807
3.15M
    line = &(file->lines[index]);
2808
2809
3.15M
    if (line->flags & RDP_FILE_LINE_FLAG_FORMATTED)
2810
3.15M
    {
2811
3.15M
      if (_stricmp(name, line->name) == 0)
2812
828k
      {
2813
828k
        bFound = TRUE;
2814
828k
        break;
2815
828k
      }
2816
3.15M
    }
2817
3.15M
  }
2818
2819
840k
  return (bFound) ? line : nullptr;
2820
840k
}
2821
/**
2822
 * Set a string option to a rdpFile
2823
 * @param file rdpFile
2824
 * @param name name of the option
2825
 * @param value value of the option
2826
 * @return 0 on success
2827
 */
2828
int freerdp_client_rdp_file_set_string_option(rdpFile* file, const char* name, const char* value)
2829
0
{
2830
0
  return freerdp_client_rdp_file_set_string(file, name, value);
2831
0
}
2832
2833
const char* freerdp_client_rdp_file_get_string_option(const rdpFile* file, const char* name)
2834
0
{
2835
0
  LPSTR* value = nullptr;
2836
0
  rdpFileLine* line = nullptr;
2837
2838
0
  rdpFile* wfile = WINPR_CAST_CONST_PTR_AWAY(file, rdpFile*);
2839
0
  if (freerdp_client_rdp_file_find_string_entry(wfile, name, &value, &line))
2840
0
  {
2841
0
    if (value && ~(size_t)(*value))
2842
0
      return *value;
2843
0
    if (line)
2844
0
      return line->sValue;
2845
0
  }
2846
2847
0
  return nullptr;
2848
0
}
2849
2850
int freerdp_client_rdp_file_set_integer_option(rdpFile* file, const char* name, int value)
2851
0
{
2852
0
  return freerdp_client_rdp_file_set_integer(file, name, value);
2853
0
}
2854
2855
int freerdp_client_rdp_file_get_integer_option(const rdpFile* file, const char* name)
2856
0
{
2857
0
  DWORD* value = nullptr;
2858
0
  rdpFileLine* line = nullptr;
2859
2860
0
  rdpFile* wfile = WINPR_CAST_CONST_PTR_AWAY(file, rdpFile*);
2861
0
  if (freerdp_client_rdp_file_find_integer_entry(wfile, name, &value, &line))
2862
0
  {
2863
0
    if (value && ~(*value))
2864
0
      return WINPR_ASSERTING_INT_CAST(int, *value);
2865
0
    if (line)
2866
0
      return (int)line->iValue;
2867
0
  }
2868
2869
0
  return -1;
2870
0
}
2871
2872
static void freerdp_client_file_string_check_free(LPSTR str)
2873
401k
{
2874
401k
  if (is_pointer_used(str))
2875
1.02k
    free(str);
2876
401k
}
2877
2878
rdpFile* freerdp_client_rdp_file_new(void)
2879
12.1k
{
2880
12.1k
  return freerdp_client_rdp_file_new_ex(0);
2881
12.1k
}
2882
2883
rdpFile* freerdp_client_rdp_file_new_ex(DWORD flags)
2884
12.1k
{
2885
12.1k
  rdpFile* file = (rdpFile*)calloc(1, sizeof(rdpFile));
2886
2887
12.1k
  if (!file)
2888
0
    return nullptr;
2889
2890
12.1k
  file->flags = flags;
2891
2892
12.1k
  FillMemory(file, sizeof(rdpFile), 0xFF);
2893
12.1k
  file->lines = nullptr;
2894
12.1k
  file->lineCount = 0;
2895
12.1k
  file->lineSize = 32;
2896
12.1k
  file->GatewayProfileUsageMethod = 1;
2897
12.1k
  file->lines = (rdpFileLine*)calloc(file->lineSize, sizeof(rdpFileLine));
2898
2899
12.1k
  file->args = freerdp_addin_argv_new(0, nullptr);
2900
12.1k
  if (!file->lines || !file->args)
2901
0
    goto fail;
2902
2903
12.1k
  if (!freerdp_client_add_option(file, "freerdp"))
2904
0
    goto fail;
2905
2906
12.1k
  return file;
2907
0
fail:
2908
0
  WINPR_PRAGMA_DIAG_PUSH
2909
0
  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
2910
0
  freerdp_client_rdp_file_free(file);
2911
0
  WINPR_PRAGMA_DIAG_POP
2912
0
  return nullptr;
2913
12.1k
}
2914
2915
void freerdp_client_rdp_file_free(rdpFile* file)
2916
12.1k
{
2917
12.1k
  if (file)
2918
12.1k
  {
2919
796k
    for (size_t i = 0; i < file->lineCount; i++)
2920
784k
    {
2921
784k
      rdpFileLine* cur = &file->lines[i];
2922
784k
      free(cur->name);
2923
784k
      free(cur->sValue);
2924
784k
    }
2925
2926
12.1k
    free(file->lines);
2927
2928
12.1k
    freerdp_addin_argv_free(file->args);
2929
2930
12.1k
    freerdp_client_file_string_check_free(file->SelectedMonitors);
2931
12.1k
    freerdp_client_file_string_check_free(file->Username);
2932
12.1k
    freerdp_client_file_string_check_free(file->Domain);
2933
12.1k
    freerdp_client_file_string_check_free(file->Password);
2934
12.1k
    freerdp_client_file_string_check_free(file->FullAddress);
2935
12.1k
    freerdp_client_file_string_check_free(file->AlternateFullAddress);
2936
12.1k
    freerdp_client_file_string_check_free(file->UsbDevicesToRedirect);
2937
12.1k
    freerdp_client_file_string_check_free(file->RedirectCameras);
2938
12.1k
    freerdp_client_file_string_check_free(file->LoadBalanceInfo);
2939
12.1k
    freerdp_client_file_string_check_free(file->RemoteApplicationName);
2940
12.1k
    freerdp_client_file_string_check_free(file->RemoteApplicationIcon);
2941
12.1k
    freerdp_client_file_string_check_free(file->RemoteApplicationProgram);
2942
12.1k
    freerdp_client_file_string_check_free(file->RemoteApplicationFile);
2943
12.1k
    freerdp_client_file_string_check_free(file->RemoteApplicationGuid);
2944
12.1k
    freerdp_client_file_string_check_free(file->RemoteApplicationCmdLine);
2945
12.1k
    freerdp_client_file_string_check_free(file->AlternateShell);
2946
12.1k
    freerdp_client_file_string_check_free(file->ShellWorkingDirectory);
2947
12.1k
    freerdp_client_file_string_check_free(file->GatewayHostname);
2948
12.1k
    freerdp_client_file_string_check_free(file->ResourceProvider);
2949
12.1k
    freerdp_client_file_string_check_free(file->WvdEndpointPool);
2950
12.1k
    freerdp_client_file_string_check_free(file->geo);
2951
12.1k
    freerdp_client_file_string_check_free(file->armpath);
2952
12.1k
    freerdp_client_file_string_check_free(file->aadtenantid);
2953
12.1k
    freerdp_client_file_string_check_free(file->diagnosticserviceurl);
2954
12.1k
    freerdp_client_file_string_check_free(file->hubdiscoverygeourl);
2955
12.1k
    freerdp_client_file_string_check_free(file->activityhint);
2956
12.1k
    freerdp_client_file_string_check_free(file->GatewayAccessToken);
2957
12.1k
    freerdp_client_file_string_check_free(file->EndpointFedAuthToken);
2958
12.1k
    freerdp_client_file_string_check_free(file->DrivesToRedirect);
2959
12.1k
    freerdp_client_file_string_check_free(file->DevicesToRedirect);
2960
12.1k
    freerdp_client_file_string_check_free(file->WinPosStr);
2961
12.1k
    freerdp_client_file_string_check_free(file->PreconnectionBlob);
2962
12.1k
    freerdp_client_file_string_check_free(file->KdcProxyName);
2963
2964
12.1k
    free(file);
2965
12.1k
  }
2966
12.1k
}
2967
2968
void freerdp_client_rdp_file_set_callback_context(rdpFile* file, void* context)
2969
0
{
2970
0
  file->context = context;
2971
0
}