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.