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)
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)> guard(title, free);
133 if (!sdl_push_user_event(SDL_EVENT_USER_AUTH_DIALOG, title, u, d, p, reason))
136 if (!sdl_wait_for_result(instance->context, SDL_EVENT_USER_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);
162 std::vector<std::string> strlist;
163 std::vector<const char*> list;
164 for (DWORD i = 0; i < count; i++)
167 char* reader = ConvertWCharToUtf8Alloc(cert->reader,
nullptr);
168 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName,
nullptr);
173 winpr_asprintf(&msg, &len,
174 "%s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s",
175 container_name, reader, cert->userHint, cert->domainHint, cert->subject,
176 cert->issuer, cert->upn);
178 strlist.emplace_back(msg);
181 free(container_name);
183 auto& m = strlist.back();
184 list.push_back(m.c_str());
187 SDL_Event
event = {};
188 const char* title =
"Select a logon smartcard certificate";
190 title =
"Select a gateway logon smartcard certificate";
191 if (!sdl_push_user_event(SDL_EVENT_USER_SCARD_DIALOG, title, list.data(), count))
194 if (!sdl_wait_for_result(instance->context, SDL_EVENT_USER_SCARD_RESULT, &event))
197 res = (
event.user.code >= 0);
198 *choice =
static_cast<DWORD
>(
event.user.code);
203SSIZE_T sdl_retry_dialog(freerdp* instance,
const char* what,
size_t current,
204 [[maybe_unused]]
void* userarg)
206 WINPR_ASSERT(instance);
207 WINPR_ASSERT(instance->context);
210 auto sdl = get_context(instance->context);
211 auto settings = instance->context->settings;
215 sdl->dialog.setTitle(
"Retry connection to %s",
218 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
220 sdl->dialog.showError(
"Unknown module %s, aborting", what);
226 if (strcmp(what,
"arm-transport") == 0)
227 sdl->dialog.showWarn(
"[%s] Starting your VM. It may take up to 5 minutes", what);
232 sdl->dialog.showError(
233 "Automatic reconnection disabled, terminating. Try to connect again later");
240 sdl->dialog.showError(
241 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
242 "tech support for help if this keeps happening.",
247 sdl->dialog.showInfo(
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
248 "ms before next attempt",
249 what, current, max, delay);
250 return WINPR_ASSERTING_INT_CAST(ssize_t, delay);
253BOOL sdl_present_gateway_message(freerdp* instance, [[maybe_unused]] UINT32 type,
254 BOOL isDisplayMandatory, BOOL isConsentMandatory,
size_t length,
255 const WCHAR* wmessage)
257 if (!isDisplayMandatory)
260 char* title =
nullptr;
262 winpr_asprintf(&title, &len,
"[gateway]");
265 if (isConsentMandatory)
266 flags = SHOW_DIALOG_ACCEPT_REJECT;
267 else if (isDisplayMandatory)
268 flags = SHOW_DIALOG_TIMED_ACCEPT;
269 char* message = ConvertWCharNToUtf8Alloc(wmessage, length,
nullptr);
271 const int rc = sdl_show_dialog(instance->context, title, message, flags);
277int sdl_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
280 const char* str_data = freerdp_get_logon_error_info_data(data);
281 const char* str_type = freerdp_get_logon_error_info_type(type);
283 if (!instance || !instance->context)
287 if (type == LOGON_MSG_SESSION_CONTINUE)
290 char* title =
nullptr;
292 winpr_asprintf(&title, &tlen,
"[%s] info",
295 char* message =
nullptr;
297 winpr_asprintf(&message, &mlen,
"Logon Error Info %s [%s]", str_data, str_type);
299 rc = sdl_show_dialog(instance->context, title, message, SHOW_DIALOG_ACCEPT_REJECT);
305static DWORD sdl_show_ceritifcate_dialog(rdpContext* context,
const char* title,
308 if (!sdl_push_user_event(SDL_EVENT_USER_CERT_DIALOG, title, message))
311 SDL_Event
event = {};
312 if (!sdl_wait_for_result(context, SDL_EVENT_USER_CERT_RESULT, &event))
314 return static_cast<DWORD
>(
event.user.code);
317static char* sdl_pem_cert(
const char* pem)
319 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
323 char* fp = freerdp_certificate_get_fingerprint(cert);
324 char* start = freerdp_certificate_get_validity(cert, TRUE);
325 char* end = freerdp_certificate_get_validity(cert, FALSE);
326 freerdp_certificate_free(cert);
330 winpr_asprintf(&str, &slen,
341DWORD sdl_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
342 const char* common_name,
const char* subject,
343 const char* issuer,
const char* new_fingerprint,
344 const char* old_subject,
const char* old_issuer,
345 const char* old_fingerprint, DWORD flags)
347 const char* type = type_str_for_flags(flags);
349 WINPR_ASSERT(instance);
350 WINPR_ASSERT(instance->context);
351 WINPR_ASSERT(instance->context->settings);
356 char* new_fp_str =
nullptr;
358 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
359 new_fp_str = sdl_pem_cert(new_fingerprint);
361 winpr_asprintf(&new_fp_str, &len,
"Thumbprint: %s\n", new_fingerprint);
366 char* old_fp_str =
nullptr;
368 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
369 old_fp_str = sdl_pem_cert(old_fingerprint);
371 winpr_asprintf(&old_fp_str, &olen,
"Thumbprint: %s\n", old_fingerprint);
373 const char* collission_str =
"";
374 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
377 "A matching entry with legacy SHA1 was found in local known_hosts2 store.\n"
378 "If you just upgraded from a FreeRDP version before 2.0 this is expected.\n"
379 "The hashing algorithm has been upgraded from SHA1 to SHA256.\n"
380 "All manually accepted certificates must be reconfirmed!\n"
384 char* title =
nullptr;
386 winpr_asprintf(&title, &tlen,
"Certificate for %s:%" PRIu16
" (%s) has changed", host, port,
389 char* message =
nullptr;
391 winpr_asprintf(&message, &mlen,
392 "New Certificate details:\n"
397 "Old Certificate details:\n"
402 "The above X.509 certificate does not match the certificate used for previous "
404 "This may indicate that the certificate has been tampered with.\n"
405 "Please contact the administrator of the RDP server and clarify.\n",
406 common_name, subject, issuer, new_fp_str, old_subject, old_issuer, old_fp_str,
409 const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
418DWORD sdl_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
419 const char* common_name,
const char* subject,
const char* issuer,
420 const char* fingerprint, DWORD flags)
422 const char* type = type_str_for_flags(flags);
427 char* fp_str =
nullptr;
429 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
430 fp_str = sdl_pem_cert(fingerprint);
432 winpr_asprintf(&fp_str, &len,
"Thumbprint: %s\n", fingerprint);
434 char* title =
nullptr;
436 winpr_asprintf(&title, &tlen,
"New certificate for %s:%" PRIu16
" (%s)", host, port, type);
438 char* message =
nullptr;
446 "The above X.509 certificate could not be verified, possibly because you do not have\n"
447 "the CA certificate in your certificate store, or the certificate has expired.\n"
448 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n",
449 common_name, subject, issuer, fp_str);
451 const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
458BOOL sdl_cert_dialog_show(
const char* title,
const char* message)
463 BUTTONID_CERT_ACCEPT_PERMANENT = 23,
464 BUTTONID_CERT_ACCEPT_TEMPORARY = 24,
465 BUTTONID_CERT_DENY = 25
467 const SDL_MessageBoxButtonData buttons[] = {
468 { 0, BUTTONID_CERT_ACCEPT_PERMANENT,
"permanent" },
469 { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_CERT_ACCEPT_TEMPORARY,
"temporary" },
470 { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_CERT_DENY,
"cancel" }
473 const SDL_MessageBoxData data = { SDL_MESSAGEBOX_WARNING,
nullptr, title, message,
474 ARRAYSIZE(buttons), buttons,
nullptr };
475 const int rc = SDL_ShowMessageBox(&data, &buttonid);
484 case BUTTONID_CERT_ACCEPT_PERMANENT:
487 case BUTTONID_CERT_ACCEPT_TEMPORARY:
496 return sdl_push_user_event(SDL_EVENT_USER_CERT_RESULT, value);
499BOOL sdl_message_dialog_show(
const char* title,
const char* message, Sint32 flags)
504 BUTTONID_SHOW_ACCEPT = 24,
505 BUTTONID_SHOW_DENY = 25
507 const SDL_MessageBoxButtonData buttons[] = {
508 { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_SHOW_ACCEPT,
"accept" },
509 { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_SHOW_DENY,
"cancel" }
512 const int button_cnt = (flags & SHOW_DIALOG_ACCEPT_REJECT) ? 2 : 1;
513 const SDL_MessageBoxData data = {
514 SDL_MESSAGEBOX_WARNING,
nullptr, title, message, button_cnt, buttons,
nullptr
516 const int rc = SDL_ShowMessageBox(&data, &buttonid);
525 case BUTTONID_SHOW_ACCEPT:
534 return sdl_push_user_event(SDL_EVENT_USER_SHOW_RESULT, value);
539 const std::vector<std::string> auth = {
"Username: ",
"Domain: ",
541 const std::vector<std::string> authPin = {
"Device: ",
"PIN: " };
542 const std::vector<std::string> gw = {
"GatewayUsername: ",
"GatewayDomain: ",
543 "GatewayPassword: " };
544 std::vector<std::string> prompt;
547 switch (args->result)
549 case AUTH_SMARTCARD_PIN:
567 std::vector<std::string> result;
571 std::vector<std::string> initial{ args->user ? args->user :
"Smartcard",
"" };
572 std::vector<Uint32> flags = { SdlInputWidgetPair::SDL_INPUT_READONLY,
573 SdlInputWidgetPair::SDL_INPUT_MASK };
574 if (args->result != AUTH_SMARTCARD_PIN)
576 if (args->result == AUTH_RDSTLS)
578 initial = { args->user ? args->user :
"", args->password ? args->password :
"" };
579 flags = { 0, SdlInputWidgetPair::SDL_INPUT_MASK };
583 initial = { args->user ? args->user :
"", args->domain ? args->domain :
"",
584 args->password ? args->password :
"" };
585 flags = { 0, 0, SdlInputWidgetPair::SDL_INPUT_MASK };
589 rc = ilist.run(result);
592 if ((result.size() < prompt.size()))
595 char* user =
nullptr;
596 char* domain =
nullptr;
600 user = _strdup(result[0].c_str());
601 if (args->result == AUTH_SMARTCARD_PIN)
602 pwd = _strdup(result[1].c_str());
605 domain = _strdup(result[1].c_str());
606 pwd = _strdup(result[2].c_str());
609 return sdl_push_user_event(SDL_EVENT_USER_AUTH_RESULT, user, domain, pwd, rc);
612BOOL sdl_scard_dialog_show(
const char* title, Sint32 count,
const char** list)
614 std::vector<std::string> vlist;
615 vlist.reserve(WINPR_ASSERTING_INT_CAST(
size_t, count));
616 for (Sint32 x = 0; x < count; x++)
617 vlist.emplace_back(list[x]);
619 Sint32 value = slist.run();
620 return sdl_push_user_event(SDL_EVENT_USER_SCARD_RESULT, value);
623void sdl_dialogs_uninit()
628void 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.