260 lines
5.9 KiB
C
260 lines
5.9 KiB
C
/*
|
|
* CU sudo version 1.3.1
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 1, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
* Please send bugs, changes, problems to sudo-bugs.cs.colorado.edu
|
|
*
|
|
*******************************************************************
|
|
*
|
|
* This module contains tgetpass(), getpass(3) with a timeout.
|
|
* It should work on any OS that supports sgtty (4BSD), termio (SYSV),
|
|
* or termios (POSIX) line disciplines.
|
|
*
|
|
* Todd C. Miller Sun Jun 5 17:22:31 MDT 1994
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "pathnames.h"
|
|
|
|
#include <stdio.h>
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif /* HAVE_UNISTD_H */
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
#include <signal.h>
|
|
#include <fcntl.h>
|
|
#ifdef HAVE_TERMIOS_H
|
|
#include <termios.h>
|
|
#else
|
|
#ifdef HAVE_TERMIO_H
|
|
#include <termio.h>
|
|
#else
|
|
#include <sgtty.h>
|
|
#include <sys/ioctl.h>
|
|
#endif /* HAVE_TERMIO_H */
|
|
#endif /* HAVE_TERMIOS_H */
|
|
|
|
#ifndef _PASSWD_LEN
|
|
#define _PASSWD_LEN 8
|
|
#endif /* _PASSWD_LEN */
|
|
|
|
/*
|
|
* Local Prototypes
|
|
*/
|
|
static int tgetc __P((FILE *, int));
|
|
|
|
|
|
/******************************************************************
|
|
*
|
|
* tgetpass()
|
|
*
|
|
* this function prints a prompt and gets a password from /dev/tty
|
|
* or stdin. Echo is turned off (if possible) during password entry
|
|
* and input will time out based on the value of timeout.
|
|
*/
|
|
|
|
char * tgetpass(prompt, timeout)
|
|
const char *prompt;
|
|
int timeout;
|
|
{
|
|
#ifdef HAVE_TERMIOS_H
|
|
struct termios term;
|
|
#else
|
|
#ifdef HAVE_TERMIO_H
|
|
struct termio term;
|
|
#else
|
|
struct sgttyb ttyb;
|
|
#endif /* HAVE_TERMIO_H */
|
|
#endif /* HAVE_TERMIOS_H */
|
|
FILE * input, * output;
|
|
static char buf[_PASSWD_LEN + 2];
|
|
#ifdef POSIX_SIGNALS
|
|
sigset_t oldmask;
|
|
sigset_t mask;
|
|
#else
|
|
int oldmask;
|
|
#endif
|
|
fd_set readfds;
|
|
struct timeval tv;
|
|
#ifdef HAVE_TERMIO_H
|
|
tcflag_t svflagval;
|
|
#else
|
|
int svflagval;
|
|
#endif
|
|
int i;
|
|
|
|
/*
|
|
* mask out SIGINT
|
|
*/
|
|
#ifdef POSIX_SIGNALS
|
|
(void) bzero((char *)(&mask), sizeof(mask));
|
|
(void) sigaddset(&mask, SIGINT);
|
|
(void) sigprocmask(SIG_BLOCK, &mask, &oldmask);
|
|
#else
|
|
oldmask = sigblock(sigmask(SIGINT));
|
|
#endif
|
|
|
|
/*
|
|
* open /dev/tty for reading/writing if possible or use
|
|
* stdin and stderr instead.
|
|
*/
|
|
input = fopen(_PATH_TTY, "r+");
|
|
if (!input) {
|
|
input = stdin;
|
|
output = stderr;
|
|
(void) fflush(output);
|
|
} else {
|
|
output = input;
|
|
}
|
|
|
|
/*
|
|
* turn off echo
|
|
*/
|
|
#ifdef HAVE_TERMIOS_H
|
|
(void) tcgetattr(fileno(input), &term);
|
|
svflagval = term.c_lflag;
|
|
term.c_lflag &= ~ECHO;
|
|
(void) tcsetattr(fileno(input), TCSAFLUSH, &term);
|
|
#else
|
|
#ifdef HAVE_TERMIO_H
|
|
(void) ioctl(fileno(input), TCGETA, &term);
|
|
svflagval = term.c_lflag;
|
|
term.c_lflag &= ~ECHO;
|
|
(void) ioctl(fileno(input), TCSETA, &term);
|
|
#else
|
|
(void) ioctl(fileno(input), TIOCGETP, &ttyb);
|
|
svflagval = ttyb.sg_flags;
|
|
ttyb.sg_flags &= ~ECHO;
|
|
(void) ioctl(fileno(input), TIOCSETP, &ttyb);
|
|
#endif /* HAVE_TERMIO_H */
|
|
#endif /* HAVE_TERMIOS_H */
|
|
|
|
/* rewind if necesary */
|
|
if (input == output) {
|
|
(void) fflush(output);
|
|
(void) rewind(output);
|
|
}
|
|
|
|
/* print the prompt */
|
|
(void) fputs(prompt, output);
|
|
|
|
/* rewind if necesary */
|
|
if (input == output) {
|
|
(void) fflush(output);
|
|
(void) rewind(output);
|
|
}
|
|
|
|
/* setup for select(2) */
|
|
FD_ZERO(&readfds);
|
|
|
|
/* get the password */
|
|
for (i=0; i <= _PASSWD_LEN; i++) {
|
|
buf[i] = tgetc(input, timeout);
|
|
if (buf[i] == EOF) {
|
|
buf[0] = '\0';
|
|
break;
|
|
}
|
|
if (buf[i] == '\n') {
|
|
buf[i] = '\0';
|
|
break;
|
|
}
|
|
}
|
|
buf[_PASSWD_LEN] = '\0';
|
|
|
|
/* rewind if necesary and print a newline */
|
|
if (input == output) {
|
|
(void) fflush(output);
|
|
(void) rewind(output);
|
|
}
|
|
|
|
/* turn on echo */
|
|
#ifdef HAVE_TERMIOS_H
|
|
term.c_lflag = svflagval;
|
|
(void) tcsetattr(fileno(input), TCSAFLUSH, &term);
|
|
#else
|
|
#ifdef HAVE_TERMIO_H
|
|
term.c_lflag = svflagval;
|
|
(void) ioctl(fileno(input), TCSETA, &term);
|
|
#else
|
|
ttyb.sg_flags = svflagval;
|
|
(void) ioctl(fileno(input), TIOCSETP, &ttyb);
|
|
#endif /* HAVE_TERMIO_H */
|
|
#endif /* HAVE_TERMIOS_H */
|
|
|
|
/* rewind if necesary */
|
|
if (input == output) {
|
|
(void) fflush(output);
|
|
(void) rewind(output);
|
|
}
|
|
#if 1
|
|
(void) write(fileno(output), "\n", 1);
|
|
#else
|
|
(void) fputc('\n', output);
|
|
#endif
|
|
|
|
/* restore old signal mask */
|
|
#ifdef POSIX_SIGNALS
|
|
(void) sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
|
#else
|
|
(void) sigsetmask(oldmask);
|
|
#endif
|
|
|
|
/* close /dev/tty if that's what we opened */
|
|
if (input != stdin)
|
|
(void) fclose(input);
|
|
|
|
if (buf[0])
|
|
return(buf);
|
|
else
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
/******************************************************************
|
|
*
|
|
* tgetc()
|
|
*
|
|
* this function returns getc(input) unless the input times out
|
|
* (based on the value of timeout).
|
|
*/
|
|
|
|
static int tgetc(stream, timeout)
|
|
FILE * stream;
|
|
int timeout;
|
|
{
|
|
fd_set readfds;
|
|
struct timeval tv;
|
|
|
|
/* setup for select(2) */
|
|
FD_ZERO(&readfds);
|
|
FD_SET(fileno(stream), &readfds);
|
|
|
|
/* set timeout for select */
|
|
tv.tv_sec = timeout;
|
|
tv.tv_usec = 0;
|
|
|
|
/* return EOF if nothing to read by timeout */
|
|
#ifdef HAVE_SYSCONF
|
|
if (select(sysconf(_SC_OPEN_MAX), &readfds, NULL, NULL, &tv) <= 0)
|
|
#else
|
|
if (select(getdtablesize(), &readfds, NULL, NULL, &tv) <= 0)
|
|
#endif /* HAVE_SYSCONF */
|
|
return(EOF);
|
|
|
|
return(getc(stream));
|
|
}
|