[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.18

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>
                     30: #ifdef HAVE_SYS_BSDTYPES_H
                     31: # include <sys/bsdtypes.h>
                     32: #endif /* HAVE_SYS_BSDTYPES_H */
                     33: #include <sys/time.h>
1.1       millert    34: #include <stdio.h>
                     35: #ifdef STDC_HEADERS
1.7       millert    36: # include <stdlib.h>
                     37: # include <stddef.h>
                     38: #else
                     39: # ifdef HAVE_STDLIB_H
                     40: #  include <stdlib.h>
                     41: # endif
1.1       millert    42: #endif /* STDC_HEADERS */
1.7       millert    43: #ifdef HAVE_STRING_H
                     44: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
                     45: #  include <memory.h>
                     46: # endif
                     47: # include <string.h>
                     48: #else
                     49: # ifdef HAVE_STRINGS_H
                     50: #  include <strings.h>
                     51: # endif
                     52: #endif /* HAVE_STRING_H */
1.1       millert    53: #ifdef HAVE_UNISTD_H
1.7       millert    54: # include <unistd.h>
1.1       millert    55: #endif /* HAVE_UNISTD_H */
                     56: #include <pwd.h>
                     57: #include <errno.h>
                     58: #include <signal.h>
                     59: #include <fcntl.h>
                     60: #ifdef HAVE_TERMIOS_H
1.7       millert    61: # include <termios.h>
1.1       millert    62: #else
1.7       millert    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 */
1.1       millert    69: #endif /* HAVE_TERMIOS_H */
                     70:
                     71: #include "sudo.h"
                     72:
1.5       millert    73: #ifndef lint
1.18    ! millert    74: __unused static const char rcsid[] = "$Sudo: tgetpass.c,v 1.126 2008/12/09 20:55:49 millert Exp $";
1.5       millert    75: #endif /* lint */
                     76:
1.1       millert    77: #ifndef TCSASOFT
1.7       millert    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
1.13      millert    90: #endif
                     91:
                     92: /*
                     93:  * Compat macros for non-termios systems.
                     94:  */
                     95: #ifndef HAVE_TERMIOS_H
1.5       millert    96: # ifdef HAVE_TERMIO_H
1.13      millert    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
1.5       millert   103: # else
1.13      millert   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
1.5       millert   111: # endif /* HAVE_TERMIO_H */
                    112: #endif /* HAVE_TERMIOS_H */
1.1       millert   113:
1.7       millert   114: static volatile sig_atomic_t signo;
                    115:
                    116: static void handler __P((int));
1.10      millert   117: static char *getln __P((int, char *, size_t));
1.18    ! millert   118: static char *sudo_askpass __P((const char *));
1.1       millert   119:
                    120: /*
                    121:  * Like getpass(3) but with timeout and echo flags.
                    122:  */
                    123: char *
1.5       millert   124: tgetpass(prompt, timeout, flags)
1.1       millert   125:     const char *prompt;
                    126:     int timeout;
1.5       millert   127:     int flags;
1.1       millert   128: {
1.10      millert   129:     sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm;
1.7       millert   130:     sigaction_t savetstp, savettin, savettou;
1.13      millert   131:     struct termios term, oterm;
1.10      millert   132:     char *pass;
1.7       millert   133:     static char buf[SUDO_PASS_MAX + 1];
                    134:     int input, output, save_errno;
1.1       millert   135:
1.10      millert   136:     (void) fflush(stdout);
1.16      millert   137:
                    138:     /* If using a helper program to get the password, run it instead. */
                    139:     if (ISSET(flags, TGP_ASKPASS) && user_askpass)
                    140:        return(sudo_askpass(prompt));
                    141:
1.7       millert   142: restart:
1.12      millert   143:     signo = 0;
                    144:     pass = NULL;
                    145:     save_errno = 0;
1.1       millert   146:     /* Open /dev/tty for reading/writing if possible else use stdin/stderr. */
1.10      millert   147:     if (ISSET(flags, TGP_STDIN) ||
1.5       millert   148:        (input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
1.1       millert   149:        input = STDIN_FILENO;
                    150:        output = STDERR_FILENO;
                    151:     }
                    152:
1.7       millert   153:     /*
                    154:      * Catch signals that would otherwise cause the user to end
1.10      millert   155:      * up with echo turned off in the shell.
1.7       millert   156:      */
1.16      millert   157:     zero_bytes(&sa, sizeof(sa));
1.7       millert   158:     sigemptyset(&sa.sa_mask);
1.10      millert   159:     sa.sa_flags = SA_INTERRUPT;        /* don't restart system calls */
1.7       millert   160:     sa.sa_handler = handler;
1.10      millert   161:     (void) sigaction(SIGALRM, &sa, &savealrm);
1.7       millert   162:     (void) sigaction(SIGINT, &sa, &saveint);
                    163:     (void) sigaction(SIGHUP, &sa, &savehup);
                    164:     (void) sigaction(SIGQUIT, &sa, &savequit);
                    165:     (void) sigaction(SIGTERM, &sa, &saveterm);
                    166:     (void) sigaction(SIGTSTP, &sa, &savetstp);
                    167:     (void) sigaction(SIGTTIN, &sa, &savettin);
                    168:     (void) sigaction(SIGTTOU, &sa, &savettou);
                    169:
1.5       millert   170:     /* Turn echo off/on as specified by flags.  */
1.13      millert   171:     if (tcgetattr(input, &oterm) == 0) {
1.7       millert   172:        (void) memcpy(&term, &oterm, sizeof(term));
1.10      millert   173:        if (!ISSET(flags, TGP_ECHO))
1.13      millert   174:            CLR(term.c_lflag, ECHO|ECHONL);
1.7       millert   175: #ifdef VSTATUS
                    176:        term.c_cc[VSTATUS] = _POSIX_VDISABLE;
                    177: #endif
1.13      millert   178:        (void) tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
1.7       millert   179:     } else {
1.16      millert   180:        zero_bytes(&term, sizeof(term));
                    181:        zero_bytes(&oterm, sizeof(oterm));
1.7       millert   182:     }
1.8       millert   183:
1.12      millert   184:     /* No output if we are already backgrounded. */
                    185:     if (signo != SIGTTOU && signo != SIGTTIN) {
                    186:        if (prompt)
                    187:            (void) write(output, prompt, strlen(prompt));
                    188:
                    189:        if (timeout > 0)
                    190:            alarm(timeout);
                    191:        pass = getln(input, buf, sizeof(buf));
                    192:        alarm(0);
                    193:        save_errno = errno;
1.1       millert   194:
1.13      millert   195:        if (!ISSET(term.c_lflag, ECHO))
1.12      millert   196:            (void) write(output, "\n", 1);
                    197:     }
1.1       millert   198:
1.7       millert   199:     /* Restore old tty settings and signals. */
1.13      millert   200:     if (memcmp(&term, &oterm, sizeof(term)) != 0) {
1.14      millert   201:        while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 &&
1.13      millert   202:            errno == EINTR)
                    203:            continue;
                    204:     }
1.10      millert   205:     (void) sigaction(SIGALRM, &savealrm, NULL);
1.7       millert   206:     (void) sigaction(SIGINT, &saveint, NULL);
                    207:     (void) sigaction(SIGHUP, &savehup, NULL);
                    208:     (void) sigaction(SIGQUIT, &savequit, NULL);
                    209:     (void) sigaction(SIGTERM, &saveterm, NULL);
                    210:     (void) sigaction(SIGTSTP, &savetstp, NULL);
                    211:     (void) sigaction(SIGTTIN, &savettin, NULL);
                    212:     (void) sigaction(SIGTTOU, &savettou, NULL);
1.1       millert   213:     if (input != STDIN_FILENO)
                    214:        (void) close(input);
                    215:
1.7       millert   216:     /*
                    217:      * If we were interrupted by a signal, resend it to ourselves
                    218:      * now that we have restored the signal handlers.
                    219:      */
                    220:     if (signo) {
1.10      millert   221:        kill(getpid(), signo);
1.7       millert   222:        switch (signo) {
                    223:            case SIGTSTP:
                    224:            case SIGTTIN:
                    225:            case SIGTTOU:
                    226:                goto restart;
                    227:        }
                    228:     }
                    229:
1.12      millert   230:     if (save_errno)
                    231:        errno = save_errno;
1.7       millert   232:     return(pass);
1.1       millert   233: }
                    234:
1.16      millert   235: /*
                    236:  * Fork a child and exec sudo-askpass to get the password from the user.
                    237:  */
                    238: static char *
                    239: sudo_askpass(prompt)
                    240:     const char *prompt;
                    241: {
                    242:     static char buf[SUDO_PASS_MAX + 1], *pass;
                    243:     sigaction_t sa, saved_sa_pipe;
                    244:     int pfd[2];
                    245:     pid_t pid;
                    246:
                    247:     if (pipe(pfd) == -1)
                    248:        error(1, "unable to create pipe");
                    249:
                    250:     if ((pid = fork()) == -1)
                    251:        error(1, "unable to fork");
                    252:
                    253:     if (pid == 0) {
                    254:        /* child, point stdout to output side of the pipe and exec askpass */
                    255:        (void) dup2(pfd[1], STDOUT_FILENO);
                    256:        set_perms(PERM_FULL_USER);
                    257:        closefrom(STDERR_FILENO + 1);
                    258:        execl(user_askpass, user_askpass, prompt, (char *)NULL);
                    259:        warning("unable to run %s", user_askpass);
                    260:        _exit(255);
                    261:     }
                    262:
                    263:     /* Ignore SIGPIPE in case child exits prematurely */
                    264:     zero_bytes(&sa, sizeof(sa));
                    265:     sigemptyset(&sa.sa_mask);
                    266:     sa.sa_flags = 0;
                    267:     sa.sa_handler = SIG_IGN;
                    268:     (void) sigaction(SIGPIPE, &sa, &saved_sa_pipe);
                    269:
                    270:     /* Get response from child (askpass) and restore SIGPIPE handler */
                    271:     (void) close(pfd[1]);
                    272:     pass = getln(pfd[0], buf, sizeof(buf));
                    273:     (void) close(pfd[0]);
                    274:     (void) sigaction(SIGPIPE, &saved_sa_pipe, NULL);
                    275:
                    276:     return(pass);
                    277: }
                    278:
1.1       millert   279: static char *
1.10      millert   280: getln(fd, buf, bufsiz)
1.1       millert   281:     int fd;
                    282:     char *buf;
                    283:     size_t bufsiz;
                    284: {
1.16      millert   285:     ssize_t nr = -1;
                    286:     char *cp = buf;
                    287:     char c = '\0';
1.1       millert   288:
1.7       millert   289:     if (bufsiz == 0) {
                    290:        errno = EINVAL;
1.1       millert   291:        return(NULL);                   /* sanity */
1.7       millert   292:     }
1.1       millert   293:
1.16      millert   294:     while (--bufsiz) {
                    295:        nr = read(fd, &c, 1);
                    296:        if (nr != 1 || c == '\n' || c == '\r')
                    297:            break;
1.10      millert   298:        *cp++ = c;
1.16      millert   299:     }
1.1       millert   300:     *cp = '\0';
1.16      millert   301:
                    302:     return(nr == 1 ? buf : NULL);
1.7       millert   303: }
                    304:
1.10      millert   305: static void
                    306: handler(s)
1.7       millert   307:     int s;
                    308: {
1.10      millert   309:     if (s != SIGALRM)
                    310:        signo = s;
1.17      millert   311: }
                    312:
                    313: int
                    314: tty_present()
                    315: {
                    316:     int fd;
                    317:
                    318:     if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) != -1)
                    319:        close(fd);
                    320:     return(fd != -1);
1.1       millert   321: }