Commit 3efad641551f79adbacead4f1d1641e63c2efa05

Guillem Jover 2018-05-21T01:56:33

Update readpassphrase() from OpenBSD

diff --git a/man/readpassphrase.3bsd b/man/readpassphrase.3bsd
index 9729061..53ad52d 100644
--- a/man/readpassphrase.3bsd
+++ b/man/readpassphrase.3bsd
@@ -1,4 +1,4 @@
-.\"	$OpenBSD: readpassphrase.3,v 1.16 2005/07/22 03:16:58 jaredy Exp $
+.\"	$OpenBSD: readpassphrase.3,v 1.20 2014/03/06 23:03:18 millert Exp $
 .\"
 .\" Copyright (c) 2000, 2002 Todd C. Miller <Todd.Miller@courtesan.com>
 .\"
@@ -18,7 +18,7 @@
 .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
 .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
 .\"
-.Dd $Mdocdate: May 31 2007 $
+.Dd $Mdocdate: March 6 2014 $
 .Dt READPASSPHRASE 3bsd
 .Os
 .Sh NAME
@@ -55,9 +55,11 @@ Up to
 Any additional
 characters and the terminating newline (or return) character are discarded.
 .Pp
-.Fn readpassphrase
-takes the following optional
-.Fa flags :
+The
+.Fa flags
+argument is the bitwise
+.Tn OR
+of zero or more of the following values:
 .Bd -literal -offset indent
 RPP_ECHO_OFF		turn off echo (default behavior)
 RPP_ECHO_ON		leave echo on
@@ -65,7 +67,7 @@ RPP_REQUIRE_TTY		fail if there is no tty
 RPP_FORCELOWER		force input to lower case
 RPP_FORCEUPPER		force input to upper case
 RPP_SEVENBIT		strip the high bit from input
-RPP_STDIN		force read of passphrase from stdin
+RPP_STDIN		read passphrase from stdin; ignore prompt
 .Ed
 .Pp
 The calling process should zero the passphrase as soon as possible to
@@ -100,7 +102,7 @@ if (compare(transform(passbuf), epass) != 0)
 
 \&...
 
-memset(passbuf, 0, sizeof(passbuf));
+explicit_bzero(passbuf, sizeof(passbuf));
 .Ed
 .Sh ERRORS
 .Bl -tag -width Er
diff --git a/src/readpassphrase.c b/src/readpassphrase.c
index 1f4fe0e..f9f6195 100644
--- a/src/readpassphrase.c
+++ b/src/readpassphrase.c
@@ -1,7 +1,8 @@
-/*	$OpenBSD: readpassphrase.c,v 1.20 2007/10/30 12:03:48 millert Exp $	*/
+/*	$OpenBSD: readpassphrase.c,v 1.26 2016/10/18 12:47:18 millert Exp $	*/
 
 /*
- * Copyright (c) 2000-2002, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2000-2002, 2007, 2010
+ *	Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -35,7 +36,7 @@
 #define TCSASOFT 0
 #endif
 
-static volatile sig_atomic_t signo;
+static volatile sig_atomic_t signo[_NSIG];
 
 static void handler(int);
 
@@ -43,7 +44,7 @@ char *
 readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
 {
 	ssize_t nr;
-	int input, output, save_errno;
+	int input, output, save_errno, i, need_restart;
 	char ch, *p, *end;
 	struct termios term, oterm;
 	struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm;
@@ -56,9 +57,11 @@ readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
 	}
 
 restart:
-	signo = 0;
+	for (i = 0; i < _NSIG; i++)
+		signo[i] = 0;
 	nr = -1;
 	save_errno = 0;
+	need_restart = 0;
 	/*
 	 * Read and write to /dev/tty if available.  If not, read from
 	 * stdin and write to stderr unless a tty is required.
@@ -74,24 +77,10 @@ restart:
 	}
 
 	/*
-	 * Catch signals that would otherwise cause the user to end
-	 * up with echo turned off in the shell.  Don't worry about
-	 * things like SIGXCPU and SIGVTALRM for now.
+	 * Turn off echo if possible.
+	 * If we are using a tty but are not the foreground pgrp this will
+	 * generate SIGTTOU, so do it *before* installing the signal handlers.
 	 */
-	sigemptyset(&sa.sa_mask);
-	sa.sa_flags = 0;		/* don't restart system calls */
-	sa.sa_handler = handler;
-	(void)sigaction(SIGALRM, &sa, &savealrm);
-	(void)sigaction(SIGHUP, &sa, &savehup);
-	(void)sigaction(SIGINT, &sa, &saveint);
-	(void)sigaction(SIGPIPE, &sa, &savepipe);
-	(void)sigaction(SIGQUIT, &sa, &savequit);
-	(void)sigaction(SIGTERM, &sa, &saveterm);
-	(void)sigaction(SIGTSTP, &sa, &savetstp);
-	(void)sigaction(SIGTTIN, &sa, &savettin);
-	(void)sigaction(SIGTTOU, &sa, &savettou);
-
-	/* Turn off echo if possible. */
 	if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) {
 		memcpy(&term, &oterm, sizeof(term));
 		if (!(flags & RPP_ECHO_ON))
@@ -108,36 +97,55 @@ restart:
 		oterm.c_lflag |= ECHO;
 	}
 
-	/* No I/O if we are already backgrounded. */
-	if (signo != SIGTTOU && signo != SIGTTIN) {
-		if (!(flags & RPP_STDIN))
-			(void)write(output, prompt, strlen(prompt));
-		end = buf + bufsiz - 1;
-		p = buf;
-		while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') {
-			if (p < end) {
-				if ((flags & RPP_SEVENBIT))
-					ch &= 0x7f;
-				if (isalpha(ch)) {
-					if ((flags & RPP_FORCELOWER))
-						ch = (char)tolower(ch);
-					if ((flags & RPP_FORCEUPPER))
-						ch = (char)toupper(ch);
-				}
-				*p++ = ch;
+	/*
+	 * Catch signals that would otherwise cause the user to end
+	 * up with echo turned off in the shell.  Don't worry about
+	 * things like SIGXCPU and SIGVTALRM for now.
+	 */
+	sigemptyset(&sa.sa_mask);
+	sa.sa_flags = 0;		/* don't restart system calls */
+	sa.sa_handler = handler;
+	(void)sigaction(SIGALRM, &sa, &savealrm);
+	(void)sigaction(SIGHUP, &sa, &savehup);
+	(void)sigaction(SIGINT, &sa, &saveint);
+	(void)sigaction(SIGPIPE, &sa, &savepipe);
+	(void)sigaction(SIGQUIT, &sa, &savequit);
+	(void)sigaction(SIGTERM, &sa, &saveterm);
+	(void)sigaction(SIGTSTP, &sa, &savetstp);
+	(void)sigaction(SIGTTIN, &sa, &savettin);
+	(void)sigaction(SIGTTOU, &sa, &savettou);
+
+	if (!(flags & RPP_STDIN))
+		(void)write(output, prompt, strlen(prompt));
+	end = buf + bufsiz - 1;
+	p = buf;
+	while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') {
+		if (p < end) {
+			if ((flags & RPP_SEVENBIT))
+				ch &= 0x7f;
+			if (isalpha((unsigned char)ch)) {
+				if ((flags & RPP_FORCELOWER))
+					ch = (char)tolower((unsigned char)ch);
+				if ((flags & RPP_FORCEUPPER))
+					ch = (char)toupper((unsigned char)ch);
 			}
+			*p++ = ch;
 		}
-		*p = '\0';
-		save_errno = errno;
-		if (!(term.c_lflag & ECHO))
-			(void)write(output, "\n", 1);
 	}
+	*p = '\0';
+	save_errno = errno;
+	if (!(term.c_lflag & ECHO))
+		(void)write(output, "\n", 1);
 
 	/* Restore old terminal settings and signals. */
 	if (memcmp(&term, &oterm, sizeof(term)) != 0) {
+		const int sigttou = signo[SIGTTOU];
+
+		/* Ignore SIGTTOU generated when we are not the fg pgrp. */
 		while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 &&
-		    errno == EINTR)
+		    errno == EINTR && !signo[SIGTTOU])
 			continue;
+		signo[SIGTTOU] = sigttou;
 	}
 	(void)sigaction(SIGALRM, &savealrm, NULL);
 	(void)sigaction(SIGHUP, &savehup, NULL);
@@ -155,15 +163,19 @@ restart:
 	 * If we were interrupted by a signal, resend it to ourselves
 	 * now that we have restored the signal handlers.
 	 */
-	if (signo) {
-		kill(getpid(), signo);
-		switch (signo) {
-		case SIGTSTP:
-		case SIGTTIN:
-		case SIGTTOU:
-			goto restart;
+	for (i = 0; i < _NSIG; i++) {
+		if (signo[i]) {
+			kill(getpid(), i);
+			switch (i) {
+			case SIGTSTP:
+			case SIGTTIN:
+			case SIGTTOU:
+				need_restart = 1;
+			}
 		}
 	}
+	if (need_restart)
+		goto restart;
 
 	if (save_errno)
 		errno = save_errno;
@@ -183,5 +195,5 @@ getpass(const char *prompt)
 static void handler(int s)
 {
 
-	signo = s;
+	signo[s] = 1;
 }