Annotation of src/usr.bin/sudo/tgetpass.c, Revision 1.19
1.1 millert 1: /*
1.16 millert 2: * Copyright (c) 1996, 1998-2005, 2007-2008
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.5 millert 59: #ifndef lint
1.19 ! millert 60: __unused static const char rcsid[] = "$Sudo: tgetpass.c,v 1.130 2009/02/15 20:53:49 millert Exp $";
1.5 millert 61: #endif /* lint */
62:
1.7 millert 63: static volatile sig_atomic_t signo;
64:
65: static void handler __P((int));
1.19 ! millert 66: static char *getln __P((int, char *, size_t, int));
1.18 millert 67: static char *sudo_askpass __P((const char *));
1.1 millert 68:
1.19 ! millert 69: extern int term_restore __P((int));
! 70: extern int term_noecho __P((int));
! 71: extern int term_raw __P((int));
! 72:
1.1 millert 73: /*
74: * Like getpass(3) but with timeout and echo flags.
75: */
76: char *
1.5 millert 77: tgetpass(prompt, timeout, flags)
1.1 millert 78: const char *prompt;
79: int timeout;
1.5 millert 80: int flags;
1.1 millert 81: {
1.10 millert 82: sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm;
1.7 millert 83: sigaction_t savetstp, savettin, savettou;
1.10 millert 84: char *pass;
1.7 millert 85: static char buf[SUDO_PASS_MAX + 1];
1.19 ! millert 86: int input, output, save_errno, neednl;;
1.1 millert 87:
1.10 millert 88: (void) fflush(stdout);
1.16 millert 89:
90: /* If using a helper program to get the password, run it instead. */
91: if (ISSET(flags, TGP_ASKPASS) && user_askpass)
92: return(sudo_askpass(prompt));
93:
1.7 millert 94: restart:
1.12 millert 95: signo = 0;
96: pass = NULL;
97: save_errno = 0;
1.1 millert 98: /* Open /dev/tty for reading/writing if possible else use stdin/stderr. */
1.10 millert 99: if (ISSET(flags, TGP_STDIN) ||
1.5 millert 100: (input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
1.1 millert 101: input = STDIN_FILENO;
102: output = STDERR_FILENO;
103: }
104:
1.7 millert 105: /*
106: * Catch signals that would otherwise cause the user to end
1.10 millert 107: * up with echo turned off in the shell.
1.7 millert 108: */
1.16 millert 109: zero_bytes(&sa, sizeof(sa));
1.7 millert 110: sigemptyset(&sa.sa_mask);
1.10 millert 111: sa.sa_flags = SA_INTERRUPT; /* don't restart system calls */
1.7 millert 112: sa.sa_handler = handler;
1.10 millert 113: (void) sigaction(SIGALRM, &sa, &savealrm);
1.7 millert 114: (void) sigaction(SIGINT, &sa, &saveint);
115: (void) sigaction(SIGHUP, &sa, &savehup);
116: (void) sigaction(SIGQUIT, &sa, &savequit);
117: (void) sigaction(SIGTERM, &sa, &saveterm);
118: (void) sigaction(SIGTSTP, &sa, &savetstp);
119: (void) sigaction(SIGTTIN, &sa, &savettin);
120: (void) sigaction(SIGTTOU, &sa, &savettou);
121:
1.19 ! millert 122: if (def_pwfeedback)
! 123: neednl = term_raw(input);
! 124: else
! 125: neednl = term_noecho(input);
1.8 millert 126:
1.12 millert 127: /* No output if we are already backgrounded. */
128: if (signo != SIGTTOU && signo != SIGTTIN) {
129: if (prompt)
130: (void) write(output, prompt, strlen(prompt));
131:
132: if (timeout > 0)
133: alarm(timeout);
1.19 ! millert 134: pass = getln(input, buf, sizeof(buf), def_pwfeedback);
1.12 millert 135: alarm(0);
136: save_errno = errno;
1.1 millert 137:
1.19 ! millert 138: if (neednl)
1.12 millert 139: (void) write(output, "\n", 1);
140: }
1.1 millert 141:
1.7 millert 142: /* Restore old tty settings and signals. */
1.19 ! millert 143: term_restore(input);
1.10 millert 144: (void) sigaction(SIGALRM, &savealrm, NULL);
1.7 millert 145: (void) sigaction(SIGINT, &saveint, NULL);
146: (void) sigaction(SIGHUP, &savehup, NULL);
147: (void) sigaction(SIGQUIT, &savequit, NULL);
148: (void) sigaction(SIGTERM, &saveterm, NULL);
149: (void) sigaction(SIGTSTP, &savetstp, NULL);
150: (void) sigaction(SIGTTIN, &savettin, NULL);
151: (void) sigaction(SIGTTOU, &savettou, NULL);
1.1 millert 152: if (input != STDIN_FILENO)
153: (void) close(input);
154:
1.7 millert 155: /*
156: * If we were interrupted by a signal, resend it to ourselves
157: * now that we have restored the signal handlers.
158: */
159: if (signo) {
1.10 millert 160: kill(getpid(), signo);
1.7 millert 161: switch (signo) {
162: case SIGTSTP:
163: case SIGTTIN:
164: case SIGTTOU:
165: goto restart;
166: }
167: }
168:
1.12 millert 169: if (save_errno)
170: errno = save_errno;
1.7 millert 171: return(pass);
1.1 millert 172: }
173:
1.16 millert 174: /*
175: * Fork a child and exec sudo-askpass to get the password from the user.
176: */
177: static char *
178: sudo_askpass(prompt)
179: const char *prompt;
180: {
181: static char buf[SUDO_PASS_MAX + 1], *pass;
182: sigaction_t sa, saved_sa_pipe;
183: int pfd[2];
184: pid_t pid;
185:
186: if (pipe(pfd) == -1)
187: error(1, "unable to create pipe");
188:
189: if ((pid = fork()) == -1)
190: error(1, "unable to fork");
191:
192: if (pid == 0) {
193: /* child, point stdout to output side of the pipe and exec askpass */
194: (void) dup2(pfd[1], STDOUT_FILENO);
195: set_perms(PERM_FULL_USER);
196: closefrom(STDERR_FILENO + 1);
197: execl(user_askpass, user_askpass, prompt, (char *)NULL);
198: warning("unable to run %s", user_askpass);
199: _exit(255);
200: }
201:
202: /* Ignore SIGPIPE in case child exits prematurely */
203: zero_bytes(&sa, sizeof(sa));
204: sigemptyset(&sa.sa_mask);
205: sa.sa_flags = 0;
206: sa.sa_handler = SIG_IGN;
207: (void) sigaction(SIGPIPE, &sa, &saved_sa_pipe);
208:
209: /* Get response from child (askpass) and restore SIGPIPE handler */
210: (void) close(pfd[1]);
1.19 ! millert 211: pass = getln(pfd[0], buf, sizeof(buf), 0);
1.16 millert 212: (void) close(pfd[0]);
213: (void) sigaction(SIGPIPE, &saved_sa_pipe, NULL);
214:
215: return(pass);
216: }
217:
1.19 ! millert 218: extern int term_erase, term_kill;
! 219:
1.1 millert 220: static char *
1.19 ! millert 221: getln(fd, buf, bufsiz, feedback)
1.1 millert 222: int fd;
223: char *buf;
224: size_t bufsiz;
1.19 ! millert 225: int feedback;
1.1 millert 226: {
1.19 ! millert 227: size_t left = bufsiz;
1.16 millert 228: ssize_t nr = -1;
229: char *cp = buf;
230: char c = '\0';
1.1 millert 231:
1.19 ! millert 232: if (left == 0) {
1.7 millert 233: errno = EINVAL;
1.1 millert 234: return(NULL); /* sanity */
1.7 millert 235: }
1.1 millert 236:
1.19 ! millert 237: while (--left) {
1.16 millert 238: nr = read(fd, &c, 1);
239: if (nr != 1 || c == '\n' || c == '\r')
240: break;
1.19 ! millert 241: if (feedback) {
! 242: if (c == term_kill) {
! 243: while (cp > buf) {
! 244: (void) write(fd, "\b \b", 3);
! 245: --cp;
! 246: }
! 247: left = bufsiz;
! 248: continue;
! 249: } else if (c == term_erase) {
! 250: if (cp > buf) {
! 251: (void) write(fd, "\b \b", 3);
! 252: --cp;
! 253: left++;
! 254: }
! 255: continue;
! 256: }
! 257: (void) write(fd, "*", 1);
! 258: }
1.10 millert 259: *cp++ = c;
1.16 millert 260: }
1.1 millert 261: *cp = '\0';
1.19 ! millert 262: if (feedback) {
! 263: /* erase stars */
! 264: while (cp > buf) {
! 265: (void) write(fd, "\b \b", 3);
! 266: --cp;
! 267: }
! 268: }
1.16 millert 269:
270: return(nr == 1 ? buf : NULL);
1.7 millert 271: }
272:
1.10 millert 273: static void
274: handler(s)
1.7 millert 275: int s;
276: {
1.10 millert 277: if (s != SIGALRM)
278: signo = s;
1.17 millert 279: }
280:
281: int
282: tty_present()
283: {
284: int fd;
285:
286: if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) != -1)
287: close(fd);
288: return(fd != -1);
1.1 millert 289: }