Annotation of src/usr.bin/sudo/tgetpass.c, Revision 1.16
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>
30: #ifdef HAVE_SYS_BSDTYPES_H
31: # include <sys/bsdtypes.h>
32: #endif /* HAVE_SYS_BSDTYPES_H */
33: #include <sys/time.h>
1.1 millert 34: #include <stdio.h>
35: #ifdef STDC_HEADERS
1.7 millert 36: # include <stdlib.h>
37: # include <stddef.h>
38: #else
39: # ifdef HAVE_STDLIB_H
40: # include <stdlib.h>
41: # endif
1.1 millert 42: #endif /* STDC_HEADERS */
1.7 millert 43: #ifdef HAVE_STRING_H
44: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
45: # include <memory.h>
46: # endif
47: # include <string.h>
48: #else
49: # ifdef HAVE_STRINGS_H
50: # include <strings.h>
51: # endif
52: #endif /* HAVE_STRING_H */
1.1 millert 53: #ifdef HAVE_UNISTD_H
1.7 millert 54: # include <unistd.h>
1.1 millert 55: #endif /* HAVE_UNISTD_H */
56: #include <pwd.h>
57: #include <errno.h>
58: #include <signal.h>
59: #include <fcntl.h>
60: #ifdef HAVE_TERMIOS_H
1.7 millert 61: # include <termios.h>
1.1 millert 62: #else
1.7 millert 63: # ifdef HAVE_TERMIO_H
64: # include <termio.h>
65: # else
66: # include <sgtty.h>
67: # include <sys/ioctl.h>
68: # endif /* HAVE_TERMIO_H */
1.1 millert 69: #endif /* HAVE_TERMIOS_H */
70:
71: #include "sudo.h"
72:
1.5 millert 73: #ifndef lint
1.16 ! millert 74: __unused static const char rcsid[] = "$Sudo: tgetpass.c,v 1.124 2008/11/08 15:30:42 millert Exp $";
1.5 millert 75: #endif /* lint */
76:
1.1 millert 77: #ifndef TCSASOFT
1.7 millert 78: # define TCSASOFT 0
79: #endif
80: #ifndef ECHONL
81: # define ECHONL 0
82: #endif
83:
84: #ifndef _POSIX_VDISABLE
85: # ifdef VDISABLE
86: # define _POSIX_VDISABLE VDISABLE
87: # else
88: # define _POSIX_VDISABLE 0
89: # endif
1.13 millert 90: #endif
91:
92: /*
93: * Compat macros for non-termios systems.
94: */
95: #ifndef HAVE_TERMIOS_H
1.5 millert 96: # ifdef HAVE_TERMIO_H
1.13 millert 97: # undef termios
98: # define termios termio
99: # define tcgetattr(f, t) ioctl(f, TCGETA, t)
100: # define tcsetattr(f, a, t) ioctl(f, a, t)
101: # undef TCSAFLUSH
102: # define TCSAFLUSH TCSETAF
1.5 millert 103: # else
1.13 millert 104: # undef termios
105: # define termios sgttyb
106: # define c_lflag sg_flags
107: # define tcgetattr(f, t) ioctl(f, TIOCGETP, t)
108: # define tcsetattr(f, a, t) ioctl(f, a, t)
109: # undef TCSAFLUSH
110: # define TCSAFLUSH TIOCSETP
1.5 millert 111: # endif /* HAVE_TERMIO_H */
112: #endif /* HAVE_TERMIOS_H */
1.1 millert 113:
1.7 millert 114: static volatile sig_atomic_t signo;
115:
116: static void handler __P((int));
1.10 millert 117: static char *getln __P((int, char *, size_t));
1.16 ! millert 118: static char *sudo_askpass(const char *);
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.13 millert 131: struct termios term, oterm;
1.10 millert 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.16 ! millert 137:
! 138: /* If using a helper program to get the password, run it instead. */
! 139: if (ISSET(flags, TGP_ASKPASS) && user_askpass)
! 140: return(sudo_askpass(prompt));
! 141:
1.7 millert 142: restart:
1.12 millert 143: signo = 0;
144: pass = NULL;
145: save_errno = 0;
1.1 millert 146: /* Open /dev/tty for reading/writing if possible else use stdin/stderr. */
1.10 millert 147: if (ISSET(flags, TGP_STDIN) ||
1.5 millert 148: (input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
1.1 millert 149: input = STDIN_FILENO;
150: output = STDERR_FILENO;
151: }
152:
1.7 millert 153: /*
154: * Catch signals that would otherwise cause the user to end
1.10 millert 155: * up with echo turned off in the shell.
1.7 millert 156: */
1.16 ! millert 157: zero_bytes(&sa, sizeof(sa));
1.7 millert 158: sigemptyset(&sa.sa_mask);
1.10 millert 159: sa.sa_flags = SA_INTERRUPT; /* don't restart system calls */
1.7 millert 160: sa.sa_handler = handler;
1.10 millert 161: (void) sigaction(SIGALRM, &sa, &savealrm);
1.7 millert 162: (void) sigaction(SIGINT, &sa, &saveint);
163: (void) sigaction(SIGHUP, &sa, &savehup);
164: (void) sigaction(SIGQUIT, &sa, &savequit);
165: (void) sigaction(SIGTERM, &sa, &saveterm);
166: (void) sigaction(SIGTSTP, &sa, &savetstp);
167: (void) sigaction(SIGTTIN, &sa, &savettin);
168: (void) sigaction(SIGTTOU, &sa, &savettou);
169:
1.5 millert 170: /* Turn echo off/on as specified by flags. */
1.13 millert 171: if (tcgetattr(input, &oterm) == 0) {
1.7 millert 172: (void) memcpy(&term, &oterm, sizeof(term));
1.10 millert 173: if (!ISSET(flags, TGP_ECHO))
1.13 millert 174: CLR(term.c_lflag, ECHO|ECHONL);
1.7 millert 175: #ifdef VSTATUS
176: term.c_cc[VSTATUS] = _POSIX_VDISABLE;
177: #endif
1.13 millert 178: (void) tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
1.7 millert 179: } else {
1.16 ! millert 180: zero_bytes(&term, sizeof(term));
! 181: zero_bytes(&oterm, sizeof(oterm));
1.7 millert 182: }
1.8 millert 183:
1.12 millert 184: /* No output if we are already backgrounded. */
185: if (signo != SIGTTOU && signo != SIGTTIN) {
186: if (prompt)
187: (void) write(output, prompt, strlen(prompt));
188:
189: if (timeout > 0)
190: alarm(timeout);
191: pass = getln(input, buf, sizeof(buf));
192: alarm(0);
193: save_errno = errno;
1.1 millert 194:
1.13 millert 195: if (!ISSET(term.c_lflag, ECHO))
1.12 millert 196: (void) write(output, "\n", 1);
197: }
1.1 millert 198:
1.7 millert 199: /* Restore old tty settings and signals. */
1.13 millert 200: if (memcmp(&term, &oterm, sizeof(term)) != 0) {
1.14 millert 201: while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 &&
1.13 millert 202: errno == EINTR)
203: continue;
204: }
1.10 millert 205: (void) sigaction(SIGALRM, &savealrm, NULL);
1.7 millert 206: (void) sigaction(SIGINT, &saveint, NULL);
207: (void) sigaction(SIGHUP, &savehup, NULL);
208: (void) sigaction(SIGQUIT, &savequit, NULL);
209: (void) sigaction(SIGTERM, &saveterm, NULL);
210: (void) sigaction(SIGTSTP, &savetstp, NULL);
211: (void) sigaction(SIGTTIN, &savettin, NULL);
212: (void) sigaction(SIGTTOU, &savettou, NULL);
1.1 millert 213: if (input != STDIN_FILENO)
214: (void) close(input);
215:
1.7 millert 216: /*
217: * If we were interrupted by a signal, resend it to ourselves
218: * now that we have restored the signal handlers.
219: */
220: if (signo) {
1.10 millert 221: kill(getpid(), signo);
1.7 millert 222: switch (signo) {
223: case SIGTSTP:
224: case SIGTTIN:
225: case SIGTTOU:
226: goto restart;
227: }
228: }
229:
1.12 millert 230: if (save_errno)
231: errno = save_errno;
1.7 millert 232: return(pass);
1.1 millert 233: }
234:
1.16 ! millert 235: /*
! 236: * Fork a child and exec sudo-askpass to get the password from the user.
! 237: */
! 238: static char *
! 239: sudo_askpass(prompt)
! 240: const char *prompt;
! 241: {
! 242: static char buf[SUDO_PASS_MAX + 1], *pass;
! 243: sigaction_t sa, saved_sa_pipe;
! 244: int pfd[2];
! 245: pid_t pid;
! 246:
! 247: if (pipe(pfd) == -1)
! 248: error(1, "unable to create pipe");
! 249:
! 250: if ((pid = fork()) == -1)
! 251: error(1, "unable to fork");
! 252:
! 253: if (pid == 0) {
! 254: /* child, point stdout to output side of the pipe and exec askpass */
! 255: (void) dup2(pfd[1], STDOUT_FILENO);
! 256: set_perms(PERM_FULL_USER);
! 257: closefrom(STDERR_FILENO + 1);
! 258: execl(user_askpass, user_askpass, prompt, (char *)NULL);
! 259: warning("unable to run %s", user_askpass);
! 260: _exit(255);
! 261: }
! 262:
! 263: /* Ignore SIGPIPE in case child exits prematurely */
! 264: zero_bytes(&sa, sizeof(sa));
! 265: sigemptyset(&sa.sa_mask);
! 266: sa.sa_flags = 0;
! 267: sa.sa_handler = SIG_IGN;
! 268: (void) sigaction(SIGPIPE, &sa, &saved_sa_pipe);
! 269:
! 270: /* Get response from child (askpass) and restore SIGPIPE handler */
! 271: (void) close(pfd[1]);
! 272: pass = getln(pfd[0], buf, sizeof(buf));
! 273: (void) close(pfd[0]);
! 274: (void) sigaction(SIGPIPE, &saved_sa_pipe, NULL);
! 275:
! 276: return(pass);
! 277: }
! 278:
1.1 millert 279: static char *
1.10 millert 280: getln(fd, buf, bufsiz)
1.1 millert 281: int fd;
282: char *buf;
283: size_t bufsiz;
284: {
1.16 ! millert 285: ssize_t nr = -1;
! 286: char *cp = buf;
! 287: char c = '\0';
1.1 millert 288:
1.7 millert 289: if (bufsiz == 0) {
290: errno = EINVAL;
1.1 millert 291: return(NULL); /* sanity */
1.7 millert 292: }
1.1 millert 293:
1.16 ! millert 294: while (--bufsiz) {
! 295: nr = read(fd, &c, 1);
! 296: if (nr != 1 || c == '\n' || c == '\r')
! 297: break;
1.10 millert 298: *cp++ = c;
1.16 ! millert 299: }
1.1 millert 300: *cp = '\0';
1.16 ! millert 301:
! 302: return(nr == 1 ? buf : NULL);
1.7 millert 303: }
304:
1.10 millert 305: static void
306: handler(s)
1.7 millert 307: int s;
308: {
1.10 millert 309: if (s != SIGALRM)
310: signo = s;
1.1 millert 311: }