summaryrefslogtreecommitdiffstats
path: root/lib/libc
diff options
context:
space:
mode:
authorjoerg <joerg@FreeBSD.org>1995-12-31 14:00:25 +0000
committerjoerg <joerg@FreeBSD.org>1995-12-31 14:00:25 +0000
commitb6da577a94b64818b9d7801831b6a6de8eccad3c (patch)
treeb46c238f3117917c3906594b0d7972513ff90cef /lib/libc
parent4417f7962367aeb4c73b3b9bad8cbc565b2ccde8 (diff)
downloadFreeBSD-src-b6da577a94b64818b9d7801831b6a6de8eccad3c.zip
FreeBSD-src-b6da577a94b64818b9d7801831b6a6de8eccad3c.tar.gz
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. :-)
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/gen/getpass.34
-rw-r--r--lib/libc/gen/getpass.c70
2 files changed, 56 insertions, 18 deletions
diff --git a/lib/libc/gen/getpass.3 b/lib/libc/gen/getpass.3
index 34e91cb..f312d42 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 cf6088a..658f5b6 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 <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);
OpenPOWER on IntegriCloud