Update readpassphrase() from OpenBSD

This commit is contained in:
Guillem Jover 2018-05-21 01:56:33 +02:00
parent a6f407ab0d
commit 3efad64155
2 changed files with 73 additions and 59 deletions

View File

@ -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> .\" Copyright (c) 2000, 2002 Todd C. Miller <Todd.Miller@courtesan.com>
.\" .\"
@ -18,7 +18,7 @@
.\" Agency (DARPA) and Air Force Research Laboratory, Air Force .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
.\" Materiel Command, USAF, under agreement number F39502-99-1-0512. .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
.\" .\"
.Dd $Mdocdate: May 31 2007 $ .Dd $Mdocdate: March 6 2014 $
.Dt READPASSPHRASE 3bsd .Dt READPASSPHRASE 3bsd
.Os .Os
.Sh NAME .Sh NAME
@ -55,9 +55,11 @@ Up to
Any additional Any additional
characters and the terminating newline (or return) character are discarded. characters and the terminating newline (or return) character are discarded.
.Pp .Pp
.Fn readpassphrase The
takes the following optional .Fa flags
.Fa flags : argument is the bitwise
.Tn OR
of zero or more of the following values:
.Bd -literal -offset indent .Bd -literal -offset indent
RPP_ECHO_OFF turn off echo (default behavior) RPP_ECHO_OFF turn off echo (default behavior)
RPP_ECHO_ON leave echo on 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_FORCELOWER force input to lower case
RPP_FORCEUPPER force input to upper case RPP_FORCEUPPER force input to upper case
RPP_SEVENBIT strip the high bit from input 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 .Ed
.Pp .Pp
The calling process should zero the passphrase as soon as possible to 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 .Ed
.Sh ERRORS .Sh ERRORS
.Bl -tag -width Er .Bl -tag -width Er

View File

@ -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 * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -35,7 +36,7 @@
#define TCSASOFT 0 #define TCSASOFT 0
#endif #endif
static volatile sig_atomic_t signo; static volatile sig_atomic_t signo[_NSIG];
static void handler(int); static void handler(int);
@ -43,7 +44,7 @@ char *
readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
{ {
ssize_t nr; ssize_t nr;
int input, output, save_errno; int input, output, save_errno, i, need_restart;
char ch, *p, *end; char ch, *p, *end;
struct termios term, oterm; struct termios term, oterm;
struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm; struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm;
@ -56,9 +57,11 @@ readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
} }
restart: restart:
signo = 0; for (i = 0; i < _NSIG; i++)
signo[i] = 0;
nr = -1; nr = -1;
save_errno = 0; save_errno = 0;
need_restart = 0;
/* /*
* Read and write to /dev/tty if available. If not, read from * Read and write to /dev/tty if available. If not, read from
* stdin and write to stderr unless a tty is required. * stdin and write to stderr unless a tty is required.
@ -73,6 +76,27 @@ restart:
output = STDERR_FILENO; output = STDERR_FILENO;
} }
/*
* 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.
*/
if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) {
memcpy(&term, &oterm, sizeof(term));
if (!(flags & RPP_ECHO_ON))
term.c_lflag &= ~(ECHO | ECHONL);
#ifdef VSTATUS
if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
term.c_cc[VSTATUS] = _POSIX_VDISABLE;
#endif
(void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
} else {
memset(&term, 0, sizeof(term));
term.c_lflag |= ECHO;
memset(&oterm, 0, sizeof(oterm));
oterm.c_lflag |= ECHO;
}
/* /*
* Catch signals that would otherwise cause the user to end * Catch signals that would otherwise cause the user to end
* up with echo turned off in the shell. Don't worry about * up with echo turned off in the shell. Don't worry about
@ -91,53 +115,37 @@ restart:
(void)sigaction(SIGTTIN, &sa, &savettin); (void)sigaction(SIGTTIN, &sa, &savettin);
(void)sigaction(SIGTTOU, &sa, &savettou); (void)sigaction(SIGTTOU, &sa, &savettou);
/* Turn off echo if possible. */ if (!(flags & RPP_STDIN))
if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) { (void)write(output, prompt, strlen(prompt));
memcpy(&term, &oterm, sizeof(term)); end = buf + bufsiz - 1;
if (!(flags & RPP_ECHO_ON)) p = buf;
term.c_lflag &= ~(ECHO | ECHONL); while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') {
#ifdef VSTATUS if (p < end) {
if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) if ((flags & RPP_SEVENBIT))
term.c_cc[VSTATUS] = _POSIX_VDISABLE; ch &= 0x7f;
#endif if (isalpha((unsigned char)ch)) {
(void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term); if ((flags & RPP_FORCELOWER))
} else { ch = (char)tolower((unsigned char)ch);
memset(&term, 0, sizeof(term)); if ((flags & RPP_FORCEUPPER))
term.c_lflag |= ECHO; ch = (char)toupper((unsigned char)ch);
memset(&oterm, 0, sizeof(oterm));
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;
} }
*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. */ /* Restore old terminal settings and signals. */
if (memcmp(&term, &oterm, sizeof(term)) != 0) { 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 && while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 &&
errno == EINTR) errno == EINTR && !signo[SIGTTOU])
continue; continue;
signo[SIGTTOU] = sigttou;
} }
(void)sigaction(SIGALRM, &savealrm, NULL); (void)sigaction(SIGALRM, &savealrm, NULL);
(void)sigaction(SIGHUP, &savehup, NULL); (void)sigaction(SIGHUP, &savehup, NULL);
@ -155,15 +163,19 @@ restart:
* If we were interrupted by a signal, resend it to ourselves * If we were interrupted by a signal, resend it to ourselves
* now that we have restored the signal handlers. * now that we have restored the signal handlers.
*/ */
if (signo) { for (i = 0; i < _NSIG; i++) {
kill(getpid(), signo); if (signo[i]) {
switch (signo) { kill(getpid(), i);
case SIGTSTP: switch (i) {
case SIGTTIN: case SIGTSTP:
case SIGTTOU: case SIGTTIN:
goto restart; case SIGTTOU:
need_restart = 1;
}
} }
} }
if (need_restart)
goto restart;
if (save_errno) if (save_errno)
errno = save_errno; errno = save_errno;
@ -183,5 +195,5 @@ getpass(const char *prompt)
static void handler(int s) static void handler(int s)
{ {
signo = s; signo[s] = 1;
} }