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
42 static 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";
54 static 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);
72 static int sdl_show_dialog(rdpContext* context,
const char* title,
const char* message,
77 if (!sdl_push_user_event(SDL_EVENT_USER_SHOW_DIALOG, title, message, flags))
80 if (!sdl_wait_for_result(context, SDL_EVENT_USER_SHOW_RESULT, &event))
83 return event.user.code;
86 BOOL 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)> 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 ? TRUE : FALSE;
146 *username = arg->user;
147 *domain = arg->domain;
148 *password = arg->password;
153 BOOL 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_EVENT_USER_SCARD_DIALOG, title, list.data(), count))
195 if (!sdl_wait_for_result(instance->context, SDL_EVENT_USER_SCARD_RESULT, &event))
198 res = (
event.user.code >= 0) ? TRUE : FALSE;
199 *choice =
static_cast<DWORD
>(
event.user.code);
204 SSIZE_T sdl_retry_dialog(freerdp* instance,
const char* what,
size_t current,
void* userarg)
206 WINPR_ASSERT(instance);
207 WINPR_ASSERT(instance->context);
210 auto sdl = get_context(instance->context);
211 auto settings = instance->context->settings;
214 std::lock_guard<CriticalSection> lock(sdl->critical);
215 if (!sdl->connection_dialog)
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",
236 sdl->connection_dialog->showError(
237 "Automatic reconnection disabled, terminating. Try to connect again later");
244 sdl->connection_dialog->showError(
245 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
246 "tech support for help if this keeps happening.",
251 sdl->connection_dialog->showInfo(
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
252 "ms before next attempt",
253 what, current, max, delay);
257 BOOL sdl_present_gateway_message(freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
258 BOOL isConsentMandatory,
size_t length,
const WCHAR* wmessage)
260 if (!isDisplayMandatory)
263 char* title =
nullptr;
265 winpr_asprintf(&title, &len,
"[gateway]");
268 if (isConsentMandatory)
269 flags = SHOW_DIALOG_ACCEPT_REJECT;
270 else if (isDisplayMandatory)
271 flags = SHOW_DIALOG_TIMED_ACCEPT;
272 char* message = ConvertWCharNToUtf8Alloc(wmessage, length,
nullptr);
275 const int rc = sdl_show_dialog(instance->context, title, message, flags);
278 return rc > 0 ? TRUE : FALSE;
281 int sdl_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
284 const char* str_data = freerdp_get_logon_error_info_data(data);
285 const char* str_type = freerdp_get_logon_error_info_type(type);
287 if (!instance || !instance->context)
291 if (type == LOGON_MSG_SESSION_CONTINUE)
296 char* title =
nullptr;
298 winpr_asprintf(&title, &tlen,
"[%s] info",
301 char* message =
nullptr;
303 winpr_asprintf(&message, &mlen,
"Logon Error Info %s [%s]", str_data, str_type);
305 rc = sdl_show_dialog(instance->context, title, message, SHOW_DIALOG_ACCEPT_REJECT);
311 static DWORD sdl_show_ceritifcate_dialog(rdpContext* context,
const char* title,
315 if (!sdl_push_user_event(SDL_EVENT_USER_CERT_DIALOG, title, message))
318 SDL_Event
event = {};
319 if (!sdl_wait_for_result(context, SDL_EVENT_USER_CERT_RESULT, &event))
321 return static_cast<DWORD
>(
event.user.code);
324 static char* sdl_pem_cert(
const char* pem)
326 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
330 char* fp = freerdp_certificate_get_fingerprint(cert);
331 char* start = freerdp_certificate_get_validity(cert, TRUE);
332 char* end = freerdp_certificate_get_validity(cert, FALSE);
333 freerdp_certificate_free(cert);
337 winpr_asprintf(&str, &slen,
348 DWORD sdl_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
349 const char* common_name,
const char* subject,
350 const char* issuer,
const char* new_fingerprint,
351 const char* old_subject,
const char* old_issuer,
352 const char* old_fingerprint, DWORD flags)
354 const char* type = type_str_for_flags(flags);
356 WINPR_ASSERT(instance);
357 WINPR_ASSERT(instance->context);
358 WINPR_ASSERT(instance->context->settings);
364 char* new_fp_str =
nullptr;
366 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
367 new_fp_str = sdl_pem_cert(new_fingerprint);
369 winpr_asprintf(&new_fp_str, &len,
"Thumbprint: %s\n", new_fingerprint);
374 char* old_fp_str =
nullptr;
376 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
377 old_fp_str = sdl_pem_cert(old_fingerprint);
379 winpr_asprintf(&old_fp_str, &olen,
"Thumbprint: %s\n", old_fingerprint);
381 const char* collission_str =
"";
382 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
385 "A matching entry with legacy SHA1 was found in local known_hosts2 store.\n"
386 "If you just upgraded from a FreeRDP version before 2.0 this is expected.\n"
387 "The hashing algorithm has been upgraded from SHA1 to SHA256.\n"
388 "All manually accepted certificates must be reconfirmed!\n"
392 char* title =
nullptr;
394 winpr_asprintf(&title, &tlen,
"Certificate for %s:%" PRIu16
" (%s) has changed", host, port,
397 char* message =
nullptr;
399 winpr_asprintf(&message, &mlen,
400 "New Certificate details:\n"
405 "Old Certificate details:\n"
410 "The above X.509 certificate does not match the certificate used for previous "
412 "This may indicate that the certificate has been tampered with.\n"
413 "Please contact the administrator of the RDP server and clarify.\n",
414 common_name, subject, issuer, new_fp_str, old_subject, old_issuer, old_fp_str,
417 const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
426 DWORD sdl_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
427 const char* common_name,
const char* subject,
const char* issuer,
428 const char* fingerprint, DWORD flags)
430 const char* type = type_str_for_flags(flags);
435 char* fp_str =
nullptr;
437 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
438 fp_str = sdl_pem_cert(fingerprint);
440 winpr_asprintf(&fp_str, &len,
"Thumbprint: %s\n", fingerprint);
442 char* title =
nullptr;
444 winpr_asprintf(&title, &tlen,
"New certificate for %s:%" PRIu16
" (%s)", host, port, type);
446 char* message =
nullptr;
454 "The above X.509 certificate could not be verified, possibly because you do not have\n"
455 "the CA certificate in your certificate store, or the certificate has expired.\n"
456 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n",
457 common_name, subject, issuer, fp_str);
460 const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
467 BOOL sdl_cert_dialog_show(
const char* title,
const char* message)
472 BUTTONID_CERT_ACCEPT_PERMANENT = 23,
473 BUTTONID_CERT_ACCEPT_TEMPORARY = 24,
474 BUTTONID_CERT_DENY = 25
476 const SDL_MessageBoxButtonData buttons[] = {
477 { 0, BUTTONID_CERT_ACCEPT_PERMANENT,
"permanent" },
478 { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_CERT_ACCEPT_TEMPORARY,
"temporary" },
479 { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_CERT_DENY,
"cancel" }
482 const SDL_MessageBoxData data = { SDL_MESSAGEBOX_WARNING,
nullptr, title, message,
483 ARRAYSIZE(buttons), buttons,
nullptr };
484 const int rc = SDL_ShowMessageBox(&data, &buttonid);
493 case BUTTONID_CERT_ACCEPT_PERMANENT:
496 case BUTTONID_CERT_ACCEPT_TEMPORARY:
505 return sdl_push_user_event(SDL_EVENT_USER_CERT_RESULT, value);
508 BOOL sdl_message_dialog_show(
const char* title,
const char* message, Sint32 flags)
513 BUTTONID_SHOW_ACCEPT = 24,
514 BUTTONID_SHOW_DENY = 25
516 const SDL_MessageBoxButtonData buttons[] = {
517 { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_SHOW_ACCEPT,
"accept" },
518 { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_SHOW_DENY,
"cancel" }
521 const int button_cnt = (flags & SHOW_DIALOG_ACCEPT_REJECT) ? 2 : 1;
522 const SDL_MessageBoxData data = {
523 SDL_MESSAGEBOX_WARNING,
nullptr, title, message, button_cnt, buttons,
nullptr
525 const int rc = SDL_ShowMessageBox(&data, &buttonid);
534 case BUTTONID_SHOW_ACCEPT:
543 return sdl_push_user_event(SDL_EVENT_USER_SHOW_RESULT, value);
548 const std::vector<std::string> auth = {
"Username: ",
"Domain: ",
550 const std::vector<std::string> authPin = {
"Device: ",
"PIN: " };
551 const std::vector<std::string> gw = {
"GatewayUsername: ",
"GatewayDomain: ",
552 "GatewayPassword: " };
553 std::vector<std::string> prompt;
556 switch (args->result)
558 case AUTH_SMARTCARD_PIN:
575 std::vector<std::string> result;
579 std::vector<std::string> initial{ args->user ? args->user :
"Smartcard",
"" };
580 std::vector<Uint32> flags = { SdlInputWidget::SDL_INPUT_READONLY,
581 SdlInputWidget::SDL_INPUT_MASK };
582 if (args->result != AUTH_SMARTCARD_PIN)
584 initial = { args->user ? args->user :
"", args->domain ? args->domain :
"",
585 args->password ? args->password :
"" };
586 flags = { 0, 0, SdlInputWidget::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);
612 BOOL sdl_scard_dialog_show(
const char* title, Sint32 count,
const char** list)
614 std::vector<std::string> vlist;
615 vlist.reserve(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);
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_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
FREERDP_API const char * freerdp_settings_get_server_name(const rdpSettings *settings)
A helper function to return the correct server name.