[BACK]Return to tgetpass.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / sudo

Annotation of src/usr.bin/sudo/tgetpass.c, Revision 1.19

1.1       millert     1: /*
1.16      millert     2:  * Copyright (c) 1996, 1998-2005, 2007-2008
                      3:  *     Todd C. Miller <Todd.Miller@courtesan.com>
1.1       millert     4:  *
1.10      millert     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.
1.9       millert    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.
1.1       millert    20:  */
                     21:
1.10      millert    22: #ifdef __TANDEM
                     23: # include <floss.h>
                     24: #endif
                     25:
1.11      millert    26: #include <config.h>
1.1       millert    27:
1.7       millert    28: #include <sys/types.h>
                     29: #include <sys/param.h>
1.1       millert    30: #include <stdio.h>
                     31: #ifdef STDC_HEADERS
1.7       millert    32: # include <stdlib.h>
                     33: # include <stddef.h>
                     34: #else
                     35: # ifdef HAVE_STDLIB_H
                     36: #  include <stdlib.h>
                     37: # endif
1.1       millert    38: #endif /* STDC_HEADERS */
1.7       millert    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: #else
                     45: # ifdef HAVE_STRINGS_H
                     46: #  include <strings.h>
                     47: # endif
                     48: #endif /* HAVE_STRING_H */
1.1       millert    49: #ifdef HAVE_UNISTD_H
1.7       millert    50: # include <unistd.h>
1.1       millert    51: #endif /* HAVE_UNISTD_H */
                     52: #include <pwd.h>
                     53: #include <errno.h>
                     54: #include <signal.h>
                     55: #include <fcntl.h>
                     56:
                     57: #include "sudo.h"
                     58:
1.5       millert    59: #ifndef lint
1.19    ! millert    60: __unused static const char rcsid[] = "$Sudo: tgetpass.c,v 1.130 2009/02/15 20:53:49 millert Exp $";
1.5       millert    61: #endif /* lint */
                     62:
1.7       millert    63: static volatile sig_atomic_t signo;
                     64:
                     65: static void handler __P((int));
1.19    ! millert    66: static char *getln __P((int, char *, size_t, int));
1.18      millert    67: static char *sudo_askpass __P((const char *));
1.1       millert    68:
1.19    ! millert    69: extern int term_restore __P((int));
        !            70: extern int term_noecho __P((int));
        !            71: extern int term_raw __P((int));
        !            72:
1.1       millert    73: /*
                     74:  * Like getpass(3) but with timeout and echo flags.
                     75:  */
                     76: char *
1.5       millert    77: tgetpass(prompt, timeout, flags)
1.1       millert    78:     const char *prompt;
                     79:     int timeout;
1.5       millert    80:     int flags;
1.1       millert    81: {
1.10      millert    82:     sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm;
1.7       millert    83:     sigaction_t savetstp, savettin, savettou;
1.10      millert    84:     char *pass;
1.7       millert    85:     static char buf[SUDO_PASS_MAX + 1];
1.19    ! millert    86:     int input, output, save_errno, neednl;;
1.1       millert    87:
1.10      millert    88:     (void) fflush(stdout);
1.16      millert    89:
                     90:     /* If using a helper program to get the password, run it instead. */
                     91:     if (ISSET(flags, TGP_ASKPASS) && user_askpass)
                     92:        return(sudo_askpass(prompt));
                     93:
1.7       millert    94: restart:
1.12      millert    95:     signo = 0;
                     96:     pass = NULL;
                     97:     save_errno = 0;
1.1       millert    98:     /* Open /dev/tty for reading/writing if possible else use stdin/stderr. */
1.10      millert    99:     if (ISSET(flags, TGP_STDIN) ||
1.5       millert   100:        (input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
1.1       millert   101:        input = STDIN_FILENO;
                    102:        output = STDERR_FILENO;
                    103:     }
                    104:
1.7       millert   105:     /*
                    106:      * Catch signals that would otherwise cause the user to end
1.10      millert   107:      * up with echo turned off in the shell.
1.7       millert   108:      */
1.16      millert   109:     zero_bytes(&sa, sizeof(sa));
1.7       millert   110:     sigemptyset(&sa.sa_mask);
1.10      millert   111:     sa.sa_flags = SA_INTERRUPT;        /* don't restart system calls */
1.7       millert   112:     sa.sa_handler = handler;
1.10      millert   113:     (void) sigaction(SIGALRM, &sa, &savealrm);
1.7       millert   114:     (void) sigaction(SIGINT, &sa, &saveint);
                    115:     (void) sigaction(SIGHUP, &sa, &savehup);
                    116:     (void) sigaction(SIGQUIT, &sa, &savequit);
                    117:     (void) sigaction(SIGTERM, &sa, &saveterm);
                    118:     (void) sigaction(SIGTSTP, &sa, &savetstp);
                    119:     (void) sigaction(SIGTTIN, &sa, &savettin);
                    120:     (void) sigaction(SIGTTOU, &sa, &savettou);
                    121:
1.19    ! millert   122:     if (def_pwfeedback)
        !           123:        neednl = term_raw(input);
        !           124:     else
        !           125:        neednl = term_noecho(input);
1.8       millert   126:
1.12      millert   127:     /* No output if we are already backgrounded. */
                    128:     if (signo != SIGTTOU && signo != SIGTTIN) {
                    129:        if (prompt)
                    130:            (void) write(output, prompt, strlen(prompt));
                    131:
                    132:        if (timeout > 0)
                    133:            alarm(timeout);
1.19    ! millert   134:        pass = getln(input, buf, sizeof(buf), def_pwfeedback);
1.12      millert   135:        alarm(0);
                    136:        save_errno = errno;
1.1       millert   137:
1.19    ! millert   138:        if (neednl)
1.12      millert   139:            (void) write(output, "\n", 1);
                    140:     }
1.1       millert   141:
1.7       millert   142:     /* Restore old tty settings and signals. */
1.19    ! millert   143:     term_restore(input);
1.10      millert   144:     (void) sigaction(SIGALRM, &savealrm, NULL);
1.7       millert   145:     (void) sigaction(SIGINT, &saveint, NULL);
                    146:     (void) sigaction(SIGHUP, &savehup, NULL);
                    147:     (void) sigaction(SIGQUIT, &savequit, NULL);
                    148:     (void) sigaction(SIGTERM, &saveterm, NULL);
                    149:     (void) sigaction(SIGTSTP, &savetstp, NULL);
                    150:     (void) sigaction(SIGTTIN, &savettin, NULL);
                    151:     (void) sigaction(SIGTTOU, &savettou, NULL);
1.1       millert   152:     if (input != STDIN_FILENO)
                    153:        (void) close(input);
                    154:
1.7       millert   155:     /*
                    156:      * If we were interrupted by a signal, resend it to ourselves
                    157:      * now that we have restored the signal handlers.
                    158:      */
                    159:     if (signo) {
1.10      millert   160:        kill(getpid(), signo);
1.7       millert   161:        switch (signo) {
                    162:            case SIGTSTP:
                    163:            case SIGTTIN:
                    164:            case SIGTTOU:
                    165:                goto restart;
                    166:        }
                    167:     }
                    168:
1.12      millert   169:     if (save_errno)
                    170:        errno = save_errno;
1.7       millert   171:     return(pass);
1.1       millert   172: }
                    173:
1.16      millert   174: /*
                    175:  * Fork a child and exec sudo-askpass to get the password from the user.
                    176:  */
                    177: static char *
                    178: sudo_askpass(prompt)
                    179:     const char *prompt;
                    180: {
                    181:     static char buf[SUDO_PASS_MAX + 1], *pass;
                    182:     sigaction_t sa, saved_sa_pipe;
                    183:     int pfd[2];
                    184:     pid_t pid;
                    185:
                    186:     if (pipe(pfd) == -1)
                    187:        error(1, "unable to create pipe");
                    188:
                    189:     if ((pid = fork()) == -1)
                    190:        error(1, "unable to fork");
                    191:
                    192:     if (pid == 0) {
                    193:        /* child, point stdout to output side of the pipe and exec askpass */
                    194:        (void) dup2(pfd[1], STDOUT_FILENO);
                    195:        set_perms(PERM_FULL_USER);
                    196:        closefrom(STDERR_FILENO + 1);
                    197:        execl(user_askpass, user_askpass, prompt, (char *)NULL);
                    198:        warning("unable to run %s", user_askpass);
                    199:        _exit(255);
                    200:     }
                    201:
                    202:     /* Ignore SIGPIPE in case child exits prematurely */
                    203:     zero_bytes(&sa, sizeof(sa));
                    204:     sigemptyset(&sa.sa_mask);
                    205:     sa.sa_flags = 0;
                    206:     sa.sa_handler = SIG_IGN;
                    207:     (void) sigaction(SIGPIPE, &sa, &saved_sa_pipe);
                    208:
                    209:     /* Get response from child (askpass) and restore SIGPIPE handler */
                    210:     (void) close(pfd[1]);
1.19    ! millert   211:     pass = getln(pfd[0], buf, sizeof(buf), 0);
1.16      millert   212:     (void) close(pfd[0]);
                    213:     (void) sigaction(SIGPIPE, &saved_sa_pipe, NULL);
                    214:
                    215:     return(pass);
                    216: }
                    217:
1.19    ! millert   218: extern int term_erase, term_kill;
        !           219:
1.1       millert   220: static char *
1.19    ! millert   221: getln(fd, buf, bufsiz, feedback)
1.1       millert   222:     int fd;
                    223:     char *buf;
                    224:     size_t bufsiz;
1.19    ! millert   225:     int feedback;
1.1       millert   226: {
1.19    ! millert   227:     size_t left = bufsiz;
1.16      millert   228:     ssize_t nr = -1;
                    229:     char *cp = buf;
                    230:     char c = '\0';
1.1       millert   231:
1.19    ! millert   232:     if (left == 0) {
1.7       millert   233:        errno = EINVAL;
1.1       millert   234:        return(NULL);                   /* sanity */
1.7       millert   235:     }
1.1       millert   236:
1.19    ! millert   237:     while (--left) {
1.16      millert   238:        nr = read(fd, &c, 1);
                    239:        if (nr != 1 || c == '\n' || c == '\r')
                    240:            break;
1.19    ! millert   241:        if (feedback) {
        !           242:            if (c == term_kill) {
        !           243:                while (cp > buf) {
        !           244:                    (void) write(fd, "\b \b", 3);
        !           245:                    --cp;
        !           246:                }
        !           247:                left = bufsiz;
        !           248:                continue;
        !           249:            } else if (c == term_erase) {
        !           250:                if (cp > buf) {
        !           251:                    (void) write(fd, "\b \b", 3);
        !           252:                    --cp;
        !           253:                    left++;
        !           254:                }
        !           255:                continue;
        !           256:            }
        !           257:            (void) write(fd, "*", 1);
        !           258:        }
1.10      millert   259:        *cp++ = c;
1.16      millert   260:     }
1.1       millert   261:     *cp = '\0';
1.19    ! millert   262:     if (feedback) {
        !           263:        /* erase stars */
        !           264:        while (cp > buf) {
        !           265:            (void) write(fd, "\b \b", 3);
        !           266:            --cp;
        !           267:        }
        !           268:     }
1.16      millert   269:
                    270:     return(nr == 1 ? buf : NULL);
1.7       millert   271: }
                    272:
1.10      millert   273: static void
                    274: handler(s)
1.7       millert   275:     int s;
                    276: {
1.10      millert   277:     if (s != SIGALRM)
                    278:        signo = s;
1.17      millert   279: }
                    280:
                    281: int
                    282: tty_present()
                    283: {
                    284:     int fd;
                    285:
                    286:     if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) != -1)
                    287:        close(fd);
                    288:     return(fd != -1);
1.1       millert   289: }