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

1.1       millert     1: /*
1.7       millert     2:  * Copyright (c) 1996, 1998-2001 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.
                     33:  */
                     34:
                     35: #include "config.h"
                     36:
1.7       millert    37: #include <sys/types.h>
                     38: #include <sys/param.h>
                     39: #ifdef HAVE_SYS_BSDTYPES_H
                     40: # include <sys/bsdtypes.h>
                     41: #endif /* HAVE_SYS_BSDTYPES_H */
                     42: #ifdef HAVE_SYS_SELECT_H
                     43: # include <sys/select.h>
                     44: #endif /* HAVE_SYS_SELECT_H */
                     45: #include <sys/time.h>
1.1       millert    46: #include <stdio.h>
                     47: #ifdef STDC_HEADERS
1.7       millert    48: # include <stdlib.h>
                     49: # include <stddef.h>
                     50: #else
                     51: # ifdef HAVE_STDLIB_H
                     52: #  include <stdlib.h>
                     53: # endif
1.1       millert    54: #endif /* STDC_HEADERS */
1.7       millert    55: #ifdef HAVE_STRING_H
                     56: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
                     57: #  include <memory.h>
                     58: # endif
                     59: # include <string.h>
                     60: #else
                     61: # ifdef HAVE_STRINGS_H
                     62: #  include <strings.h>
                     63: # endif
                     64: #endif /* HAVE_STRING_H */
1.1       millert    65: #ifdef HAVE_UNISTD_H
1.7       millert    66: # include <unistd.h>
1.1       millert    67: #endif /* HAVE_UNISTD_H */
                     68: #include <pwd.h>
                     69: #include <errno.h>
                     70: #include <signal.h>
                     71: #include <fcntl.h>
                     72: #ifdef HAVE_TERMIOS_H
1.7       millert    73: # include <termios.h>
1.1       millert    74: #else
1.7       millert    75: # ifdef HAVE_TERMIO_H
                     76: #  include <termio.h>
                     77: # else
                     78: #  include <sgtty.h>
                     79: #  include <sys/ioctl.h>
                     80: # endif /* HAVE_TERMIO_H */
1.1       millert    81: #endif /* HAVE_TERMIOS_H */
                     82:
                     83: #include "sudo.h"
                     84:
1.5       millert    85: #ifndef lint
1.8     ! millert    86: static const char rcsid[] = "$Sudo: tgetpass.c,v 1.104 2002/12/13 18:20:34 millert Exp $";
1.5       millert    87: #endif /* lint */
                     88:
1.1       millert    89: #ifndef TCSASOFT
1.7       millert    90: # define TCSASOFT      0
                     91: #endif
                     92: #ifndef ECHONL
                     93: # define ECHONL        0
                     94: #endif
                     95:
                     96: #ifndef _POSIX_VDISABLE
                     97: # ifdef VDISABLE
                     98: #  define _POSIX_VDISABLE      VDISABLE
                     99: # else
                    100: #  define _POSIX_VDISABLE      0
                    101: # endif
                    102: #endif
1.1       millert   103:
1.5       millert   104: /*
                    105:  * Abstract method of getting at the term flags.
                    106:  */
                    107: #undef TERM
                    108: #undef tflags
                    109: #ifdef HAVE_TERMIOS_H
                    110: # define TERM                  termios
                    111: # define tflags                        c_lflag
                    112: # define term_getattr(f, t)    tcgetattr(f, t)
                    113: # define term_setattr(f, t)    tcsetattr(f, TCSAFLUSH|TCSASOFT, t)
                    114: #else
                    115: # ifdef HAVE_TERMIO_H
                    116: # define TERM                  termio
                    117: # define tflags                        c_lflag
                    118: # define term_getattr(f, t)    ioctl(f, TCGETA, t)
1.7       millert   119: # define term_setattr(f, t)    ioctl(f, TCSETAF, t)
1.5       millert   120: # else
                    121: #  define TERM                 sgttyb
                    122: #  define tflags               sg_flags
                    123: #  define term_getattr(f, t)   ioctl(f, TIOCGETP, t)
                    124: #  define term_setattr(f, t)   ioctl(f, TIOCSETP, t)
                    125: # endif /* HAVE_TERMIO_H */
                    126: #endif /* HAVE_TERMIOS_H */
1.1       millert   127:
1.7       millert   128: static volatile sig_atomic_t signo;
                    129:
1.1       millert   130: static char *tgetline __P((int, char *, size_t, int));
1.7       millert   131: static void handler __P((int));
1.1       millert   132:
                    133: /*
                    134:  * Like getpass(3) but with timeout and echo flags.
                    135:  */
                    136: char *
1.5       millert   137: tgetpass(prompt, timeout, flags)
1.1       millert   138:     const char *prompt;
                    139:     int timeout;
1.5       millert   140:     int flags;
1.1       millert   141: {
1.7       millert   142:     sigaction_t sa, saveint, savehup, savequit, saveterm;
                    143:     sigaction_t savetstp, savettin, savettou;
                    144:     static char buf[SUDO_PASS_MAX + 1];
                    145:     int input, output, save_errno;
1.5       millert   146:     struct TERM term, oterm;
1.7       millert   147:     char *pass;
1.1       millert   148:
1.7       millert   149: restart:
1.1       millert   150:     /* Open /dev/tty for reading/writing if possible else use stdin/stderr. */
1.5       millert   151:     if ((flags & TGP_STDIN) ||
                    152:        (input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
1.1       millert   153:        input = STDIN_FILENO;
                    154:        output = STDERR_FILENO;
                    155:     }
                    156:
1.7       millert   157:     /*
                    158:      * Catch signals that would otherwise cause the user to end
                    159:      * up with echo turned off in the shell.  Don't worry about
                    160:      * things like SIGALRM and SIGPIPE for now.
                    161:      */
                    162:     sigemptyset(&sa.sa_mask);
                    163:     sa.sa_flags = 0;           /* don't restart system calls */
                    164:     sa.sa_handler = handler;
                    165:     (void) sigaction(SIGINT, &sa, &saveint);
                    166:     (void) sigaction(SIGHUP, &sa, &savehup);
                    167:     (void) sigaction(SIGQUIT, &sa, &savequit);
                    168:     (void) sigaction(SIGTERM, &sa, &saveterm);
                    169:     (void) sigaction(SIGTSTP, &sa, &savetstp);
                    170:     (void) sigaction(SIGTTIN, &sa, &savettin);
                    171:     (void) sigaction(SIGTTOU, &sa, &savettou);
                    172:
1.5       millert   173:     /* Turn echo off/on as specified by flags.  */
1.7       millert   174:     if (term_getattr(input, &oterm) == 0) {
                    175:        (void) memcpy(&term, &oterm, sizeof(term));
                    176:        if (!(flags & TGP_ECHO))
                    177:            term.tflags &= ~(ECHO | ECHONL);
                    178: #ifdef VSTATUS
                    179:        term.c_cc[VSTATUS] = _POSIX_VDISABLE;
                    180: #endif
                    181:        (void) term_setattr(input, &term);
                    182:     } else {
                    183:        memset(&term, 0, sizeof(term));
                    184:        memset(&oterm, 0, sizeof(oterm));
                    185:     }
1.8     ! millert   186:
        !           187:     if (prompt)
        !           188:        (void) write(output, prompt, strlen(prompt));
1.1       millert   189:
1.7       millert   190:     pass = tgetline(input, buf, sizeof(buf), timeout);
                    191:     save_errno = errno;
1.1       millert   192:
1.7       millert   193:     if (!(term.tflags & ECHO))
1.1       millert   194:        (void) write(output, "\n", 1);
                    195:
1.7       millert   196:     /* Restore old tty settings and signals. */
                    197:     if (memcmp(&term, &oterm, sizeof(term)) != 0)
                    198:        (void) term_setattr(input, &oterm);
                    199:     (void) sigaction(SIGINT, &saveint, NULL);
                    200:     (void) sigaction(SIGHUP, &savehup, NULL);
                    201:     (void) sigaction(SIGQUIT, &savequit, NULL);
                    202:     (void) sigaction(SIGTERM, &saveterm, NULL);
                    203:     (void) sigaction(SIGTSTP, &savetstp, NULL);
                    204:     (void) sigaction(SIGTTIN, &savettin, NULL);
                    205:     (void) sigaction(SIGTTOU, &savettou, NULL);
1.1       millert   206:     if (input != STDIN_FILENO)
                    207:        (void) close(input);
                    208:
1.7       millert   209:     /*
                    210:      * If we were interrupted by a signal, resend it to ourselves
                    211:      * now that we have restored the signal handlers.
                    212:      */
                    213:     if (signo) {
                    214:        kill(getpid(), signo);
                    215:        switch (signo) {
                    216:            case SIGTSTP:
                    217:            case SIGTTIN:
                    218:            case SIGTTOU:
                    219:                signo = 0;
                    220:                goto restart;
                    221:        }
                    222:     }
                    223:
                    224:     errno = save_errno;
                    225:     return(pass);
1.1       millert   226: }
                    227:
                    228: /*
                    229:  * Get a line of input (optionally timing out) and place it in buf.
                    230:  */
                    231: static char *
                    232: tgetline(fd, buf, bufsiz, timeout)
                    233:     int fd;
                    234:     char *buf;
                    235:     size_t bufsiz;
                    236:     int timeout;
                    237: {
                    238:     fd_set *readfds = NULL;
                    239:     struct timeval tv;
1.7       millert   240:     size_t left;
                    241:     char *cp;
1.1       millert   242:     char c;
1.7       millert   243:     int n;
1.1       millert   244:
1.7       millert   245:     if (bufsiz == 0) {
                    246:        errno = EINVAL;
1.1       millert   247:        return(NULL);                   /* sanity */
1.7       millert   248:     }
1.1       millert   249:
1.2       millert   250:     cp = buf;
                    251:     left = bufsiz;
                    252:
1.1       millert   253:     /*
                    254:      * Timeout of <= 0 means no timeout.
                    255:      */
                    256:     if (timeout > 0) {
                    257:        /* Setup for select(2) */
                    258:        n = howmany(fd + 1, NFDBITS) * sizeof(fd_mask);
                    259:        readfds = (fd_set *) emalloc(n);
                    260:        (void) memset((VOID *)readfds, 0, n);
                    261:
                    262:        /* Set timeout for select */
                    263:        tv.tv_sec = timeout;
                    264:        tv.tv_usec = 0;
                    265:
1.2       millert   266:        while (--left) {
                    267:            FD_SET(fd, readfds);
                    268:
                    269:            /* Make sure there is something to read (or timeout) */
                    270:            while ((n = select(fd + 1, readfds, 0, 0, &tv)) == -1 &&
1.7       millert   271:                errno == EAGAIN)
1.2       millert   272:                ;
1.7       millert   273:            if (n <= 0) {
                    274:                free(readfds);
                    275:                return(NULL);           /* timeout or interrupt */
                    276:            }
1.2       millert   277:
                    278:            /* Read a character, exit loop on error, EOF or EOL */
                    279:            n = read(fd, &c, 1);
1.3       millert   280:            if (n != 1 || c == '\n' || c == '\r')
1.2       millert   281:                break;
                    282:            *cp++ = c;
                    283:        }
                    284:        free(readfds);
                    285:     } else {
                    286:        /* Keep reading until out of space, EOF, error, or newline */
1.7       millert   287:        n = -1;
1.4       millert   288:        while (--left && (n = read(fd, &c, 1)) == 1 && c != '\n' && c != '\r')
1.2       millert   289:            *cp++ = c;
1.1       millert   290:     }
                    291:     *cp = '\0';
                    292:
1.7       millert   293:     return(n == -1 ? NULL : buf);
                    294: }
                    295:
                    296: static void handler(s)
                    297:     int s;
                    298: {
                    299:     signo = s;
1.1       millert   300: }