1/* 2 * Copyright (c) 1996, 1998-2005, 2007-2010 3 * Todd C. Miller <Todd.Miller@courtesan.com> 4 * 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. 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. 20 */ 21 22#ifdef __TANDEM 23# include <floss.h> 24#endif 25 26#include <config.h> 27 28#include <sys/types.h> 29#include <sys/param.h> 30#include <stdio.h> 31#ifdef STDC_HEADERS 32# include <stdlib.h> 33# include <stddef.h> 34#else 35# ifdef HAVE_STDLIB_H 36# include <stdlib.h> 37# endif 38#endif /* STDC_HEADERS */ 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#endif /* HAVE_STRING_H */ 45#ifdef HAVE_STRINGS_H 46# include <strings.h> 47#endif /* HAVE_STRINGS_H */ 48#ifdef HAVE_UNISTD_H 49# include <unistd.h> 50#endif /* HAVE_UNISTD_H */ 51#include <pwd.h> 52#include <errno.h> 53#include <signal.h> 54#include <fcntl.h> 55 56#include "sudo.h" 57 58static volatile sig_atomic_t signo[NSIG]; 59 60static RETSIGTYPE handler __P((int)); 61static char *getln __P((int, char *, size_t, int)); 62static char *sudo_askpass __P((const char *)); 63 64/* 65 * Like getpass(3) but with timeout and echo flags. 66 */ 67char * 68tgetpass(prompt, timeout, flags) 69 const char *prompt; 70 int timeout; 71 int flags; 72{ 73 sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm; 74 sigaction_t savetstp, savettin, savettou, savepipe; 75 char *pass; 76 static char buf[SUDO_PASS_MAX + 1]; 77 int i, input, output, save_errno, neednl = 0, need_restart; 78 79 (void) fflush(stdout); 80 81 /* If using a helper program to get the password, run it instead. */ 82 if (ISSET(flags, TGP_ASKPASS) && user_askpass) 83 return sudo_askpass(prompt); 84 85restart: 86 for (i = 0; i < NSIG; i++) 87 signo[i] = 0; 88 pass = NULL; 89 save_errno = 0; 90 need_restart = 0; 91 /* Open /dev/tty for reading/writing if possible else use stdin/stderr. */ 92 if (ISSET(flags, TGP_STDIN) || 93 (input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) { 94 input = STDIN_FILENO; 95 output = STDERR_FILENO; 96 } 97 98 /* 99 * If we are using a tty but are not the foreground pgrp this will 100 * generate SIGTTOU, so do it *before* installing the signal handlers. 101 */ 102 if (!ISSET(flags, TGP_ECHO)) { 103 if (def_pwfeedback) 104 neednl = term_cbreak(input); 105 else 106 neednl = term_noecho(input); 107 } 108 109 /* 110 * Catch signals that would otherwise cause the user to end 111 * up with echo turned off in the shell. 112 */ 113 zero_bytes(&sa, sizeof(sa)); 114 sigemptyset(&sa.sa_mask); 115 sa.sa_flags = SA_INTERRUPT; /* don't restart system calls */ 116 sa.sa_handler = handler; 117 (void) sigaction(SIGALRM, &sa, &savealrm); 118 (void) sigaction(SIGINT, &sa, &saveint); 119 (void) sigaction(SIGHUP, &sa, &savehup); 120 (void) sigaction(SIGQUIT, &sa, &savequit); 121 (void) sigaction(SIGTERM, &sa, &saveterm); 122 (void) sigaction(SIGTSTP, &sa, &savetstp); 123 (void) sigaction(SIGTTIN, &sa, &savettin); 124 (void) sigaction(SIGTTOU, &sa, &savettou); 125 126 /* Ignore SIGPIPE in case stdin is a pipe and TGP_STDIN is set */ 127 sa.sa_handler = SIG_IGN; 128 (void) sigaction(SIGPIPE, &sa, &savepipe); 129 130 if (prompt) { 131 if (write(output, prompt, strlen(prompt)) == -1) 132 goto restore; 133 } 134 135 if (timeout > 0) 136 alarm(timeout); 137 pass = getln(input, buf, sizeof(buf), def_pwfeedback); 138 alarm(0); 139 save_errno = errno; 140 141 if (neednl || pass == NULL) { 142 if (write(output, "\n", 1) == -1) 143 goto restore; 144 } 145 146restore: 147 /* Restore old tty settings and signals. */ 148 if (!ISSET(flags, TGP_ECHO)) 149 term_restore(input, 1); 150 (void) sigaction(SIGALRM, &savealrm, NULL); 151 (void) sigaction(SIGINT, &saveint, NULL); 152 (void) sigaction(SIGHUP, &savehup, NULL); 153 (void) sigaction(SIGQUIT, &savequit, NULL); 154 (void) sigaction(SIGTERM, &saveterm, NULL); 155 (void) sigaction(SIGTSTP, &savetstp, NULL); 156 (void) sigaction(SIGTTIN, &savettin, NULL); 157 (void) sigaction(SIGTTOU, &savettou, NULL); 158 (void) sigaction(SIGTTOU, &savepipe, NULL); 159 if (input != STDIN_FILENO) 160 (void) close(input); 161 162 /* 163 * If we were interrupted by a signal, resend it to ourselves 164 * now that we have restored the signal handlers. 165 */ 166 for (i = 0; i < NSIG; i++) { 167 if (signo[i]) { 168 kill(getpid(), i); 169 switch (i) { 170 case SIGTSTP: 171 case SIGTTIN: 172 case SIGTTOU: 173 need_restart = 1; 174 break; 175 } 176 } 177 } 178 if (need_restart) 179 goto restart; 180 181 if (save_errno) 182 errno = save_errno; 183 return pass; 184} 185 186/* 187 * Fork a child and exec sudo-askpass to get the password from the user. 188 */ 189static char * 190sudo_askpass(prompt) 191 const char *prompt; 192{ 193 static char buf[SUDO_PASS_MAX + 1], *pass; 194 sigaction_t sa, saved_sa_pipe; 195 int pfd[2]; 196 pid_t pid; 197 198 if (pipe(pfd) == -1) 199 error(1, "unable to create pipe"); 200 201 if ((pid = fork()) == -1) 202 error(1, "unable to fork"); 203 204 if (pid == 0) { 205 /* child, point stdout to output side of the pipe and exec askpass */ 206 if (dup2(pfd[1], STDOUT_FILENO) == -1) { 207 warning("dup2"); 208 _exit(255); 209 } 210 (void) dup2(pfd[1], STDOUT_FILENO); 211 set_perms(PERM_FULL_USER); 212 closefrom(STDERR_FILENO + 1); 213 execl(user_askpass, user_askpass, prompt, (char *)NULL); 214 warning("unable to run %s", user_askpass); 215 _exit(255); 216 } 217 218 /* Ignore SIGPIPE in case child exits prematurely */ 219 zero_bytes(&sa, sizeof(sa)); 220 sigemptyset(&sa.sa_mask); 221 sa.sa_flags = SA_INTERRUPT; 222 sa.sa_handler = SIG_IGN; 223 (void) sigaction(SIGPIPE, &sa, &saved_sa_pipe); 224 225 /* Get response from child (askpass) and restore SIGPIPE handler */ 226 (void) close(pfd[1]); 227 pass = getln(pfd[0], buf, sizeof(buf), 0); 228 (void) close(pfd[0]); 229 (void) sigaction(SIGPIPE, &saved_sa_pipe, NULL); 230 231 if (pass == NULL) 232 errno = EINTR; /* make cancel button simulate ^C */ 233 234 return pass; 235} 236 237extern int term_erase, term_kill; 238 239static char * 240getln(fd, buf, bufsiz, feedback) 241 int fd; 242 char *buf; 243 size_t bufsiz; 244 int feedback; 245{ 246 size_t left = bufsiz; 247 ssize_t nr = -1; 248 char *cp = buf; 249 char c = '\0'; 250 251 if (left == 0) { 252 errno = EINVAL; 253 return NULL; /* sanity */ 254 } 255 256 while (--left) { 257 nr = read(fd, &c, 1); 258 if (nr != 1 || c == '\n' || c == '\r') 259 break; 260 if (feedback) { 261 if (c == term_kill) { 262 while (cp > buf) { 263 if (write(fd, "\b \b", 3) == -1) 264 break; 265 --cp; 266 } 267 left = bufsiz; 268 continue; 269 } else if (c == term_erase) { 270 if (cp > buf) { 271 if (write(fd, "\b \b", 3) == -1) 272 break; 273 --cp; 274 left++; 275 } 276 continue; 277 } 278 ignore_result(write(fd, "*", 1)); 279 } 280 *cp++ = c; 281 } 282 *cp = '\0'; 283 if (feedback) { 284 /* erase stars */ 285 while (cp > buf) { 286 if (write(fd, "\b \b", 3) == -1) 287 break; 288 --cp; 289 } 290 } 291 292 return nr == 1 ? buf : NULL; 293} 294 295static RETSIGTYPE 296handler(s) 297 int s; 298{ 299 if (s != SIGALRM) 300 signo[s] = 1; 301} 302 303int 304tty_present() 305{ 306 int fd; 307 308 if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) != -1) 309 close(fd); 310 return fd != -1; 311} 312