Annotation of src/usr.bin/sudo/tgetpass.c, Revision 1.6
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)
1.6 ! millert 131: (void) write(output, prompt, strlen(prompt));
1.1 millert 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: }