20#include <winpr/atexit.h>
21#include <winpr/environment.h>
23#include <freerdp/config.h>
24#include <freerdp/freerdp.h>
27#include <freerdp/utils/passphrase.h>
37static char read_chr(FILE* f)
40 const BOOL isTty = _isatty(_fileno(f));
43 if (fscanf_s(f,
"%c", &chr, (UINT32)
sizeof(
char)) && !feof(f))
48int freerdp_interruptible_getc(rdpContext* context, FILE* f)
53const char* freerdp_passphrase_read(rdpContext* context,
const char* prompt,
char* buf,
54 size_t bufsiz,
int from_stdin)
68 HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
69 const BOOL isTty = _isatty(_fileno(stdin)) != 0;
71 BOOL echoSuppressed = FALSE;
73 if (isTty && hStdin && hStdin != INVALID_HANDLE_VALUE && GetConsoleMode(hStdin, &origMode))
75 if (SetConsoleMode(hStdin, origMode & ~(DWORD)ENABLE_ECHO_INPUT))
76 echoSuppressed = TRUE;
81 (void)fputs(prompt, stdout);
85 WINPR_ASSERT(bufsiz <= INT32_MAX);
86 const char* rc = fgets(buf, (
int)bufsiz, stdin);
90 (void)SetConsoleMode(hStdin, origMode);
91 (void)fputc(
'\n', stdout);
98 buf[strcspn(buf,
"\r\n")] =
'\0';
102 WCHAR UserNameW[CREDUI_MAX_USERNAME_LENGTH + 1] = {
'p',
'r',
'e',
'f',
'i',
103 'l',
'l',
'e',
'd',
'\0' };
104 WCHAR PasswordW[CREDUI_MAX_PASSWORD_LENGTH + 1] = WINPR_C_ARRAY_INIT;
107 WCHAR* promptW = ConvertUtf8ToWCharAlloc(prompt,
nullptr);
109 CredUICmdLinePromptForCredentialsW(promptW,
nullptr, 0, UserNameW, ARRAYSIZE(UserNameW),
110 PasswordW, ARRAYSIZE(PasswordW), &fSave, dwFlags);
112 if (ConvertWCharNToUtf8(PasswordW, ARRAYSIZE(PasswordW), buf, bufsiz) < 0)
117#elif !defined(ANDROID)
126#include <freerdp/utils/signal.h>
127#include <freerdp/log.h>
128#if defined(WINPR_HAVE_POLL_H) && !defined(__APPLE__)
132#include <sys/select.h>
135#define TAG FREERDP_TAG("utils.passphrase")
137static int wait_for_fd(
int fd,
int timeout)
140#if defined(WINPR_HAVE_POLL_H) && !defined(__APPLE__)
141 struct pollfd pollset = WINPR_C_ARRAY_INIT;
143 pollset.events = POLLIN;
148 status = poll(&pollset, 1, timeout);
149 }
while ((status < 0) && (errno == EINTR));
152 fd_set rset = WINPR_C_ARRAY_INIT;
153 struct timeval tv = WINPR_C_ARRAY_INIT;
159 tv.tv_sec = timeout / 1000;
160 tv.tv_usec = (timeout % 1000) * 1000;
165 status = select(fd + 1, &rset,
nullptr,
nullptr, timeout ? &tv : nullptr);
166 }
while ((status < 0) && (errno == EINTR));
172static void replace_char(
char* buffer, WINPR_ATTR_UNUSED
size_t buffer_len,
const char* toreplace)
174 while (*toreplace !=
'\0')
177 while ((ptr = strrchr(buffer, *toreplace)) !=
nullptr)
183static const char* freerdp_passphrase_read_tty(rdpContext* context,
const char* prompt,
char* buf,
184 size_t bufsiz,
int from_stdin)
186 BOOL terminal_needs_reset = FALSE;
187 char term_name[L_ctermid] = WINPR_C_ARRAY_INIT;
189 FILE* fout =
nullptr;
198 int terminal_fildes = 0;
199 if (from_stdin || (strcmp(term_name,
"") == 0))
202 terminal_fildes = STDIN_FILENO;
206 const int term_file = open(term_name, O_RDWR);
210 terminal_fildes = STDIN_FILENO;
214 fout = fdopen(term_file,
"w");
220 terminal_fildes = term_file;
224 struct termios orig_flags = WINPR_C_ARRAY_INIT;
225 if (tcgetattr(terminal_fildes, &orig_flags) != -1)
227 struct termios new_flags = WINPR_C_ARRAY_INIT;
228 new_flags = orig_flags;
229 new_flags.c_lflag &= (uint32_t)~ECHO;
230 new_flags.c_lflag |= ECHONL;
231 terminal_needs_reset = TRUE;
232 if (tcsetattr(terminal_fildes, TCSAFLUSH, &new_flags) == -1)
233 terminal_needs_reset = FALSE;
236 FILE* fp = fdopen(terminal_fildes,
"r");
240 (void)fprintf(fout,
"%s", prompt);
246 const SSIZE_T res = freerdp_interruptible_get_line(context, &ptr, &ptr_len, fp);
250 replace_char(ptr, ptr_len,
"\r\n");
252 strncpy(buf, ptr, MIN(bufsiz, ptr_len));
256 if (terminal_needs_reset)
258 if (tcsetattr(terminal_fildes, TCSAFLUSH, &orig_flags) == -1)
262 if (terminal_fildes != STDIN_FILENO)
270 int saved_errno = errno;
271 if (terminal_needs_reset)
272 (void)tcsetattr(terminal_fildes, TCSAFLUSH, &orig_flags);
274 if (terminal_fildes != STDIN_FILENO)
286static const char* freerdp_passphrase_read_askpass(
const char* prompt,
char* buf,
size_t bufsiz,
287 char const* askpass_env)
289 char command[4096] = WINPR_C_ARRAY_INIT;
291 (void)sprintf_s(command,
sizeof(command),
"%s 'FreeRDP authentication\n%s'", askpass_env,
294 FILE* askproc = popen(command,
"r");
297 WINPR_ASSERT(bufsiz <= INT32_MAX);
298 if (fgets(buf, (
int)bufsiz, askproc) !=
nullptr)
299 buf[strcspn(buf,
"\r\n")] =
'\0';
302 const int status = pclose(askproc);
303 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
309const char* freerdp_passphrase_read(rdpContext* context,
const char* prompt,
char* buf,
310 size_t bufsiz,
int from_stdin)
313 const char* askpass_env = getenv(
"FREERDP_ASKPASS");
316 return freerdp_passphrase_read_askpass(prompt, buf, bufsiz, askpass_env);
318 return freerdp_passphrase_read_tty(context, prompt, buf, bufsiz, from_stdin);
321static BOOL set_termianl_nonblock(
int ifd, BOOL nonblock);
323static void restore_terminal(
void)
325 (void)set_termianl_nonblock(-1, FALSE);
328BOOL set_termianl_nonblock(
int ifd, BOOL nonblock)
331 static bool registered =
false;
333 static struct termios termios = WINPR_C_ARRAY_INIT;
345 (void)winpr_atexit(restore_terminal);
349 const int rc1 = fcntl(fd, F_SETFL, orig | O_NONBLOCK);
352 char buffer[128] = WINPR_C_ARRAY_INIT;
353 WLog_ERR(TAG,
"fcntl(F_SETFL) failed with %s",
354 winpr_strerror(errno, buffer,
sizeof(buffer)));
357 const int rc2 = tcgetattr(fd, &termios);
360 char buffer[128] = WINPR_C_ARRAY_INIT;
361 WLog_ERR(TAG,
"tcgetattr() failed with %s",
362 winpr_strerror(errno, buffer,
sizeof(buffer)));
366 struct termios now = termios;
368 const int rc3 = tcsetattr(fd, TCSANOW, &now);
371 char buffer[128] = WINPR_C_ARRAY_INIT;
372 WLog_ERR(TAG,
"tcsetattr(TCSANOW) failed with %s",
373 winpr_strerror(errno, buffer,
sizeof(buffer)));
379 const int rc1 = tcsetattr(fd, TCSANOW, &termios);
382 char buffer[128] = WINPR_C_ARRAY_INIT;
383 WLog_ERR(TAG,
"tcsetattr(TCSANOW) failed with %s",
384 winpr_strerror(errno, buffer,
sizeof(buffer)));
387 const int rc2 = fcntl(fd, F_SETFL, orig);
390 char buffer[128] = WINPR_C_ARRAY_INIT;
391 WLog_ERR(TAG,
"fcntl(F_SETFL) failed with %s",
392 winpr_strerror(errno, buffer,
sizeof(buffer)));
400int freerdp_interruptible_getc(rdpContext* context, FILE* stream)
403 const int fd = fileno(stream);
405 (void)set_termianl_nonblock(fd, TRUE);
409 const int res = wait_for_fd(fd, 10);
413 const ssize_t rd = read(fd, &c, 1);
426 }
while (!freerdp_shall_disconnect_context(context));
428 (void)set_termianl_nonblock(fd, FALSE);
435const char* freerdp_passphrase_read(rdpContext* context,
const char* prompt,
char* buf,
436 size_t bufsiz,
int from_stdin)
441int freerdp_interruptible_getc(rdpContext* context, FILE* f)
447SSIZE_T freerdp_interruptible_get_line(rdpContext* context,
char** plineptr,
size_t* psize,
457 if (!plineptr || !psize)
464#if !defined(_WIN32) && !defined(ANDROID)
466 const int fd = fileno(stream);
468 struct termios termios = WINPR_C_ARRAY_INIT;
470 if (tcgetattr(fd, &termios) == 0)
471 echo = (termios.c_lflag & ECHO) != 0;
477 if (*plineptr && (*psize > 0))
484 (void)fflush(stdout);
493 n = realloc(ptr, len);
505 c = freerdp_interruptible_getc(context, stream);
516 (void)fflush(stdout);
524 (void)fflush(stdout);
527 ptr[used++] = (char)c;
528 }
while ((c !=
'\n') && (c !=
'\r') && (c != EOF));
540 return WINPR_ASSERTING_INT_CAST(SSIZE_T, used);