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: }