diff --git a/lib/libc/gen/getpass.3 b/lib/libc/gen/getpass.3 index 34e91cbd47f..f312d42b8f5 100644 --- a/lib/libc/gen/getpass.3 +++ b/lib/libc/gen/getpass.3 @@ -86,3 +86,7 @@ will modify the same object. The calling process should zero the password as soon as possible to avoid leaving the cleartext password visible in the process's address space. +.Pp +Upon receipt of a SIGTSTP, the input buffer will be flushed, so any +partially typed password must be retyped when the process +continues. diff --git a/lib/libc/gen/getpass.c b/lib/libc/gen/getpass.c index cf6088a82c7..658f5b6d6ab 100644 --- a/lib/libc/gen/getpass.c +++ b/lib/libc/gen/getpass.c @@ -43,16 +43,47 @@ static char sccsid[] = "@(#)getpass.c 8.1 (Berkeley) 6/4/93"; #include #include +static struct termios oterm, term; +static sig_t ointhandler, oquithandler, otstphandler, oconthandler; +static FILE *fp; + +static void +sighandler(int signo) +{ + /* restore tty state */ + (void)tcsetattr(fileno(fp), TCSAFLUSH|TCSASOFT, &oterm); + + /* restore old sig handlers */ + (void)signal(SIGINT, ointhandler); + (void)signal(SIGQUIT, oquithandler); + (void)signal(SIGTSTP, otstphandler); + + /* resend us this signal */ + (void)kill(getpid(), signo); +} + +/* ARGSUSED */ +static void +sigconthandler(int signo) +{ + /* re-install our signal handlers */ + ointhandler = signal(SIGINT, sighandler); + oquithandler = signal(SIGQUIT, sighandler); + otstphandler = signal(SIGTSTP, sighandler); + + /* turn off echo again */ + (void)tcsetattr(fileno(fp), TCSAFLUSH|TCSASOFT, &term); +} + + char * getpass(prompt) const char *prompt; { - struct termios term; register int ch; register char *p; - FILE *fp, *outfp; + FILE *outfp; long omask; - int echo; static char buf[_PASSWORD_LEN + 1]; /* @@ -63,16 +94,16 @@ getpass(prompt) outfp = stderr; fp = stdin; } - /* - * note - blocking signals isn't necessarily the - * right thing, but we leave it for now. - */ - omask = sigblock(sigmask(SIGTSTP)); - (void)tcgetattr(fileno(fp), &term); - if (echo = (term.c_lflag & ECHO)) { - term.c_lflag &= ~ECHO; - (void)tcsetattr(fileno(fp), TCSAFLUSH|TCSASOFT, &term); - } + + ointhandler = signal(SIGINT, sighandler); + oquithandler = signal(SIGQUIT, sighandler); + otstphandler = signal(SIGTSTP, sighandler); + oconthandler = signal(SIGCONT, sigconthandler); + + (void)tcgetattr(fileno(fp), &oterm); + term = oterm; + term.c_lflag &= ~ECHO; + (void)tcsetattr(fileno(fp), TCSAFLUSH|TCSASOFT, &term); (void)fputs(prompt, outfp); rewind(outfp); /* implied flush */ for (p = buf; (ch = getc(fp)) != EOF && ch != '\n';) @@ -80,11 +111,14 @@ getpass(prompt) *p++ = ch; *p = '\0'; (void)write(fileno(outfp), "\n", 1); - if (echo) { - term.c_lflag |= ECHO; - (void)tcsetattr(fileno(fp), TCSAFLUSH|TCSASOFT, &term); - } - (void)sigsetmask(omask); + (void)tcsetattr(fileno(fp), TCSAFLUSH|TCSASOFT, &oterm); + + /* restore old sig handlers */ + (void)signal(SIGINT, ointhandler); + (void)signal(SIGQUIT, oquithandler); + (void)signal(SIGTSTP, otstphandler); + (void)signal(SIGCONT, oconthandler); + if (fp != stdin) (void)fclose(fp); return(buf);