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
 
   42static 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";
 
   54static 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);
 
   72static 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;
 
   86BOOL 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;
 
  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);
 
  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);
 
  199  *choice = 
static_cast<DWORD
>(
event.user.code);
 
  204SSIZE_T sdl_retry_dialog(freerdp* instance, 
const char* what, 
size_t current,
 
  205                         [[maybe_unused]] 
void* userarg)
 
  207  WINPR_ASSERT(instance);
 
  208  WINPR_ASSERT(instance->context);
 
  211  auto sdl = get_context(instance->context);
 
  212  auto settings = instance->context->settings;
 
  214  std::lock_guard<CriticalSection> lock(sdl->critical);
 
  215  if (!sdl->connection_dialog)
 
  216    return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
 
  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",
 
  238    sdl->connection_dialog->showError(
 
  239        "Automatic reconnection disabled, terminating. Try to connect again later");
 
  247    sdl->connection_dialog->showError(
 
  248        "[%s] retries exceeded. Your VM failed to start. Try again later or contact your " 
  249        "tech support for help if this keeps happening.",
 
  254  sdl->connection_dialog->showInfo(
"[%s] retry %" PRIuz 
"/%" PRIuz 
", delaying %" PRIuz
 
  255                                   "ms before next attempt",
 
  256                                   what, current, max, delay);
 
  257  return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
 
  260BOOL sdl_present_gateway_message(freerdp* instance, [[maybe_unused]] UINT32 type,
 
  261                                 BOOL isDisplayMandatory, BOOL isConsentMandatory, 
size_t length,
 
  262                                 const WCHAR* wmessage)
 
  264  if (!isDisplayMandatory)
 
  267  char* title = 
nullptr;
 
  269  winpr_asprintf(&title, &len, 
"[gateway]");
 
  272  if (isConsentMandatory)
 
  273    flags = SHOW_DIALOG_ACCEPT_REJECT;
 
  274  else if (isDisplayMandatory)
 
  275    flags = SHOW_DIALOG_TIMED_ACCEPT;
 
  276  char* message = ConvertWCharNToUtf8Alloc(wmessage, length, 
nullptr);
 
  279  const int rc = sdl_show_dialog(instance->context, title, message, flags);
 
  285int sdl_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
 
  288  const char* str_data = freerdp_get_logon_error_info_data(data);
 
  289  const char* str_type = freerdp_get_logon_error_info_type(type);
 
  291  if (!instance || !instance->context)
 
  295  if (type == LOGON_MSG_SESSION_CONTINUE)
 
  300  char* title = 
nullptr;
 
  302  winpr_asprintf(&title, &tlen, 
"[%s] info",
 
  305  char* message = 
nullptr;
 
  307  winpr_asprintf(&message, &mlen, 
"Logon Error Info %s [%s]", str_data, str_type);
 
  309  rc = sdl_show_dialog(instance->context, title, message, SHOW_DIALOG_ACCEPT_REJECT);
 
  315static DWORD sdl_show_ceritifcate_dialog(rdpContext* context, 
const char* title,
 
  319  if (!sdl_push_user_event(SDL_USEREVENT_CERT_DIALOG, title, message))
 
  322  SDL_Event 
event = {};
 
  323  if (!sdl_wait_for_result(context, SDL_USEREVENT_CERT_RESULT, &event))
 
  325  return static_cast<DWORD
>(
event.user.code);
 
  328static char* sdl_pem_cert(
const char* pem)
 
  330  rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
 
  334  char* fp = freerdp_certificate_get_fingerprint(cert);
 
  335  char* start = freerdp_certificate_get_validity(cert, TRUE);
 
  336  char* end = freerdp_certificate_get_validity(cert, FALSE);
 
  337  freerdp_certificate_free(cert);
 
  341  winpr_asprintf(&str, &slen,
 
  352DWORD sdl_verify_changed_certificate_ex(freerdp* instance, 
const char* host, UINT16 port,
 
  353                                        const char* common_name, 
const char* subject,
 
  354                                        const char* issuer, 
const char* new_fingerprint,
 
  355                                        const char* old_subject, 
const char* old_issuer,
 
  356                                        const char* old_fingerprint, DWORD flags)
 
  358  const char* type = type_str_for_flags(flags);
 
  360  WINPR_ASSERT(instance);
 
  361  WINPR_ASSERT(instance->context);
 
  362  WINPR_ASSERT(instance->context->settings);
 
  368  char* new_fp_str = 
nullptr;
 
  370  if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
 
  371    new_fp_str = sdl_pem_cert(new_fingerprint);
 
  373    winpr_asprintf(&new_fp_str, &len, 
"Thumbprint:  %s\n", new_fingerprint);
 
  378  char* old_fp_str = 
nullptr;
 
  380  if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
 
  381    old_fp_str = sdl_pem_cert(old_fingerprint);
 
  383    winpr_asprintf(&old_fp_str, &olen, 
"Thumbprint:  %s\n", old_fingerprint);
 
  385  const char* collission_str = 
"";
 
  386  if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
 
  389        "A matching entry with legacy SHA1 was found in local known_hosts2 store.\n" 
  390        "If you just upgraded from a FreeRDP version before 2.0 this is expected.\n" 
  391        "The hashing algorithm has been upgraded from SHA1 to SHA256.\n" 
  392        "All manually accepted certificates must be reconfirmed!\n" 
  396  char* title = 
nullptr;
 
  398  winpr_asprintf(&title, &tlen, 
"Certificate for %s:%" PRIu16 
" (%s) has changed", host, port,
 
  401  char* message = 
nullptr;
 
  403  winpr_asprintf(&message, &mlen,
 
  404                 "New Certificate details:\n" 
  409                 "Old Certificate details:\n" 
  414                 "The above X.509 certificate does not match the certificate used for previous " 
  416                 "This may indicate that the certificate has been tampered with.\n" 
  417                 "Please contact the administrator of the RDP server and clarify.\n",
 
  418                 common_name, subject, issuer, new_fp_str, old_subject, old_issuer, old_fp_str,
 
  421  const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
 
  430DWORD sdl_verify_certificate_ex(freerdp* instance, 
const char* host, UINT16 port,
 
  431                                const char* common_name, 
const char* subject, 
const char* issuer,
 
  432                                const char* fingerprint, DWORD flags)
 
  434  const char* type = type_str_for_flags(flags);
 
  439  char* fp_str = 
nullptr;
 
  441  if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
 
  442    fp_str = sdl_pem_cert(fingerprint);
 
  444    winpr_asprintf(&fp_str, &len, 
"Thumbprint:  %s\n", fingerprint);
 
  446  char* title = 
nullptr;
 
  448  winpr_asprintf(&title, &tlen, 
"New certificate for %s:%" PRIu16 
" (%s)", host, port, type);
 
  450  char* message = 
nullptr;
 
  458      "The above X.509 certificate could not be verified, possibly because you do not have\n" 
  459      "the CA certificate in your certificate store, or the certificate has expired.\n" 
  460      "Please look at the OpenSSL documentation on how to add a private CA to the store.\n",
 
  461      common_name, subject, issuer, fp_str);
 
  464  const DWORD rc = sdl_show_ceritifcate_dialog(instance->context, title, message);
 
  471BOOL sdl_cert_dialog_show(
const char* title, 
const char* message)
 
  476    BUTTONID_CERT_ACCEPT_PERMANENT = 23,
 
  477    BUTTONID_CERT_ACCEPT_TEMPORARY = 24,
 
  478    BUTTONID_CERT_DENY = 25
 
  480  const SDL_MessageBoxButtonData buttons[] = {
 
  481    { 0, BUTTONID_CERT_ACCEPT_PERMANENT, 
"permanent" },
 
  482    { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_CERT_ACCEPT_TEMPORARY, 
"temporary" },
 
  483    { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_CERT_DENY, 
"cancel" }
 
  486  const SDL_MessageBoxData data = { SDL_MESSAGEBOX_WARNING, 
nullptr, title,  message,
 
  487                                  ARRAYSIZE(buttons),     buttons, 
nullptr };
 
  488  const int rc = SDL_ShowMessageBox(&data, &buttonid);
 
  497      case BUTTONID_CERT_ACCEPT_PERMANENT:
 
  500      case BUTTONID_CERT_ACCEPT_TEMPORARY:
 
  509  return sdl_push_user_event(SDL_USEREVENT_CERT_RESULT, value);
 
  512BOOL sdl_message_dialog_show(
const char* title, 
const char* message, Sint32 flags)
 
  517    BUTTONID_SHOW_ACCEPT = 24,
 
  518    BUTTONID_SHOW_DENY = 25
 
  520  const SDL_MessageBoxButtonData buttons[] = {
 
  521    { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, BUTTONID_SHOW_ACCEPT, 
"accept" },
 
  522    { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, BUTTONID_SHOW_DENY, 
"cancel" }
 
  525  const int button_cnt = (flags & SHOW_DIALOG_ACCEPT_REJECT) ? 2 : 1;
 
  526  const SDL_MessageBoxData data = {
 
  527    SDL_MESSAGEBOX_WARNING, 
nullptr, title, message, button_cnt, buttons, 
nullptr 
  529  const int rc = SDL_ShowMessageBox(&data, &buttonid);
 
  538      case BUTTONID_SHOW_ACCEPT:
 
  547  return sdl_push_user_event(SDL_USEREVENT_SHOW_RESULT, value);
 
  552  std::vector<std::string> auth = { 
"Username:        ", 
"Domain:          ",
 
  554  std::vector<std::string> authPin = { 
"Device:       ", 
"PIN:        " };
 
  555  std::vector<std::string> gw = { 
"GatewayUsername: ", 
"GatewayDomain:   ", 
"GatewayPassword: " };
 
  556  std::vector<std::string> prompt;
 
  559  switch (args->result)
 
  561    case AUTH_SMARTCARD_PIN:
 
  562      prompt = std::move(authPin);
 
  567      prompt = std::move(auth);
 
  572      prompt = std::move(gw);
 
  578  std::vector<std::string> result;
 
  582    std::vector<std::string> initial{ args->user ? args->user : 
"Smartcard", 
"" };
 
  583    std::vector<Uint32> flags = { SdlInputWidget::SDL_INPUT_READONLY,
 
  584                                SdlInputWidget::SDL_INPUT_MASK };
 
  585    if (args->result != AUTH_SMARTCARD_PIN)
 
  587      initial = { args->user ? args->user : 
"", args->domain ? args->domain : 
"",
 
  588                args->password ? args->password : 
"" };
 
  589      flags = { 0, 0, SdlInputWidget::SDL_INPUT_MASK };
 
  592    rc = ilist.run(result);
 
  595  if ((result.size() < prompt.size()))
 
  598  char* user = 
nullptr;
 
  599  char* domain = 
nullptr;
 
  603    user = _strdup(result[0].c_str());
 
  604    if (args->result == AUTH_SMARTCARD_PIN)
 
  605      pwd = _strdup(result[1].c_str());
 
  608      domain = _strdup(result[1].c_str());
 
  609      pwd = _strdup(result[2].c_str());
 
  612  return sdl_push_user_event(SDL_USEREVENT_AUTH_RESULT, user, domain, pwd, rc);
 
  615BOOL sdl_scard_dialog_show(
const char* title, Sint32 count, 
const char** list)
 
  617  const auto scount = WINPR_ASSERTING_INT_CAST(
size_t, count);
 
  618  std::vector<std::string> vlist;
 
  619  vlist.reserve(scount);
 
  620  for (
size_t x = 0; x < scount; x++)
 
  621    vlist.emplace_back(list[x]);
 
  623  Sint32 value = slist.run();
 
  624  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_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.