FreeRDP
Loading...
Searching...
No Matches
utils.c
1
21#include <freerdp/config.h>
22
23#include "settings.h"
24
25#include <winpr/assert.h>
26
27#include <freerdp/freerdp.h>
28#include <freerdp/channels/cliprdr.h>
29#include <freerdp/channels/rdpdr.h>
30
31#include <freerdp/log.h>
32#define TAG FREERDP_TAG("core.gateway.utils")
33
34#include "utils.h"
35
36#if !defined(_WIN32)
37#include <sys/stat.h>
38#endif
39
40#include "../core/rdp.h"
41
42BOOL utils_str_copy(const char* value, char** dst)
43{
44 WINPR_ASSERT(dst);
45
46 free(*dst);
47 *dst = nullptr;
48 if (!value)
49 return TRUE;
50
51 (*dst) = _strdup(value);
52 return (*dst) != nullptr;
53}
54
55WINPR_ATTR_NODISCARD
56static BOOL utils_copy_smartcard_settings(const rdpSettings* settings, rdpSettings* origSettings)
57{
58 /* update original settings with provided smart card settings */
59 origSettings->SmartcardLogon = settings->SmartcardLogon;
60 origSettings->PasswordIsSmartcardPin = settings->PasswordIsSmartcardPin;
61 if (!utils_str_copy(settings->ReaderName, &origSettings->ReaderName))
62 return FALSE;
63 if (!utils_str_copy(settings->CspName, &origSettings->CspName))
64 return FALSE;
65 if (!utils_str_copy(settings->ContainerName, &origSettings->ContainerName))
66 return FALSE;
67
68 return TRUE;
69}
70
71WINPR_ATTR_NODISCARD
72static BOOL utils_auth_skip(freerdp* instance, rdp_auth_reason reason, BOOL gateway)
73{
74 WINPR_ASSERT(instance);
75 WINPR_ASSERT(instance->context);
76
77 const char* password = freerdp_settings_get_string(
78 instance->context->settings, gateway ? FreeRDP_GatewayPassword : FreeRDP_Password);
79 const char* username = freerdp_settings_get_string(
80 instance->context->settings, gateway ? FreeRDP_GatewayUsername : FreeRDP_Username);
81
82 switch (reason)
83 {
84 case AUTH_TLS:
85 case AUTH_RDP:
86 case AUTH_SMARTCARD_PIN: /* in this case password is pin code */
87 case AUTH_FIDO_PIN:
88 if (username && password)
89 return TRUE;
90 break;
91 default:
92 break;
93 }
94
95 return FALSE;
96}
97
98auth_status utils_authenticate_gateway(freerdp* instance, rdp_auth_reason reason)
99{
100 rdpSettings* settings = nullptr;
101 rdpSettings* origSettings = nullptr;
102 BOOL prompt = FALSE;
103 BOOL proceed = 0;
104
105 WINPR_ASSERT(instance);
106 WINPR_ASSERT(instance->context);
107 WINPR_ASSERT(instance->context->settings);
108 WINPR_ASSERT(instance->context->rdp);
109 WINPR_ASSERT(instance->context->rdp->originalSettings);
110
111 settings = instance->context->settings;
112 origSettings = instance->context->rdp->originalSettings;
113
114 if (freerdp_shall_disconnect_context(instance->context))
115 return AUTH_FAILED;
116
117 if (utils_str_is_empty(freerdp_settings_get_string(settings, FreeRDP_GatewayPassword)))
118 prompt = TRUE;
119 if (utils_str_is_empty(freerdp_settings_get_string(settings, FreeRDP_GatewayUsername)))
120 prompt = TRUE;
121
122 if (!prompt)
123 {
124 if (!utils_sync_credentials(settings, FALSE))
125 return AUTH_FAILED;
126 return AUTH_SKIP;
127 }
128 const BOOL skip = utils_auth_skip(instance, reason, TRUE);
129 if (skip)
130 return AUTH_SKIP;
131
132#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
133 WINPR_PRAGMA_DIAG_PUSH
134 WINPR_PRAGMA_DIAG_IGNORED_DEPRECATED_DECL
135#endif
136
137#if defined(WITHOUT_FREERDP_3x_DEPRECATED)
138 if (!instance->AuthenticateEx)
139 return AUTH_NO_CREDENTIALS;
140#else
141 if (!instance->GatewayAuthenticate && !instance->AuthenticateEx)
142 return AUTH_NO_CREDENTIALS;
143
144 if (!instance->GatewayAuthenticate)
145#endif
146 {
147 proceed =
148 instance->AuthenticateEx(instance, &settings->GatewayUsername,
149 &settings->GatewayPassword, &settings->GatewayDomain, reason);
150 if (!proceed)
151 return AUTH_CANCELLED;
152 }
153#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
154 else
155 {
156 proceed =
157 instance->GatewayAuthenticate(instance, &settings->GatewayUsername,
158 &settings->GatewayPassword, &settings->GatewayDomain);
159 if (!proceed)
160 return AUTH_CANCELLED;
161 }
162#endif
163
164#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
165 WINPR_PRAGMA_DIAG_POP
166#endif
167
168 if (utils_str_is_empty(settings->GatewayUsername) ||
169 utils_str_is_empty(settings->GatewayPassword))
170 return AUTH_NO_CREDENTIALS;
171
172 if (!utils_sync_credentials(settings, FALSE))
173 return AUTH_FAILED;
174
175 /* update original settings with provided user credentials */
176 if (!utils_str_copy(settings->GatewayUsername, &origSettings->GatewayUsername))
177 return AUTH_FAILED;
178 if (!utils_str_copy(settings->GatewayDomain, &origSettings->GatewayDomain))
179 return AUTH_FAILED;
180 if (!utils_str_copy(settings->GatewayPassword, &origSettings->GatewayPassword))
181 return AUTH_FAILED;
182 if (!utils_sync_credentials(origSettings, FALSE))
183 return AUTH_FAILED;
184
185 if (!utils_copy_smartcard_settings(settings, origSettings))
186 return AUTH_FAILED;
187
188 return AUTH_SUCCESS;
189}
190
191auth_status utils_authenticate(freerdp* instance, rdp_auth_reason reason, BOOL override)
192{
193 rdpSettings* settings = nullptr;
194 rdpSettings* origSettings = nullptr;
195 BOOL prompt = !override;
196 BOOL proceed = 0;
197
198 WINPR_ASSERT(instance);
199 WINPR_ASSERT(instance->context);
200 WINPR_ASSERT(instance->context->settings);
201 WINPR_ASSERT(instance->context->rdp);
202 WINPR_ASSERT(instance->context->rdp->originalSettings);
203
204 settings = instance->context->settings;
205 origSettings = instance->context->rdp->originalSettings;
206
207 if (freerdp_shall_disconnect_context(instance->context))
208 return AUTH_FAILED;
209
210 if (settings->ConnectChildSession)
211 return AUTH_NO_CREDENTIALS;
212
213 /* Ask for auth data if no or an empty username was specified or no password was given */
214 if (utils_str_is_empty(freerdp_settings_get_string(settings, FreeRDP_Username)) ||
215 (settings->Password == nullptr && settings->RedirectionPassword == nullptr))
216 prompt = TRUE;
217
218 const BOOL skip = utils_auth_skip(instance, reason, FALSE);
219 if (!prompt || skip)
220 return AUTH_SKIP;
221
222 switch (reason)
223 {
224 case AUTH_RDP:
225 case AUTH_TLS:
226 if (settings->SmartcardLogon)
227 {
228 if (!utils_str_is_empty(settings->Password))
229 {
230 WLog_INFO(TAG, "Authentication via smartcard");
231 return AUTH_SUCCESS;
232 }
233 reason = AUTH_SMARTCARD_PIN;
234 }
235 break;
236 case AUTH_NLA:
237 if (settings->SmartcardLogon)
238 reason = AUTH_SMARTCARD_PIN;
239 break;
240 case AUTH_RDSTLS:
241 default:
242 break;
243 }
244
245#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
246 WINPR_PRAGMA_DIAG_PUSH
247 WINPR_PRAGMA_DIAG_IGNORED_DEPRECATED_DECL
248#endif
249
250 /* If no callback is specified still continue connection */
251#if defined(WITHOUT_FREERDP_3x_DEPRECATED)
252 if (!instance->AuthenticateEx)
253 return AUTH_NO_CREDENTIALS;
254#else
255 if (!instance->Authenticate && !instance->AuthenticateEx)
256 return AUTH_NO_CREDENTIALS;
257 if (!instance->Authenticate)
258#endif
259 {
260 proceed = instance->AuthenticateEx(instance, &settings->Username, &settings->Password,
261 &settings->Domain, reason);
262 if (!proceed)
263 return AUTH_CANCELLED;
264 }
265#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
266 else
267 {
268 proceed = instance->Authenticate(instance, &settings->Username, &settings->Password,
269 &settings->Domain);
270 if (!proceed)
271 return AUTH_NO_CREDENTIALS;
272 }
273#endif
274
275#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
276 WINPR_PRAGMA_DIAG_POP
277#endif
278
279 if (utils_str_is_empty(settings->Username) || utils_str_is_empty(settings->Password))
280 return AUTH_NO_CREDENTIALS;
281
282 if (!utils_sync_credentials(settings, TRUE))
283 return AUTH_FAILED;
284
285 /* update original settings with provided user credentials */
286 if (!utils_str_copy(settings->Username, &origSettings->Username))
287 return AUTH_FAILED;
288 if (!utils_str_copy(settings->Domain, &origSettings->Domain))
289 return AUTH_FAILED;
290 if (!utils_str_copy(settings->Password, &origSettings->Password))
291 return AUTH_FAILED;
292 if (!utils_sync_credentials(origSettings, TRUE))
293 return AUTH_FAILED;
294
295 if (!utils_copy_smartcard_settings(settings, origSettings))
296 return AUTH_FAILED;
297
298 return AUTH_SUCCESS;
299}
300
301BOOL utils_sync_credentials(rdpSettings* settings, BOOL toGateway)
302{
303 WINPR_ASSERT(settings);
304 if (!settings->GatewayUseSameCredentials)
305 return TRUE;
306
307 if (toGateway)
308 {
309 if (!utils_str_copy(settings->Username, &settings->GatewayUsername))
310 return FALSE;
311 if (!utils_str_copy(settings->Domain, &settings->GatewayDomain))
312 return FALSE;
313 if (!utils_str_copy(settings->Password, &settings->GatewayPassword))
314 return FALSE;
315 }
316 else
317 {
318 if (!utils_str_copy(settings->GatewayUsername, &settings->Username))
319 return FALSE;
320 if (!utils_str_copy(settings->GatewayDomain, &settings->Domain))
321 return FALSE;
322 if (!utils_str_copy(settings->GatewayPassword, &settings->Password))
323 return FALSE;
324 }
325 return TRUE;
326}
327
328BOOL utils_persist_credentials(rdpSettings* settings, const rdpSettings* current)
329{
330 if (!settings || !current)
331 return FALSE;
332
333 const SSIZE_T keys[] = { FreeRDP_GatewayUsername, FreeRDP_GatewayDomain,
334 FreeRDP_GatewayPassword, FreeRDP_Username,
335 FreeRDP_Domain, FreeRDP_Password };
336
337 for (size_t x = 0; x < ARRAYSIZE(keys); x++)
338 {
339 const SSIZE_T key = keys[x];
340 if (!freerdp_settings_copy_item(settings, current, key))
341 {
342 WLog_ERR(TAG, "Failed to copy %s from current to backup settings",
344 return FALSE;
345 }
346 }
347
348 return TRUE;
349}
350
351BOOL utils_str_is_empty(const char* str)
352{
353 if (!str)
354 return TRUE;
355 if (*str == '\0')
356 return TRUE;
357 return FALSE;
358}
359
360BOOL utils_abort_connect(rdpRdp* rdp)
361{
362 if (!rdp)
363 return FALSE;
364
365 return SetEvent(rdp->abortEvent);
366}
367
368BOOL utils_reset_abort(rdpRdp* rdp)
369{
370 WINPR_ASSERT(rdp);
371
372 return ResetEvent(rdp->abortEvent);
373}
374
375HANDLE utils_get_abort_event(rdpRdp* rdp)
376{
377 WINPR_ASSERT(rdp);
378 return rdp->abortEvent;
379}
380
381BOOL utils_abort_event_is_set(const rdpRdp* rdp)
382{
383 DWORD status = 0;
384 WINPR_ASSERT(rdp);
385 status = WaitForSingleObject(rdp->abortEvent, 0);
386 return status == WAIT_OBJECT_0;
387}
388
389const char* utils_is_vsock(const char* hostname)
390{
391 if (!hostname)
392 return nullptr;
393
394 const char vsock[8] = { 'v', 's', 'o', 'c', 'k', ':', '/', '/' };
395 if (strncmp(hostname, vsock, sizeof(vsock)) == 0)
396 return &hostname[sizeof(vsock)];
397 return nullptr;
398}
399
400WINPR_ATTR_NODISCARD
401static BOOL remove_rdpdr_type(rdpSettings* settings, UINT32 type)
402{
403 BOOL rc = TRUE;
404 RDPDR_DEVICE* printer = nullptr;
405 do
406 {
407 printer = freerdp_device_collection_find_type(settings, type);
408 if (printer)
409 {
410 if (!freerdp_device_collection_del(settings, printer))
411 rc = FALSE;
412 }
413 freerdp_device_free(printer);
414 } while (printer);
415 return rc;
416}
417
418WINPR_ATTR_NODISCARD
419static BOOL disable_clipboard(rdpSettings* settings)
420{
421 if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectClipboard, FALSE))
422 return FALSE;
423 freerdp_static_channel_collection_del(settings, CLIPRDR_SVC_CHANNEL_NAME);
424 return TRUE;
425}
426
427WINPR_ATTR_NODISCARD
428static BOOL disable_drive(rdpSettings* settings)
429{
430 if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectDrives, FALSE))
431 return FALSE;
432 if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectHomeDrive, FALSE))
433 return FALSE;
434
435 return remove_rdpdr_type(settings, RDPDR_DTYP_FILESYSTEM);
436}
437
438WINPR_ATTR_NODISCARD
439static BOOL disable_printers(rdpSettings* settings)
440{
441 if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectPrinters, FALSE))
442 return FALSE;
443
444 return remove_rdpdr_type(settings, RDPDR_DTYP_PRINT);
445}
446
447WINPR_ATTR_NODISCARD
448static BOOL disable_port(rdpSettings* settings)
449{
450 if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectParallelPorts, FALSE))
451 return FALSE;
452 if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectSerialPorts, FALSE))
453 return FALSE;
454 if (!remove_rdpdr_type(settings, RDPDR_DTYP_SERIAL))
455 return FALSE;
456 return remove_rdpdr_type(settings, RDPDR_DTYP_PARALLEL);
457}
458
459WINPR_ATTR_NODISCARD
460static BOOL disable_pnp(WINPR_ATTR_UNUSED rdpSettings* settings)
461{
462 // TODO(akallabeth): [MS-RDPEPNP] related stuff is disabled.
463 return TRUE;
464}
465
466WINPR_ATTR_NODISCARD
467static BOOL apply_gw_policy(rdpContext* context)
468{
469 WINPR_ASSERT(context);
470 return utils_reload_channels(context);
471}
472
473BOOL utils_apply_gateway_policy(wLog* log, rdpContext* context, UINT32 flags, const char* module)
474{
475 WINPR_ASSERT(log);
476 WINPR_ASSERT(context);
477
478 rdpSettings* settings = context->settings;
479 WINPR_ASSERT(settings);
480
481 if (flags & HTTP_TUNNEL_REDIR_ENABLE_ALL)
482 {
483 WLog_Print(log, WLOG_DEBUG, "[%s] policy allows all redirections", module);
484 }
485 else if (freerdp_settings_get_bool(settings, FreeRDP_GatewayIgnoreRedirectionPolicy))
486 {
487 char buffer[128] = WINPR_C_ARRAY_INIT;
488 WLog_Print(log, WLOG_INFO, "[%s] policy ignored on user request %s", module,
489 utils_redir_flags_to_string(flags, buffer, sizeof(buffer)));
490 }
491 else if (flags & HTTP_TUNNEL_REDIR_DISABLE_ALL)
492 {
493 WLog_Print(log, WLOG_INFO, "[%s] policy denies all redirections", module);
494 if (!disable_drive(settings))
495 return FALSE;
496 if (!disable_printers(settings))
497 return FALSE;
498 if (!disable_clipboard(settings))
499 return FALSE;
500 if (!disable_port(settings))
501 return FALSE;
502 if (!disable_pnp(settings))
503 return FALSE;
504 if (!apply_gw_policy(context))
505 return FALSE;
506 }
507 else
508 {
509 if (flags & HTTP_TUNNEL_REDIR_DISABLE_DRIVE)
510 {
511 WLog_Print(log, WLOG_INFO, "[%s] policy denies drive redirections", module);
512 if (!disable_drive(settings))
513 return FALSE;
514 }
515 if (flags & HTTP_TUNNEL_REDIR_DISABLE_PRINTER)
516 {
517 WLog_Print(log, WLOG_INFO, "[%s] policy denies printer redirections", module);
518 if (!disable_printers(settings))
519 return FALSE;
520 }
521 if (flags & HTTP_TUNNEL_REDIR_DISABLE_PORT)
522 {
523 WLog_Print(log, WLOG_INFO, "[%s] policy denies port redirections", module);
524 if (!disable_port(settings))
525 return FALSE;
526 }
527 if (flags & HTTP_TUNNEL_REDIR_DISABLE_CLIPBOARD)
528 {
529 WLog_Print(log, WLOG_INFO, "[%s] policy denies clipboard redirections", module);
530 if (!disable_clipboard(settings))
531 return FALSE;
532 }
533 if (flags & HTTP_TUNNEL_REDIR_DISABLE_PNP)
534 {
535 WLog_Print(log, WLOG_INFO, "[%s] policy denies PNP redirections", module);
536 if (!disable_pnp(settings))
537 return FALSE;
538 }
539 if (flags != 0)
540 {
541 if (!apply_gw_policy(context))
542 return FALSE;
543 }
544 }
545 return TRUE;
546}
547
548char* utils_redir_flags_to_string(UINT32 flags, char* buffer, size_t size)
549{
550 winpr_str_append("{", buffer, size, "");
551 if (flags & HTTP_TUNNEL_REDIR_ENABLE_ALL)
552 winpr_str_append("ENABLE_ALL", buffer, size, "|");
553 if (flags & HTTP_TUNNEL_REDIR_DISABLE_ALL)
554 winpr_str_append("DISABLE_ALL", buffer, size, "|");
555 if (flags & HTTP_TUNNEL_REDIR_DISABLE_DRIVE)
556 winpr_str_append("DISABLE_DRIVE", buffer, size, "|");
557 if (flags & HTTP_TUNNEL_REDIR_DISABLE_PRINTER)
558 winpr_str_append("DISABLE_PRINTER", buffer, size, "|");
559 if (flags & HTTP_TUNNEL_REDIR_DISABLE_PORT)
560 winpr_str_append("DISABLE_PORT", buffer, size, "|");
561 if (flags & HTTP_TUNNEL_REDIR_DISABLE_CLIPBOARD)
562 winpr_str_append("DISABLE_CLIPBOARD", buffer, size, "|");
563 if (flags & HTTP_TUNNEL_REDIR_DISABLE_PNP)
564 winpr_str_append("DISABLE_PNP", buffer, size, "|");
565
566 char fbuffer[16] = WINPR_C_ARRAY_INIT;
567 (void)_snprintf(fbuffer, sizeof(fbuffer), "[0x%08" PRIx32 "]", flags);
568
569 winpr_str_append(fbuffer, buffer, size, " ");
570 winpr_str_append("{", buffer, size, "}");
571 return buffer;
572}
573
574BOOL utils_reload_channels(rdpContext* context)
575{
576 WINPR_ASSERT(context);
577
578 if (context->channels)
579 {
580 freerdp_channels_disconnect(context->channels, context->instance);
581 freerdp_channels_close(context->channels, context->instance);
582 freerdp_channels_free(context->channels);
583 }
584
585 context->channels = freerdp_channels_new(context->instance);
586 if (!context->channels)
587 return FALSE;
588
589 freerdp_channels_register_instance(context->channels, context->instance);
590
591 BOOL rc = TRUE;
592 IFCALLRET(context->instance->LoadChannels, rc, context->instance);
593 if (rc)
594 return freerdp_channels_pre_connect(context->channels, context->instance) == CHANNEL_RC_OK;
595 return rc;
596}
597
598const char* guid2str(const GUID* guid, char* buffer, size_t len)
599{
600 if (!guid)
601 return nullptr;
602 RPC_CSTR strguid = nullptr;
603
604 RPC_STATUS rpcStatus = UuidToStringA(guid, &strguid);
605
606 if (rpcStatus != RPC_S_OK)
607 return nullptr;
608
609 (void)sprintf_s(buffer, len, "%s", strguid);
610 RpcStringFreeA(&strguid);
611 return buffer;
612}
613
614WINPR_ATTR_NODISCARD
615static BOOL isValidIPv4(const char* ipAddress)
616{
617 struct sockaddr_in sa = WINPR_C_ARRAY_INIT;
618 int result = inet_pton(AF_INET, ipAddress, &(sa.sin_addr));
619 return result != 0;
620}
621
622WINPR_ATTR_NODISCARD
623static BOOL isValidIPv6(const char* ipAddress)
624{
625 struct sockaddr_in6 sa = WINPR_C_ARRAY_INIT;
626 int result = inet_pton(AF_INET6, ipAddress, &(sa.sin6_addr));
627 return result != 0;
628}
629
630BOOL utils_is_valid_ip(const char* ipAddress)
631{
632 return isValidIPv4(ipAddress) || isValidIPv6(ipAddress);
633}
634
635BOOL utils_set_umask(void)
636{
637#if !defined(_WIN32)
638 (void)umask(S_IRWXG | S_IRWXO);
639#endif
640 return TRUE;
641}
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_copy_item(rdpSettings *dst, const rdpSettings *src, SSIZE_T id)
copies one setting identified by id from src to dst
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_device_collection_del(rdpSettings *settings, const RDPDR_DEVICE *device)
Removed a device from the settings, returns ownership of the allocated device to caller.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_name_for_key(SSIZE_T key)
Returns the type name for a key.