Annotation of src/usr.bin/sudo/tgetpass.c, Revision 1.12
1.1 millert 1: /*
1.11 millert 2: * Copyright (c) 1996, 1998-2005 Todd C. Miller <Todd.Miller@courtesan.com>
1.1 millert 3: *
1.10 millert 4: * Permission to use, copy, modify, and distribute this software for any
5: * purpose with or without fee is hereby granted, provided that the above
6: * copyright notice and this permission notice appear in all copies.
7: *
8: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.9 millert 15: *
16: * Sponsored in part by the Defense Advanced Research Projects
17: * Agency (DARPA) and Air Force Research Laboratory, Air Force
18: * Materiel Command, USAF, under agreement number F39502-99-1-0512.
1.1 millert 19: */
20:
1.10 millert 21: #ifdef __TANDEM
22: # include <floss.h>
23: #endif
24:
1.11 millert 25: #include <config.h>
1.1 millert 26:
1.7 millert 27: #include <sys/types.h>
28: #include <sys/param.h>
29: #ifdef HAVE_SYS_BSDTYPES_H
30: # include <sys/bsdtypes.h>
31: #endif /* HAVE_SYS_BSDTYPES_H */
32: #include <sys/time.h>
1.1 millert 33: #include <stdio.h>
34: #ifdef STDC_HEADERS
1.7 millert 35: # include <stdlib.h>
36: # include <stddef.h>
37: #else
38: # ifdef HAVE_STDLIB_H
39: # include <stdlib.h>
40: # endif
1.1 millert 41: #endif /* STDC_HEADERS */
1.7 millert 42: #ifdef HAVE_STRING_H
43: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
44: # include <memory.h>
45: # endif
46: # include <string.h>
47: #else
48: # ifdef HAVE_STRINGS_H
49: # include <strings.h>
50: # endif
51: #endif /* HAVE_STRING_H */
1.1 millert 52: #ifdef HAVE_UNISTD_H
1.7 millert 53: # include <unistd.h>
1.1 millert 54: #endif /* HAVE_UNISTD_H */
55: #include <pwd.h>
56: #include <errno.h>
57: #include <signal.h>
58: #include <fcntl.h>
59: #ifdef HAVE_TERMIOS_H
1.7 millert 60: # include <termios.h>
1.1 millert 61: #else
1.7 millert 62: # ifdef HAVE_TERMIO_H
63: # include <termio.h>
64: # else
65: # include <sgtty.h>
66: # include <sys/ioctl.h>
67: # endif /* HAVE_TERMIO_H */
1.1 millert 68: #endif /* HAVE_TERMIOS_H */
69:
70: #include "sudo.h"
71:
1.5 millert 72: #ifndef lint
1.12 ! millert 73: __unused static const char rcsid[] = "$Sudo: tgetpass.c,v 1.111.2.4 2007/10/08 16:01:10 millert Exp $";
1.5 millert 74: #endif /* lint */
75:
1.1 millert 76: #ifndef TCSASOFT
1.7 millert 77: # define TCSASOFT 0
78: #endif
79: #ifndef ECHONL
80: # define ECHONL 0
81: #endif
82:
83: #ifndef _POSIX_VDISABLE
84: # ifdef VDISABLE
85: # define _POSIX_VDISABLE VDISABLE
86: # else
87: # define _POSIX_VDISABLE 0
88: # endif
89: #endif
1.1 millert 90:
1.5 millert 91: /*
92: * Abstract method of getting at the term flags.
93: */
94: #undef TERM
95: #undef tflags
96: #ifdef HAVE_TERMIOS_H
97: # define TERM termios
98: # define tflags c_lflag
99: # define term_getattr(f, t) tcgetattr(f, t)
1.11 millert 100: # define term_setattr(f, t) tcsetattr(f, TCSADRAIN|TCSASOFT, t)
1.5 millert 101: #else
102: # ifdef HAVE_TERMIO_H
103: # define TERM termio
104: # define tflags c_lflag
105: # define term_getattr(f, t) ioctl(f, TCGETA, t)
1.7 millert 106: # define term_setattr(f, t) ioctl(f, TCSETAF, t)
1.5 millert 107: # else
108: # define TERM sgttyb
109: # define tflags sg_flags
110: # define term_getattr(f, t) ioctl(f, TIOCGETP, t)
111: # define term_setattr(f, t) ioctl(f, TIOCSETP, t)
112: # endif /* HAVE_TERMIO_H */
113: #endif /* HAVE_TERMIOS_H */
1.1 millert 114:
1.7 millert 115: static volatile sig_atomic_t signo;
116:
117: static void handler __P((int));
1.10 millert 118: static char *getln __P((int, char *, size_t));
1.1 millert 119:
120: /*
121: * Like getpass(3) but with timeout and echo flags.
122: */
123: char *
1.5 millert 124: tgetpass(prompt, timeout, flags)
1.1 millert 125: const char *prompt;
126: int timeout;
1.5 millert 127: int flags;
1.1 millert 128: {
1.10 millert 129: sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm;
1.7 millert 130: sigaction_t savetstp, savettin, savettou;
1.10 millert 131: struct TERM term, oterm;
132: char *pass;
1.7 millert 133: static char buf[SUDO_PASS_MAX + 1];
134: int input, output, save_errno;
1.1 millert 135:
1.10 millert 136: (void) fflush(stdout);
1.7 millert 137: restart:
1.12 ! millert 138: signo = 0;
! 139: pass = NULL;
! 140: save_errno = 0;
1.1 millert 141: /* Open /dev/tty for reading/writing if possible else use stdin/stderr. */
1.10 millert 142: if (ISSET(flags, TGP_STDIN) ||
1.5 millert 143: (input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
1.1 millert 144: input = STDIN_FILENO;
145: output = STDERR_FILENO;
146: }
147:
1.7 millert 148: /*
149: * Catch signals that would otherwise cause the user to end
1.10 millert 150: * up with echo turned off in the shell.
1.7 millert 151: */
152: sigemptyset(&sa.sa_mask);
1.10 millert 153: sa.sa_flags = SA_INTERRUPT; /* don't restart system calls */
1.7 millert 154: sa.sa_handler = handler;
1.10 millert 155: (void) sigaction(SIGALRM, &sa, &savealrm);
1.7 millert 156: (void) sigaction(SIGINT, &sa, &saveint);
157: (void) sigaction(SIGHUP, &sa, &savehup);
158: (void) sigaction(SIGQUIT, &sa, &savequit);
159: (void) sigaction(SIGTERM, &sa, &saveterm);
160: (void) sigaction(SIGTSTP, &sa, &savetstp);
161: (void) sigaction(SIGTTIN, &sa, &savettin);
162: (void) sigaction(SIGTTOU, &sa, &savettou);
163:
1.5 millert 164: /* Turn echo off/on as specified by flags. */
1.7 millert 165: if (term_getattr(input, &oterm) == 0) {
166: (void) memcpy(&term, &oterm, sizeof(term));
1.10 millert 167: if (!ISSET(flags, TGP_ECHO))
168: CLR(term.tflags, (ECHO | ECHONL));
1.7 millert 169: #ifdef VSTATUS
170: term.c_cc[VSTATUS] = _POSIX_VDISABLE;
171: #endif
172: (void) term_setattr(input, &term);
173: } else {
174: memset(&term, 0, sizeof(term));
175: memset(&oterm, 0, sizeof(oterm));
176: }
1.8 millert 177:
1.12 ! millert 178: /* No output if we are already backgrounded. */
! 179: if (signo != SIGTTOU && signo != SIGTTIN) {
! 180: if (prompt)
! 181: (void) write(output, prompt, strlen(prompt));
! 182:
! 183: if (timeout > 0)
! 184: alarm(timeout);
! 185: pass = getln(input, buf, sizeof(buf));
! 186: alarm(0);
! 187: save_errno = errno;
1.1 millert 188:
1.12 ! millert 189: if (!ISSET(term.tflags, ECHO))
! 190: (void) write(output, "\n", 1);
! 191: }
1.1 millert 192:
1.7 millert 193: /* Restore old tty settings and signals. */
194: if (memcmp(&term, &oterm, sizeof(term)) != 0)
195: (void) term_setattr(input, &oterm);
1.10 millert 196: (void) sigaction(SIGALRM, &savealrm, NULL);
1.7 millert 197: (void) sigaction(SIGINT, &saveint, NULL);
198: (void) sigaction(SIGHUP, &savehup, NULL);
199: (void) sigaction(SIGQUIT, &savequit, NULL);
200: (void) sigaction(SIGTERM, &saveterm, NULL);
201: (void) sigaction(SIGTSTP, &savetstp, NULL);
202: (void) sigaction(SIGTTIN, &savettin, NULL);
203: (void) sigaction(SIGTTOU, &savettou, NULL);
1.1 millert 204: if (input != STDIN_FILENO)
205: (void) close(input);
206:
1.7 millert 207: /*
208: * If we were interrupted by a signal, resend it to ourselves
209: * now that we have restored the signal handlers.
210: */
211: if (signo) {
1.10 millert 212: kill(getpid(), signo);
1.7 millert 213: switch (signo) {
214: case SIGTSTP:
215: case SIGTTIN:
216: case SIGTTOU:
217: goto restart;
218: }
219: }
220:
1.12 ! millert 221: if (save_errno)
! 222: errno = save_errno;
1.7 millert 223: return(pass);
1.1 millert 224: }
225:
226: static char *
1.10 millert 227: getln(fd, buf, bufsiz)
1.1 millert 228: int fd;
229: char *buf;
230: size_t bufsiz;
231: {
1.10 millert 232: char c, *cp;
233: ssize_t nr;
1.1 millert 234:
1.7 millert 235: if (bufsiz == 0) {
236: errno = EINVAL;
1.1 millert 237: return(NULL); /* sanity */
1.7 millert 238: }
1.1 millert 239:
1.2 millert 240: cp = buf;
1.10 millert 241: nr = -1;
242: while (--bufsiz && (nr = read(fd, &c, 1)) == 1 && c != '\n' && c != '\r')
243: *cp++ = c;
1.1 millert 244: *cp = '\0';
1.10 millert 245: return(nr == -1 ? NULL : buf);
1.7 millert 246: }
247:
1.10 millert 248: static void
249: handler(s)
1.7 millert 250: int s;
251: {
1.10 millert 252: if (s != SIGALRM)
253: signo = s;
1.1 millert 254: }