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:
103 if ((*username) && (*password))
116 char* title =
nullptr;
117 size_t titlesize = 0;
118 winpr_asprintf(&title, &titlesize,
"Credentials required for %s", target);
120 std::unique_ptr<char,
decltype(&free)> scope(title, free);
133 if (!sdl_push_user_event(SDL_USEREVENT_AUTH_DIALOG, title, u, d, p, reason))
136 if (!sdl_wait_for_result(instance->context, SDL_USEREVENT_AUTH_RESULT, &event))
141 res = arg->result > 0;
146 *username = arg->user;
147 *domain = arg->domain;
148 *password = arg->password;
153BOOL sdl_choose_smartcard(freerdp* instance,
SmartcardCertInfo** cert_list, DWORD count,
154 DWORD* choice, BOOL gateway)
158 WINPR_ASSERT(instance);
159 WINPR_ASSERT(cert_list);
160 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_USEREVENT_SCARD_DIALOG, title, list.data(), count))
195 if (!sdl_wait_for_result(instance->context, SDL_USEREVENT_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;
214 std::lock_guard<CriticalSection> lock(sdl->critical);
215 if (!sdl->connection_dialog)
216 return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
218 sdl->connection_dialog->setTitle(
"Retry connection to %s",
221 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
223 sdl->connection_dialog->showError(
"Unknown module %s, aborting", what);
229 if (strcmp(what,
"arm-transport") == 0)
230 sdl->connection_dialog->showWarn(
"[%s] Starting your VM. It may take up to 5 minutes",
238 sdl->connection_dialog->showError(
239 "Automatic reconnection disabled, terminating. Try to connect again later");
247 sdl->connection_dialog->showError(
248 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
249 "tech support for help if this keeps happening.",
254 sdl->connection_dialog->showInfo(
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
255 "ms before next attempt",
256 what, current, max, delay);
257 return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
260BOOL sdl_present_gateway_message(freerdp* instance, [[maybe_unused]] UINT32 type,
261 BOOL isDisplayMandatory, BOOL isConsentMandatory,
size_t length,
262 const WCHAR* wmessage)
264 if (!isDisplayMandatory)
267 char* title =
nullptr;
269 winpr_asprintf(&title, &len,
"[gateway]");
272 if (isConsentMandatory)
273 flags = SHOW_DIALOG_ACCEPT_REJECT;
274 else if (isDisplayMandatory)
275 flags = SHOW_DIALOG_TIMED_ACCEPT;
276 char* message = ConvertWCharNToUtf8Alloc(wmessage, length,
nullptr);
279 const int rc = sdl_show_dialog(instance->context, title, message, flags);
285int sdl_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
288 const char* str_data = freerdp_get_logon_error_info_data(data);
289 const char* str_type = freerdp_get_logon_error_info_type(type);
291 if (!instance || !instance->context)
295 if (type == LOGON_MSG_SESSION_CONTINUE)
300 char* title =
nullptr;
302 winpr_asprintf(&title, &tlen,
"[%s] info",
305 char* message =
nullptr;
307 winpr_asprintf(&message, &mlen,
"Logon Error Info %s [%s]", str_data, str_type);
309 rc = sdl_show_dialog(instance->context, title, message, SHOW_DIALOG_ACCEPT_REJECT);
315static DWORD sdl_show_ceritifcate_dialog(rdpContext* context,
const char* title,
319 if (!sdl_push_user_event(SDL_USEREVENT_CERT_DIALOG, title, message))
322 SDL_Event
event = {};
323 if (!sdl_wait_for_result(context, SDL_USEREVENT_CERT_RESULT, &event))
325 return static_cast<DWORD
>(
event.user.code);
328static char* sdl_pem_cert(
const char* pem)
330 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
334 char* fp = freerdp_certificate_get_fingerprint(cert);
335 char* start = freerdp_certificate_get_validity(cert, TRUE);
336 char* end = freerdp_certificate_get_validity(cert, FALSE);
337 freerdp_certificate_free(cert);
341 winpr_asprintf(&str, &slen,
352DWORD sdl_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
353 const char* common_name,
const char* subject,
354 const char* issuer,
const char* new_fingerprint,
355 const char* old_subject,
const char* old_issuer,
356 const char* old_fingerprint, DWORD flags)
358 const char* type = type_str_for_flags(flags);
360 WINPR_ASSERT(instance);
361 WINPR_ASSERT(instance->context);
362 WINPR_ASSERT(instance->context->settings);
368 char* new_fp_str =
nullptr;
370 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
371 new_fp_str = sdl_pem_cert(new_fingerprint);
373 winpr_asprintf(&new_fp_str, &len,
"Thumbprint: %s\n", new_fingerprint);
378 char* old_fp_str =
nullptr;
380 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
381 old_fp_str = sdl_pem_cert(old_fingerprint);
383 winpr_asprintf(&old_fp_str, &olen,
"Thumbprint: %s\n", old_fingerprint);
385 const char* collission_str =
"";
386 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
389 "A matching entry with legacy SHA1 was found in local known_hosts2 store.\n"
390 "If you just upgraded from a FreeRDP version before 2.0 this is expected.\n"
391 "The hashing algorithm has been upgraded from SHA1 to SHA256.\n"
392 "All manually accepted certificates must be reconfirmed!\n"
396 char* title =
nullptr;
398 winpr_asprintf(&title, &tlen,
"Certificate for %s:%" PRIu16
" (%s) has changed", host, port,
401 char* message =
nullptr;
403 winpr_asprintf(&message, &mlen,
404 "New Certificate details:\n"
409 "Old Certificate details:\n"
414 "The above X.509 certificate does not match the certificate used for previous "
416 "This may indicate that the certificate has been tampered with.\n"
417 "Please contact the administrator of the RDP server and clarify.\n",
418 common_name, subject, issuer, new_fp_str, old_subject, old_issuer, old_fp_str,
421 const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
430DWORD sdl_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
431 const char* common_name,
const char* subject,
const char* issuer,
432 const char* fingerprint, DWORD flags)
434 const char* type = type_str_for_flags(flags);
439 char* fp_str =
nullptr;
441 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
442 fp_str = sdl_pem_cert(fingerprint);
444 winpr_asprintf(&fp_str, &len,
"Thumbprint: %s\n", fingerprint);
446 char* title =
nullptr;
448 winpr_asprintf(&title, &tlen,
"New certificate for %s:%" PRIu16
" (%s)", host, port, type);
450 char* message =
nullptr;
458 "The above X.509 certificate could not be verified, possibly because you do not have\n"
459 "the CA certificate in your certificate store, or the certificate has expired.\n"
460 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n",
461 common_name, subject, issuer, fp_str);
464 const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
471BOOL sdl_cert_dialog_show(
const char* title,
const char* message)
476 BUTTONID_CERT_ACCEPT_PERMANENT = 23,
477 BUTTONID_CERT_ACCEPT_TEMPORARY = 24,
478 BUTTONID_CERT_DENY = 25
480 const SDL_MessageBoxButtonData buttons[] = {
481 { 0, BUTTONID_CERT_ACCEPT_PERMANENT,
"permanent" },
482 { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_CERT_ACCEPT_TEMPORARY,
"temporary" },
483 { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_CERT_DENY,
"cancel" }
486 const SDL_MessageBoxData data = { SDL_MESSAGEBOX_WARNING,
nullptr, title, message,
487 ARRAYSIZE(buttons), buttons,
nullptr };
488 const int rc = SDL_ShowMessageBox(&data, &buttonid);
497 case BUTTONID_CERT_ACCEPT_PERMANENT:
500 case BUTTONID_CERT_ACCEPT_TEMPORARY:
509 return sdl_push_user_event(SDL_USEREVENT_CERT_RESULT, value);
512BOOL sdl_message_dialog_show(
const char* title,
const char* message, Sint32 flags)
517 BUTTONID_SHOW_ACCEPT = 24,
518 BUTTONID_SHOW_DENY = 25
520 const SDL_MessageBoxButtonData buttons[] = {
521 { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_SHOW_ACCEPT,
"accept" },
522 { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_SHOW_DENY,
"cancel" }
525 const int button_cnt = (flags & SHOW_DIALOG_ACCEPT_REJECT) ? 2 : 1;
526 const SDL_MessageBoxData data = {
527 SDL_MESSAGEBOX_WARNING,
nullptr, title, message, button_cnt, buttons,
nullptr
529 const int rc = SDL_ShowMessageBox(&data, &buttonid);
538 case BUTTONID_SHOW_ACCEPT:
547 return sdl_push_user_event(SDL_USEREVENT_SHOW_RESULT, value);
552 std::vector<std::string> auth = {
"Username: ",
"Domain: ",
554 std::vector<std::string> authPin = {
"Device: ",
"PIN: " };
555 std::vector<std::string> gw = {
"GatewayUsername: ",
"GatewayDomain: ",
"GatewayPassword: " };
556 std::vector<std::string> prompt;
559 switch (args->result)
561 case AUTH_SMARTCARD_PIN:
562 prompt = std::move(authPin);
567 prompt = std::move(auth);
572 prompt = std::move(gw);
578 std::vector<std::string> result;
582 std::vector<std::string> initial{ args->user ? args->user :
"Smartcard",
"" };
583 std::vector<Uint32> flags = { SdlInputWidget::SDL_INPUT_READONLY,
584 SdlInputWidget::SDL_INPUT_MASK };
585 if (args->result != AUTH_SMARTCARD_PIN)
587 initial = { args->user ? args->user :
"", args->domain ? args->domain :
"",
588 args->password ? args->password :
"" };
589 flags = { 0, 0, SdlInputWidget::SDL_INPUT_MASK };
592 rc = ilist.run(result);
595 if ((result.size() < prompt.size()))
598 char* user =
nullptr;
599 char* domain =
nullptr;
603 user = _strdup(result[0].c_str());
604 if (args->result == AUTH_SMARTCARD_PIN)
605 pwd = _strdup(result[1].c_str());
608 domain = _strdup(result[1].c_str());
609 pwd = _strdup(result[2].c_str());
612 return sdl_push_user_event(SDL_USEREVENT_AUTH_RESULT, user, domain, pwd, rc);
615BOOL sdl_scard_dialog_show(
const char* title, Sint32 count,
const char** list)
617 const auto scount = WINPR_ASSERTING_INT_CAST(
size_t, count);
618 std::vector<std::string> vlist;
619 vlist.reserve(scount);
620 for (
size_t x = 0; x < scount; x++)
621 vlist.emplace_back(list[x]);
623 Sint32 value = slist.run();
624 return sdl_push_user_event(SDL_USEREVENT_SCARD_RESULT, value);
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API const char * freerdp_settings_get_server_name(const rdpSettings *settings)
A helper function to return the correct server name.
FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.