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