Annotation of src/usr.bin/sudo/tgetpass.c, Revision 1.15
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.15 ! millert 73: __unused static const char rcsid[] = "$Sudo: tgetpass.c,v 1.111.2.7 2008/06/21 00:27:01 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
1.13 millert 89: #endif
90:
91: /*
92: * Compat macros for non-termios systems.
93: */
94: #ifndef HAVE_TERMIOS_H
1.5 millert 95: # ifdef HAVE_TERMIO_H
1.13 millert 96: # undef termios
97: # define termios termio
98: # define tcgetattr(f, t) ioctl(f, TCGETA, t)
99: # define tcsetattr(f, a, t) ioctl(f, a, t)
100: # undef TCSAFLUSH
101: # define TCSAFLUSH TCSETAF
1.5 millert 102: # else
1.13 millert 103: # undef termios
104: # define termios sgttyb
105: # define c_lflag sg_flags
106: # define tcgetattr(f, t) ioctl(f, TIOCGETP, t)
107: # define tcsetattr(f, a, t) ioctl(f, a, t)
108: # undef TCSAFLUSH
109: # define TCSAFLUSH TIOCSETP
1.5 millert 110: # endif /* HAVE_TERMIO_H */
111: #endif /* HAVE_TERMIOS_H */
1.1 millert 112:
1.7 millert 113: static volatile sig_atomic_t signo;
114:
115: static void handler __P((int));
1.10 millert 116: static char *getln __P((int, char *, size_t));
1.1 millert 117:
118: /*
119: * Like getpass(3) but with timeout and echo flags.
120: */
121: char *
1.5 millert 122: tgetpass(prompt, timeout, flags)
1.1 millert 123: const char *prompt;
124: int timeout;
1.5 millert 125: int flags;
1.1 millert 126: {
1.10 millert 127: sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm;
1.7 millert 128: sigaction_t savetstp, savettin, savettou;
1.13 millert 129: struct termios term, oterm;
1.10 millert 130: char *pass;
1.7 millert 131: static char buf[SUDO_PASS_MAX + 1];
132: int input, output, save_errno;
1.1 millert 133:
1.10 millert 134: (void) fflush(stdout);
1.7 millert 135: restart:
1.12 millert 136: signo = 0;
137: pass = NULL;
138: save_errno = 0;
1.1 millert 139: /* Open /dev/tty for reading/writing if possible else use stdin/stderr. */
1.10 millert 140: if (ISSET(flags, TGP_STDIN) ||
1.5 millert 141: (input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
1.1 millert 142: input = STDIN_FILENO;
143: output = STDERR_FILENO;
144: }
145:
1.7 millert 146: /*
147: * Catch signals that would otherwise cause the user to end
1.10 millert 148: * up with echo turned off in the shell.
1.7 millert 149: */
150: sigemptyset(&sa.sa_mask);
1.10 millert 151: sa.sa_flags = SA_INTERRUPT; /* don't restart system calls */
1.7 millert 152: sa.sa_handler = handler;
1.10 millert 153: (void) sigaction(SIGALRM, &sa, &savealrm);
1.7 millert 154: (void) sigaction(SIGINT, &sa, &saveint);
155: (void) sigaction(SIGHUP, &sa, &savehup);
156: (void) sigaction(SIGQUIT, &sa, &savequit);
157: (void) sigaction(SIGTERM, &sa, &saveterm);
158: (void) sigaction(SIGTSTP, &sa, &savetstp);
159: (void) sigaction(SIGTTIN, &sa, &savettin);
160: (void) sigaction(SIGTTOU, &sa, &savettou);
161:
1.5 millert 162: /* Turn echo off/on as specified by flags. */
1.13 millert 163: if (tcgetattr(input, &oterm) == 0) {
1.7 millert 164: (void) memcpy(&term, &oterm, sizeof(term));
1.10 millert 165: if (!ISSET(flags, TGP_ECHO))
1.13 millert 166: CLR(term.c_lflag, ECHO|ECHONL);
1.7 millert 167: #ifdef VSTATUS
168: term.c_cc[VSTATUS] = _POSIX_VDISABLE;
169: #endif
1.13 millert 170: (void) tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
1.7 millert 171: } else {
172: memset(&term, 0, sizeof(term));
173: memset(&oterm, 0, sizeof(oterm));
174: }
1.8 millert 175:
1.12 millert 176: /* No output if we are already backgrounded. */
177: if (signo != SIGTTOU && signo != SIGTTIN) {
178: if (prompt)
179: (void) write(output, prompt, strlen(prompt));
180:
181: if (timeout > 0)
182: alarm(timeout);
183: pass = getln(input, buf, sizeof(buf));
184: alarm(0);
185: save_errno = errno;
1.1 millert 186:
1.13 millert 187: if (!ISSET(term.c_lflag, ECHO))
1.12 millert 188: (void) write(output, "\n", 1);
189: }
1.1 millert 190:
1.7 millert 191: /* Restore old tty settings and signals. */
1.13 millert 192: if (memcmp(&term, &oterm, sizeof(term)) != 0) {
1.14 millert 193: while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 &&
1.13 millert 194: errno == EINTR)
195: continue;
196: }
1.10 millert 197: (void) sigaction(SIGALRM, &savealrm, NULL);
1.7 millert 198: (void) sigaction(SIGINT, &saveint, NULL);
199: (void) sigaction(SIGHUP, &savehup, NULL);
200: (void) sigaction(SIGQUIT, &savequit, NULL);
201: (void) sigaction(SIGTERM, &saveterm, NULL);
202: (void) sigaction(SIGTSTP, &savetstp, NULL);
203: (void) sigaction(SIGTTIN, &savettin, NULL);
204: (void) sigaction(SIGTTOU, &savettou, NULL);
1.1 millert 205: if (input != STDIN_FILENO)
206: (void) close(input);
207:
1.7 millert 208: /*
209: * If we were interrupted by a signal, resend it to ourselves
210: * now that we have restored the signal handlers.
211: */
212: if (signo) {
1.10 millert 213: kill(getpid(), signo);
1.7 millert 214: switch (signo) {
215: case SIGTSTP:
216: case SIGTTIN:
217: case SIGTTOU:
218: goto restart;
219: }
220: }
221:
1.12 millert 222: if (save_errno)
223: errno = save_errno;
1.7 millert 224: return(pass);
1.1 millert 225: }
226:
227: static char *
1.10 millert 228: getln(fd, buf, bufsiz)
1.1 millert 229: int fd;
230: char *buf;
231: size_t bufsiz;
232: {
1.10 millert 233: char c, *cp;
234: ssize_t nr;
1.1 millert 235:
1.7 millert 236: if (bufsiz == 0) {
237: errno = EINVAL;
1.1 millert 238: return(NULL); /* sanity */
1.7 millert 239: }
1.1 millert 240:
1.2 millert 241: cp = buf;
1.10 millert 242: nr = -1;
243: while (--bufsiz && (nr = read(fd, &c, 1)) == 1 && c != '\n' && c != '\r')
244: *cp++ = c;
1.1 millert 245: *cp = '\0';
1.10 millert 246: return(nr == -1 ? NULL : buf);
1.7 millert 247: }
248:
1.10 millert 249: static void
250: handler(s)
1.7 millert 251: int s;
252: {
1.10 millert 253: if (s != SIGALRM)
254: signo = s;
1.1 millert 255: }