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)
117const char* freerdp_passphrase_from_env(WINPR_ATTR_UNUSED rdpContext* context,
118 WINPR_ATTR_UNUSED
const char* prompt,
119 WINPR_ATTR_UNUSED
char* buf,
120 WINPR_ATTR_UNUSED
size_t bufsiz)
125const char* freerdp_passphrase_read_tty(WINPR_ATTR_UNUSED rdpContext* context,
126 WINPR_ATTR_UNUSED
const char* prompt,
127 WINPR_ATTR_UNUSED
char* buf,
128 WINPR_ATTR_UNUSED
size_t bufsiz,
129 WINPR_ATTR_UNUSED
int from_stdin)
134#elif !defined(ANDROID)
143#include <freerdp/utils/signal.h>
144#include <freerdp/log.h>
145#if defined(WINPR_HAVE_POLL_H) && !defined(__APPLE__)
149#include <sys/select.h>
152#define TAG FREERDP_TAG("utils.passphrase")
154static int wait_for_fd(
int fd,
int timeout)
157#if defined(WINPR_HAVE_POLL_H) && !defined(__APPLE__)
158 struct pollfd pollset = WINPR_C_ARRAY_INIT;
160 pollset.events = POLLIN;
165 status = poll(&pollset, 1, timeout);
166 }
while ((status < 0) && (errno == EINTR));
169 fd_set rset = WINPR_C_ARRAY_INIT;
170 struct timeval tv = WINPR_C_ARRAY_INIT;
176 tv.tv_sec = timeout / 1000;
177 tv.tv_usec = (timeout % 1000) * 1000;
182 status = select(fd + 1, &rset,
nullptr,
nullptr, timeout ? &tv : nullptr);
183 }
while ((status < 0) && (errno == EINTR));
189static void replace_char(
char* buffer, WINPR_ATTR_UNUSED
size_t buffer_len,
const char* toreplace)
191 while (*toreplace !=
'\0')
194 while ((ptr = strrchr(buffer, *toreplace)) !=
nullptr)
200const char* freerdp_passphrase_read_tty(rdpContext* context,
const char* prompt,
char* buf,
201 size_t bufsiz,
int from_stdin)
203 BOOL terminal_needs_reset = FALSE;
204 char term_name[L_ctermid] = WINPR_C_ARRAY_INIT;
206 FILE* fout =
nullptr;
215 int terminal_fildes = 0;
216 if (from_stdin || (strcmp(term_name,
"") == 0))
219 terminal_fildes = STDIN_FILENO;
223 const int term_file = open(term_name, O_RDWR);
227 terminal_fildes = STDIN_FILENO;
231 fout = fdopen(term_file,
"w");
237 terminal_fildes = term_file;
241 struct termios orig_flags = WINPR_C_ARRAY_INIT;
242 if (tcgetattr(terminal_fildes, &orig_flags) != -1)
244 struct termios new_flags = WINPR_C_ARRAY_INIT;
245 new_flags = orig_flags;
246 new_flags.c_lflag &= (uint32_t)~ECHO;
247 new_flags.c_lflag |= ECHONL;
248 terminal_needs_reset = TRUE;
249 if (tcsetattr(terminal_fildes, TCSAFLUSH, &new_flags) == -1)
250 terminal_needs_reset = FALSE;
253 FILE* fp = fdopen(terminal_fildes,
"r");
257 (void)fprintf(fout,
"%s", prompt);
263 const SSIZE_T res = freerdp_interruptible_get_line(context, &ptr, &ptr_len, fp);
267 replace_char(ptr, ptr_len,
"\r\n");
269 strncpy(buf, ptr, MIN(bufsiz, ptr_len));
273 if (terminal_needs_reset)
275 if (tcsetattr(terminal_fildes, TCSAFLUSH, &orig_flags) == -1)
279 if (terminal_fildes != STDIN_FILENO)
287 int saved_errno = errno;
288 if (terminal_needs_reset)
289 (void)tcsetattr(terminal_fildes, TCSAFLUSH, &orig_flags);
291 if (terminal_fildes != STDIN_FILENO)
303static const char* freerdp_passphrase_read_askpass(
const char* prompt,
char* buf,
size_t bufsiz,
304 char const* askpass_env)
306 char command[4096] = WINPR_C_ARRAY_INIT;
308 (void)sprintf_s(command,
sizeof(command),
"%s 'FreeRDP authentication\n%s'", askpass_env,
311 FILE* askproc = popen(command,
"r");
314 WINPR_ASSERT(bufsiz <= INT32_MAX);
315 if (fgets(buf, (
int)bufsiz, askproc) !=
nullptr)
316 buf[strcspn(buf,
"\r\n")] =
'\0';
319 const int status = pclose(askproc);
320 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
326const char* freerdp_passphrase_from_env(WINPR_ATTR_UNUSED rdpContext* context,
const char* prompt,
327 char* buf,
size_t bufsiz)
330 const char* askpass_env = getenv(
"FREERDP_ASKPASS");
333 return freerdp_passphrase_read_askpass(prompt, buf, bufsiz, askpass_env);
336const char* freerdp_passphrase_read(rdpContext* context,
const char* prompt,
char* buf,
337 size_t bufsiz,
int from_stdin)
339 const char* askpass_env = freerdp_passphrase_from_env(context, prompt, buf, bufsiz);
343 return freerdp_passphrase_read_tty(context, prompt, buf, bufsiz, from_stdin);
346static BOOL set_termianl_nonblock(
int ifd, BOOL nonblock);
348static void restore_terminal(
void)
350 (void)set_termianl_nonblock(-1, FALSE);
353BOOL set_termianl_nonblock(
int ifd, BOOL nonblock)
356 static bool registered =
false;
358 static struct termios termios = WINPR_C_ARRAY_INIT;
370 (void)winpr_atexit(restore_terminal);
374 const int rc1 = fcntl(fd, F_SETFL, orig | O_NONBLOCK);
377 char buffer[128] = WINPR_C_ARRAY_INIT;
378 WLog_ERR(TAG,
"fcntl(F_SETFL) failed with %s",
379 winpr_strerror(errno, buffer,
sizeof(buffer)));
382 const int rc2 = tcgetattr(fd, &termios);
385 char buffer[128] = WINPR_C_ARRAY_INIT;
386 WLog_ERR(TAG,
"tcgetattr() failed with %s",
387 winpr_strerror(errno, buffer,
sizeof(buffer)));
391 struct termios now = termios;
393 const int rc3 = tcsetattr(fd, TCSANOW, &now);
396 char buffer[128] = WINPR_C_ARRAY_INIT;
397 WLog_ERR(TAG,
"tcsetattr(TCSANOW) failed with %s",
398 winpr_strerror(errno, buffer,
sizeof(buffer)));
404 const int rc1 = tcsetattr(fd, TCSANOW, &termios);
407 char buffer[128] = WINPR_C_ARRAY_INIT;
408 WLog_ERR(TAG,
"tcsetattr(TCSANOW) failed with %s",
409 winpr_strerror(errno, buffer,
sizeof(buffer)));
412 const int rc2 = fcntl(fd, F_SETFL, orig);
415 char buffer[128] = WINPR_C_ARRAY_INIT;
416 WLog_ERR(TAG,
"fcntl(F_SETFL) failed with %s",
417 winpr_strerror(errno, buffer,
sizeof(buffer)));
425int freerdp_interruptible_getc(rdpContext* context, FILE* stream)
428 const int fd = fileno(stream);
430 (void)set_termianl_nonblock(fd, TRUE);
434 const int res = wait_for_fd(fd, 10);
438 const ssize_t rd = read(fd, &c, 1);
451 }
while (!freerdp_shall_disconnect_context(context));
453 (void)set_termianl_nonblock(fd, FALSE);
460const char* freerdp_passphrase_read(rdpContext* context,
const char* prompt,
char* buf,
461 size_t bufsiz,
int from_stdin)
466int freerdp_interruptible_getc(rdpContext* context, FILE* f)
471const char* freerdp_passphrase_from_env(WINPR_ATTR_UNUSED rdpContext* context,
472 WINPR_ATTR_UNUSED
const char* prompt,
473 WINPR_ATTR_UNUSED
char* buf,
474 WINPR_ATTR_UNUSED
size_t bufsiz)
479const char* freerdp_passphrase_read_tty(WINPR_ATTR_UNUSED rdpContext* context,
480 WINPR_ATTR_UNUSED
const char* prompt,
481 WINPR_ATTR_UNUSED
char* buf,
482 WINPR_ATTR_UNUSED
size_t bufsiz,
483 WINPR_ATTR_UNUSED
int from_stdin)
489SSIZE_T freerdp_interruptible_get_line(rdpContext* context,
char** plineptr,
size_t* psize,
499 if (!plineptr || !psize)
506#if !defined(_WIN32) && !defined(ANDROID)
508 const int fd = fileno(stream);
510 struct termios termios = WINPR_C_ARRAY_INIT;
512 if (tcgetattr(fd, &termios) == 0)
513 echo = (termios.c_lflag & ECHO) != 0;
519 if (*plineptr && (*psize > 0))
526 (void)fflush(stdout);
535 n = realloc(ptr, len);
547 c = freerdp_interruptible_getc(context, stream);
558 (void)fflush(stdout);
566 (void)fflush(stdout);
569 ptr[used++] = (char)c;
570 }
while ((c !=
'\n') && (c !=
'\r') && (c != EOF));
582 return WINPR_ASSERTING_INT_CAST(SSIZE_T, used);