From 7c1d11f7e82c0ff8563d4426262f1025ac03d6dc Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 4 Apr 2012 09:57:17 +0000 Subject: [PATCH] * passwd.cc (_getpass_close_fd): New static pthread cleanup handler. (getpass): Rework to use /dev/tty in the first place. Install _getpass_close_fd as pthread cleanup handler. Flush prompt explicitely. Lock input and switch off signal input handling when reading password. --- winsup/cygwin/ChangeLog | 7 +++++++ winsup/cygwin/passwd.cc | 45 ++++++++++++++++++++++++++++++----------- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 80cf8643b..3ac3e33c9 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,10 @@ +2012-04-04 Corinna Vinschen + + * passwd.cc (_getpass_close_fd): New static pthread cleanup handler. + (getpass): Rework to use /dev/tty in the first place. Install + _getpass_close_fd as pthread cleanup handler. Flush prompt explicitely. + Lock input and switch off signal input handling when reading password. + 2012-04-03 Corinna Vinschen * include/cygwin/version.h (CYGWIN_VERSION_DLL_MINOR): Bump to 13. diff --git a/winsup/cygwin/passwd.cc b/winsup/cygwin/passwd.cc index 962bf776e..74b8020b8 100644 --- a/winsup/cygwin/passwd.cc +++ b/winsup/cygwin/passwd.cc @@ -269,29 +269,50 @@ setpassent () return 0; } +static void +_getpass_close_fd (void *arg) +{ + if (arg) + fclose ((FILE *) arg); +} + extern "C" char * getpass (const char * prompt) { char *pass = _my_tls.locals.pass; struct termios ti, newti; - cygheap_fdget fhstdin (0); + /* Try to use controlling tty in the first place. Use stdin and stderr + only as fallback. */ + FILE *in = stdin, *err = stderr; + FILE *tty = fopen ("/dev/tty", "w+b"); + pthread_cleanup_push (_getpass_close_fd, tty); + if (tty) + { + /* Set close-on-exec for obvious reasons. */ + fcntl (fileno (tty), F_SETFD, fcntl (fileno (tty), F_GETFD) | FD_CLOEXEC); + in = err = tty; + } - if (fhstdin < 0) + /* Make sure to notice if stdin is closed. */ + if (tcgetattr (fileno (in), &ti) == -1) pass[0] = '\0'; else { - fhstdin->tcgetattr (&ti); + flockfile (in); newti = ti; - newti.c_lflag &= ~ECHO; - fhstdin->tcsetattr (TCSANOW, &newti); - fputs (prompt, stderr); - fgets (pass, _PASSWORD_LEN, stdin); - fprintf (stderr, "\n"); - for (int i=0; pass[i]; i++) - if (pass[i] == '\r' || pass[i] == '\n') - pass[i] = '\0'; - fhstdin->tcsetattr (TCSANOW, &ti); + newti.c_lflag &= ~(ECHO | ISIG); /* No echo, no signal handling. */ + tcsetattr (fileno (in), TCSANOW, &newti); + fputs (prompt, err); + fflush (err); + fgets (pass, _PASSWORD_LEN, in); + fprintf (err, "\n"); + tcsetattr (fileno (in), TCSANOW, &ti); + funlockfile (in); + char *crlf = strpbrk (pass, "\r\n"); + if (crlf) + *crlf = '\0'; } + pthread_cleanup_pop (1); return pass; }