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);
202 replace_char(ptr, ptr_len,
"\r\n");
204 strncpy(buf, ptr, MIN(bufsiz, ptr_len));
208 if (terminal_needs_reset)
210 if (tcsetattr(terminal_fildes, TCSAFLUSH, &orig_flags) == -1)
214 if (terminal_fildes != STDIN_FILENO)
222 int saved_errno = errno;
223 if (terminal_needs_reset)
224 (void)tcsetattr(terminal_fildes, TCSAFLUSH, &orig_flags);
226 if (terminal_fildes != STDIN_FILENO)
238static const char* freerdp_passphrase_read_askpass(
const char* prompt,
char* buf,
size_t bufsiz,
239 char const* askpass_env)
241 char command[4096] = { 0 };
243 (void)sprintf_s(command,
sizeof(command),
"%s 'FreeRDP authentication\n%s'", askpass_env,
246 FILE* askproc = popen(command,
"r");
249 WINPR_ASSERT(bufsiz <= INT32_MAX);
250 if (fgets(buf, (
int)bufsiz, askproc) != NULL)
251 buf[strcspn(buf,
"\r\n")] =
'\0';
254 const int status = pclose(askproc);
255 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
261const char* freerdp_passphrase_read(rdpContext* context,
const char* prompt,
char* buf,
262 size_t bufsiz,
int from_stdin)
265 const char* askpass_env = getenv(
"FREERDP_ASKPASS");
268 return freerdp_passphrase_read_askpass(prompt, buf, bufsiz, askpass_env);
270 return freerdp_passphrase_read_tty(context, prompt, buf, bufsiz, from_stdin);
273static BOOL set_termianl_nonblock(
int ifd, BOOL nonblock);
275static void restore_terminal(
void)
277 (void)set_termianl_nonblock(-1, FALSE);
280BOOL set_termianl_nonblock(
int ifd, BOOL nonblock)
283 static bool registered =
false;
285 static struct termios termios = { 0 };
297 (void)atexit(restore_terminal);
301 const int rc1 = fcntl(fd, F_SETFL, orig | O_NONBLOCK);
304 char buffer[128] = { 0 };
305 WLog_ERR(TAG,
"fcntl(F_SETFL) failed with %s",
306 winpr_strerror(errno, buffer,
sizeof(buffer)));
309 const int rc2 = tcgetattr(fd, &termios);
312 char buffer[128] = { 0 };
313 WLog_ERR(TAG,
"tcgetattr() failed with %s",
314 winpr_strerror(errno, buffer,
sizeof(buffer)));
318 struct termios now = termios;
320 const int rc3 = tcsetattr(fd, TCSANOW, &now);
323 char buffer[128] = { 0 };
324 WLog_ERR(TAG,
"tcsetattr(TCSANOW) failed with %s",
325 winpr_strerror(errno, buffer,
sizeof(buffer)));
331 const int rc1 = tcsetattr(fd, TCSANOW, &termios);
334 char buffer[128] = { 0 };
335 WLog_ERR(TAG,
"tcsetattr(TCSANOW) failed with %s",
336 winpr_strerror(errno, buffer,
sizeof(buffer)));
339 const int rc2 = fcntl(fd, F_SETFL, orig);
342 char buffer[128] = { 0 };
343 WLog_ERR(TAG,
"fcntl(F_SETFL) failed with %s",
344 winpr_strerror(errno, buffer,
sizeof(buffer)));
352int freerdp_interruptible_getc(rdpContext* context, FILE* stream)
355 const int fd = fileno(stream);
357 (void)set_termianl_nonblock(fd, TRUE);
361 const int res = wait_for_fd(fd, 10);
365 const ssize_t rd = read(fd, &c, 1);
378 }
while (!freerdp_shall_disconnect_context(context));
380 (void)set_termianl_nonblock(fd, FALSE);
387const char* freerdp_passphrase_read(rdpContext* context,
const char* prompt,
char* buf,
388 size_t bufsiz,
int from_stdin)
393int freerdp_interruptible_getc(rdpContext* context, FILE* f)
399SSIZE_T freerdp_interruptible_get_line(rdpContext* context,
char** plineptr,
size_t* psize,
409 if (!plineptr || !psize)
416#if !defined(_WIN32) && !defined(ANDROID)
418 const int fd = fileno(stream);
420 struct termios termios = { 0 };
422 if (tcgetattr(fd, &termios) == 0)
423 echo = (termios.c_lflag & ECHO) != 0;
429 if (*plineptr && (*psize > 0))
436 (void)fflush(stdout);
445 n = realloc(ptr, len);
457 c = freerdp_interruptible_getc(context, stream);
468 (void)fflush(stdout);
476 (void)fflush(stdout);
479 ptr[used++] = (char)c;
480 }
while ((c !=
'\n') && (c !=
'\r') && (c != EOF));
492 return WINPR_ASSERTING_INT_CAST(SSIZE_T, used);