24#include <freerdp/log.h>
25#include <freerdp/utils/smartcardlogon.h>
29#include "../sdl_context.hpp"
30#include "sdl_dialogs.hpp"
31#include "sdl_input_widget_pair.hpp"
32#include "sdl_input_widget_pair_list.hpp"
33#include "sdl_select.hpp"
34#include "sdl_select_list.hpp"
35#include "sdl_connection_dialog.hpp"
39 SHOW_DIALOG_ACCEPT_REJECT = 1,
40 SHOW_DIALOG_TIMED_ACCEPT = 2
43static const char* type_str_for_flags(UINT32 flags)
45 const char* type =
"RDP-Server";
47 if (flags & VERIFY_CERT_FLAG_GATEWAY)
50 if (flags & VERIFY_CERT_FLAG_REDIRECT)
51 type =
"RDP-Redirect";
55static BOOL sdl_wait_for_result(rdpContext* context, Uint32 type, SDL_Event* result)
57 const SDL_Event empty = {};
59 WINPR_ASSERT(context);
62 while (!freerdp_shall_disconnect_context(context))
65 const int rc = SDL_PeepEvents(result, 1, SDL_GETEVENT, type, type);
73static int sdl_show_dialog(rdpContext* context,
const char* title,
const char* message,
78 if (!sdl_push_user_event(SDL_EVENT_USER_SHOW_DIALOG, title, message, flags))
81 if (!sdl_wait_for_result(context, SDL_EVENT_USER_SHOW_RESULT, &event))
84 return event.user.code;
87BOOL sdl_authenticate_ex(freerdp* instance,
char** username,
char** password,
char** domain,
88 rdp_auth_reason reason)
102 case AUTH_SMARTCARD_PIN:
104 if ((*username) && (*password))
117 char* title =
nullptr;
118 size_t titlesize = 0;
119 winpr_asprintf(&title, &titlesize,
"Credentials required for %s", target);
121 CStringPtr guard(title, free);
134 if (!sdl_push_user_event(SDL_EVENT_USER_AUTH_DIALOG, title, u, d, p, reason))
137 if (!sdl_wait_for_result(instance->context, SDL_EVENT_USER_AUTH_RESULT, &event))
142 res = arg->result > 0;
147 *username = arg->user;
148 *domain = arg->domain;
149 *password = arg->password;
154BOOL sdl_choose_smartcard(freerdp* instance,
SmartcardCertInfo** cert_list, DWORD count,
155 DWORD* choice, BOOL gateway)
159 WINPR_ASSERT(instance);
160 WINPR_ASSERT(cert_list);
161 WINPR_ASSERT(choice);
163 std::vector<std::string> strlist;
164 std::vector<const char*> list;
165 for (DWORD i = 0; i < count; i++)
168 char* reader = ConvertWCharToUtf8Alloc(cert->reader,
nullptr);
169 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName,
nullptr);
174 winpr_asprintf(&msg, &len,
175 "%s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s",
176 container_name, reader, cert->userHint, cert->domainHint, cert->subject,
177 cert->issuer, cert->upn);
179 strlist.emplace_back(msg);
182 free(container_name);
184 auto& m = strlist.back();
185 list.push_back(m.c_str());
188 SDL_Event
event = {};
189 const char* title =
"Select a logon smartcard certificate";
191 title =
"Select a gateway logon smartcard certificate";
192 if (!sdl_push_user_event(SDL_EVENT_USER_SCARD_DIALOG, title, list.data(), count))
195 if (!sdl_wait_for_result(instance->context, SDL_EVENT_USER_SCARD_RESULT, &event))
198 res = (
event.user.code >= 0);
199 *choice =
static_cast<DWORD
>(
event.user.code);
204SSIZE_T sdl_retry_dialog(freerdp* instance,
const char* what,
size_t current,
205 [[maybe_unused]]
void* userarg)
207 WINPR_ASSERT(instance);
208 WINPR_ASSERT(instance->context);
211 auto sdl = get_context(instance->context);
212 auto settings = instance->context->settings;
216 sdl->getDialog().setTitle(
"Retry connection to %s",
219 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
221 sdl->getDialog().showError(
"Unknown module %s, aborting", what);
227 if (strcmp(what,
"arm-transport") == 0)
228 sdl->getDialog().showWarn(
"[%s] Starting your VM. It may take up to 5 minutes", what);
233 sdl->getDialog().showError(
234 "Automatic reconnection disabled, terminating. Try to connect again later");
241 sdl->getDialog().showError(
242 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
243 "tech support for help if this keeps happening.",
248 sdl->getDialog().showInfo(
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
249 "ms before next attempt",
250 what, current + 1, max, delay);
251 return WINPR_ASSERTING_INT_CAST(ssize_t, delay);
254BOOL sdl_present_gateway_message(freerdp* instance, [[maybe_unused]] UINT32 type,
255 BOOL isDisplayMandatory, BOOL isConsentMandatory,
size_t length,
256 const WCHAR* wmessage)
258 if (!isDisplayMandatory)
261 char* title =
nullptr;
263 winpr_asprintf(&title, &len,
"[gateway]");
266 if (isConsentMandatory)
267 flags = SHOW_DIALOG_ACCEPT_REJECT;
268 else if (isDisplayMandatory)
269 flags = SHOW_DIALOG_TIMED_ACCEPT;
270 char* message = ConvertWCharNToUtf8Alloc(wmessage, length,
nullptr);
272 const int rc = sdl_show_dialog(instance->context, title, message, flags);
278int sdl_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
281 const char* str_data = freerdp_get_logon_error_info_data(data);
282 const char* str_type = freerdp_get_logon_error_info_type(type);
284 if (!instance || !instance->context)
288 if (type == LOGON_MSG_SESSION_CONTINUE)
291 char* title =
nullptr;
293 winpr_asprintf(&title, &tlen,
"[%s] info",
296 char* message =
nullptr;
298 winpr_asprintf(&message, &mlen,
"Logon Error Info %s [%s]", str_data, str_type);
300 rc = sdl_show_dialog(instance->context, title, message, SHOW_DIALOG_ACCEPT_REJECT);
306static DWORD sdl_show_ceritifcate_dialog(rdpContext* context,
const char* title,
309 if (!sdl_push_user_event(SDL_EVENT_USER_CERT_DIALOG, title, message))
312 SDL_Event
event = {};
313 if (!sdl_wait_for_result(context, SDL_EVENT_USER_CERT_RESULT, &event))
315 return static_cast<DWORD
>(
event.user.code);
318static char* sdl_pem_cert(
const char* pem)
320 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
324 char* fp = freerdp_certificate_get_fingerprint(cert);
325 char* start = freerdp_certificate_get_validity(cert, TRUE);
326 char* end = freerdp_certificate_get_validity(cert, FALSE);
327 freerdp_certificate_free(cert);
331 winpr_asprintf(&str, &slen,
342DWORD sdl_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
343 const char* common_name,
const char* subject,
344 const char* issuer,
const char* new_fingerprint,
345 const char* old_subject,
const char* old_issuer,
346 const char* old_fingerprint, DWORD flags)
348 const char* type = type_str_for_flags(flags);
350 WINPR_ASSERT(instance);
351 WINPR_ASSERT(instance->context);
352 WINPR_ASSERT(instance->context->settings);
357 char* new_fp_str =
nullptr;
359 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
360 new_fp_str = sdl_pem_cert(new_fingerprint);
362 winpr_asprintf(&new_fp_str, &len,
"Thumbprint: %s\n", new_fingerprint);
367 char* old_fp_str =
nullptr;
369 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
370 old_fp_str = sdl_pem_cert(old_fingerprint);
372 winpr_asprintf(&old_fp_str, &olen,
"Thumbprint: %s\n", old_fingerprint);
374 const char* collission_str =
"";
375 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
378 "A matching entry with legacy SHA1 was found in local known_hosts2 store.\n"
379 "If you just upgraded from a FreeRDP version before 2.0 this is expected.\n"
380 "The hashing algorithm has been upgraded from SHA1 to SHA256.\n"
381 "All manually accepted certificates must be reconfirmed!\n"
385 char* title =
nullptr;
387 winpr_asprintf(&title, &tlen,
"Certificate for %s:%" PRIu16
" (%s) has changed", host, port,
390 char* message =
nullptr;
392 winpr_asprintf(&message, &mlen,
393 "New Certificate details:\n"
398 "Old Certificate details:\n"
403 "The above X.509 certificate does not match the certificate used for previous "
405 "This may indicate that the certificate has been tampered with.\n"
406 "Please contact the administrator of the RDP server and clarify.\n",
407 common_name, subject, issuer, new_fp_str, old_subject, old_issuer, old_fp_str,
410 const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
419DWORD sdl_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
420 const char* common_name,
const char* subject,
const char* issuer,
421 const char* fingerprint, DWORD flags)
423 const char* type = type_str_for_flags(flags);
428 char* fp_str =
nullptr;
430 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
431 fp_str = sdl_pem_cert(fingerprint);
433 winpr_asprintf(&fp_str, &len,
"Thumbprint: %s\n", fingerprint);
435 char* title =
nullptr;
437 winpr_asprintf(&title, &tlen,
"New certificate for %s:%" PRIu16
" (%s)", host, port, type);
439 char* message =
nullptr;
447 "The above X.509 certificate could not be verified, possibly because you do not have\n"
448 "the CA certificate in your certificate store, or the certificate has expired.\n"
449 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n",
450 common_name, subject, issuer, fp_str);
452 const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
459BOOL sdl_cert_dialog_show(
const char* title,
const char* message)
464 BUTTONID_CERT_ACCEPT_PERMANENT = 23,
465 BUTTONID_CERT_ACCEPT_TEMPORARY = 24,
466 BUTTONID_CERT_DENY = 25
468 const SDL_MessageBoxButtonData buttons[] = {
469 { 0, BUTTONID_CERT_ACCEPT_PERMANENT,
"permanent" },
470 { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_CERT_ACCEPT_TEMPORARY,
"temporary" },
471 { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_CERT_DENY,
"cancel" }
474 const SDL_MessageBoxData data = { SDL_MESSAGEBOX_WARNING,
nullptr, title, message,
475 ARRAYSIZE(buttons), buttons,
nullptr };
476 const int rc = SDL_ShowMessageBox(&data, &buttonid);
485 case BUTTONID_CERT_ACCEPT_PERMANENT:
488 case BUTTONID_CERT_ACCEPT_TEMPORARY:
497 return sdl_push_user_event(SDL_EVENT_USER_CERT_RESULT, value);
500BOOL sdl_message_dialog_show(
const char* title,
const char* message, Sint32 flags)
505 BUTTONID_SHOW_ACCEPT = 24,
506 BUTTONID_SHOW_DENY = 25
508 const SDL_MessageBoxButtonData buttons[] = {
509 { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_SHOW_ACCEPT,
"accept" },
510 { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_SHOW_DENY,
"cancel" }
513 const int button_cnt = (flags & SHOW_DIALOG_ACCEPT_REJECT) ? 2 : 1;
514 const SDL_MessageBoxData data = {
515 SDL_MESSAGEBOX_WARNING,
nullptr, title, message, button_cnt, buttons,
nullptr
517 const int rc = SDL_ShowMessageBox(&data, &buttonid);
526 case BUTTONID_SHOW_ACCEPT:
535 return sdl_push_user_event(SDL_EVENT_USER_SHOW_RESULT, value);
540 const std::vector<std::string> auth = {
"Username: ",
"Domain: ",
542 const std::vector<std::string> authPin = {
"Device: ",
"PIN: " };
543 const std::vector<std::string> fidoPin = {
"FIDO2 PIN: " };
544 const std::vector<std::string> gw = {
"GatewayUsername: ",
"GatewayDomain: ",
545 "GatewayPassword: " };
546 std::vector<std::string> prompt;
549 switch (args->result)
551 case AUTH_SMARTCARD_PIN:
572 std::vector<std::string> result;
574 auto parent = SDL_GetMouseFocus();
576 parent = SDL_GetKeyboardFocus();
580 std::vector<std::string> initial{ args->user ? args->user :
"Smartcard",
"" };
581 std::vector<Uint32> flags = { SdlInputWidgetPair::SDL_INPUT_READONLY,
582 SdlInputWidgetPair::SDL_INPUT_MASK };
583 if (args->result == AUTH_FIDO_PIN)
586 flags = { SdlInputWidgetPair::SDL_INPUT_MASK };
588 else if (args->result != AUTH_SMARTCARD_PIN)
590 if (args->result == AUTH_RDSTLS)
592 initial = { args->user ? args->user :
"", args->password ? args->password :
"" };
593 flags = { 0, SdlInputWidgetPair::SDL_INPUT_MASK };
597 initial = { args->user ? args->user :
"", args->domain ? args->domain :
"",
598 args->password ? args->password :
"" };
599 flags = { 0, 0, SdlInputWidgetPair::SDL_INPUT_MASK };
603 ssize_t selected = -1;
604 switch (args->result)
606 case AUTH_SMARTCARD_PIN:
619 ilist.parent(parent);
620 rc = ilist.run(result);
623 if ((result.size() < prompt.size()))
626 char* user =
nullptr;
627 char* domain =
nullptr;
631 if (args->result == AUTH_FIDO_PIN)
633 pwd = _strdup(result.at(0).c_str());
637 user = _strdup(result.at(0).c_str());
638 if (args->result == AUTH_SMARTCARD_PIN)
639 pwd = _strdup(result.at(1).c_str());
642 domain = _strdup(result.at(1).c_str());
643 pwd = _strdup(result.at(2).c_str());
648 return sdl_push_user_event(SDL_EVENT_USER_AUTH_RESULT, user, domain, pwd, rc);
651BOOL sdl_scard_dialog_show(
const char* title, Sint32 count,
const char** list)
653 std::vector<std::string> vlist;
654 vlist.reserve(WINPR_ASSERTING_INT_CAST(
size_t, count));
655 for (Sint32 x = 0; x < count; x++)
656 vlist.emplace_back(list[x]);
658 Sint32 value = slist.run();
659 return sdl_push_user_event(SDL_EVENT_USER_SCARD_RESULT, value);
662void sdl_dialogs_uninit()
667void 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.