24#include <freerdp/log.h>
25#include <freerdp/utils/smartcardlogon.h>
29#include "../sdl_freerdp.hpp"
30#include "sdl_dialogs.hpp"
31#include "sdl_input.hpp"
32#include "sdl_input_widgets.hpp"
33#include "sdl_select.hpp"
34#include "sdl_selectlist.hpp"
38 SHOW_DIALOG_ACCEPT_REJECT = 1,
39 SHOW_DIALOG_TIMED_ACCEPT = 2
42static const char* type_str_for_flags(UINT32 flags)
44 const char* type =
"RDP-Server";
46 if (flags & VERIFY_CERT_FLAG_GATEWAY)
49 if (flags & VERIFY_CERT_FLAG_REDIRECT)
50 type =
"RDP-Redirect";
54static BOOL sdl_wait_for_result(rdpContext* context, Uint32 type, SDL_Event* result)
56 const SDL_Event empty = {};
58 WINPR_ASSERT(context);
61 while (!freerdp_shall_disconnect_context(context))
64 const int rc = SDL_PeepEvents(result, 1, SDL_GETEVENT, type, type);
72static int sdl_show_dialog(rdpContext* context,
const char* title,
const char* message,
77 if (!sdl_push_user_event(SDL_USEREVENT_SHOW_DIALOG, title, message, flags))
80 if (!sdl_wait_for_result(context, SDL_USEREVENT_SHOW_RESULT, &event))
83 return event.user.code;
86BOOL sdl_authenticate_ex(freerdp* instance,
char** username,
char** password,
char** domain,
87 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 scope(title, free);
134 if (!sdl_push_user_event(SDL_USEREVENT_AUTH_DIALOG, title, u, d, p, reason))
137 if (!sdl_wait_for_result(instance->context, SDL_USEREVENT_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);
164 std::vector<std::string> strlist;
165 std::vector<const char*> list;
166 for (DWORD i = 0; i < count; i++)
169 char* reader = ConvertWCharToUtf8Alloc(cert->reader,
nullptr);
170 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName,
nullptr);
175 winpr_asprintf(&msg, &len,
176 "%s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s",
177 container_name, reader, cert->userHint, cert->domainHint, cert->subject,
178 cert->issuer, cert->upn);
180 strlist.emplace_back(msg);
183 free(container_name);
185 auto& m = strlist.back();
186 list.push_back(m.c_str());
189 SDL_Event
event = {};
190 const char* title =
"Select a logon smartcard certificate";
192 title =
"Select a gateway logon smartcard certificate";
193 if (!sdl_push_user_event(SDL_USEREVENT_SCARD_DIALOG, title, list.data(), count))
196 if (!sdl_wait_for_result(instance->context, SDL_USEREVENT_SCARD_RESULT, &event))
199 res = (
event.user.code >= 0);
200 *choice =
static_cast<DWORD
>(
event.user.code);
205SSIZE_T sdl_retry_dialog(freerdp* instance,
const char* what,
size_t current,
206 [[maybe_unused]]
void* userarg)
208 WINPR_ASSERT(instance);
209 WINPR_ASSERT(instance->context);
212 auto sdl = get_context(instance->context);
213 auto settings = instance->context->settings;
215 std::scoped_lock lock(sdl->critical);
216 if (!sdl->connection_dialog)
217 return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
219 sdl->connection_dialog->setTitle(
"Retry connection to %s",
222 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
224 sdl->connection_dialog->showError(
"Unknown module %s, aborting", what);
230 if (strcmp(what,
"arm-transport") == 0)
231 sdl->connection_dialog->showWarn(
"[%s] Starting your VM. It may take up to 5 minutes",
239 sdl->connection_dialog->showError(
240 "Automatic reconnection disabled, terminating. Try to connect again later");
248 sdl->connection_dialog->showError(
249 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
250 "tech support for help if this keeps happening.",
255 sdl->connection_dialog->showInfo(
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
256 "ms before next attempt",
257 what, current + 1, max, delay);
258 return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
261BOOL sdl_present_gateway_message(freerdp* instance, [[maybe_unused]] UINT32 type,
262 BOOL isDisplayMandatory, BOOL isConsentMandatory,
size_t length,
263 const WCHAR* wmessage)
265 if (!isDisplayMandatory)
268 char* title =
nullptr;
270 winpr_asprintf(&title, &len,
"[gateway]");
273 if (isConsentMandatory)
274 flags = SHOW_DIALOG_ACCEPT_REJECT;
275 else if (isDisplayMandatory)
276 flags = SHOW_DIALOG_TIMED_ACCEPT;
277 char* message = ConvertWCharNToUtf8Alloc(wmessage, length,
nullptr);
280 const int rc = sdl_show_dialog(instance->context, title, message, flags);
286int sdl_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
289 const char* str_data = freerdp_get_logon_error_info_data(data);
290 const char* str_type = freerdp_get_logon_error_info_type(type);
292 if (!instance || !instance->context)
296 if (type == LOGON_MSG_SESSION_CONTINUE)
301 char* title =
nullptr;
303 winpr_asprintf(&title, &tlen,
"[%s] info",
306 char* message =
nullptr;
308 winpr_asprintf(&message, &mlen,
"Logon Error Info %s [%s]", str_data, str_type);
310 rc = sdl_show_dialog(instance->context, title, message, SHOW_DIALOG_ACCEPT_REJECT);
316static DWORD sdl_show_ceritifcate_dialog(rdpContext* context,
const char* title,
320 if (!sdl_push_user_event(SDL_USEREVENT_CERT_DIALOG, title, message))
323 SDL_Event
event = {};
324 if (!sdl_wait_for_result(context, SDL_USEREVENT_CERT_RESULT, &event))
326 return static_cast<DWORD
>(
event.user.code);
329static char* sdl_pem_cert(
const char* pem)
331 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
335 char* fp = freerdp_certificate_get_fingerprint(cert);
336 char* start = freerdp_certificate_get_validity(cert, TRUE);
337 char* end = freerdp_certificate_get_validity(cert, FALSE);
338 freerdp_certificate_free(cert);
342 winpr_asprintf(&str, &slen,
353DWORD sdl_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
354 const char* common_name,
const char* subject,
355 const char* issuer,
const char* new_fingerprint,
356 const char* old_subject,
const char* old_issuer,
357 const char* old_fingerprint, DWORD flags)
359 const char* type = type_str_for_flags(flags);
361 WINPR_ASSERT(instance);
362 WINPR_ASSERT(instance->context);
363 WINPR_ASSERT(instance->context->settings);
369 char* new_fp_str =
nullptr;
371 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
372 new_fp_str = sdl_pem_cert(new_fingerprint);
374 winpr_asprintf(&new_fp_str, &len,
"Thumbprint: %s\n", new_fingerprint);
379 char* old_fp_str =
nullptr;
381 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
382 old_fp_str = sdl_pem_cert(old_fingerprint);
384 winpr_asprintf(&old_fp_str, &olen,
"Thumbprint: %s\n", old_fingerprint);
386 const char* collission_str =
"";
387 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
390 "A matching entry with legacy SHA1 was found in local known_hosts2 store.\n"
391 "If you just upgraded from a FreeRDP version before 2.0 this is expected.\n"
392 "The hashing algorithm has been upgraded from SHA1 to SHA256.\n"
393 "All manually accepted certificates must be reconfirmed!\n"
397 char* title =
nullptr;
399 winpr_asprintf(&title, &tlen,
"Certificate for %s:%" PRIu16
" (%s) has changed", host, port,
402 char* message =
nullptr;
404 winpr_asprintf(&message, &mlen,
405 "New Certificate details:\n"
410 "Old Certificate details:\n"
415 "The above X.509 certificate does not match the certificate used for previous "
417 "This may indicate that the certificate has been tampered with.\n"
418 "Please contact the administrator of the RDP server and clarify.\n",
419 common_name, subject, issuer, new_fp_str, old_subject, old_issuer, old_fp_str,
422 const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
431DWORD sdl_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
432 const char* common_name,
const char* subject,
const char* issuer,
433 const char* fingerprint, DWORD flags)
435 const char* type = type_str_for_flags(flags);
440 char* fp_str =
nullptr;
442 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
443 fp_str = sdl_pem_cert(fingerprint);
445 winpr_asprintf(&fp_str, &len,
"Thumbprint: %s\n", fingerprint);
447 char* title =
nullptr;
449 winpr_asprintf(&title, &tlen,
"New certificate for %s:%" PRIu16
" (%s)", host, port, type);
451 char* message =
nullptr;
459 "The above X.509 certificate could not be verified, possibly because you do not have\n"
460 "the CA certificate in your certificate store, or the certificate has expired.\n"
461 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n",
462 common_name, subject, issuer, fp_str);
465 const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
472BOOL sdl_cert_dialog_show(
const char* title,
const char* message)
477 BUTTONID_CERT_ACCEPT_PERMANENT = 23,
478 BUTTONID_CERT_ACCEPT_TEMPORARY = 24,
479 BUTTONID_CERT_DENY = 25
481 const SDL_MessageBoxButtonData buttons[] = {
482 { 0, BUTTONID_CERT_ACCEPT_PERMANENT,
"permanent" },
483 { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_CERT_ACCEPT_TEMPORARY,
"temporary" },
484 { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_CERT_DENY,
"cancel" }
487 const SDL_MessageBoxData data = { SDL_MESSAGEBOX_WARNING,
nullptr, title, message,
488 ARRAYSIZE(buttons), buttons,
nullptr };
489 const int rc = SDL_ShowMessageBox(&data, &buttonid);
498 case BUTTONID_CERT_ACCEPT_PERMANENT:
501 case BUTTONID_CERT_ACCEPT_TEMPORARY:
510 return sdl_push_user_event(SDL_USEREVENT_CERT_RESULT, value);
513BOOL sdl_message_dialog_show(
const char* title,
const char* message, Sint32 flags)
518 BUTTONID_SHOW_ACCEPT = 24,
519 BUTTONID_SHOW_DENY = 25
521 const SDL_MessageBoxButtonData buttons[] = {
522 { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_SHOW_ACCEPT,
"accept" },
523 { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_SHOW_DENY,
"cancel" }
526 const int button_cnt = (flags & SHOW_DIALOG_ACCEPT_REJECT) ? 2 : 1;
527 const SDL_MessageBoxData data = {
528 SDL_MESSAGEBOX_WARNING,
nullptr, title, message, button_cnt, buttons,
nullptr
530 const int rc = SDL_ShowMessageBox(&data, &buttonid);
539 case BUTTONID_SHOW_ACCEPT:
548 return sdl_push_user_event(SDL_USEREVENT_SHOW_RESULT, value);
553 const std::vector<std::string> auth = {
"Username: ",
"Domain: ",
555 const std::vector<std::string> authPin = {
"Device: ",
"PIN: " };
556 const std::vector<std::string> fidoPin = {
"FIDO2 PIN: " };
557 const std::vector<std::string> gw = {
"GatewayUsername: ",
"GatewayDomain: ",
558 "GatewayPassword: " };
559 std::vector<std::string> prompt;
562 switch (args->result)
564 case AUTH_SMARTCARD_PIN:
584 std::vector<std::string> result;
588 std::vector<std::string> initial{ args->user ? args->user :
"Smartcard",
"" };
589 std::vector<Uint32> flags = { SdlInputWidget::SDL_INPUT_READONLY,
590 SdlInputWidget::SDL_INPUT_MASK };
591 if (args->result == AUTH_FIDO_PIN)
594 flags = { SdlInputWidget::SDL_INPUT_MASK };
596 else if (args->result != AUTH_SMARTCARD_PIN)
598 initial = { args->user ? args->user :
"", args->domain ? args->domain :
"",
599 args->password ? args->password :
"" };
600 flags = { 0, 0, SdlInputWidget::SDL_INPUT_MASK };
603 rc = ilist.run(result);
606 if ((result.size() < prompt.size()))
609 char* user =
nullptr;
610 char* domain =
nullptr;
614 if (args->result == AUTH_FIDO_PIN)
616 pwd = _strdup(result.at(0).c_str());
620 user = _strdup(result.at(0).c_str());
621 if (args->result == AUTH_SMARTCARD_PIN)
622 pwd = _strdup(result.at(1).c_str());
625 domain = _strdup(result.at(1).c_str());
626 pwd = _strdup(result.at(2).c_str());
630 return sdl_push_user_event(SDL_USEREVENT_AUTH_RESULT, user, domain, pwd, rc);
633BOOL sdl_scard_dialog_show(
const char* title, Sint32 count,
const char** list)
635 const auto scount = WINPR_ASSERTING_INT_CAST(
size_t, count);
636 std::vector<std::string> vlist;
637 vlist.reserve(scount);
638 for (
size_t x = 0; x < scount; x++)
639 vlist.emplace_back(list[x]);
641 Sint32 value = slist.run();
642 return sdl_push_user_event(SDL_USEREVENT_SCARD_RESULT, value);
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.