~ubuntu-branches/ubuntu/quantal/sudo/quantal

« back to all changes in this revision

Viewing changes to src/tgetpass.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2011-11-20 12:07:45 UTC
  • mfrom: (1.3.17 sid)
  • Revision ID: package-import@ubuntu.com-20111120120745-o3qpklobmygytndc
Tags: 1.8.3p1-1ubuntu1
* Merge from debian/testing, remaining changes:
  - debian/patches/keep_home_by_default.patch:
    + Set HOME in initial_keepenv_table. (rebased for 1.8.3p1)
  - debian/patches/enable_badpass.patch: turn on "mail_badpass" by default:
    + attempting sudo without knowing a login password is as bad as not
      being listed in the sudoers file, especially if getting the password
      wrong means doing the access-check-email-notification never happens
      (rebased for 1.8.3p1)
  - debian/rules:
    + compile with --without-lecture --with-tty-tickets (Ubuntu specific)
    + install man/man8/sudo_root.8 (Ubuntu specific)
    + install apport hooks
    + The ubuntu-sudo-as-admin-successful.patch was taken upstream by
      Debian however it requires a --enable-admin-flag configure flag to
      actually enable it.
  - debian/sudoers: 
    + grant admin group sudo access
  - debian/sudo-ldap.dirs, debian/sudo.dirs: 
    + add usr/share/apport/package-hooks
  - debian/sudo.preinst:
    + avoid conffile prompt by checking for known default /etc/sudoers
      and if found installing the correct default /etc/sudoers file

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 1996, 1998-2005, 2007-2011
 
3
 *      Todd C. Miller <Todd.Miller@courtesan.com>
 
4
 *
 
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.
 
8
 *
 
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.
 
16
 *
 
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.
 
20
 */
 
21
 
 
22
#ifdef __TANDEM
 
23
# include <floss.h>
 
24
#endif
 
25
 
 
26
#include <config.h>
 
27
 
 
28
#include <sys/types.h>
 
29
#include <sys/param.h>
 
30
#include <stdio.h>
 
31
#ifdef STDC_HEADERS
 
32
# include <stdlib.h>
 
33
# include <stddef.h>
 
34
#else
 
35
# ifdef HAVE_STDLIB_H
 
36
#  include <stdlib.h>
 
37
# endif
 
38
#endif /* STDC_HEADERS */
 
39
#ifdef HAVE_STRING_H
 
40
# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
 
41
#  include <memory.h>
 
42
# endif
 
43
# include <string.h>
 
44
#endif /* HAVE_STRING_H */
 
45
#ifdef HAVE_STRINGS_H
 
46
# include <strings.h>
 
47
#endif /* HAVE_STRINGS_H */
 
48
#ifdef HAVE_UNISTD_H
 
49
# include <unistd.h>
 
50
#endif /* HAVE_UNISTD_H */
 
51
#include <pwd.h>
 
52
#include <errno.h>
 
53
#include <signal.h>
 
54
#include <fcntl.h>
 
55
 
 
56
#include "sudo.h"
 
57
 
 
58
static volatile sig_atomic_t signo[NSIG];
 
59
 
 
60
static void handler(int);
 
61
static char *getln(int, char *, size_t, int);
 
62
static char *sudo_askpass(const char *, const char *);
 
63
 
 
64
#ifdef _PATH_SUDO_ASKPASS
 
65
const char *askpass_path = _PATH_SUDO_ASKPASS;
 
66
#else
 
67
const char *askpass_path;
 
68
#endif
 
69
 
 
70
/*
 
71
 * Like getpass(3) but with timeout and echo flags.
 
72
 */
 
73
char *
 
74
tgetpass(const char *prompt, int timeout, int flags)
 
75
{
 
76
    sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm;
 
77
    sigaction_t savetstp, savettin, savettou, savepipe;
 
78
    char *pass;
 
79
    static const char *askpass;
 
80
    static char buf[SUDO_PASS_MAX + 1];
 
81
    int i, input, output, save_errno, neednl = 0, need_restart;
 
82
 
 
83
    (void) fflush(stdout);
 
84
 
 
85
    if (askpass == NULL) {
 
86
        askpass = getenv("SUDO_ASKPASS");
 
87
        if (askpass == NULL || *askpass == '\0')
 
88
            askpass = askpass_path;
 
89
    }
 
90
 
 
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) &&
 
93
        !tty_present()) {
 
94
        if (askpass == NULL || getenv("DISPLAY") == NULL) {
 
95
            warningx(_("no tty present and no askpass program specified"));
 
96
            return NULL;
 
97
        }
 
98
        SET(flags, TGP_ASKPASS);
 
99
    }
 
100
 
 
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);
 
106
    }
 
107
 
 
108
restart:
 
109
    for (i = 0; i < NSIG; i++)
 
110
        signo[i] = 0;
 
111
    pass = NULL;
 
112
    save_errno = 0;
 
113
    need_restart = 0;
 
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;
 
119
    }
 
120
 
 
121
    /*
 
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.
 
124
     */
 
125
    if (!ISSET(flags, TGP_ECHO)) {
 
126
        if (ISSET(flags, TGP_MASK))
 
127
            neednl = term_cbreak(input);
 
128
        else
 
129
            neednl = term_noecho(input);
 
130
    }
 
131
 
 
132
    /*
 
133
     * Catch signals that would otherwise cause the user to end
 
134
     * up with echo turned off in the shell.
 
135
     */
 
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);
 
148
 
 
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);
 
152
 
 
153
    if (prompt) {
 
154
        if (write(output, prompt, strlen(prompt)) == -1)
 
155
            goto restore;
 
156
    }
 
157
 
 
158
    if (timeout > 0)
 
159
        alarm(timeout);
 
160
    pass = getln(input, buf, sizeof(buf), ISSET(flags, TGP_MASK));
 
161
    alarm(0);
 
162
    save_errno = errno;
 
163
 
 
164
    if (neednl || pass == NULL) {
 
165
        if (write(output, "\n", 1) == -1)
 
166
            goto restore;
 
167
    }
 
168
 
 
169
restore:
 
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)
 
183
        (void) close(input);
 
184
 
 
185
    /*
 
186
     * If we were interrupted by a signal, resend it to ourselves
 
187
     * now that we have restored the signal handlers.
 
188
     */
 
189
    for (i = 0; i < NSIG; i++) {
 
190
        if (signo[i]) {
 
191
            kill(getpid(), i);
 
192
            switch (i) {
 
193
                case SIGTSTP:
 
194
                case SIGTTIN:
 
195
                case SIGTTOU:
 
196
                    need_restart = 1;
 
197
                    break;
 
198
            }
 
199
        }
 
200
    }
 
201
    if (need_restart)
 
202
        goto restart;
 
203
 
 
204
    if (save_errno)
 
205
        errno = save_errno;
 
206
    return pass;
 
207
}
 
208
 
 
209
/*
 
210
 * Fork a child and exec sudo-askpass to get the password from the user.
 
211
 */
 
212
static char *
 
213
sudo_askpass(const char *askpass, const char *prompt)
 
214
{
 
215
    static char buf[SUDO_PASS_MAX + 1], *pass;
 
216
    sigaction_t sa, saved_sa_pipe;
 
217
    int pfd[2];
 
218
    pid_t pid;
 
219
 
 
220
    if (pipe(pfd) == -1)
 
221
        error(1, _("unable to create pipe"));
 
222
 
 
223
    if ((pid = fork()) == -1)
 
224
        error(1, _("unable to fork"));
 
225
 
 
226
    if (pid == 0) {
 
227
        /* child, point stdout to output side of the pipe and exec askpass */
 
228
        if (dup2(pfd[1], STDOUT_FILENO) == -1) {
 
229
            warning("dup2");
 
230
            _exit(255);
 
231
        }
 
232
        (void) setuid(ROOT_UID);
 
233
        if (setgid(user_details.gid)) {
 
234
            warning(_("unable to set gid to %u"), (unsigned int)user_details.gid);
 
235
            _exit(255);
 
236
        }
 
237
        if (setuid(user_details.uid)) {
 
238
            warning(_("unable to set uid to %u"), (unsigned int)user_details.uid);
 
239
            _exit(255);
 
240
        }
 
241
        closefrom(STDERR_FILENO + 1);
 
242
        execl(askpass, askpass, prompt, (char *)NULL);
 
243
        warning(_("unable to run %s"), askpass);
 
244
        _exit(255);
 
245
    }
 
246
 
 
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);
 
253
 
 
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);
 
259
 
 
260
    return pass;
 
261
}
 
262
 
 
263
extern int term_erase, term_kill;
 
264
 
 
265
static char *
 
266
getln(int fd, char *buf, size_t bufsiz, int feedback)
 
267
{
 
268
    size_t left = bufsiz;
 
269
    ssize_t nr = -1;
 
270
    char *cp = buf;
 
271
    char c = '\0';
 
272
 
 
273
    if (left == 0) {
 
274
        errno = EINVAL;
 
275
        return NULL;                    /* sanity */
 
276
    }
 
277
 
 
278
    while (--left) {
 
279
        nr = read(fd, &c, 1);
 
280
        if (nr != 1 || c == '\n' || c == '\r')
 
281
            break;
 
282
        if (feedback) {
 
283
            if (c == term_kill) {
 
284
                while (cp > buf) {
 
285
                    if (write(fd, "\b \b", 3) == -1)
 
286
                        break;
 
287
                    --cp;
 
288
                }
 
289
                left = bufsiz;
 
290
                continue;
 
291
            } else if (c == term_erase) {
 
292
                if (cp > buf) {
 
293
                    if (write(fd, "\b \b", 3) == -1)
 
294
                        break;
 
295
                    --cp;
 
296
                    left++;
 
297
                }
 
298
                continue;
 
299
            }
 
300
            if (write(fd, "*", 1) == -1)
 
301
                /* shut up glibc */;
 
302
        }
 
303
        *cp++ = c;
 
304
    }
 
305
    *cp = '\0';
 
306
    if (feedback) {
 
307
        /* erase stars */
 
308
        while (cp > buf) {
 
309
            if (write(fd, "\b \b", 3) == -1)
 
310
                break;
 
311
            --cp;
 
312
        }
 
313
    }
 
314
 
 
315
    return nr == 1 ? buf : NULL;
 
316
}
 
317
 
 
318
static void
 
319
handler(int s)
 
320
{
 
321
    if (s != SIGALRM)
 
322
        signo[s] = 1;
 
323
}
 
324
 
 
325
int
 
326
tty_present(void)
 
327
{
 
328
    int fd;
 
329
 
 
330
    if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) != -1)
 
331
        close(fd);
 
332
    return fd != -1;
 
333
}