isblank.c lbuf.c ldap.c list.c logging.c match.c mkstemp.c memrchr.c \
parse.c pwutil.c set_perms.c sigaction.c snprintf.c strcasecmp.c \
strerror.c strlcat.c strlcpy.c sudo.c sudo_noexec.c sudo_edit.c \
- sudo_nss.c testsudoers.c tgetpass.c toke.c toke.l tsgetgrpw.c utimes.c \
- visudo.c zero_bytes.c redblack.c selinux.c sesh.c $(AUTH_SRCS)
+ sudo_nss.c term.c testsudoers.c tgetpass.c toke.c toke.l tsgetgrpw.c \
+ utimes.c visudo.c zero_bytes.c redblack.c selinux.c sesh.c $(AUTH_SRCS)
AUTH_SRCS = auth/afs.c auth/aix_auth.c auth/bsdauth.c auth/dce.c auth/fwtk.c \
auth/kerb4.c auth/kerb5.c auth/pam.c auth/passwd.c auth/rfc1938.c \
SUDO_OBJS = $(COMMON_OBJS) $(AUTH_OBJS) @SUDO_OBJS@ check.o env.o \
getspwuid.o gettime.o goodpath.o fileops.o find_path.o \
interfaces.o lbuf.o logging.o parse.o pwutil.o set_perms.o \
- sudo.o sudo_edit.o sudo_nss.o tgetpass.o
+ sudo.o sudo_edit.o sudo_nss.o term.o tgetpass.o
VISUDO_OBJS = $(COMMON_OBJS) visudo.o fileops.o gettime.o goodpath.o \
find_path.o pwutil.o
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_noexec.c
sudo_nss.o: $(srcdir)/sudo_nss.c $(SUDODEP)
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_nss.c
+term.o: $(srcdir)/term.c $(SUDODEP)
+ $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/term.c
testsudoers.o: $(srcdir)/testsudoers.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(srcdir)/interfaces.h $(devdir)/gram.h
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/testsudoers.c
tgetpass.o: $(srcdir)/tgetpass.c $(SUDODEP)
=item preserve_groups
-By default B<sudo> will initialize the group vector to the list of
+By default, B<sudo> will initialize the group vector to the list of
groups the target user is in. When I<preserve_groups> is set, the
user's existing group vector is left unaltered. The real and
effective group IDs, however, are still set to match the target
user. This flag is I<off> by default.
+=item pwstars
+
+By default, B<sudo> reads the password like most other Unix programs,
+by turning off echo until the user hits the return (or enter) key.
+Some users become confused by this as it appears to them that B<sudo>
+has hung at this point. When I<pwstars> is set, B<sudo> will print
+a star for each character of the password the user enters. Note
+that this does have a security impact, as an onlooker will be able
+to determine the length of the password being entered.
+This flag is I<off> by default.
+
=item requiretty
If set, B<sudo> will only run when the user is logged in to a real
#include <sys/types.h>
#include <sys/param.h>
-#ifdef HAVE_SYS_BSDTYPES_H
-# include <sys/bsdtypes.h>
-#endif /* HAVE_SYS_BSDTYPES_H */
-#include <sys/time.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
#include <errno.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 */
#include "sudo.h"
__unused static const char rcsid[] = "$Sudo$";
#endif /* lint */
-#ifndef 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
-
-/*
- * Compat macros for non-termios systems.
- */
-#ifndef HAVE_TERMIOS_H
-# ifdef HAVE_TERMIO_H
-# undef termios
-# define termios termio
-# define tcgetattr(f, t) ioctl(f, TCGETA, t)
-# define tcsetattr(f, a, t) ioctl(f, a, t)
-# undef TCSAFLUSH
-# define TCSAFLUSH TCSETAF
-# else
-# undef termios
-# define termios sgttyb
-# define c_lflag sg_flags
-# define tcgetattr(f, t) ioctl(f, TIOCGETP, t)
-# define tcsetattr(f, a, t) ioctl(f, a, t)
-# undef TCSAFLUSH
-# define TCSAFLUSH TIOCSETP
-# endif /* HAVE_TERMIO_H */
-#endif /* HAVE_TERMIOS_H */
-
static volatile sig_atomic_t signo;
static void handler __P((int));
-static char *getln __P((int, char *, size_t));
+static char *getln __P((int, char *, size_t, int));
static char *sudo_askpass __P((const char *));
/*
{
sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm;
sigaction_t savetstp, savettin, savettou;
- struct termios term, oterm;
char *pass;
static char buf[SUDO_PASS_MAX + 1];
- int input, output, save_errno;
+ int input, output, save_errno, neednl;;
(void) fflush(stdout);
(void) sigaction(SIGTTIN, &sa, &savettin);
(void) sigaction(SIGTTOU, &sa, &savettou);
- /* Turn echo off/on as specified by flags. */
- if (tcgetattr(input, &oterm) == 0) {
- (void) memcpy(&term, &oterm, sizeof(term));
- if (!ISSET(flags, TGP_ECHO))
- CLR(term.c_lflag, ECHO|ECHONL);
-#ifdef VSTATUS
- term.c_cc[VSTATUS] = _POSIX_VDISABLE;
-#endif
- (void) tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
- } else {
- zero_bytes(&term, sizeof(term));
- zero_bytes(&oterm, sizeof(oterm));
- }
+ if (def_pwstars)
+ neednl = term_raw(input);
+ else
+ neednl = term_noecho(input);
/* No output if we are already backgrounded. */
if (signo != SIGTTOU && signo != SIGTTIN) {
if (timeout > 0)
alarm(timeout);
- pass = getln(input, buf, sizeof(buf));
+ pass = getln(input, buf, sizeof(buf), def_pwstars);
alarm(0);
save_errno = errno;
- if (!ISSET(term.c_lflag, ECHO))
+ if (neednl)
(void) write(output, "\n", 1);
}
/* Restore old tty settings and signals. */
- if (memcmp(&term, &oterm, sizeof(term)) != 0) {
- while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 &&
- errno == EINTR)
- continue;
- }
+ term_restore(input);
(void) sigaction(SIGALRM, &savealrm, NULL);
(void) sigaction(SIGINT, &saveint, NULL);
(void) sigaction(SIGHUP, &savehup, NULL);
/* Get response from child (askpass) and restore SIGPIPE handler */
(void) close(pfd[1]);
- pass = getln(pfd[0], buf, sizeof(buf));
+ pass = getln(pfd[0], buf, sizeof(buf), 0);
(void) close(pfd[0]);
(void) sigaction(SIGPIPE, &saved_sa_pipe, NULL);
return(pass);
}
+extern int term_erase, term_kill;
+
static char *
-getln(fd, buf, bufsiz)
+getln(fd, buf, bufsiz, stars)
int fd;
char *buf;
size_t bufsiz;
+ int stars;
{
+ size_t left = bufsiz;
ssize_t nr = -1;
char *cp = buf;
char c = '\0';
- if (bufsiz == 0) {
+ if (left == 0) {
errno = EINVAL;
return(NULL); /* sanity */
}
- while (--bufsiz) {
+ while (--left) {
nr = read(fd, &c, 1);
if (nr != 1 || c == '\n' || c == '\r')
break;
+ if (stars) {
+ if (c == term_kill) {
+ while (cp > buf) {
+ (void) write(fd, "\b \b", 3);
+ --cp;
+ }
+ left = bufsiz;
+ continue;
+ } else if (c == term_erase) {
+ if (cp > buf) {
+ (void) write(fd, "\b \b", 3);
+ --cp;
+ left++;
+ }
+ continue;
+ }
+ (void) write(fd, "*", 1);
+ }
*cp++ = c;
}
*cp = '\0';