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