24#include <freerdp/log.h>
25#include <freerdp/utils/passphrase.h>
26#include <freerdp/utils/smartcardlogon.h>
30#include "../sdl_context.hpp"
31#include "sdl_dialogs.hpp"
32#include "sdl_input_widget_pair.hpp"
33#include "sdl_input_widget_pair_list.hpp"
34#include "sdl_select.hpp"
35#include "sdl_select_list.hpp"
36#include "sdl_connection_dialog.hpp"
40 SHOW_DIALOG_ACCEPT_REJECT = 1,
41 SHOW_DIALOG_TIMED_ACCEPT = 2
44static const char* type_str_for_flags(UINT32 flags)
46 const char* type =
"RDP-Server";
48 if (flags & VERIFY_CERT_FLAG_GATEWAY)
51 if (flags & VERIFY_CERT_FLAG_REDIRECT)
52 type =
"RDP-Redirect";
56static BOOL sdl_wait_for_result(rdpContext* context, Uint32 type, SDL_Event* result)
58 const SDL_Event empty = {};
60 WINPR_ASSERT(context);
63 while (!freerdp_shall_disconnect_context(context))
66 const int rc = SDL_PeepEvents(result, 1, SDL_GETEVENT, type, type);
74static int sdl_show_dialog(rdpContext* context,
const char* title,
const char* message,
79 if (!sdl_push_user_event(SDL_EVENT_USER_SHOW_DIALOG, title, message, flags))
82 if (!sdl_wait_for_result(context, SDL_EVENT_USER_SHOW_RESULT, &event))
85 return event.user.code;
88BOOL sdl_authenticate_ex(freerdp* instance,
char** username,
char** password,
char** domain,
89 rdp_auth_reason reason)
103 case AUTH_SMARTCARD_PIN:
105 if ((*username) && (*password))
118 char* title =
nullptr;
119 size_t titlesize = 0;
120 winpr_asprintf(&title, &titlesize,
"Credentials required for %s", target);
122 CStringPtr guard(title, free);
135 auto sdl = get_context(instance);
136 if (!p && !
sdl->credentialsRead())
141 const BOOL fromStdin =
144 freerdp_passphrase_from_env(instance->context, title, line.data(), line.capacity());
145 if (!env && fromStdin)
146 env = freerdp_passphrase_read(instance->context, title, line.data(), line.capacity(),
154 sdl->setCredentialsRead();
160 if (!sdl_push_user_event(SDL_EVENT_USER_AUTH_DIALOG, title, u, d, p, reason))
163 if (!sdl_wait_for_result(instance->context, SDL_EVENT_USER_AUTH_RESULT, &event))
168 res = arg->result > 0;
173 *username = arg->user;
174 *domain = arg->domain;
175 *password = arg->password;
180BOOL sdl_choose_smartcard(freerdp* instance,
SmartcardCertInfo** cert_list, DWORD count,
181 DWORD* choice, BOOL gateway)
185 WINPR_ASSERT(instance);
186 WINPR_ASSERT(cert_list);
187 WINPR_ASSERT(choice);
189 std::vector<std::string> strlist;
190 std::vector<const char*> list;
191 for (DWORD i = 0; i < count; i++)
194 char* reader = ConvertWCharToUtf8Alloc(cert->reader,
nullptr);
195 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName,
nullptr);
200 winpr_asprintf(&msg, &len,
201 "%s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s",
202 container_name, reader, cert->userHint, cert->domainHint, cert->subject,
203 cert->issuer, cert->upn);
205 strlist.emplace_back(msg);
208 free(container_name);
210 auto& m = strlist.back();
211 list.push_back(m.c_str());
214 SDL_Event
event = {};
215 const char* title =
"Select a logon smartcard certificate";
217 title =
"Select a gateway logon smartcard certificate";
218 if (!sdl_push_user_event(SDL_EVENT_USER_SCARD_DIALOG, title, list.data(), count))
221 if (!sdl_wait_for_result(instance->context, SDL_EVENT_USER_SCARD_RESULT, &event))
224 res = (
event.user.code >= 0);
225 *choice =
static_cast<DWORD
>(
event.user.code);
230SSIZE_T sdl_retry_dialog(freerdp* instance,
const char* what,
size_t current,
231 [[maybe_unused]]
void* userarg)
233 WINPR_ASSERT(instance);
234 WINPR_ASSERT(instance->context);
237 auto sdl = get_context(instance->context);
238 auto settings = instance->context->settings;
242 sdl->getDialog().setTitle(
"Retry connection to %s",
245 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
247 sdl->getDialog().showError(
"Unknown module %s, aborting", what);
253 if (strcmp(what,
"arm-transport") == 0)
254 sdl->getDialog().showWarn(
"[%s] Starting your VM. It may take up to 5 minutes", what);
259 sdl->getDialog().showError(
260 "Automatic reconnection disabled, terminating. Try to connect again later");
267 sdl->getDialog().showError(
268 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
269 "tech support for help if this keeps happening.",
274 sdl->getDialog().showInfo(
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
275 "ms before next attempt",
276 what, current + 1, max, delay);
277 return WINPR_ASSERTING_INT_CAST(ssize_t, delay);
280BOOL sdl_present_gateway_message(freerdp* instance, [[maybe_unused]] UINT32 type,
281 BOOL isDisplayMandatory, BOOL isConsentMandatory,
size_t length,
282 const WCHAR* wmessage)
284 if (!isDisplayMandatory)
287 char* title =
nullptr;
289 winpr_asprintf(&title, &len,
"[gateway]");
292 if (isConsentMandatory)
293 flags = SHOW_DIALOG_ACCEPT_REJECT;
294 else if (isDisplayMandatory)
295 flags = SHOW_DIALOG_TIMED_ACCEPT;
296 char* message = ConvertWCharNToUtf8Alloc(wmessage, length,
nullptr);
298 const int rc = sdl_show_dialog(instance->context, title, message, flags);
304int sdl_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
308 if (!instance || !instance->context)
314 case LOGON_MSG_SESSION_CONTINUE:
322 case LOGON_FAILED_OTHER:
328 const char* str_data = freerdp_get_logon_error_info_data(data);
329 const char* str_type = freerdp_get_logon_error_info_type(type);
330 char* title =
nullptr;
332 winpr_asprintf(&title, &tlen,
"[%s] info",
335 char* message =
nullptr;
337 winpr_asprintf(&message, &mlen,
"Logon Error Info %s [%s]", str_data, str_type);
339 rc = sdl_show_dialog(instance->context, title, message, SHOW_DIALOG_ACCEPT_REJECT);
345static DWORD sdl_show_ceritifcate_dialog(rdpContext* context,
const char* title,
348 if (!sdl_push_user_event(SDL_EVENT_USER_CERT_DIALOG, title, message))
351 SDL_Event
event = {};
352 if (!sdl_wait_for_result(context, SDL_EVENT_USER_CERT_RESULT, &event))
354 return static_cast<DWORD
>(
event.user.code);
357static char* sdl_pem_cert(
const char* pem)
359 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
363 char* fp = freerdp_certificate_get_fingerprint(cert);
364 char* start = freerdp_certificate_get_validity(cert, TRUE);
365 char* end = freerdp_certificate_get_validity(cert, FALSE);
366 freerdp_certificate_free(cert);
370 winpr_asprintf(&str, &slen,
381DWORD sdl_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
382 const char* common_name,
const char* subject,
383 const char* issuer,
const char* new_fingerprint,
384 const char* old_subject,
const char* old_issuer,
385 const char* old_fingerprint, DWORD flags)
387 const char* type = type_str_for_flags(flags);
389 WINPR_ASSERT(instance);
390 WINPR_ASSERT(instance->context);
391 WINPR_ASSERT(instance->context->settings);
396 char* new_fp_str =
nullptr;
398 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
399 new_fp_str = sdl_pem_cert(new_fingerprint);
401 winpr_asprintf(&new_fp_str, &len,
"Thumbprint: %s\n", new_fingerprint);
406 char* old_fp_str =
nullptr;
408 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
409 old_fp_str = sdl_pem_cert(old_fingerprint);
411 winpr_asprintf(&old_fp_str, &olen,
"Thumbprint: %s\n", old_fingerprint);
413 const char* collission_str =
"";
414 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
417 "A matching entry with legacy SHA1 was found in local known_hosts2 store.\n"
418 "If you just upgraded from a FreeRDP version before 2.0 this is expected.\n"
419 "The hashing algorithm has been upgraded from SHA1 to SHA256.\n"
420 "All manually accepted certificates must be reconfirmed!\n"
424 char* title =
nullptr;
426 winpr_asprintf(&title, &tlen,
"Certificate for %s:%" PRIu16
" (%s) has changed", host, port,
429 char* message =
nullptr;
431 winpr_asprintf(&message, &mlen,
432 "New Certificate details:\n"
437 "Old Certificate details:\n"
442 "The above X.509 certificate does not match the certificate used for previous "
444 "This may indicate that the certificate has been tampered with.\n"
445 "Please contact the administrator of the RDP server and clarify.\n",
446 common_name, subject, issuer, new_fp_str, old_subject, old_issuer, old_fp_str,
449 const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
458DWORD sdl_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
459 const char* common_name,
const char* subject,
const char* issuer,
460 const char* fingerprint, DWORD flags)
462 const char* type = type_str_for_flags(flags);
467 char* fp_str =
nullptr;
469 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
470 fp_str = sdl_pem_cert(fingerprint);
472 winpr_asprintf(&fp_str, &len,
"Thumbprint: %s\n", fingerprint);
474 char* title =
nullptr;
476 winpr_asprintf(&title, &tlen,
"New certificate for %s:%" PRIu16
" (%s)", host, port, type);
478 char* message =
nullptr;
486 "The above X.509 certificate could not be verified, possibly because you do not have\n"
487 "the CA certificate in your certificate store, or the certificate has expired.\n"
488 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n",
489 common_name, subject, issuer, fp_str);
491 const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
498BOOL sdl_cert_dialog_show(
const char* title,
const char* message)
503 BUTTONID_CERT_ACCEPT_PERMANENT = 23,
504 BUTTONID_CERT_ACCEPT_TEMPORARY = 24,
505 BUTTONID_CERT_DENY = 25
507 const SDL_MessageBoxButtonData buttons[] = {
508 { 0, BUTTONID_CERT_ACCEPT_PERMANENT,
"permanent" },
509 { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_CERT_ACCEPT_TEMPORARY,
"temporary" },
510 { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_CERT_DENY,
"cancel" }
513 const SDL_MessageBoxData data = { SDL_MESSAGEBOX_WARNING,
nullptr, title, message,
514 ARRAYSIZE(buttons), buttons,
nullptr };
515 const int rc = SDL_ShowMessageBox(&data, &buttonid);
524 case BUTTONID_CERT_ACCEPT_PERMANENT:
527 case BUTTONID_CERT_ACCEPT_TEMPORARY:
536 return sdl_push_user_event(SDL_EVENT_USER_CERT_RESULT, value);
539BOOL sdl_message_dialog_show(
const char* title,
const char* message, Sint32 flags)
544 BUTTONID_SHOW_ACCEPT = 24,
545 BUTTONID_SHOW_DENY = 25
547 const SDL_MessageBoxButtonData buttons[] = {
548 { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_SHOW_ACCEPT,
"accept" },
549 { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_SHOW_DENY,
"cancel" }
552 const int button_cnt = (flags & SHOW_DIALOG_ACCEPT_REJECT) ? 2 : 1;
553 const SDL_MessageBoxData data = {
554 SDL_MESSAGEBOX_WARNING,
nullptr, title, message, button_cnt, buttons,
nullptr
556 const int rc = SDL_ShowMessageBox(&data, &buttonid);
565 case BUTTONID_SHOW_ACCEPT:
574 return sdl_push_user_event(SDL_EVENT_USER_SHOW_RESULT, value);
579 const std::vector<std::string> auth = {
"Username: ",
"Domain: ",
581 const std::vector<std::string> authPin = {
"Device: ",
"PIN: " };
582 const std::vector<std::string> fidoPin = {
"FIDO2 PIN: " };
583 const std::vector<std::string> gw = {
"GatewayUsername: ",
"GatewayDomain: ",
584 "GatewayPassword: " };
585 std::vector<std::string> prompt;
588 switch (args->result)
590 case AUTH_SMARTCARD_PIN:
611 std::vector<std::string> result;
613 auto parent = SDL_GetMouseFocus();
615 parent = SDL_GetKeyboardFocus();
619 std::vector<std::string> initial{ args->user ? args->user :
"Smartcard",
"" };
620 std::vector<Uint32> flags = { SdlInputWidgetPair::SDL_INPUT_READONLY,
621 SdlInputWidgetPair::SDL_INPUT_MASK };
622 if (args->result == AUTH_FIDO_PIN)
625 flags = { SdlInputWidgetPair::SDL_INPUT_MASK };
627 else if (args->result != AUTH_SMARTCARD_PIN)
629 initial = { args->user ? args->user :
"", args->domain ? args->domain :
"",
630 args->password ? args->password :
"" };
631 flags = { 0, 0, SdlInputWidgetPair::SDL_INPUT_MASK };
634 ssize_t selected = -1;
635 switch (args->result)
637 case AUTH_SMARTCARD_PIN:
651 ilist.parent(parent);
652 rc = ilist.run(result);
655 if ((result.size() < prompt.size()))
658 char* user =
nullptr;
659 char* domain =
nullptr;
663 if (args->result == AUTH_FIDO_PIN)
665 pwd = _strdup(result.at(0).c_str());
669 user = _strdup(result.at(0).c_str());
670 if (args->result == AUTH_SMARTCARD_PIN)
671 pwd = _strdup(result.at(1).c_str());
674 domain = _strdup(result.at(1).c_str());
675 pwd = _strdup(result.at(2).c_str());
680 return sdl_push_user_event(SDL_EVENT_USER_AUTH_RESULT, user, domain, pwd, rc);
683BOOL sdl_scard_dialog_show(
const char* title, Sint32 count,
const char** list)
685 std::vector<std::string> vlist;
686 vlist.reserve(WINPR_ASSERTING_INT_CAST(
size_t, count));
687 for (Sint32 x = 0; x < count; x++)
688 vlist.emplace_back(list[x]);
690 Sint32 value = slist.run();
691 return sdl_push_user_event(SDL_EVENT_USER_SCARD_RESULT, value);
694void sdl_dialogs_uninit()
699void sdl_dialogs_init()
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_server_name(const rdpSettings *settings)
A helper function to return the correct server name.
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 UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.