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_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)
101 case AUTH_SMARTCARD_PIN:
102 if ((*username) && (*password))
115 char* title =
nullptr;
116 size_t titlesize = 0;
117 winpr_asprintf(&title, &titlesize,
"Credentials required for %s", target);
119 std::unique_ptr<char,
decltype(&free)> guard(title, free);
132 if (!sdl_push_user_event(SDL_EVENT_USER_AUTH_DIALOG, title, u, d, p, reason))
135 if (!sdl_wait_for_result(instance->context, SDL_EVENT_USER_AUTH_RESULT, &event))
140 res = arg->result > 0;
145 *username = arg->user;
146 *domain = arg->domain;
147 *password = arg->password;
152BOOL sdl_choose_smartcard(freerdp* instance,
SmartcardCertInfo** cert_list, DWORD count,
153 DWORD* choice, BOOL gateway)
157 WINPR_ASSERT(instance);
158 WINPR_ASSERT(cert_list);
159 WINPR_ASSERT(choice);
161 std::vector<std::string> strlist;
162 std::vector<const char*> list;
163 for (DWORD i = 0; i < count; i++)
166 char* reader = ConvertWCharToUtf8Alloc(cert->reader,
nullptr);
167 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName,
nullptr);
172 winpr_asprintf(&msg, &len,
173 "%s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s",
174 container_name, reader, cert->userHint, cert->domainHint, cert->subject,
175 cert->issuer, cert->upn);
177 strlist.emplace_back(msg);
180 free(container_name);
182 auto& m = strlist.back();
183 list.push_back(m.c_str());
186 SDL_Event
event = {};
187 const char* title =
"Select a logon smartcard certificate";
189 title =
"Select a gateway logon smartcard certificate";
190 if (!sdl_push_user_event(SDL_EVENT_USER_SCARD_DIALOG, title, list.data(), count))
193 if (!sdl_wait_for_result(instance->context, SDL_EVENT_USER_SCARD_RESULT, &event))
196 res = (
event.user.code >= 0);
197 *choice =
static_cast<DWORD
>(
event.user.code);
202SSIZE_T sdl_retry_dialog(freerdp* instance,
const char* what,
size_t current,
203 [[maybe_unused]]
void* userarg)
205 WINPR_ASSERT(instance);
206 WINPR_ASSERT(instance->context);
209 auto sdl = get_context(instance->context);
210 auto settings = instance->context->settings;
214 sdl->dialog.setTitle(
"Retry connection to %s",
217 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
219 sdl->dialog.showError(
"Unknown module %s, aborting", what);
225 if (strcmp(what,
"arm-transport") == 0)
226 sdl->dialog.showWarn(
"[%s] Starting your VM. It may take up to 5 minutes", what);
231 sdl->dialog.showError(
232 "Automatic reconnection disabled, terminating. Try to connect again later");
239 sdl->dialog.showError(
240 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
241 "tech support for help if this keeps happening.",
246 sdl->dialog.showInfo(
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
247 "ms before next attempt",
248 what, current, max, delay);
249 return WINPR_ASSERTING_INT_CAST(ssize_t, delay);
252BOOL sdl_present_gateway_message(freerdp* instance, [[maybe_unused]] UINT32 type,
253 BOOL isDisplayMandatory, BOOL isConsentMandatory,
size_t length,
254 const WCHAR* wmessage)
256 if (!isDisplayMandatory)
259 char* title =
nullptr;
261 winpr_asprintf(&title, &len,
"[gateway]");
264 if (isConsentMandatory)
265 flags = SHOW_DIALOG_ACCEPT_REJECT;
266 else if (isDisplayMandatory)
267 flags = SHOW_DIALOG_TIMED_ACCEPT;
268 char* message = ConvertWCharNToUtf8Alloc(wmessage, length,
nullptr);
270 const int rc = sdl_show_dialog(instance->context, title, message, flags);
276int sdl_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
279 const char* str_data = freerdp_get_logon_error_info_data(data);
280 const char* str_type = freerdp_get_logon_error_info_type(type);
282 if (!instance || !instance->context)
286 if (type == LOGON_MSG_SESSION_CONTINUE)
289 char* title =
nullptr;
291 winpr_asprintf(&title, &tlen,
"[%s] info",
294 char* message =
nullptr;
296 winpr_asprintf(&message, &mlen,
"Logon Error Info %s [%s]", str_data, str_type);
298 rc = sdl_show_dialog(instance->context, title, message, SHOW_DIALOG_ACCEPT_REJECT);
304static DWORD sdl_show_ceritifcate_dialog(rdpContext* context,
const char* title,
307 if (!sdl_push_user_event(SDL_EVENT_USER_CERT_DIALOG, title, message))
310 SDL_Event
event = {};
311 if (!sdl_wait_for_result(context, SDL_EVENT_USER_CERT_RESULT, &event))
313 return static_cast<DWORD
>(
event.user.code);
316static char* sdl_pem_cert(
const char* pem)
318 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
322 char* fp = freerdp_certificate_get_fingerprint(cert);
323 char* start = freerdp_certificate_get_validity(cert, TRUE);
324 char* end = freerdp_certificate_get_validity(cert, FALSE);
325 freerdp_certificate_free(cert);
329 winpr_asprintf(&str, &slen,
340DWORD sdl_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
341 const char* common_name,
const char* subject,
342 const char* issuer,
const char* new_fingerprint,
343 const char* old_subject,
const char* old_issuer,
344 const char* old_fingerprint, DWORD flags)
346 const char* type = type_str_for_flags(flags);
348 WINPR_ASSERT(instance);
349 WINPR_ASSERT(instance->context);
350 WINPR_ASSERT(instance->context->settings);
355 char* new_fp_str =
nullptr;
357 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
358 new_fp_str = sdl_pem_cert(new_fingerprint);
360 winpr_asprintf(&new_fp_str, &len,
"Thumbprint: %s\n", new_fingerprint);
365 char* old_fp_str =
nullptr;
367 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
368 old_fp_str = sdl_pem_cert(old_fingerprint);
370 winpr_asprintf(&old_fp_str, &olen,
"Thumbprint: %s\n", old_fingerprint);
372 const char* collission_str =
"";
373 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
376 "A matching entry with legacy SHA1 was found in local known_hosts2 store.\n"
377 "If you just upgraded from a FreeRDP version before 2.0 this is expected.\n"
378 "The hashing algorithm has been upgraded from SHA1 to SHA256.\n"
379 "All manually accepted certificates must be reconfirmed!\n"
383 char* title =
nullptr;
385 winpr_asprintf(&title, &tlen,
"Certificate for %s:%" PRIu16
" (%s) has changed", host, port,
388 char* message =
nullptr;
390 winpr_asprintf(&message, &mlen,
391 "New Certificate details:\n"
396 "Old Certificate details:\n"
401 "The above X.509 certificate does not match the certificate used for previous "
403 "This may indicate that the certificate has been tampered with.\n"
404 "Please contact the administrator of the RDP server and clarify.\n",
405 common_name, subject, issuer, new_fp_str, old_subject, old_issuer, old_fp_str,
408 const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
417DWORD sdl_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
418 const char* common_name,
const char* subject,
const char* issuer,
419 const char* fingerprint, DWORD flags)
421 const char* type = type_str_for_flags(flags);
426 char* fp_str =
nullptr;
428 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
429 fp_str = sdl_pem_cert(fingerprint);
431 winpr_asprintf(&fp_str, &len,
"Thumbprint: %s\n", fingerprint);
433 char* title =
nullptr;
435 winpr_asprintf(&title, &tlen,
"New certificate for %s:%" PRIu16
" (%s)", host, port, type);
437 char* message =
nullptr;
445 "The above X.509 certificate could not be verified, possibly because you do not have\n"
446 "the CA certificate in your certificate store, or the certificate has expired.\n"
447 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n",
448 common_name, subject, issuer, fp_str);
450 const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
457BOOL sdl_cert_dialog_show(
const char* title,
const char* message)
462 BUTTONID_CERT_ACCEPT_PERMANENT = 23,
463 BUTTONID_CERT_ACCEPT_TEMPORARY = 24,
464 BUTTONID_CERT_DENY = 25
466 const SDL_MessageBoxButtonData buttons[] = {
467 { 0, BUTTONID_CERT_ACCEPT_PERMANENT,
"permanent" },
468 { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_CERT_ACCEPT_TEMPORARY,
"temporary" },
469 { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_CERT_DENY,
"cancel" }
472 const SDL_MessageBoxData data = { SDL_MESSAGEBOX_WARNING,
nullptr, title, message,
473 ARRAYSIZE(buttons), buttons,
nullptr };
474 const int rc = SDL_ShowMessageBox(&data, &buttonid);
483 case BUTTONID_CERT_ACCEPT_PERMANENT:
486 case BUTTONID_CERT_ACCEPT_TEMPORARY:
495 return sdl_push_user_event(SDL_EVENT_USER_CERT_RESULT, value);
498BOOL sdl_message_dialog_show(
const char* title,
const char* message, Sint32 flags)
503 BUTTONID_SHOW_ACCEPT = 24,
504 BUTTONID_SHOW_DENY = 25
506 const SDL_MessageBoxButtonData buttons[] = {
507 { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_SHOW_ACCEPT,
"accept" },
508 { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_SHOW_DENY,
"cancel" }
511 const int button_cnt = (flags & SHOW_DIALOG_ACCEPT_REJECT) ? 2 : 1;
512 const SDL_MessageBoxData data = {
513 SDL_MESSAGEBOX_WARNING,
nullptr, title, message, button_cnt, buttons,
nullptr
515 const int rc = SDL_ShowMessageBox(&data, &buttonid);
524 case BUTTONID_SHOW_ACCEPT:
533 return sdl_push_user_event(SDL_EVENT_USER_SHOW_RESULT, value);
538 std::vector<std::string> auth = {
"Username: ",
"Domain: ",
540 std::vector<std::string> authPin = {
"Device: ",
"PIN: " };
541 std::vector<std::string> gw = {
"GatewayUsername: ",
"GatewayDomain: ",
"GatewayPassword: " };
542 std::vector<std::string> prompt;
545 switch (args->result)
547 case AUTH_SMARTCARD_PIN:
548 prompt = std::move(authPin);
553 prompt = std::move(auth);
558 prompt = std::move(gw);
564 std::vector<std::string> result;
568 std::vector<std::string> initial{ args->user ? args->user :
"Smartcard",
"" };
569 std::vector<Uint32> flags = { SdlInputWidgetPair::SDL_INPUT_READONLY,
570 SdlInputWidgetPair::SDL_INPUT_MASK };
571 if (args->result != AUTH_SMARTCARD_PIN)
573 initial = { args->user ? args->user :
"", args->domain ? args->domain :
"",
574 args->password ? args->password :
"" };
575 flags = { 0, 0, SdlInputWidgetPair::SDL_INPUT_MASK };
578 rc = ilist.run(result);
581 if ((result.size() < prompt.size()))
584 char* user =
nullptr;
585 char* domain =
nullptr;
589 user = _strdup(result[0].c_str());
590 if (args->result == AUTH_SMARTCARD_PIN)
591 pwd = _strdup(result[1].c_str());
594 domain = _strdup(result[1].c_str());
595 pwd = _strdup(result[2].c_str());
598 return sdl_push_user_event(SDL_EVENT_USER_AUTH_RESULT, user, domain, pwd, rc);
601BOOL sdl_scard_dialog_show(
const char* title, Sint32 count,
const char** list)
603 std::vector<std::string> vlist;
604 vlist.reserve(WINPR_ASSERTING_INT_CAST(
size_t, count));
605 for (Sint32 x = 0; x < count; x++)
606 vlist.emplace_back(list[x]);
608 Sint32 value = slist.run();
609 return sdl_push_user_event(SDL_EVENT_USER_SCARD_RESULT, value);
612void sdl_dialogs_uninit()
617void sdl_dialogs_init()
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.