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 if (isatty(fileno(fp)))
259 (void)fprintf(fout,
"%s", prompt);
266 const SSIZE_T res = freerdp_interruptible_get_line(context, &ptr, &ptr_len, fp);
270 replace_char(ptr, ptr_len,
"\r\n");
272 strncpy(buf, ptr, MIN(bufsiz, ptr_len));
276 if (terminal_needs_reset)
278 if (tcsetattr(terminal_fildes, TCSAFLUSH, &orig_flags) == -1)
282 if (terminal_fildes != STDIN_FILENO)
290 int saved_errno = errno;
291 if (terminal_needs_reset)
292 (void)tcsetattr(terminal_fildes, TCSAFLUSH, &orig_flags);
294 if (terminal_fildes != STDIN_FILENO)
306static const char* freerdp_passphrase_read_askpass(
const char* prompt,
char* buf,
size_t bufsiz,
307 char const* askpass_env)
309 char command[4096] = WINPR_C_ARRAY_INIT;
311 (void)sprintf_s(command,
sizeof(command),
"%s 'FreeRDP authentication\n%s'", askpass_env,
314 FILE* askproc = popen(command,
"r");
317 WINPR_ASSERT(bufsiz <= INT32_MAX);
318 if (fgets(buf, (
int)bufsiz, askproc) !=
nullptr)
319 buf[strcspn(buf,
"\r\n")] =
'\0';
322 const int status = pclose(askproc);
323 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
329const char* freerdp_passphrase_from_env(WINPR_ATTR_UNUSED rdpContext* context,
const char* prompt,
330 char* buf,
size_t bufsiz)
333 const char* askpass_env = getenv(
"FREERDP_ASKPASS");
336 return freerdp_passphrase_read_askpass(prompt, buf, bufsiz, askpass_env);
339const char* freerdp_passphrase_read(rdpContext* context,
const char* prompt,
char* buf,
340 size_t bufsiz,
int from_stdin)
342 const char* askpass_env = freerdp_passphrase_from_env(context, prompt, buf, bufsiz);
346 return freerdp_passphrase_read_tty(context, prompt, buf, bufsiz, from_stdin);
349static BOOL set_terminal_nonblock(
int ifd, BOOL nonblock);
351static void restore_terminal(
void)
353 (void)set_terminal_nonblock(-1, FALSE);
356BOOL set_terminal_nonblock(
int ifd, BOOL nonblock)
359 static bool registered =
false;
361 static struct termios termios = WINPR_C_ARRAY_INIT;
376 (void)winpr_atexit(restore_terminal);
380 const int rc1 = fcntl(fd, F_SETFL, orig | O_NONBLOCK);
383 char buffer[128] = WINPR_C_ARRAY_INIT;
384 WLog_ERR(TAG,
"fcntl(F_SETFL) failed with %s",
385 winpr_strerror(errno, buffer,
sizeof(buffer)));
388 const int rc2 = tcgetattr(fd, &termios);
391 char buffer[128] = WINPR_C_ARRAY_INIT;
392 WLog_ERR(TAG,
"tcgetattr() failed with %s",
393 winpr_strerror(errno, buffer,
sizeof(buffer)));
397 struct termios now = termios;
399 const int rc3 = tcsetattr(fd, TCSANOW, &now);
402 char buffer[128] = WINPR_C_ARRAY_INIT;
403 WLog_ERR(TAG,
"tcsetattr(TCSANOW) failed with %s",
404 winpr_strerror(errno, buffer,
sizeof(buffer)));
410 const int rc1 = tcsetattr(fd, TCSANOW, &termios);
413 char buffer[128] = WINPR_C_ARRAY_INIT;
414 WLog_ERR(TAG,
"tcsetattr(TCSANOW) failed with %s",
415 winpr_strerror(errno, buffer,
sizeof(buffer)));
418 const int rc2 = fcntl(fd, F_SETFL, orig);
421 char buffer[128] = WINPR_C_ARRAY_INIT;
422 WLog_ERR(TAG,
"fcntl(F_SETFL) failed with %s",
423 winpr_strerror(errno, buffer,
sizeof(buffer)));
431int freerdp_interruptible_getc(rdpContext* context, FILE* stream)
434 const int fd = fileno(stream);
436 (void)set_terminal_nonblock(fd, TRUE);
440 const int res = wait_for_fd(fd, 10);
444 const ssize_t rd = read(fd, &c, 1);
457 }
while (!freerdp_shall_disconnect_context(context));
459 (void)set_terminal_nonblock(fd, FALSE);
466const char* freerdp_passphrase_read(rdpContext* context,
const char* prompt,
char* buf,
467 size_t bufsiz,
int from_stdin)
472int freerdp_interruptible_getc(rdpContext* context, FILE* f)
477const char* freerdp_passphrase_from_env(WINPR_ATTR_UNUSED rdpContext* context,
478 WINPR_ATTR_UNUSED
const char* prompt,
479 WINPR_ATTR_UNUSED
char* buf,
480 WINPR_ATTR_UNUSED
size_t bufsiz)
485const char* freerdp_passphrase_read_tty(WINPR_ATTR_UNUSED rdpContext* context,
486 WINPR_ATTR_UNUSED
const char* prompt,
487 WINPR_ATTR_UNUSED
char* buf,
488 WINPR_ATTR_UNUSED
size_t bufsiz,
489 WINPR_ATTR_UNUSED
int from_stdin)
495SSIZE_T freerdp_interruptible_get_line(rdpContext* context,
char** plineptr,
size_t* psize,
505 if (!plineptr || !psize)
512#if !defined(_WIN32) && !defined(ANDROID)
514 const int fd = fileno(stream);
516 struct termios termios = WINPR_C_ARRAY_INIT;
518 if (tcgetattr(fd, &termios) == 0)
519 echo = (termios.c_lflag & ECHO) != 0;
525 if (*plineptr && (*psize > 0))
532 (void)fflush(stdout);
541 n = realloc(ptr, len);
553 c = freerdp_interruptible_getc(context, stream);
564 (void)fflush(stdout);
572 (void)fflush(stdout);
575 ptr[used++] = (char)c;
576 }
while ((c !=
'\n') && (c !=
'\r') && (c != EOF));
588 return WINPR_ASSERTING_INT_CAST(SSIZE_T, used);