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

1.1       millert     1: /*
1.9     ! millert     2:  * Copyright (c) 1996, 1998-2002 Todd C. Miller <Todd.Miller@courtesan.com>
1.1       millert     3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  *
                      9:  * 1. Redistributions of source code must retain the above copyright
                     10:  *    notice, this list of conditions and the following disclaimer.
                     11:  *
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * 3. The name of the author may not be used to endorse or promote products
                     17:  *    derived from this software without specific prior written permission.
                     18:  *
                     19:  * 4. Products derived from this software may not be called "Sudo" nor
                     20:  *    may "Sudo" appear in their names without specific prior written
                     21:  *    permission from the author.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
                     24:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
                     25:  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
                     26:  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
                     27:  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     28:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
                     29:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     30:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     31:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     32:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.9     ! millert    33:  *
        !            34:  * Sponsored in part by the Defense Advanced Research Projects
        !            35:  * Agency (DARPA) and Air Force Research Laboratory, Air Force
        !            36:  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
1.1       millert    37:  */
                     38:
                     39: #include "config.h"
                     40:
1.7       millert    41: #include <sys/types.h>
                     42: #include <sys/param.h>
                     43: #ifdef HAVE_SYS_BSDTYPES_H
                     44: # include <sys/bsdtypes.h>
                     45: #endif /* HAVE_SYS_BSDTYPES_H */
                     46: #ifdef HAVE_SYS_SELECT_H
                     47: # include <sys/select.h>
                     48: #endif /* HAVE_SYS_SELECT_H */
                     49: #include <sys/time.h>
1.1       millert    50: #include <stdio.h>
                     51: #ifdef STDC_HEADERS
1.7       millert    52: # include <stdlib.h>
                     53: # include <stddef.h>
                     54: #else
                     55: # ifdef HAVE_STDLIB_H
                     56: #  include <stdlib.h>
                     57: # endif
1.1       millert    58: #endif /* STDC_HEADERS */
1.7       millert    59: #ifdef HAVE_STRING_H
                     60: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
                     61: #  include <memory.h>
                     62: # endif
                     63: # include <string.h>
                     64: #else
                     65: # ifdef HAVE_STRINGS_H
                     66: #  include <strings.h>
                     67: # endif
                     68: #endif /* HAVE_STRING_H */
1.1       millert    69: #ifdef HAVE_UNISTD_H
1.7       millert    70: # include <unistd.h>
1.1       millert    71: #endif /* HAVE_UNISTD_H */
                     72: #include <pwd.h>
                     73: #include <errno.h>
                     74: #include <signal.h>
                     75: #include <fcntl.h>
                     76: #ifdef HAVE_TERMIOS_H
1.7       millert    77: # include <termios.h>
1.1       millert    78: #else
1.7       millert    79: # ifdef HAVE_TERMIO_H
                     80: #  include <termio.h>
                     81: # else
                     82: #  include <sgtty.h>
                     83: #  include <sys/ioctl.h>
                     84: # endif /* HAVE_TERMIO_H */
1.1       millert    85: #endif /* HAVE_TERMIOS_H */
                     86:
                     87: #include "sudo.h"
                     88:
1.5       millert    89: #ifndef lint
1.9     ! millert    90: static const char rcsid[] = "$Sudo: tgetpass.c,v 1.105 2003/04/16 00:42:10 millert Exp $";
1.5       millert    91: #endif /* lint */
                     92:
1.1       millert    93: #ifndef TCSASOFT
1.7       millert    94: # define TCSASOFT      0
                     95: #endif
                     96: #ifndef ECHONL
                     97: # define ECHONL        0
                     98: #endif
                     99:
                    100: #ifndef _POSIX_VDISABLE
                    101: # ifdef VDISABLE
                    102: #  define _POSIX_VDISABLE      VDISABLE
                    103: # else
                    104: #  define _POSIX_VDISABLE      0
                    105: # endif
                    106: #endif
1.1       millert   107:
1.5       millert   108: /*
                    109:  * Abstract method of getting at the term flags.
                    110:  */
                    111: #undef TERM
                    112: #undef tflags
                    113: #ifdef HAVE_TERMIOS_H
                    114: # define TERM                  termios
                    115: # define tflags                        c_lflag
                    116: # define term_getattr(f, t)    tcgetattr(f, t)
                    117: # define term_setattr(f, t)    tcsetattr(f, TCSAFLUSH|TCSASOFT, t)
                    118: #else
                    119: # ifdef HAVE_TERMIO_H
                    120: # define TERM                  termio
                    121: # define tflags                        c_lflag
                    122: # define term_getattr(f, t)    ioctl(f, TCGETA, t)
1.7       millert   123: # define term_setattr(f, t)    ioctl(f, TCSETAF, t)
1.5       millert   124: # else
                    125: #  define TERM                 sgttyb
                    126: #  define tflags               sg_flags
                    127: #  define term_getattr(f, t)   ioctl(f, TIOCGETP, t)
                    128: #  define term_setattr(f, t)   ioctl(f, TIOCSETP, t)
                    129: # endif /* HAVE_TERMIO_H */
                    130: #endif /* HAVE_TERMIOS_H */
1.1       millert   131:
1.7       millert   132: static volatile sig_atomic_t signo;
                    133:
1.1       millert   134: static char *tgetline __P((int, char *, size_t, int));
1.7       millert   135: static void handler __P((int));
1.1       millert   136:
                    137: /*
                    138:  * Like getpass(3) but with timeout and echo flags.
                    139:  */
                    140: char *
1.5       millert   141: tgetpass(prompt, timeout, flags)
1.1       millert   142:     const char *prompt;
                    143:     int timeout;
1.5       millert   144:     int flags;
1.1       millert   145: {
1.7       millert   146:     sigaction_t sa, saveint, savehup, savequit, saveterm;
                    147:     sigaction_t savetstp, savettin, savettou;
                    148:     static char buf[SUDO_PASS_MAX + 1];
                    149:     int input, output, save_errno;
1.5       millert   150:     struct TERM term, oterm;
1.7       millert   151:     char *pass;
1.1       millert   152:
1.7       millert   153: restart:
1.1       millert   154:     /* Open /dev/tty for reading/writing if possible else use stdin/stderr. */
1.5       millert   155:     if ((flags & TGP_STDIN) ||
                    156:        (input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
1.1       millert   157:        input = STDIN_FILENO;
                    158:        output = STDERR_FILENO;
                    159:     }
                    160:
1.7       millert   161:     /*
                    162:      * Catch signals that would otherwise cause the user to end
                    163:      * up with echo turned off in the shell.  Don't worry about
                    164:      * things like SIGALRM and SIGPIPE for now.
                    165:      */
                    166:     sigemptyset(&sa.sa_mask);
                    167:     sa.sa_flags = 0;           /* don't restart system calls */
                    168:     sa.sa_handler = handler;
                    169:     (void) sigaction(SIGINT, &sa, &saveint);
                    170:     (void) sigaction(SIGHUP, &sa, &savehup);
                    171:     (void) sigaction(SIGQUIT, &sa, &savequit);
                    172:     (void) sigaction(SIGTERM, &sa, &saveterm);
                    173:     (void) sigaction(SIGTSTP, &sa, &savetstp);
                    174:     (void) sigaction(SIGTTIN, &sa, &savettin);
                    175:     (void) sigaction(SIGTTOU, &sa, &savettou);
                    176:
1.5       millert   177:     /* Turn echo off/on as specified by flags.  */
1.7       millert   178:     if (term_getattr(input, &oterm) == 0) {
                    179:        (void) memcpy(&term, &oterm, sizeof(term));
                    180:        if (!(flags & TGP_ECHO))
                    181:            term.tflags &= ~(ECHO | ECHONL);
                    182: #ifdef VSTATUS
                    183:        term.c_cc[VSTATUS] = _POSIX_VDISABLE;
                    184: #endif
                    185:        (void) term_setattr(input, &term);
                    186:     } else {
                    187:        memset(&term, 0, sizeof(term));
                    188:        memset(&oterm, 0, sizeof(oterm));
                    189:     }
1.8       millert   190:
                    191:     if (prompt)
                    192:        (void) write(output, prompt, strlen(prompt));
1.1       millert   193:
1.7       millert   194:     pass = tgetline(input, buf, sizeof(buf), timeout);
                    195:     save_errno = errno;
1.1       millert   196:
1.7       millert   197:     if (!(term.tflags & ECHO))
1.1       millert   198:        (void) write(output, "\n", 1);
                    199:
1.7       millert   200:     /* Restore old tty settings and signals. */
                    201:     if (memcmp(&term, &oterm, sizeof(term)) != 0)
                    202:        (void) term_setattr(input, &oterm);
                    203:     (void) sigaction(SIGINT, &saveint, NULL);
                    204:     (void) sigaction(SIGHUP, &savehup, NULL);
                    205:     (void) sigaction(SIGQUIT, &savequit, NULL);
                    206:     (void) sigaction(SIGTERM, &saveterm, NULL);
                    207:     (void) sigaction(SIGTSTP, &savetstp, NULL);
                    208:     (void) sigaction(SIGTTIN, &savettin, NULL);
                    209:     (void) sigaction(SIGTTOU, &savettou, NULL);
1.1       millert   210:     if (input != STDIN_FILENO)
                    211:        (void) close(input);
                    212:
1.7       millert   213:     /*
                    214:      * If we were interrupted by a signal, resend it to ourselves
                    215:      * now that we have restored the signal handlers.
                    216:      */
                    217:     if (signo) {
                    218:        kill(getpid(), signo);
                    219:        switch (signo) {
                    220:            case SIGTSTP:
                    221:            case SIGTTIN:
                    222:            case SIGTTOU:
                    223:                signo = 0;
                    224:                goto restart;
                    225:        }
                    226:     }
                    227:
                    228:     errno = save_errno;
                    229:     return(pass);
1.1       millert   230: }
                    231:
                    232: /*
                    233:  * Get a line of input (optionally timing out) and place it in buf.
                    234:  */
                    235: static char *
                    236: tgetline(fd, buf, bufsiz, timeout)
                    237:     int fd;
                    238:     char *buf;
                    239:     size_t bufsiz;
                    240:     int timeout;
                    241: {
                    242:     fd_set *readfds = NULL;
                    243:     struct timeval tv;
1.7       millert   244:     size_t left;
                    245:     char *cp;
1.1       millert   246:     char c;
1.7       millert   247:     int n;
1.1       millert   248:
1.7       millert   249:     if (bufsiz == 0) {
                    250:        errno = EINVAL;
1.1       millert   251:        return(NULL);                   /* sanity */
1.7       millert   252:     }
1.1       millert   253:
1.2       millert   254:     cp = buf;
                    255:     left = bufsiz;
                    256:
1.1       millert   257:     /*
                    258:      * Timeout of <= 0 means no timeout.
                    259:      */
                    260:     if (timeout > 0) {
                    261:        /* Setup for select(2) */
                    262:        n = howmany(fd + 1, NFDBITS) * sizeof(fd_mask);
                    263:        readfds = (fd_set *) emalloc(n);
                    264:        (void) memset((VOID *)readfds, 0, n);
                    265:
                    266:        /* Set timeout for select */
                    267:        tv.tv_sec = timeout;
                    268:        tv.tv_usec = 0;
                    269:
1.2       millert   270:        while (--left) {
                    271:            FD_SET(fd, readfds);
                    272:
                    273:            /* Make sure there is something to read (or timeout) */
                    274:            while ((n = select(fd + 1, readfds, 0, 0, &tv)) == -1 &&
1.7       millert   275:                errno == EAGAIN)
1.2       millert   276:                ;
1.7       millert   277:            if (n <= 0) {
                    278:                free(readfds);
                    279:                return(NULL);           /* timeout or interrupt */
                    280:            }
1.2       millert   281:
                    282:            /* Read a character, exit loop on error, EOF or EOL */
                    283:            n = read(fd, &c, 1);
1.3       millert   284:            if (n != 1 || c == '\n' || c == '\r')
1.2       millert   285:                break;
                    286:            *cp++ = c;
                    287:        }
                    288:        free(readfds);
                    289:     } else {
                    290:        /* Keep reading until out of space, EOF, error, or newline */
1.7       millert   291:        n = -1;
1.4       millert   292:        while (--left && (n = read(fd, &c, 1)) == 1 && c != '\n' && c != '\r')
1.2       millert   293:            *cp++ = c;
1.1       millert   294:     }
                    295:     *cp = '\0';
                    296:
1.7       millert   297:     return(n == -1 ? NULL : buf);
                    298: }
                    299:
                    300: static void handler(s)
                    301:     int s;
                    302: {
                    303:     signo = s;
1.1       millert   304: }