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

1.1       millert     1: /*
1.3       millert     2:  * Copyright (c) 1996, 1998-2000 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:
                     37: #include <stdio.h>
                     38: #ifdef STDC_HEADERS
                     39: #include <stdlib.h>
                     40: #endif /* STDC_HEADERS */
                     41: #ifdef HAVE_UNISTD_H
                     42: #include <unistd.h>
                     43: #endif /* HAVE_UNISTD_H */
                     44: #ifdef HAVE_STRING_H
                     45: #include <string.h>
                     46: #endif /* HAVE_STRING_H */
                     47: #ifdef HAVE_STRINGS_H
                     48: #include <strings.h>
                     49: #endif /* HAVE_STRINGS_H */
                     50: #include <pwd.h>
                     51: #include <sys/param.h>
                     52: #include <sys/types.h>
                     53: #ifdef HAVE_SYS_BSDTYPES_H
                     54: #include <sys/bsdtypes.h>
                     55: #endif /* HAVE_SYS_BSDTYPES_H */
                     56: #ifdef HAVE_SYS_SELECT_H
                     57: #include <sys/select.h>
                     58: #endif /* HAVE_SYS_SELECT_H */
                     59: #include <sys/time.h>
                     60: #include <errno.h>
                     61: #include <signal.h>
                     62: #include <fcntl.h>
                     63: #ifdef HAVE_TERMIOS_H
                     64: #include <termios.h>
                     65: #else
                     66: #ifdef HAVE_TERMIO_H
                     67: #include <termio.h>
                     68: #else
                     69: #include <sgtty.h>
                     70: #include <sys/ioctl.h>
                     71: #endif /* HAVE_TERMIO_H */
                     72: #endif /* HAVE_TERMIOS_H */
                     73:
                     74: #include "sudo.h"
                     75:
1.5     ! millert    76: #ifndef lint
        !            77: static const char rcsid[] = "$Sudo: tgetpass.c,v 1.95 2000/02/27 03:48:56 millert Exp $";
        !            78: #endif /* lint */
        !            79:
1.1       millert    80: #ifndef TCSASOFT
                     81: #define TCSASOFT       0
                     82: #endif /* TCSASOFT */
                     83:
1.5     ! millert    84: /*
        !            85:  * Abstract method of getting at the term flags.
        !            86:  */
        !            87: #undef TERM
        !            88: #undef tflags
        !            89: #ifdef HAVE_TERMIOS_H
        !            90: # define TERM                  termios
        !            91: # define tflags                        c_lflag
        !            92: # define term_getattr(f, t)    tcgetattr(f, t)
        !            93: # define term_setattr(f, t)    tcsetattr(f, TCSAFLUSH|TCSASOFT, t)
        !            94: #else
        !            95: # ifdef HAVE_TERMIO_H
        !            96: # define TERM                  termio
        !            97: # define tflags                        c_lflag
        !            98: # define term_getattr(f, t)    ioctl(f, TCGETA, t)
        !            99: # define term_setattr(f, t)    ioctl(f, TCSETA, t)
        !           100: # else
        !           101: #  define TERM                 sgttyb
        !           102: #  define tflags               sg_flags
        !           103: #  define term_getattr(f, t)   ioctl(f, TIOCGETP, t)
        !           104: #  define term_setattr(f, t)   ioctl(f, TIOCSETP, t)
        !           105: # endif /* HAVE_TERMIO_H */
        !           106: #endif /* HAVE_TERMIOS_H */
1.1       millert   107:
                    108: static char *tgetline __P((int, char *, size_t, int));
                    109:
                    110: /*
                    111:  * Like getpass(3) but with timeout and echo flags.
                    112:  */
                    113: char *
1.5     ! millert   114: tgetpass(prompt, timeout, flags)
1.1       millert   115:     const char *prompt;
                    116:     int timeout;
1.5     ! millert   117:     int flags;
1.1       millert   118: {
1.5     ! millert   119:     struct TERM term, oterm;
1.1       millert   120:     int input, output;
                    121:     static char buf[SUDO_PASS_MAX + 1];
                    122:
                    123:     /* Open /dev/tty for reading/writing if possible else use stdin/stderr. */
1.5     ! millert   124:     if ((flags & TGP_STDIN) ||
        !           125:        (input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
1.1       millert   126:        input = STDIN_FILENO;
                    127:        output = STDERR_FILENO;
                    128:     }
                    129:
                    130:     if (prompt)
                    131:        (void) write(output, prompt, strlen(prompt) + 1);
                    132:
1.5     ! millert   133:     /* Turn echo off/on as specified by flags.  */
        !           134:     (void) term_getattr(input, &oterm);
        !           135:     (void) memcpy(&term, &oterm, sizeof(term));
        !           136:     if ((flags & TGP_ECHO) && !(term.tflags & ECHO))
        !           137:        term.tflags |= ECHO;
        !           138:     else if (!(flags & TGP_ECHO) && (term.tflags & ECHO))
        !           139:        term.tflags &= ~ECHO;
        !           140:     (void) term_setattr(input, &term);
1.1       millert   141:
                    142:     buf[0] = '\0';
                    143:     tgetline(input, buf, sizeof(buf), timeout);
                    144:
1.5     ! millert   145:     /* Restore old tty flags.  */
        !           146:     (void) term_setattr(input, &oterm);
1.1       millert   147:
1.5     ! millert   148:     if (!(flags & TGP_ECHO))
1.1       millert   149:        (void) write(output, "\n", 1);
                    150:
                    151:     if (input != STDIN_FILENO)
                    152:        (void) close(input);
                    153:
                    154:     return(buf);
                    155: }
                    156:
                    157: /*
                    158:  * Get a line of input (optionally timing out) and place it in buf.
                    159:  */
                    160: static char *
                    161: tgetline(fd, buf, bufsiz, timeout)
                    162:     int fd;
                    163:     char *buf;
                    164:     size_t bufsiz;
                    165:     int timeout;
                    166: {
                    167:     size_t left;
                    168:     int n;
                    169:     fd_set *readfds = NULL;
                    170:     struct timeval tv;
                    171:     char c;
                    172:     char *cp;
                    173:
                    174:     if (bufsiz == 0)
                    175:        return(NULL);                   /* sanity */
                    176:
1.2       millert   177:     cp = buf;
                    178:     left = bufsiz;
                    179:
1.1       millert   180:     /*
                    181:      * Timeout of <= 0 means no timeout.
                    182:      */
                    183:     if (timeout > 0) {
                    184:        /* Setup for select(2) */
                    185:        n = howmany(fd + 1, NFDBITS) * sizeof(fd_mask);
                    186:        readfds = (fd_set *) emalloc(n);
                    187:        (void) memset((VOID *)readfds, 0, n);
                    188:
                    189:        /* Set timeout for select */
                    190:        tv.tv_sec = timeout;
                    191:        tv.tv_usec = 0;
                    192:
1.2       millert   193:        while (--left) {
                    194:            FD_SET(fd, readfds);
                    195:
                    196:            /* Make sure there is something to read (or timeout) */
                    197:            while ((n = select(fd + 1, readfds, 0, 0, &tv)) == -1 &&
                    198:                errno == EINTR)
                    199:                ;
                    200:            if (n == 0)
                    201:                return(NULL);           /* timeout */
                    202:
                    203:            /* Read a character, exit loop on error, EOF or EOL */
                    204:            n = read(fd, &c, 1);
1.3       millert   205:            if (n != 1 || c == '\n' || c == '\r')
1.2       millert   206:                break;
                    207:            *cp++ = c;
                    208:        }
                    209:        free(readfds);
                    210:     } else {
                    211:        /* Keep reading until out of space, EOF, error, or newline */
1.4       millert   212:        while (--left && (n = read(fd, &c, 1)) == 1 && c != '\n' && c != '\r')
1.2       millert   213:            *cp++ = c;
1.1       millert   214:     }
                    215:     *cp = '\0';
                    216:
                    217:     return(cp == buf ? NULL : buf);
                    218: }