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_USEREVENT_SHOW_DIALOG, title, message, flags))
80 if (!sdl_wait_for_result(context, SDL_USEREVENT_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)> 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 ? 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_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) ? 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;
213 std::lock_guard<CriticalSection> lock(sdl->critical);
214 if (!sdl->connection_dialog)
217 sdl->connection_dialog->setTitle(
"Retry connection to %s",
220 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
222 sdl->connection_dialog->showError(
"Unknown module %s, aborting", what);
228 if (strcmp(what,
"arm-transport") == 0)
229 sdl->connection_dialog->showWarn(
"[%s] Starting your VM. It may take up to 5 minutes",
237 sdl->connection_dialog->showError(
238 "Automatic reconnection disabled, terminating. Try to connect again later");
246 sdl->connection_dialog->showError(
247 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
248 "tech support for help if this keeps happening.",
253 sdl->connection_dialog->showInfo(
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
254 "ms before next attempt",
255 what, current, max, delay);
259 BOOL sdl_present_gateway_message(freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
260 BOOL isConsentMandatory,
size_t length,
const WCHAR* wmessage)
262 if (!isDisplayMandatory)
265 char* title =
nullptr;
267 winpr_asprintf(&title, &len,
"[gateway]");
270 if (isConsentMandatory)
271 flags = SHOW_DIALOG_ACCEPT_REJECT;
272 else if (isDisplayMandatory)
273 flags = SHOW_DIALOG_TIMED_ACCEPT;
274 char* message = ConvertWCharNToUtf8Alloc(wmessage, length,
nullptr);
277 const int rc = sdl_show_dialog(instance->context, title, message, flags);
280 return rc > 0 ? TRUE : FALSE;
283 int sdl_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
286 const char* str_data = freerdp_get_logon_error_info_data(data);
287 const char* str_type = freerdp_get_logon_error_info_type(type);
289 if (!instance || !instance->context)
293 if (type == LOGON_MSG_SESSION_CONTINUE)
298 char* title =
nullptr;
300 winpr_asprintf(&title, &tlen,
"[%s] info",
303 char* message =
nullptr;
305 winpr_asprintf(&message, &mlen,
"Logon Error Info %s [%s]", str_data, str_type);
307 rc = sdl_show_dialog(instance->context, title, message, SHOW_DIALOG_ACCEPT_REJECT);
313 static DWORD sdl_show_ceritifcate_dialog(rdpContext* context,
const char* title,
317 if (!sdl_push_user_event(SDL_USEREVENT_CERT_DIALOG, title, message))
320 SDL_Event
event = {};
321 if (!sdl_wait_for_result(context, SDL_USEREVENT_CERT_RESULT, &event))
323 return static_cast<DWORD
>(
event.user.code);
326 static char* sdl_pem_cert(
const char* pem)
328 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
332 char* fp = freerdp_certificate_get_fingerprint(cert);
333 char* start = freerdp_certificate_get_validity(cert, TRUE);
334 char* end = freerdp_certificate_get_validity(cert, FALSE);
335 freerdp_certificate_free(cert);
339 winpr_asprintf(&str, &slen,
350 DWORD sdl_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
351 const char* common_name,
const char* subject,
352 const char* issuer,
const char* new_fingerprint,
353 const char* old_subject,
const char* old_issuer,
354 const char* old_fingerprint, DWORD flags)
356 const char* type = type_str_for_flags(flags);
358 WINPR_ASSERT(instance);
359 WINPR_ASSERT(instance->context);
360 WINPR_ASSERT(instance->context->settings);
366 char* new_fp_str =
nullptr;
368 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
369 new_fp_str = sdl_pem_cert(new_fingerprint);
371 winpr_asprintf(&new_fp_str, &len,
"Thumbprint: %s\n", new_fingerprint);
376 char* old_fp_str =
nullptr;
378 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
379 old_fp_str = sdl_pem_cert(old_fingerprint);
381 winpr_asprintf(&old_fp_str, &olen,
"Thumbprint: %s\n", old_fingerprint);
383 const char* collission_str =
"";
384 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
387 "A matching entry with legacy SHA1 was found in local known_hosts2 store.\n"
388 "If you just upgraded from a FreeRDP version before 2.0 this is expected.\n"
389 "The hashing algorithm has been upgraded from SHA1 to SHA256.\n"
390 "All manually accepted certificates must be reconfirmed!\n"
394 char* title =
nullptr;
396 winpr_asprintf(&title, &tlen,
"Certificate for %s:%" PRIu16
" (%s) has changed", host, port,
399 char* message =
nullptr;
401 winpr_asprintf(&message, &mlen,
402 "New Certificate details:\n"
407 "Old Certificate details:\n"
412 "The above X.509 certificate does not match the certificate used for previous "
414 "This may indicate that the certificate has been tampered with.\n"
415 "Please contact the administrator of the RDP server and clarify.\n",
416 common_name, subject, issuer, new_fp_str, old_subject, old_issuer, old_fp_str,
419 const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
428 DWORD sdl_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
429 const char* common_name,
const char* subject,
const char* issuer,
430 const char* fingerprint, DWORD flags)
432 const char* type = type_str_for_flags(flags);
437 char* fp_str =
nullptr;
439 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
440 fp_str = sdl_pem_cert(fingerprint);
442 winpr_asprintf(&fp_str, &len,
"Thumbprint: %s\n", fingerprint);
444 char* title =
nullptr;
446 winpr_asprintf(&title, &tlen,
"New certificate for %s:%" PRIu16
" (%s)", host, port, type);
448 char* message =
nullptr;
456 "The above X.509 certificate could not be verified, possibly because you do not have\n"
457 "the CA certificate in your certificate store, or the certificate has expired.\n"
458 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n",
459 common_name, subject, issuer, fp_str);
462 const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
469 BOOL sdl_cert_dialog_show(
const char* title,
const char* message)
474 BUTTONID_CERT_ACCEPT_PERMANENT = 23,
475 BUTTONID_CERT_ACCEPT_TEMPORARY = 24,
476 BUTTONID_CERT_DENY = 25
478 const SDL_MessageBoxButtonData buttons[] = {
479 { 0, BUTTONID_CERT_ACCEPT_PERMANENT,
"permanent" },
480 { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_CERT_ACCEPT_TEMPORARY,
"temporary" },
481 { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_CERT_DENY,
"cancel" }
484 const SDL_MessageBoxData data = { SDL_MESSAGEBOX_WARNING,
nullptr, title, message,
485 ARRAYSIZE(buttons), buttons,
nullptr };
486 const int rc = SDL_ShowMessageBox(&data, &buttonid);
495 case BUTTONID_CERT_ACCEPT_PERMANENT:
498 case BUTTONID_CERT_ACCEPT_TEMPORARY:
507 return sdl_push_user_event(SDL_USEREVENT_CERT_RESULT, value);
510 BOOL sdl_message_dialog_show(
const char* title,
const char* message, Sint32 flags)
515 BUTTONID_SHOW_ACCEPT = 24,
516 BUTTONID_SHOW_DENY = 25
518 const SDL_MessageBoxButtonData buttons[] = {
519 { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_SHOW_ACCEPT,
"accept" },
520 { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_SHOW_DENY,
"cancel" }
523 const int button_cnt = (flags & SHOW_DIALOG_ACCEPT_REJECT) ? 2 : 1;
524 const SDL_MessageBoxData data = {
525 SDL_MESSAGEBOX_WARNING,
nullptr, title, message, button_cnt, buttons,
nullptr
527 const int rc = SDL_ShowMessageBox(&data, &buttonid);
536 case BUTTONID_SHOW_ACCEPT:
545 return sdl_push_user_event(SDL_USEREVENT_SHOW_RESULT, value);
550 const std::vector<std::string> auth = {
"Username: ",
"Domain: ",
552 const std::vector<std::string> authPin = {
"Device: ",
"PIN: " };
553 const std::vector<std::string> gw = {
"GatewayUsername: ",
"GatewayDomain: ",
554 "GatewayPassword: " };
555 std::vector<std::string> prompt;
558 switch (args->result)
560 case AUTH_SMARTCARD_PIN:
577 std::vector<std::string> result;
581 std::vector<std::string> initial{ args->user ? args->user :
"Smartcard",
"" };
582 std::vector<Uint32> flags = { SdlInputWidget::SDL_INPUT_READONLY,
583 SdlInputWidget::SDL_INPUT_MASK };
584 if (args->result != AUTH_SMARTCARD_PIN)
586 initial = { args->user ? args->user :
"", args->domain ? args->domain :
"",
587 args->password ? args->password :
"" };
588 flags = { 0, 0, SdlInputWidget::SDL_INPUT_MASK };
591 rc = ilist.run(result);
594 if ((result.size() < prompt.size()))
597 char* user =
nullptr;
598 char* domain =
nullptr;
602 user = _strdup(result[0].c_str());
603 if (args->result == AUTH_SMARTCARD_PIN)
604 pwd = _strdup(result[1].c_str());
607 domain = _strdup(result[1].c_str());
608 pwd = _strdup(result[2].c_str());
611 return sdl_push_user_event(SDL_USEREVENT_AUTH_RESULT, user, domain, pwd, rc);
614 BOOL sdl_scard_dialog_show(
const char* title, Sint32 count,
const char** list)
616 std::vector<std::string> vlist;
617 vlist.reserve(count);
618 for (Sint32 x = 0; x < count; x++)
619 vlist.emplace_back(list[x]);
621 Sint32 value = slist.run();
622 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_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.