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 */ #endif /* lint */
#ifndef TCSASOFT #ifndef TCSASOFT
#define TCSASOFT 0 # define TCSASOFT 0
#endif /* TCSASOFT */ #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. * Abstract method of getting at the term flags.
@@ -105,7 +116,10 @@ static const char rcsid[] = "$Sudo$";
# endif /* HAVE_TERMIO_H */ # endif /* HAVE_TERMIO_H */
#endif /* HAVE_TERMIOS_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 char *tgetline __P((int, char *, size_t, int));
static void handler __P((int));
/* /*
* Like getpass(3) but with timeout and echo flags. * Like getpass(3) but with timeout and echo flags.
@@ -116,10 +130,13 @@ tgetpass(prompt, timeout, flags)
int timeout; int timeout;
int flags; int flags;
{ {
struct TERM term, oterm; struct sigaction sa, saveint, savehup, savequit, saveterm, savetstp;
int input, output;
static char buf[SUDO_PASS_MAX + 1]; 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. */ /* Open /dev/tty for reading/writing if possible else use stdin/stderr. */
if ((flags & TGP_STDIN) || if ((flags & TGP_STDIN) ||
(input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) { (input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
@@ -130,28 +147,65 @@ tgetpass(prompt, timeout, flags)
if (prompt) if (prompt)
(void) write(output, prompt, strlen(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. */ /* Turn echo off/on as specified by flags. */
(void) term_getattr(input, &oterm); if (term_getattr(input, &oterm) == 0) {
(void) memcpy(&term, &oterm, sizeof(term)); (void) memcpy(&term, &oterm, sizeof(term));
if ((flags & TGP_ECHO) && !(term.tflags & ECHO)) if (!(flags & TGP_ECHO))
term.tflags |= ECHO; term.tflags &= ~(ECHO | ECHONL);
else if (!(flags & TGP_ECHO) && (term.tflags & ECHO)) #ifdef VSTATUS
term.tflags &= ~ECHO; term.c_cc[VSTATUS] = _POSIX_VDISABLE;
(void) term_setattr(input, &term); #endif
(void) term_setattr(input, &term);
} else {
memset(&term, 0, sizeof(term));
memset(&oterm, 0, sizeof(oterm));
}
buf[0] = '\0'; pass = tgetline(input, buf, sizeof(buf), timeout);
tgetline(input, buf, sizeof(buf), timeout); save_errno = errno;
/* Restore old tty flags. */ if (!(term.tflags & ECHO))
(void) term_setattr(input, &oterm);
if (!(flags & TGP_ECHO))
(void) write(output, "\n", 1); (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) if (input != STDIN_FILENO)
(void) close(input); (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; size_t bufsiz;
int timeout; int timeout;
{ {
size_t left;
int n;
fd_set *readfds = NULL; fd_set *readfds = NULL;
struct timeval tv; struct timeval tv;
char c; size_t left;
char *cp; char *cp;
char c;
int n;
if (bufsiz == 0) if (bufsiz == 0) {
errno = EINVAL;
return(NULL); /* sanity */ return(NULL); /* sanity */
}
cp = buf; cp = buf;
left = bufsiz; left = bufsiz;
@@ -195,11 +251,11 @@ tgetline(fd, buf, bufsiz, timeout)
/* Make sure there is something to read (or timeout) */ /* Make sure there is something to read (or timeout) */
while ((n = select(fd + 1, readfds, 0, 0, &tv)) == -1 && while ((n = select(fd + 1, readfds, 0, 0, &tv)) == -1 &&
(errno == EINTR || errno == EAGAIN)) errno == EAGAIN)
; ;
if (n == 0) { if (n <= 0) {
free(readfds); free(readfds);
return(NULL); /* timeout */ return(NULL); /* timeout or interrupt */
} }
/* Read a character, exit loop on error, EOF or EOL */ /* Read a character, exit loop on error, EOF or EOL */
@@ -216,5 +272,11 @@ tgetline(fd, buf, bufsiz, timeout)
} }
*cp = '\0'; *cp = '\0';
return(cp == buf ? NULL : buf); return(n == -1 ? NULL : buf);
}
static void handler(s)
int s;
{
signo = s;
} }