Annotation of src/usr.bin/sudo/tgetpass.c, Revision 1.21
1.1 millert 1: /*
1.20 millert 2: * Copyright (c) 1996, 1998-2005, 2007-2009
1.16 millert 3: * Todd C. Miller <Todd.Miller@courtesan.com>
1.1 millert 4: *
1.10 millert 5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.9 millert 16: *
17: * Sponsored in part by the Defense Advanced Research Projects
18: * Agency (DARPA) and Air Force Research Laboratory, Air Force
19: * Materiel Command, USAF, under agreement number F39502-99-1-0512.
1.1 millert 20: */
21:
1.10 millert 22: #ifdef __TANDEM
23: # include <floss.h>
24: #endif
25:
1.11 millert 26: #include <config.h>
1.1 millert 27:
1.7 millert 28: #include <sys/types.h>
29: #include <sys/param.h>
1.1 millert 30: #include <stdio.h>
31: #ifdef STDC_HEADERS
1.7 millert 32: # include <stdlib.h>
33: # include <stddef.h>
34: #else
35: # ifdef HAVE_STDLIB_H
36: # include <stdlib.h>
37: # endif
1.1 millert 38: #endif /* STDC_HEADERS */
1.7 millert 39: #ifdef HAVE_STRING_H
40: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
41: # include <memory.h>
42: # endif
43: # include <string.h>
44: #else
45: # ifdef HAVE_STRINGS_H
46: # include <strings.h>
47: # endif
48: #endif /* HAVE_STRING_H */
1.1 millert 49: #ifdef HAVE_UNISTD_H
1.7 millert 50: # include <unistd.h>
1.1 millert 51: #endif /* HAVE_UNISTD_H */
52: #include <pwd.h>
53: #include <errno.h>
54: #include <signal.h>
55: #include <fcntl.h>
56:
57: #include "sudo.h"
58:
1.7 millert 59: static volatile sig_atomic_t signo;
60:
61: static void handler __P((int));
1.19 millert 62: static char *getln __P((int, char *, size_t, int));
1.18 millert 63: static char *sudo_askpass __P((const char *));
1.1 millert 64:
1.19 millert 65: extern int term_restore __P((int));
66: extern int term_noecho __P((int));
67: extern int term_raw __P((int));
68:
1.1 millert 69: /*
70: * Like getpass(3) but with timeout and echo flags.
71: */
72: char *
1.5 millert 73: tgetpass(prompt, timeout, flags)
1.1 millert 74: const char *prompt;
75: int timeout;
1.5 millert 76: int flags;
1.1 millert 77: {
1.10 millert 78: sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm;
1.7 millert 79: sigaction_t savetstp, savettin, savettou;
1.10 millert 80: char *pass;
1.7 millert 81: static char buf[SUDO_PASS_MAX + 1];
1.19 millert 82: int input, output, save_errno, neednl;;
1.1 millert 83:
1.10 millert 84: (void) fflush(stdout);
1.16 millert 85:
86: /* If using a helper program to get the password, run it instead. */
87: if (ISSET(flags, TGP_ASKPASS) && user_askpass)
88: return(sudo_askpass(prompt));
89:
1.7 millert 90: restart:
1.12 millert 91: signo = 0;
92: pass = NULL;
93: save_errno = 0;
1.1 millert 94: /* Open /dev/tty for reading/writing if possible else use stdin/stderr. */
1.10 millert 95: if (ISSET(flags, TGP_STDIN) ||
1.5 millert 96: (input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
1.1 millert 97: input = STDIN_FILENO;
98: output = STDERR_FILENO;
99: }
100:
1.7 millert 101: /*
102: * Catch signals that would otherwise cause the user to end
1.10 millert 103: * up with echo turned off in the shell.
1.7 millert 104: */
1.16 millert 105: zero_bytes(&sa, sizeof(sa));
1.7 millert 106: sigemptyset(&sa.sa_mask);
1.10 millert 107: sa.sa_flags = SA_INTERRUPT; /* don't restart system calls */
1.7 millert 108: sa.sa_handler = handler;
1.10 millert 109: (void) sigaction(SIGALRM, &sa, &savealrm);
1.7 millert 110: (void) sigaction(SIGINT, &sa, &saveint);
111: (void) sigaction(SIGHUP, &sa, &savehup);
112: (void) sigaction(SIGQUIT, &sa, &savequit);
113: (void) sigaction(SIGTERM, &sa, &saveterm);
114: (void) sigaction(SIGTSTP, &sa, &savetstp);
115: (void) sigaction(SIGTTIN, &sa, &savettin);
116: (void) sigaction(SIGTTOU, &sa, &savettou);
117:
1.19 millert 118: if (def_pwfeedback)
119: neednl = term_raw(input);
120: else
121: neednl = term_noecho(input);
1.8 millert 122:
1.12 millert 123: /* No output if we are already backgrounded. */
124: if (signo != SIGTTOU && signo != SIGTTIN) {
125: if (prompt)
126: (void) write(output, prompt, strlen(prompt));
127:
128: if (timeout > 0)
129: alarm(timeout);
1.19 millert 130: pass = getln(input, buf, sizeof(buf), def_pwfeedback);
1.12 millert 131: alarm(0);
132: save_errno = errno;
1.1 millert 133:
1.19 millert 134: if (neednl)
1.12 millert 135: (void) write(output, "\n", 1);
136: }
1.1 millert 137:
1.7 millert 138: /* Restore old tty settings and signals. */
1.19 millert 139: term_restore(input);
1.10 millert 140: (void) sigaction(SIGALRM, &savealrm, NULL);
1.7 millert 141: (void) sigaction(SIGINT, &saveint, NULL);
142: (void) sigaction(SIGHUP, &savehup, NULL);
143: (void) sigaction(SIGQUIT, &savequit, NULL);
144: (void) sigaction(SIGTERM, &saveterm, NULL);
145: (void) sigaction(SIGTSTP, &savetstp, NULL);
146: (void) sigaction(SIGTTIN, &savettin, NULL);
147: (void) sigaction(SIGTTOU, &savettou, NULL);
1.1 millert 148: if (input != STDIN_FILENO)
149: (void) close(input);
150:
1.7 millert 151: /*
152: * If we were interrupted by a signal, resend it to ourselves
153: * now that we have restored the signal handlers.
154: */
155: if (signo) {
1.10 millert 156: kill(getpid(), signo);
1.7 millert 157: switch (signo) {
158: case SIGTSTP:
159: case SIGTTIN:
160: case SIGTTOU:
161: goto restart;
162: }
163: }
164:
1.12 millert 165: if (save_errno)
166: errno = save_errno;
1.7 millert 167: return(pass);
1.1 millert 168: }
169:
1.16 millert 170: /*
171: * Fork a child and exec sudo-askpass to get the password from the user.
172: */
173: static char *
174: sudo_askpass(prompt)
175: const char *prompt;
176: {
177: static char buf[SUDO_PASS_MAX + 1], *pass;
178: sigaction_t sa, saved_sa_pipe;
179: int pfd[2];
180: pid_t pid;
181:
182: if (pipe(pfd) == -1)
183: error(1, "unable to create pipe");
184:
185: if ((pid = fork()) == -1)
186: error(1, "unable to fork");
187:
188: if (pid == 0) {
189: /* child, point stdout to output side of the pipe and exec askpass */
190: (void) dup2(pfd[1], STDOUT_FILENO);
191: set_perms(PERM_FULL_USER);
192: closefrom(STDERR_FILENO + 1);
193: execl(user_askpass, user_askpass, prompt, (char *)NULL);
194: warning("unable to run %s", user_askpass);
195: _exit(255);
196: }
197:
198: /* Ignore SIGPIPE in case child exits prematurely */
199: zero_bytes(&sa, sizeof(sa));
200: sigemptyset(&sa.sa_mask);
201: sa.sa_flags = 0;
202: sa.sa_handler = SIG_IGN;
203: (void) sigaction(SIGPIPE, &sa, &saved_sa_pipe);
204:
205: /* Get response from child (askpass) and restore SIGPIPE handler */
206: (void) close(pfd[1]);
1.19 millert 207: pass = getln(pfd[0], buf, sizeof(buf), 0);
1.16 millert 208: (void) close(pfd[0]);
209: (void) sigaction(SIGPIPE, &saved_sa_pipe, NULL);
210:
211: return(pass);
212: }
213:
1.19 millert 214: extern int term_erase, term_kill;
215:
1.1 millert 216: static char *
1.19 millert 217: getln(fd, buf, bufsiz, feedback)
1.1 millert 218: int fd;
219: char *buf;
220: size_t bufsiz;
1.19 millert 221: int feedback;
1.1 millert 222: {
1.19 millert 223: size_t left = bufsiz;
1.16 millert 224: ssize_t nr = -1;
225: char *cp = buf;
226: char c = '\0';
1.1 millert 227:
1.19 millert 228: if (left == 0) {
1.7 millert 229: errno = EINVAL;
1.1 millert 230: return(NULL); /* sanity */
1.7 millert 231: }
1.1 millert 232:
1.19 millert 233: while (--left) {
1.16 millert 234: nr = read(fd, &c, 1);
235: if (nr != 1 || c == '\n' || c == '\r')
236: break;
1.19 millert 237: if (feedback) {
238: if (c == term_kill) {
239: while (cp > buf) {
240: (void) write(fd, "\b \b", 3);
241: --cp;
242: }
243: left = bufsiz;
244: continue;
245: } else if (c == term_erase) {
246: if (cp > buf) {
247: (void) write(fd, "\b \b", 3);
248: --cp;
249: left++;
250: }
251: continue;
252: }
253: (void) write(fd, "*", 1);
254: }
1.10 millert 255: *cp++ = c;
1.16 millert 256: }
1.1 millert 257: *cp = '\0';
1.19 millert 258: if (feedback) {
259: /* erase stars */
260: while (cp > buf) {
261: (void) write(fd, "\b \b", 3);
262: --cp;
263: }
264: }
1.16 millert 265:
266: return(nr == 1 ? buf : NULL);
1.7 millert 267: }
268:
1.10 millert 269: static void
270: handler(s)
1.7 millert 271: int s;
272: {
1.10 millert 273: if (s != SIGALRM)
274: signo = s;
1.17 millert 275: }
276:
277: int
278: tty_present()
279: {
280: int fd;
281:
282: if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) != -1)
283: close(fd);
284: return(fd != -1);
1.1 millert 285: }