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