20#include <winpr/environment.h> 
   22#include <freerdp/config.h> 
   23#include <freerdp/freerdp.h> 
   26#include <freerdp/utils/passphrase.h> 
   35static char read_chr(FILE* f)
 
   38  const BOOL isTty = _isatty(_fileno(f));
 
   41  if (fscanf_s(f, 
"%c", &chr, (UINT32)
sizeof(
char)) && !feof(f))
 
   46int freerdp_interruptible_getc(rdpContext* context, FILE* f)
 
   51const char* freerdp_passphrase_read(rdpContext* context, 
const char* prompt, 
char* buf,
 
   52                                    size_t bufsiz, 
int from_stdin)
 
   54  WCHAR UserNameW[CREDUI_MAX_USERNAME_LENGTH + 1] = { 
'p', 
'r', 
'e', 
'f', 
'i',
 
   55                                                    'l', 
'l', 
'e', 
'd', 
'\0' };
 
   56  WCHAR PasswordW[CREDUI_MAX_PASSWORD_LENGTH + 1] = { 0 };
 
   59  WCHAR* promptW = ConvertUtf8ToWCharAlloc(prompt, NULL);
 
   61      CredUICmdLinePromptForCredentialsW(promptW, NULL, 0, UserNameW, ARRAYSIZE(UserNameW),
 
   62                                         PasswordW, ARRAYSIZE(PasswordW), &fSave, dwFlags);
 
   64  if (ConvertWCharNToUtf8(PasswordW, ARRAYSIZE(PasswordW), buf, bufsiz) < 0)
 
   69#elif !defined(ANDROID) 
   78#include <freerdp/utils/signal.h> 
   79#include <freerdp/log.h> 
   80#if defined(WINPR_HAVE_POLL_H) && !defined(__APPLE__) 
   84#include <sys/select.h> 
   87#define TAG FREERDP_TAG("utils.passphrase") 
   89static int wait_for_fd(
int fd, 
int timeout)
 
   92#if defined(WINPR_HAVE_POLL_H) && !defined(__APPLE__) 
   93  struct pollfd pollset = { 0 };
 
   95  pollset.events = POLLIN;
 
  100    status = poll(&pollset, 1, timeout);
 
  101  } 
while ((status < 0) && (errno == EINTR));
 
  105  struct timeval tv = { 0 };
 
  111    tv.tv_sec = timeout / 1000;
 
  112    tv.tv_usec = (timeout % 1000) * 1000;
 
  117    status = select(fd + 1, &rset, NULL, NULL, timeout ? &tv : NULL);
 
  118  } 
while ((status < 0) && (errno == EINTR));
 
  124static void replace_char(
char* buffer, WINPR_ATTR_UNUSED 
size_t buffer_len, 
const char* toreplace)
 
  126  while (*toreplace != 
'\0')
 
  129    while ((ptr = strrchr(buffer, *toreplace)) != NULL)
 
  135static const char* freerdp_passphrase_read_tty(rdpContext* context, 
const char* prompt, 
char* buf,
 
  136                                               size_t bufsiz, 
int from_stdin)
 
  138  BOOL terminal_needs_reset = FALSE;
 
  139  char term_name[L_ctermid] = { 0 };
 
  150  int terminal_fildes = 0;
 
  151  if (from_stdin || (strcmp(term_name, 
"") == 0))
 
  154    terminal_fildes = STDIN_FILENO;
 
  158    const int term_file = open(term_name, O_RDWR);
 
  162      terminal_fildes = STDIN_FILENO;
 
  166      fout = fdopen(term_file, 
"w");
 
  172      terminal_fildes = term_file;
 
  176  struct termios orig_flags = { 0 };
 
  177  if (tcgetattr(terminal_fildes, &orig_flags) != -1)
 
  179    struct termios new_flags = { 0 };
 
  180    new_flags = orig_flags;
 
  181    new_flags.c_lflag &= (uint32_t)~ECHO;
 
  182    new_flags.c_lflag |= ECHONL;
 
  183    terminal_needs_reset = TRUE;
 
  184    if (tcsetattr(terminal_fildes, TCSAFLUSH, &new_flags) == -1)
 
  185      terminal_needs_reset = FALSE;
 
  188  FILE* fp = fdopen(terminal_fildes, 
"r");
 
  192  (void)fprintf(fout, 
"%s", prompt);
 
  198  const SSIZE_T res = freerdp_interruptible_get_line(context, &ptr, &ptr_len, fp);
 
  201  replace_char(ptr, ptr_len, 
"\r\n");
 
  203  strncpy(buf, ptr, MIN(bufsiz, ptr_len));
 
  205  if (terminal_needs_reset)
 
  207    if (tcsetattr(terminal_fildes, TCSAFLUSH, &orig_flags) == -1)
 
  211  if (terminal_fildes != STDIN_FILENO)
 
  219  int saved_errno = errno;
 
  220  if (terminal_needs_reset)
 
  221    (void)tcsetattr(terminal_fildes, TCSAFLUSH, &orig_flags);
 
  223  if (terminal_fildes != STDIN_FILENO)
 
  235static const char* freerdp_passphrase_read_askpass(
const char* prompt, 
char* buf, 
size_t bufsiz,
 
  236                                                   char const* askpass_env)
 
  238  char command[4096] = { 0 };
 
  240  (void)sprintf_s(command, 
sizeof(command), 
"%s 'FreeRDP authentication\n%s'", askpass_env,
 
  243  FILE* askproc = popen(command, 
"r");
 
  246  WINPR_ASSERT(bufsiz <= INT32_MAX);
 
  247  if (fgets(buf, (
int)bufsiz, askproc) != NULL)
 
  248    buf[strcspn(buf, 
"\r\n")] = 
'\0';
 
  251  const int status = pclose(askproc);
 
  252  if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
 
  258const char* freerdp_passphrase_read(rdpContext* context, 
const char* prompt, 
char* buf,
 
  259                                    size_t bufsiz, 
int from_stdin)
 
  262  const char* askpass_env = getenv(
"FREERDP_ASKPASS");
 
  265    return freerdp_passphrase_read_askpass(prompt, buf, bufsiz, askpass_env);
 
  267    return freerdp_passphrase_read_tty(context, prompt, buf, bufsiz, from_stdin);
 
  270static BOOL set_termianl_nonblock(
int ifd, BOOL nonblock);
 
  272static void restore_terminal(
void)
 
  274  (void)set_termianl_nonblock(-1, FALSE);
 
  277BOOL set_termianl_nonblock(
int ifd, BOOL nonblock)
 
  280  static bool registered = 
false;
 
  282  static struct termios termios = { 0 };
 
  294      (void)atexit(restore_terminal);
 
  298    const int rc1 = fcntl(fd, F_SETFL, orig | O_NONBLOCK);
 
  301      char buffer[128] = { 0 };
 
  302      WLog_ERR(TAG, 
"fcntl(F_SETFL) failed with %s",
 
  303               winpr_strerror(errno, buffer, 
sizeof(buffer)));
 
  306    const int rc2 = tcgetattr(fd, &termios);
 
  309      char buffer[128] = { 0 };
 
  310      WLog_ERR(TAG, 
"tcgetattr() failed with %s",
 
  311               winpr_strerror(errno, buffer, 
sizeof(buffer)));
 
  315    struct termios now = termios;
 
  317    const int rc3 = tcsetattr(fd, TCSANOW, &now);
 
  320      char buffer[128] = { 0 };
 
  321      WLog_ERR(TAG, 
"tcsetattr(TCSANOW) failed with %s",
 
  322               winpr_strerror(errno, buffer, 
sizeof(buffer)));
 
  328    const int rc1 = tcsetattr(fd, TCSANOW, &termios);
 
  331      char buffer[128] = { 0 };
 
  332      WLog_ERR(TAG, 
"tcsetattr(TCSANOW) failed with %s",
 
  333               winpr_strerror(errno, buffer, 
sizeof(buffer)));
 
  336    const int rc2 = fcntl(fd, F_SETFL, orig);
 
  339      char buffer[128] = { 0 };
 
  340      WLog_ERR(TAG, 
"fcntl(F_SETFL) failed with %s",
 
  341               winpr_strerror(errno, buffer, 
sizeof(buffer)));
 
  349int freerdp_interruptible_getc(rdpContext* context, FILE* stream)
 
  352  const int fd = fileno(stream);
 
  354  (void)set_termianl_nonblock(fd, TRUE);
 
  358    const int res = wait_for_fd(fd, 10);
 
  362      const ssize_t rd = read(fd, &c, 1);
 
  375  } 
while (!freerdp_shall_disconnect_context(context));
 
  377  (void)set_termianl_nonblock(fd, FALSE);
 
  384const char* freerdp_passphrase_read(rdpContext* context, 
const char* prompt, 
char* buf,
 
  385                                    size_t bufsiz, 
int from_stdin)
 
  390int freerdp_interruptible_getc(rdpContext* context, FILE* f)
 
  396SSIZE_T freerdp_interruptible_get_line(rdpContext* context, 
char** plineptr, 
size_t* psize,
 
  406  if (!plineptr || !psize)
 
  413#if !defined(_WIN32) && !defined(ANDROID) 
  415    const int fd = fileno(stream);
 
  417    struct termios termios = { 0 };
 
  419    if (tcgetattr(fd, &termios) == 0)
 
  420      echo = (termios.c_lflag & ECHO) != 0;
 
  426  if (*plineptr && (*psize > 0))
 
  433      (void)fflush(stdout);
 
  442      n = realloc(ptr, len);
 
  452    c = freerdp_interruptible_getc(context, stream);
 
  463          (void)fflush(stdout);
 
  471      (void)fflush(stdout);
 
  474      ptr[used++] = (char)c;
 
  475  } 
while ((c != 
'\n') && (c != 
'\r') && (c != EOF));
 
  486  return WINPR_ASSERTING_INT_CAST(SSIZE_T, used);