Add support for interrupting/suspending tgetpass via keyboard input.

If you suspend sudo from the password prompt and resume it will
re-prompt you.
This commit is contained in:
Todd C. Miller
2001-12-09 05:14:23 +00:00
parent 60bbfa42df
commit 6d6d4628f4

View File

@@ -78,8 +78,19 @@ static const char rcsid[] = "$Sudo$";
#endif /* lint */
#ifndef TCSASOFT
#define TCSASOFT 0
#endif /* TCSASOFT */
# define TCSASOFT 0
#endif
#ifndef ECHONL
# define ECHONL 0
#endif
#ifndef _POSIX_VDISABLE
# ifdef VDISABLE
# define _POSIX_VDISABLE VDISABLE
# else
# define _POSIX_VDISABLE 0
# endif
#endif
/*
* Abstract method of getting at the term flags.
@@ -105,7 +116,10 @@ static const char rcsid[] = "$Sudo$";
# endif /* HAVE_TERMIO_H */
#endif /* HAVE_TERMIOS_H */
static int signo; /* XXX - should be volatile sig_atomic_t */
static char *tgetline __P((int, char *, size_t, int));
static void handler __P((int));
/*
* Like getpass(3) but with timeout and echo flags.
@@ -116,10 +130,13 @@ tgetpass(prompt, timeout, flags)
int timeout;
int flags;
{
struct TERM term, oterm;
int input, output;
struct sigaction sa, saveint, savehup, savequit, saveterm, savetstp;
static char buf[SUDO_PASS_MAX + 1];
int input, output, save_errno;
struct TERM term, oterm;
char *pass;
restart:
/* Open /dev/tty for reading/writing if possible else use stdin/stderr. */
if ((flags & TGP_STDIN) ||
(input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
@@ -130,28 +147,65 @@ tgetpass(prompt, timeout, flags)
if (prompt)
(void) write(output, prompt, strlen(prompt));
/*
* Catch signals that would otherwise cause the user to end
* up with echo turned off in the shell. Don't worry about
* things like SIGALRM and SIGPIPE for now.
*/
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0; /* don't restart system calls */
sa.sa_handler = handler;
(void)sigaction(SIGINT, &sa, &saveint);
(void)sigaction(SIGHUP, &sa, &savehup);
(void)sigaction(SIGQUIT, &sa, &savequit);
(void)sigaction(SIGTERM, &sa, &saveterm);
(void)sigaction(SIGTSTP, &sa, &savetstp);
/* Turn echo off/on as specified by flags. */
(void) term_getattr(input, &oterm);
(void) memcpy(&term, &oterm, sizeof(term));
if ((flags & TGP_ECHO) && !(term.tflags & ECHO))
term.tflags |= ECHO;
else if (!(flags & TGP_ECHO) && (term.tflags & ECHO))
term.tflags &= ~ECHO;
(void) term_setattr(input, &term);
if (term_getattr(input, &oterm) == 0) {
(void) memcpy(&term, &oterm, sizeof(term));
if (!(flags & TGP_ECHO))
term.tflags &= ~(ECHO | ECHONL);
#ifdef VSTATUS
term.c_cc[VSTATUS] = _POSIX_VDISABLE;
#endif
(void) term_setattr(input, &term);
} else {
memset(&term, 0, sizeof(term));
memset(&oterm, 0, sizeof(oterm));
}
buf[0] = '\0';
tgetline(input, buf, sizeof(buf), timeout);
pass = tgetline(input, buf, sizeof(buf), timeout);
save_errno = errno;
/* Restore old tty flags. */
(void) term_setattr(input, &oterm);
if (!(flags & TGP_ECHO))
if (!(term.tflags & ECHO))
(void) write(output, "\n", 1);
/* Restore old tty settings and signals. */
if (memcmp(&term, &oterm, sizeof(term)) != 0)
(void) term_setattr(input, &oterm);
(void) sigaction(SIGINT, &saveint, NULL);
(void) sigaction(SIGHUP, &savehup, NULL);
(void) sigaction(SIGQUIT, &savequit, NULL);
(void) sigaction(SIGTERM, &saveterm, NULL);
(void) sigaction(SIGTSTP, &savetstp, NULL);
if (input != STDIN_FILENO)
(void) close(input);
return(buf);
/*
* If we were interrupted by a signal, resend it to ourselves
* now that we have restored the signal handlers.
*/
if (signo) {
kill(getpid(), signo);
if (signo == SIGTSTP) {
signo = 0;
goto restart;
}
}
errno = save_errno;
return(pass);
}
/*
@@ -164,15 +218,17 @@ tgetline(fd, buf, bufsiz, timeout)
size_t bufsiz;
int timeout;
{
size_t left;
int n;
fd_set *readfds = NULL;
struct timeval tv;
char c;
size_t left;
char *cp;
char c;
int n;
if (bufsiz == 0)
if (bufsiz == 0) {
errno = EINVAL;
return(NULL); /* sanity */
}
cp = buf;
left = bufsiz;
@@ -195,11 +251,11 @@ tgetline(fd, buf, bufsiz, timeout)
/* Make sure there is something to read (or timeout) */
while ((n = select(fd + 1, readfds, 0, 0, &tv)) == -1 &&
(errno == EINTR || errno == EAGAIN))
errno == EAGAIN)
;
if (n == 0) {
if (n <= 0) {
free(readfds);
return(NULL); /* timeout */
return(NULL); /* timeout or interrupt */
}
/* Read a character, exit loop on error, EOF or EOL */
@@ -216,5 +272,11 @@ tgetline(fd, buf, bufsiz, timeout)
}
*cp = '\0';
return(cp == buf ? NULL : buf);
return(n == -1 ? NULL : buf);
}
static void handler(s)
int s;
{
signo = s;
}