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>
36static char read_chr(FILE* f)
39 const BOOL isTty = _isatty(_fileno(f));
42 if (fscanf_s(f,
"%c", &chr, (UINT32)
sizeof(
char)) && !feof(f))
47int freerdp_interruptible_getc(rdpContext* context, FILE* f)
52const char* freerdp_passphrase_read(rdpContext* context,
const char* prompt,
char* buf,
53 size_t bufsiz,
int from_stdin)
55 WCHAR UserNameW[CREDUI_MAX_USERNAME_LENGTH + 1] = {
'p',
'r',
'e',
'f',
'i',
56 'l',
'l',
'e',
'd',
'\0' };
57 WCHAR PasswordW[CREDUI_MAX_PASSWORD_LENGTH + 1] = WINPR_C_ARRAY_INIT;
60 WCHAR* promptW = ConvertUtf8ToWCharAlloc(prompt,
nullptr);
62 CredUICmdLinePromptForCredentialsW(promptW,
nullptr, 0, UserNameW, ARRAYSIZE(UserNameW),
63 PasswordW, ARRAYSIZE(PasswordW), &fSave, dwFlags);
65 if (ConvertWCharNToUtf8(PasswordW, ARRAYSIZE(PasswordW), buf, bufsiz) < 0)
70#elif !defined(ANDROID)
79#include <freerdp/utils/signal.h>
80#include <freerdp/log.h>
81#if defined(WINPR_HAVE_POLL_H) && !defined(__APPLE__)
85#include <sys/select.h>
88#define TAG FREERDP_TAG("utils.passphrase")
90static int wait_for_fd(
int fd,
int timeout)
93#if defined(WINPR_HAVE_POLL_H) && !defined(__APPLE__)
94 struct pollfd pollset = WINPR_C_ARRAY_INIT;
96 pollset.events = POLLIN;
101 status = poll(&pollset, 1, timeout);
102 }
while ((status < 0) && (errno == EINTR));
105 fd_set rset = WINPR_C_ARRAY_INIT;
106 struct timeval tv = WINPR_C_ARRAY_INIT;
112 tv.tv_sec = timeout / 1000;
113 tv.tv_usec = (timeout % 1000) * 1000;
118 status = select(fd + 1, &rset,
nullptr,
nullptr, timeout ? &tv : nullptr);
119 }
while ((status < 0) && (errno == EINTR));
125static void replace_char(
char* buffer, WINPR_ATTR_UNUSED
size_t buffer_len,
const char* toreplace)
127 while (*toreplace !=
'\0')
130 while ((ptr = strrchr(buffer, *toreplace)) !=
nullptr)
136static const char* freerdp_passphrase_read_tty(rdpContext* context,
const char* prompt,
char* buf,
137 size_t bufsiz,
int from_stdin)
139 BOOL terminal_needs_reset = FALSE;
140 char term_name[L_ctermid] = WINPR_C_ARRAY_INIT;
142 FILE* fout =
nullptr;
151 int terminal_fildes = 0;
152 if (from_stdin || (strcmp(term_name,
"") == 0))
155 terminal_fildes = STDIN_FILENO;
159 const int term_file = open(term_name, O_RDWR);
163 terminal_fildes = STDIN_FILENO;
167 fout = fdopen(term_file,
"w");
173 terminal_fildes = term_file;
177 struct termios orig_flags = WINPR_C_ARRAY_INIT;
178 if (tcgetattr(terminal_fildes, &orig_flags) != -1)
180 struct termios new_flags = WINPR_C_ARRAY_INIT;
181 new_flags = orig_flags;
182 new_flags.c_lflag &= (uint32_t)~ECHO;
183 new_flags.c_lflag |= ECHONL;
184 terminal_needs_reset = TRUE;
185 if (tcsetattr(terminal_fildes, TCSAFLUSH, &new_flags) == -1)
186 terminal_needs_reset = FALSE;
189 FILE* fp = fdopen(terminal_fildes,
"r");
193 (void)fprintf(fout,
"%s", prompt);
199 const SSIZE_T res = freerdp_interruptible_get_line(context, &ptr, &ptr_len, fp);
203 replace_char(ptr, ptr_len,
"\r\n");
205 strncpy(buf, ptr, MIN(bufsiz, ptr_len));
209 if (terminal_needs_reset)
211 if (tcsetattr(terminal_fildes, TCSAFLUSH, &orig_flags) == -1)
215 if (terminal_fildes != STDIN_FILENO)
223 int saved_errno = errno;
224 if (terminal_needs_reset)
225 (void)tcsetattr(terminal_fildes, TCSAFLUSH, &orig_flags);
227 if (terminal_fildes != STDIN_FILENO)
239static const char* freerdp_passphrase_read_askpass(
const char* prompt,
char* buf,
size_t bufsiz,
240 char const* askpass_env)
242 char command[4096] = WINPR_C_ARRAY_INIT;
244 (void)sprintf_s(command,
sizeof(command),
"%s 'FreeRDP authentication\n%s'", askpass_env,
247 FILE* askproc = popen(command,
"r");
250 WINPR_ASSERT(bufsiz <= INT32_MAX);
251 if (fgets(buf, (
int)bufsiz, askproc) !=
nullptr)
252 buf[strcspn(buf,
"\r\n")] =
'\0';
255 const int status = pclose(askproc);
256 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
262const char* freerdp_passphrase_read(rdpContext* context,
const char* prompt,
char* buf,
263 size_t bufsiz,
int from_stdin)
266 const char* askpass_env = getenv(
"FREERDP_ASKPASS");
269 return freerdp_passphrase_read_askpass(prompt, buf, bufsiz, askpass_env);
271 return freerdp_passphrase_read_tty(context, prompt, buf, bufsiz, from_stdin);
274static BOOL set_termianl_nonblock(
int ifd, BOOL nonblock);
276static void restore_terminal(
void)
278 (void)set_termianl_nonblock(-1, FALSE);
281BOOL set_termianl_nonblock(
int ifd, BOOL nonblock)
284 static bool registered =
false;
286 static struct termios termios = WINPR_C_ARRAY_INIT;
298 (void)winpr_atexit(restore_terminal);
302 const int rc1 = fcntl(fd, F_SETFL, orig | O_NONBLOCK);
305 char buffer[128] = WINPR_C_ARRAY_INIT;
306 WLog_ERR(TAG,
"fcntl(F_SETFL) failed with %s",
307 winpr_strerror(errno, buffer,
sizeof(buffer)));
310 const int rc2 = tcgetattr(fd, &termios);
313 char buffer[128] = WINPR_C_ARRAY_INIT;
314 WLog_ERR(TAG,
"tcgetattr() failed with %s",
315 winpr_strerror(errno, buffer,
sizeof(buffer)));
319 struct termios now = termios;
321 const int rc3 = tcsetattr(fd, TCSANOW, &now);
324 char buffer[128] = WINPR_C_ARRAY_INIT;
325 WLog_ERR(TAG,
"tcsetattr(TCSANOW) failed with %s",
326 winpr_strerror(errno, buffer,
sizeof(buffer)));
332 const int rc1 = tcsetattr(fd, TCSANOW, &termios);
335 char buffer[128] = WINPR_C_ARRAY_INIT;
336 WLog_ERR(TAG,
"tcsetattr(TCSANOW) failed with %s",
337 winpr_strerror(errno, buffer,
sizeof(buffer)));
340 const int rc2 = fcntl(fd, F_SETFL, orig);
343 char buffer[128] = WINPR_C_ARRAY_INIT;
344 WLog_ERR(TAG,
"fcntl(F_SETFL) failed with %s",
345 winpr_strerror(errno, buffer,
sizeof(buffer)));
353int freerdp_interruptible_getc(rdpContext* context, FILE* stream)
356 const int fd = fileno(stream);
358 (void)set_termianl_nonblock(fd, TRUE);
362 const int res = wait_for_fd(fd, 10);
366 const ssize_t rd = read(fd, &c, 1);
379 }
while (!freerdp_shall_disconnect_context(context));
381 (void)set_termianl_nonblock(fd, FALSE);
388const char* freerdp_passphrase_read(rdpContext* context,
const char* prompt,
char* buf,
389 size_t bufsiz,
int from_stdin)
394int freerdp_interruptible_getc(rdpContext* context, FILE* f)
400SSIZE_T freerdp_interruptible_get_line(rdpContext* context,
char** plineptr,
size_t* psize,
410 if (!plineptr || !psize)
417#if !defined(_WIN32) && !defined(ANDROID)
419 const int fd = fileno(stream);
421 struct termios termios = WINPR_C_ARRAY_INIT;
423 if (tcgetattr(fd, &termios) == 0)
424 echo = (termios.c_lflag & ECHO) != 0;
430 if (*plineptr && (*psize > 0))
437 (void)fflush(stdout);
446 n = realloc(ptr, len);
458 c = freerdp_interruptible_getc(context, stream);
469 (void)fflush(stdout);
477 (void)fflush(stdout);
480 ptr[used++] = (char)c;
481 }
while ((c !=
'\n') && (c !=
'\r') && (c != EOF));
493 return WINPR_ASSERTING_INT_CAST(SSIZE_T, used);