2
* Copyright (c) 1996, 1998-2005, 2007-2011
3
* Todd C. Miller <Todd.Miller@courtesan.com>
5
* Permission to use, copy, modify, and distribute this software for any
6
* purpose with or without fee is hereby granted, provided that the above
7
* copyright notice and this permission notice appear in all copies.
9
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
* Sponsored in part by the Defense Advanced Research Projects
18
* Agency (DARPA) and Air Force Research Laboratory, Air Force
19
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
28
#include <sys/types.h>
29
#include <sys/param.h>
38
#endif /* STDC_HEADERS */
40
# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
44
#endif /* HAVE_STRING_H */
47
#endif /* HAVE_STRINGS_H */
50
#endif /* HAVE_UNISTD_H */
58
static volatile sig_atomic_t signo[NSIG];
60
static void handler(int);
61
static char *getln(int, char *, size_t, int);
62
static char *sudo_askpass(const char *, const char *);
64
#ifdef _PATH_SUDO_ASKPASS
65
const char *askpass_path = _PATH_SUDO_ASKPASS;
67
const char *askpass_path;
71
* Like getpass(3) but with timeout and echo flags.
74
tgetpass(const char *prompt, int timeout, int flags)
76
sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm;
77
sigaction_t savetstp, savettin, savettou, savepipe;
79
static const char *askpass;
80
static char buf[SUDO_PASS_MAX + 1];
81
int i, input, output, save_errno, neednl = 0, need_restart;
83
(void) fflush(stdout);
85
if (askpass == NULL) {
86
askpass = getenv("SUDO_ASKPASS");
87
if (askpass == NULL || *askpass == '\0')
88
askpass = askpass_path;
91
/* If no tty present and we need to disable echo, try askpass. */
92
if (!ISSET(flags, TGP_STDIN|TGP_ECHO|TGP_ASKPASS|TGP_NOECHO_TRY) &&
94
if (askpass == NULL || getenv("DISPLAY") == NULL) {
95
warningx(_("no tty present and no askpass program specified"));
98
SET(flags, TGP_ASKPASS);
101
/* If using a helper program to get the password, run it instead. */
102
if (ISSET(flags, TGP_ASKPASS)) {
103
if (askpass == NULL || *askpass == '\0')
104
errorx(1, _("no askpass program specified, try setting SUDO_ASKPASS"));
105
return sudo_askpass(askpass, prompt);
109
for (i = 0; i < NSIG; i++)
114
/* Open /dev/tty for reading/writing if possible else use stdin/stderr. */
115
if (ISSET(flags, TGP_STDIN) ||
116
(input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
117
input = STDIN_FILENO;
118
output = STDERR_FILENO;
122
* If we are using a tty but are not the foreground pgrp this will
123
* generate SIGTTOU, so do it *before* installing the signal handlers.
125
if (!ISSET(flags, TGP_ECHO)) {
126
if (ISSET(flags, TGP_MASK))
127
neednl = term_cbreak(input);
129
neednl = term_noecho(input);
133
* Catch signals that would otherwise cause the user to end
134
* up with echo turned off in the shell.
136
zero_bytes(&sa, sizeof(sa));
137
sigemptyset(&sa.sa_mask);
138
sa.sa_flags = SA_INTERRUPT; /* don't restart system calls */
139
sa.sa_handler = handler;
140
(void) sigaction(SIGALRM, &sa, &savealrm);
141
(void) sigaction(SIGINT, &sa, &saveint);
142
(void) sigaction(SIGHUP, &sa, &savehup);
143
(void) sigaction(SIGQUIT, &sa, &savequit);
144
(void) sigaction(SIGTERM, &sa, &saveterm);
145
(void) sigaction(SIGTSTP, &sa, &savetstp);
146
(void) sigaction(SIGTTIN, &sa, &savettin);
147
(void) sigaction(SIGTTOU, &sa, &savettou);
149
/* Ignore SIGPIPE in case stdin is a pipe and TGP_STDIN is set */
150
sa.sa_handler = SIG_IGN;
151
(void) sigaction(SIGPIPE, &sa, &savepipe);
154
if (write(output, prompt, strlen(prompt)) == -1)
160
pass = getln(input, buf, sizeof(buf), ISSET(flags, TGP_MASK));
164
if (neednl || pass == NULL) {
165
if (write(output, "\n", 1) == -1)
170
/* Restore old tty settings and signals. */
171
if (!ISSET(flags, TGP_ECHO))
172
term_restore(input, 1);
173
(void) sigaction(SIGALRM, &savealrm, NULL);
174
(void) sigaction(SIGINT, &saveint, NULL);
175
(void) sigaction(SIGHUP, &savehup, NULL);
176
(void) sigaction(SIGQUIT, &savequit, NULL);
177
(void) sigaction(SIGTERM, &saveterm, NULL);
178
(void) sigaction(SIGTSTP, &savetstp, NULL);
179
(void) sigaction(SIGTTIN, &savettin, NULL);
180
(void) sigaction(SIGTTOU, &savettou, NULL);
181
(void) sigaction(SIGTTOU, &savepipe, NULL);
182
if (input != STDIN_FILENO)
186
* If we were interrupted by a signal, resend it to ourselves
187
* now that we have restored the signal handlers.
189
for (i = 0; i < NSIG; i++) {
210
* Fork a child and exec sudo-askpass to get the password from the user.
213
sudo_askpass(const char *askpass, const char *prompt)
215
static char buf[SUDO_PASS_MAX + 1], *pass;
216
sigaction_t sa, saved_sa_pipe;
221
error(1, _("unable to create pipe"));
223
if ((pid = fork()) == -1)
224
error(1, _("unable to fork"));
227
/* child, point stdout to output side of the pipe and exec askpass */
228
if (dup2(pfd[1], STDOUT_FILENO) == -1) {
232
(void) setuid(ROOT_UID);
233
if (setgid(user_details.gid)) {
234
warning(_("unable to set gid to %u"), (unsigned int)user_details.gid);
237
if (setuid(user_details.uid)) {
238
warning(_("unable to set uid to %u"), (unsigned int)user_details.uid);
241
closefrom(STDERR_FILENO + 1);
242
execl(askpass, askpass, prompt, (char *)NULL);
243
warning(_("unable to run %s"), askpass);
247
/* Ignore SIGPIPE in case child exits prematurely */
248
zero_bytes(&sa, sizeof(sa));
249
sigemptyset(&sa.sa_mask);
250
sa.sa_flags = SA_INTERRUPT;
251
sa.sa_handler = SIG_IGN;
252
(void) sigaction(SIGPIPE, &sa, &saved_sa_pipe);
254
/* Get response from child (askpass) and restore SIGPIPE handler */
255
(void) close(pfd[1]);
256
pass = getln(pfd[0], buf, sizeof(buf), 0);
257
(void) close(pfd[0]);
258
(void) sigaction(SIGPIPE, &saved_sa_pipe, NULL);
263
extern int term_erase, term_kill;
266
getln(int fd, char *buf, size_t bufsiz, int feedback)
268
size_t left = bufsiz;
275
return NULL; /* sanity */
279
nr = read(fd, &c, 1);
280
if (nr != 1 || c == '\n' || c == '\r')
283
if (c == term_kill) {
285
if (write(fd, "\b \b", 3) == -1)
291
} else if (c == term_erase) {
293
if (write(fd, "\b \b", 3) == -1)
300
if (write(fd, "*", 1) == -1)
309
if (write(fd, "\b \b", 3) == -1)
315
return nr == 1 ? buf : NULL;
330
if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) != -1)