Annotation of embedaddon/sudo/src/tgetpass.c, revision 1.1.1.1

1.1       misho       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: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>