Finally complete my fix for the behaviour of getpass(3) upon receipt

of signals.  Signals are now properly caught, tty state is being
restored, and the previous sigaction triggered.  Upon receipt of a
sigcont, echo is turned off again.

SIGTSTP causes a buffer flush, the man page mentions this.  (Although
i rather think of it as a feature than a bug.)

This is likely to be my last FreeBSD action for 1995, xearth shows
me that our .au guys must already write 1996. :-)
This commit is contained in:
Joerg Wunsch 1995-12-31 14:00:25 +00:00
parent cfaaf1594e
commit 7560bb26ff
2 changed files with 56 additions and 18 deletions

View File

@ -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.

View File

@ -43,16 +43,47 @@ static char sccsid[] = "@(#)getpass.c 8.1 (Berkeley) 6/4/93";
#include <stdio.h>
#include <unistd.h>
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);