Skip to content

Commit 38c225a

Browse files
committed
Add pwstars sudoers option that causes sudo to print a star every
time the user presses a key.
1 parent 6d88a04 commit 38c225a

File tree

6 files changed

+61
-82
lines changed

6 files changed

+61
-82
lines changed

Makefile.in

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ SRCS = aix.c alias.c alloc.c check.c closefrom.c def_data.c defaults.c env.c \
108108
isblank.c lbuf.c ldap.c list.c logging.c match.c mkstemp.c memrchr.c \
109109
parse.c pwutil.c set_perms.c sigaction.c snprintf.c strcasecmp.c \
110110
strerror.c strlcat.c strlcpy.c sudo.c sudo_noexec.c sudo_edit.c \
111-
sudo_nss.c testsudoers.c tgetpass.c toke.c toke.l tsgetgrpw.c utimes.c \
112-
visudo.c zero_bytes.c redblack.c selinux.c sesh.c $(AUTH_SRCS)
111+
sudo_nss.c term.c testsudoers.c tgetpass.c toke.c toke.l tsgetgrpw.c \
112+
utimes.c visudo.c zero_bytes.c redblack.c selinux.c sesh.c $(AUTH_SRCS)
113113

114114
AUTH_SRCS = auth/afs.c auth/aix_auth.c auth/bsdauth.c auth/dce.c auth/fwtk.c \
115115
auth/kerb4.c auth/kerb5.c auth/pam.c auth/passwd.c auth/rfc1938.c \
@@ -131,7 +131,7 @@ COMMON_OBJS = gram.o alias.o alloc.o defaults.o error.o list.o match.o \
131131
SUDO_OBJS = $(COMMON_OBJS) $(AUTH_OBJS) @SUDO_OBJS@ check.o env.o \
132132
getspwuid.o gettime.o goodpath.o fileops.o find_path.o \
133133
interfaces.o lbuf.o logging.o parse.o pwutil.o set_perms.o \
134-
sudo.o sudo_edit.o sudo_nss.o tgetpass.o
134+
sudo.o sudo_edit.o sudo_nss.o term.o tgetpass.o
135135

136136
VISUDO_OBJS = $(COMMON_OBJS) visudo.o fileops.o gettime.o goodpath.o \
137137
find_path.o pwutil.o
@@ -304,6 +304,8 @@ sudo_noexec.o: $(srcdir)/sudo_noexec.c $(srcdir)/compat.h config.h
304304
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_noexec.c
305305
sudo_nss.o: $(srcdir)/sudo_nss.c $(SUDODEP)
306306
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_nss.c
307+
term.o: $(srcdir)/term.c $(SUDODEP)
308+
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/term.c
307309
testsudoers.o: $(srcdir)/testsudoers.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(srcdir)/interfaces.h $(devdir)/gram.h
308310
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/testsudoers.c
309311
tgetpass.o: $(srcdir)/tgetpass.c $(SUDODEP)

def_data.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,10 @@ struct sudo_defs_types sudo_defs_table[] = {
302302
"visiblepw", T_FLAG,
303303
"Allow sudo to prompt for a password even if it would be visisble",
304304
NULL,
305+
}, {
306+
"pwstars", T_FLAG,
307+
"Print a stars at the password prompt when there is user input",
308+
NULL,
305309
}, {
306310
NULL, 0, NULL
307311
}

def_data.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@
138138
#define I_SUDOERS_LOCALE 68
139139
#define def_visiblepw (sudo_defs_table[69].sd_un.flag)
140140
#define I_VISIBLEPW 69
141+
#define def_pwstars (sudo_defs_table[70].sd_un.flag)
142+
#define I_PWSTARS 70
141143

142144
enum def_tupple {
143145
never,

def_data.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,3 +223,6 @@ sudoers_locale
223223
visiblepw
224224
T_FLAG
225225
"Allow sudo to prompt for a password even if it would be visisble"
226+
pwstars
227+
T_FLAG
228+
"Print a stars at the password prompt when there is user input"

sudoers.pod

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,12 +653,23 @@ will always be used. This flag is I<off> by default.
653653

654654
=item preserve_groups
655655

656-
By default B<sudo> will initialize the group vector to the list of
656+
By default, B<sudo> will initialize the group vector to the list of
657657
groups the target user is in. When I<preserve_groups> is set, the
658658
user's existing group vector is left unaltered. The real and
659659
effective group IDs, however, are still set to match the target
660660
user. This flag is I<off> by default.
661661

662+
=item pwstars
663+
664+
By default, B<sudo> reads the password like most other Unix programs,
665+
by turning off echo until the user hits the return (or enter) key.
666+
Some users become confused by this as it appears to them that B<sudo>
667+
has hung at this point. When I<pwstars> is set, B<sudo> will print
668+
a star for each character of the password the user enters. Note
669+
that this does have a security impact, as an onlooker will be able
670+
to determine the length of the password being entered.
671+
This flag is I<off> by default.
672+
662673
=item requiretty
663674

664675
If set, B<sudo> will only run when the user is logged in to a real

tgetpass.c

Lines changed: 35 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,6 @@
2727

2828
#include <sys/types.h>
2929
#include <sys/param.h>
30-
#ifdef HAVE_SYS_BSDTYPES_H
31-
# include <sys/bsdtypes.h>
32-
#endif /* HAVE_SYS_BSDTYPES_H */
33-
#include <sys/time.h>
3430
#include <stdio.h>
3531
#ifdef STDC_HEADERS
3632
# include <stdlib.h>
@@ -57,64 +53,17 @@
5753
#include <errno.h>
5854
#include <signal.h>
5955
#include <fcntl.h>
60-
#ifdef HAVE_TERMIOS_H
61-
# include <termios.h>
62-
#else
63-
# ifdef HAVE_TERMIO_H
64-
# include <termio.h>
65-
# else
66-
# include <sgtty.h>
67-
# include <sys/ioctl.h>
68-
# endif /* HAVE_TERMIO_H */
69-
#endif /* HAVE_TERMIOS_H */
7056

7157
#include "sudo.h"
7258

7359
#ifndef lint
7460
__unused static const char rcsid[] = "$Sudo$";
7561
#endif /* lint */
7662

77-
#ifndef TCSASOFT
78-
# define TCSASOFT 0
79-
#endif
80-
#ifndef ECHONL
81-
# define ECHONL 0
82-
#endif
83-
84-
#ifndef _POSIX_VDISABLE
85-
# ifdef VDISABLE
86-
# define _POSIX_VDISABLE VDISABLE
87-
# else
88-
# define _POSIX_VDISABLE 0
89-
# endif
90-
#endif
91-
92-
/*
93-
* Compat macros for non-termios systems.
94-
*/
95-
#ifndef HAVE_TERMIOS_H
96-
# ifdef HAVE_TERMIO_H
97-
# undef termios
98-
# define termios termio
99-
# define tcgetattr(f, t) ioctl(f, TCGETA, t)
100-
# define tcsetattr(f, a, t) ioctl(f, a, t)
101-
# undef TCSAFLUSH
102-
# define TCSAFLUSH TCSETAF
103-
# else
104-
# undef termios
105-
# define termios sgttyb
106-
# define c_lflag sg_flags
107-
# define tcgetattr(f, t) ioctl(f, TIOCGETP, t)
108-
# define tcsetattr(f, a, t) ioctl(f, a, t)
109-
# undef TCSAFLUSH
110-
# define TCSAFLUSH TIOCSETP
111-
# endif /* HAVE_TERMIO_H */
112-
#endif /* HAVE_TERMIOS_H */
113-
11463
static volatile sig_atomic_t signo;
11564

11665
static void handler __P((int));
117-
static char *getln __P((int, char *, size_t));
66+
static char *getln __P((int, char *, size_t, int));
11867
static char *sudo_askpass __P((const char *));
11968

12069
/*
@@ -128,10 +77,9 @@ tgetpass(prompt, timeout, flags)
12877
{
12978
sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm;
13079
sigaction_t savetstp, savettin, savettou;
131-
struct termios term, oterm;
13280
char *pass;
13381
static char buf[SUDO_PASS_MAX + 1];
134-
int input, output, save_errno;
82+
int input, output, save_errno, neednl;;
13583

13684
(void) fflush(stdout);
13785

@@ -167,19 +115,10 @@ tgetpass(prompt, timeout, flags)
167115
(void) sigaction(SIGTTIN, &sa, &savettin);
168116
(void) sigaction(SIGTTOU, &sa, &savettou);
169117

170-
/* Turn echo off/on as specified by flags. */
171-
if (tcgetattr(input, &oterm) == 0) {
172-
(void) memcpy(&term, &oterm, sizeof(term));
173-
if (!ISSET(flags, TGP_ECHO))
174-
CLR(term.c_lflag, ECHO|ECHONL);
175-
#ifdef VSTATUS
176-
term.c_cc[VSTATUS] = _POSIX_VDISABLE;
177-
#endif
178-
(void) tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
179-
} else {
180-
zero_bytes(&term, sizeof(term));
181-
zero_bytes(&oterm, sizeof(oterm));
182-
}
118+
if (def_pwstars)
119+
neednl = term_raw(input);
120+
else
121+
neednl = term_noecho(input);
183122

184123
/* No output if we are already backgrounded. */
185124
if (signo != SIGTTOU && signo != SIGTTIN) {
@@ -188,20 +127,16 @@ tgetpass(prompt, timeout, flags)
188127

189128
if (timeout > 0)
190129
alarm(timeout);
191-
pass = getln(input, buf, sizeof(buf));
130+
pass = getln(input, buf, sizeof(buf), def_pwstars);
192131
alarm(0);
193132
save_errno = errno;
194133

195-
if (!ISSET(term.c_lflag, ECHO))
134+
if (neednl)
196135
(void) write(output, "\n", 1);
197136
}
198137

199138
/* Restore old tty settings and signals. */
200-
if (memcmp(&term, &oterm, sizeof(term)) != 0) {
201-
while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 &&
202-
errno == EINTR)
203-
continue;
204-
}
139+
term_restore(input);
205140
(void) sigaction(SIGALRM, &savealrm, NULL);
206141
(void) sigaction(SIGINT, &saveint, NULL);
207142
(void) sigaction(SIGHUP, &savehup, NULL);
@@ -269,32 +204,54 @@ sudo_askpass(prompt)
269204

270205
/* Get response from child (askpass) and restore SIGPIPE handler */
271206
(void) close(pfd[1]);
272-
pass = getln(pfd[0], buf, sizeof(buf));
207+
pass = getln(pfd[0], buf, sizeof(buf), 0);
273208
(void) close(pfd[0]);
274209
(void) sigaction(SIGPIPE, &saved_sa_pipe, NULL);
275210

276211
return(pass);
277212
}
278213

214+
extern int term_erase, term_kill;
215+
279216
static char *
280-
getln(fd, buf, bufsiz)
217+
getln(fd, buf, bufsiz, stars)
281218
int fd;
282219
char *buf;
283220
size_t bufsiz;
221+
int stars;
284222
{
223+
size_t left = bufsiz;
285224
ssize_t nr = -1;
286225
char *cp = buf;
287226
char c = '\0';
288227

289-
if (bufsiz == 0) {
228+
if (left == 0) {
290229
errno = EINVAL;
291230
return(NULL); /* sanity */
292231
}
293232

294-
while (--bufsiz) {
233+
while (--left) {
295234
nr = read(fd, &c, 1);
296235
if (nr != 1 || c == '\n' || c == '\r')
297236
break;
237+
if (stars) {
238+
if (c == term_kill) {
239+
while (cp > buf) {
240+
(void) write(fd, "\b \b", 3);
241+
--cp;
242+
}
243+
left = bufsiz;
244+
continue;
245+
} else if (c == term_erase) {
246+
if (cp > buf) {
247+
(void) write(fd, "\b \b", 3);
248+
--cp;
249+
left++;
250+
}
251+
continue;
252+
}
253+
(void) write(fd, "*", 1);
254+
}
298255
*cp++ = c;
299256
}
300257
*cp = '\0';

0 commit comments

Comments
 (0)