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"
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)
103 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 std::unique_ptr<char,
decltype(&free)> 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);
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_EVENT_USER_SCARD_DIALOG, title, list.data(), count))
196 if (!sdl_wait_for_result(instance->context, SDL_EVENT_USER_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;
217 sdl->dialog.setTitle(
"Retry connection to %s",
220 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
222 sdl->dialog.showError(
"Unknown module %s, aborting", what);
228 if (strcmp(what,
"arm-transport") == 0)
229 sdl->dialog.showWarn(
"[%s] Starting your VM. It may take up to 5 minutes", what);
234 sdl->dialog.showError(
235 "Automatic reconnection disabled, terminating. Try to connect again later");
242 sdl->dialog.showError(
243 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
244 "tech support for help if this keeps happening.",
249 sdl->dialog.showInfo(
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
250 "ms before next attempt",
251 what, current, max, delay);
252 return WINPR_ASSERTING_INT_CAST(ssize_t, delay);
255BOOL sdl_present_gateway_message(freerdp* instance, [[maybe_unused]] UINT32 type,
256 BOOL isDisplayMandatory, BOOL isConsentMandatory,
size_t length,
257 const WCHAR* wmessage)
259 if (!isDisplayMandatory)
262 char* title =
nullptr;
264 winpr_asprintf(&title, &len,
"[gateway]");
267 if (isConsentMandatory)
268 flags = SHOW_DIALOG_ACCEPT_REJECT;
269 else if (isDisplayMandatory)
270 flags = SHOW_DIALOG_TIMED_ACCEPT;
271 char* message = ConvertWCharNToUtf8Alloc(wmessage, length,
nullptr);
274 const int rc = sdl_show_dialog(instance->context, title, message, flags);
280int sdl_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
283 const char* str_data = freerdp_get_logon_error_info_data(data);
284 const char* str_type = freerdp_get_logon_error_info_type(type);
286 if (!instance || !instance->context)
290 if (type == LOGON_MSG_SESSION_CONTINUE)
295 char* title =
nullptr;
297 winpr_asprintf(&title, &tlen,
"[%s] info",
300 char* message =
nullptr;
302 winpr_asprintf(&message, &mlen,
"Logon Error Info %s [%s]", str_data, str_type);
304 rc = sdl_show_dialog(instance->context, title, message, SHOW_DIALOG_ACCEPT_REJECT);
310static DWORD sdl_show_ceritifcate_dialog(rdpContext* context,
const char* title,
314 if (!sdl_push_user_event(SDL_EVENT_USER_CERT_DIALOG, title, message))
317 SDL_Event
event = {};
318 if (!sdl_wait_for_result(context, SDL_EVENT_USER_CERT_RESULT, &event))
320 return static_cast<DWORD
>(
event.user.code);
323static char* sdl_pem_cert(
const char* pem)
325 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
329 char* fp = freerdp_certificate_get_fingerprint(cert);
330 char* start = freerdp_certificate_get_validity(cert, TRUE);
331 char* end = freerdp_certificate_get_validity(cert, FALSE);
332 freerdp_certificate_free(cert);
336 winpr_asprintf(&str, &slen,
347DWORD sdl_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
348 const char* common_name,
const char* subject,
349 const char* issuer,
const char* new_fingerprint,
350 const char* old_subject,
const char* old_issuer,
351 const char* old_fingerprint, DWORD flags)
353 const char* type = type_str_for_flags(flags);
355 WINPR_ASSERT(instance);
356 WINPR_ASSERT(instance->context);
357 WINPR_ASSERT(instance->context->settings);
363 char* new_fp_str =
nullptr;
365 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
366 new_fp_str = sdl_pem_cert(new_fingerprint);
368 winpr_asprintf(&new_fp_str, &len,
"Thumbprint: %s\n", new_fingerprint);
373 char* old_fp_str =
nullptr;
375 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
376 old_fp_str = sdl_pem_cert(old_fingerprint);
378 winpr_asprintf(&old_fp_str, &olen,
"Thumbprint: %s\n", old_fingerprint);
380 const char* collission_str =
"";
381 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
384 "A matching entry with legacy SHA1 was found in local known_hosts2 store.\n"
385 "If you just upgraded from a FreeRDP version before 2.0 this is expected.\n"
386 "The hashing algorithm has been upgraded from SHA1 to SHA256.\n"
387 "All manually accepted certificates must be reconfirmed!\n"
391 char* title =
nullptr;
393 winpr_asprintf(&title, &tlen,
"Certificate for %s:%" PRIu16
" (%s) has changed", host, port,
396 char* message =
nullptr;
398 winpr_asprintf(&message, &mlen,
399 "New Certificate details:\n"
404 "Old Certificate details:\n"
409 "The above X.509 certificate does not match the certificate used for previous "
411 "This may indicate that the certificate has been tampered with.\n"
412 "Please contact the administrator of the RDP server and clarify.\n",
413 common_name, subject, issuer, new_fp_str, old_subject, old_issuer, old_fp_str,
416 const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
425DWORD sdl_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
426 const char* common_name,
const char* subject,
const char* issuer,
427 const char* fingerprint, DWORD flags)
429 const char* type = type_str_for_flags(flags);
434 char* fp_str =
nullptr;
436 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
437 fp_str = sdl_pem_cert(fingerprint);
439 winpr_asprintf(&fp_str, &len,
"Thumbprint: %s\n", fingerprint);
441 char* title =
nullptr;
443 winpr_asprintf(&title, &tlen,
"New certificate for %s:%" PRIu16
" (%s)", host, port, type);
445 char* message =
nullptr;
453 "The above X.509 certificate could not be verified, possibly because you do not have\n"
454 "the CA certificate in your certificate store, or the certificate has expired.\n"
455 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n",
456 common_name, subject, issuer, fp_str);
459 const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
466BOOL sdl_cert_dialog_show(
const char* title,
const char* message)
471 BUTTONID_CERT_ACCEPT_PERMANENT = 23,
472 BUTTONID_CERT_ACCEPT_TEMPORARY = 24,
473 BUTTONID_CERT_DENY = 25
475 const SDL_MessageBoxButtonData buttons[] = {
476 { 0, BUTTONID_CERT_ACCEPT_PERMANENT,
"permanent" },
477 { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_CERT_ACCEPT_TEMPORARY,
"temporary" },
478 { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_CERT_DENY,
"cancel" }
481 const SDL_MessageBoxData data = { SDL_MESSAGEBOX_WARNING,
nullptr, title, message,
482 ARRAYSIZE(buttons), buttons,
nullptr };
483 const int rc = SDL_ShowMessageBox(&data, &buttonid);
492 case BUTTONID_CERT_ACCEPT_PERMANENT:
495 case BUTTONID_CERT_ACCEPT_TEMPORARY:
504 return sdl_push_user_event(SDL_EVENT_USER_CERT_RESULT, value);
507BOOL sdl_message_dialog_show(
const char* title,
const char* message, Sint32 flags)
512 BUTTONID_SHOW_ACCEPT = 24,
513 BUTTONID_SHOW_DENY = 25
515 const SDL_MessageBoxButtonData buttons[] = {
516 { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_SHOW_ACCEPT,
"accept" },
517 { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_SHOW_DENY,
"cancel" }
520 const int button_cnt = (flags & SHOW_DIALOG_ACCEPT_REJECT) ? 2 : 1;
521 const SDL_MessageBoxData data = {
522 SDL_MESSAGEBOX_WARNING,
nullptr, title, message, button_cnt, buttons,
nullptr
524 const int rc = SDL_ShowMessageBox(&data, &buttonid);
533 case BUTTONID_SHOW_ACCEPT:
542 return sdl_push_user_event(SDL_EVENT_USER_SHOW_RESULT, value);
547 std::vector<std::string> auth = {
"Username: ",
"Domain: ",
549 std::vector<std::string> authPin = {
"Device: ",
"PIN: " };
550 std::vector<std::string> gw = {
"GatewayUsername: ",
"GatewayDomain: ",
"GatewayPassword: " };
551 std::vector<std::string> prompt;
554 switch (args->result)
556 case AUTH_SMARTCARD_PIN:
557 prompt = std::move(authPin);
562 prompt = std::move(auth);
567 prompt = std::move(gw);
573 std::vector<std::string> result;
577 std::vector<std::string> initial{ args->user ? args->user :
"Smartcard",
"" };
578 std::vector<Uint32> flags = { SdlInputWidget::SDL_INPUT_READONLY,
579 SdlInputWidget::SDL_INPUT_MASK };
580 if (args->result != AUTH_SMARTCARD_PIN)
582 initial = { args->user ? args->user :
"", args->domain ? args->domain :
"",
583 args->password ? args->password :
"" };
584 flags = { 0, 0, SdlInputWidget::SDL_INPUT_MASK };
587 rc = ilist.run(result);
590 if ((result.size() < prompt.size()))
593 char* user =
nullptr;
594 char* domain =
nullptr;
598 user = _strdup(result[0].c_str());
599 if (args->result == AUTH_SMARTCARD_PIN)
600 pwd = _strdup(result[1].c_str());
603 domain = _strdup(result[1].c_str());
604 pwd = _strdup(result[2].c_str());
607 return sdl_push_user_event(SDL_EVENT_USER_AUTH_RESULT, user, domain, pwd, rc);
610BOOL sdl_scard_dialog_show(
const char* title, Sint32 count,
const char** list)
612 std::vector<std::string> vlist;
613 vlist.reserve(WINPR_ASSERTING_INT_CAST(
size_t, count));
614 for (Sint32 x = 0; x < count; x++)
615 vlist.emplace_back(list[x]);
617 Sint32 value = slist.run();
618 return sdl_push_user_event(SDL_EVENT_USER_SCARD_RESULT, value);
621void sdl_dialogs_uninit()
626void 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.