1 /* $OpenBSD: readpassphrase.c,v 1.26 2016/10/18 12:47:18 millert Exp $ */ 2 3 /* 4 * Copyright (c) 2000-2002, 2007, 2010 5 * Todd C. Miller <Todd.Miller@courtesan.com> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 * 19 * Sponsored in part by the Defense Advanced Research Projects 20 * Agency (DARPA) and Air Force Research Laboratory, Air Force 21 * Materiel Command, USAF, under agreement number F39502-99-1-0512. 22 */ 23 24 /* OPENBSD ORIGINAL: lib/libc/gen/readpassphrase.c */ 25 26 #include "includes.h" 27 28 #ifndef HAVE_READPASSPHRASE 29 30 #include <termios.h> 31 #include <signal.h> 32 #include <ctype.h> 33 #include <fcntl.h> 34 #include <readpassphrase.h> 35 #include <errno.h> 36 #include <string.h> 37 #include <unistd.h> 38 39 #ifndef TCSASOFT 40 /* If we don't have TCSASOFT define it so that ORing it it below is a no-op. */ 41 # define TCSASOFT 0 42 #endif 43 44 /* SunOS 4.x which lacks _POSIX_VDISABLE, but has VDISABLE */ 45 #if !defined(_POSIX_VDISABLE) && defined(VDISABLE) 46 # define _POSIX_VDISABLE VDISABLE 47 #endif 48 49 #ifndef _NSIG 50 # ifdef NSIG 51 # define _NSIG NSIG 52 # else 53 # define _NSIG 128 54 # endif 55 #endif 56 57 static volatile sig_atomic_t signo[_NSIG]; 58 59 static void handler(int); 60 61 char * 62 readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) 63 { 64 ssize_t nr; 65 int input, output, save_errno, i, need_restart; 66 char ch, *p, *end; 67 struct termios term, oterm; 68 struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm; 69 struct sigaction savetstp, savettin, savettou, savepipe; 70 71 /* I suppose we could alloc on demand in this case (XXX). */ 72 if (bufsiz == 0) { 73 errno = EINVAL; 74 return(NULL); 75 } 76 77 restart: 78 for (i = 0; i < _NSIG; i++) 79 signo[i] = 0; 80 nr = -1; 81 save_errno = 0; 82 need_restart = 0; 83 /* 84 * Read and write to /dev/tty if available. If not, read from 85 * stdin and write to stderr unless a tty is required. 86 */ 87 if ((flags & RPP_STDIN) || 88 (input = output = open(_PATH_TTY, O_RDWR)) == -1) { 89 if (flags & RPP_REQUIRE_TTY) { 90 errno = ENOTTY; 91 return(NULL); 92 } 93 input = STDIN_FILENO; 94 output = STDERR_FILENO; 95 } 96 97 /* 98 * Turn off echo if possible. 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 (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) { 103 memcpy(&term, &oterm, sizeof(term)); 104 if (!(flags & RPP_ECHO_ON)) 105 term.c_lflag &= ~(ECHO | ECHONL); 106 #ifdef VSTATUS 107 if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) 108 term.c_cc[VSTATUS] = _POSIX_VDISABLE; 109 #endif 110 (void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term); 111 } else { 112 memset(&term, 0, sizeof(term)); 113 term.c_lflag |= ECHO; 114 memset(&oterm, 0, sizeof(oterm)); 115 oterm.c_lflag |= ECHO; 116 } 117 118 /* 119 * Catch signals that would otherwise cause the user to end 120 * up with echo turned off in the shell. Don't worry about 121 * things like SIGXCPU and SIGVTALRM for now. 122 */ 123 sigemptyset(&sa.sa_mask); 124 sa.sa_flags = 0; /* don't restart system calls */ 125 sa.sa_handler = handler; 126 (void)sigaction(SIGALRM, &sa, &savealrm); 127 (void)sigaction(SIGHUP, &sa, &savehup); 128 (void)sigaction(SIGINT, &sa, &saveint); 129 (void)sigaction(SIGPIPE, &sa, &savepipe); 130 (void)sigaction(SIGQUIT, &sa, &savequit); 131 (void)sigaction(SIGTERM, &sa, &saveterm); 132 (void)sigaction(SIGTSTP, &sa, &savetstp); 133 (void)sigaction(SIGTTIN, &sa, &savettin); 134 (void)sigaction(SIGTTOU, &sa, &savettou); 135 136 if (!(flags & RPP_STDIN)) 137 (void)write(output, prompt, strlen(prompt)); 138 end = buf + bufsiz - 1; 139 p = buf; 140 while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') { 141 if (p < end) { 142 if ((flags & RPP_SEVENBIT)) 143 ch &= 0x7f; 144 if (isalpha((unsigned char)ch)) { 145 if ((flags & RPP_FORCELOWER)) 146 ch = (char)tolower((unsigned char)ch); 147 if ((flags & RPP_FORCEUPPER)) 148 ch = (char)toupper((unsigned char)ch); 149 } 150 *p++ = ch; 151 } 152 } 153 *p = '\0'; 154 save_errno = errno; 155 if (!(term.c_lflag & ECHO)) 156 (void)write(output, "\n", 1); 157 158 /* Restore old terminal settings and signals. */ 159 if (memcmp(&term, &oterm, sizeof(term)) != 0) { 160 const int sigttou = signo[SIGTTOU]; 161 162 /* Ignore SIGTTOU generated when we are not the fg pgrp. */ 163 while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 && 164 errno == EINTR && !signo[SIGTTOU]) 165 continue; 166 signo[SIGTTOU] = sigttou; 167 } 168 (void)sigaction(SIGALRM, &savealrm, NULL); 169 (void)sigaction(SIGHUP, &savehup, NULL); 170 (void)sigaction(SIGINT, &saveint, NULL); 171 (void)sigaction(SIGQUIT, &savequit, NULL); 172 (void)sigaction(SIGPIPE, &savepipe, NULL); 173 (void)sigaction(SIGTERM, &saveterm, NULL); 174 (void)sigaction(SIGTSTP, &savetstp, NULL); 175 (void)sigaction(SIGTTIN, &savettin, NULL); 176 (void)sigaction(SIGTTOU, &savettou, NULL); 177 if (input != STDIN_FILENO) 178 (void)close(input); 179 180 /* 181 * If we were interrupted by a signal, resend it to ourselves 182 * now that we have restored the signal handlers. 183 */ 184 for (i = 0; i < _NSIG; i++) { 185 if (signo[i]) { 186 kill(getpid(), i); 187 switch (i) { 188 case SIGTSTP: 189 case SIGTTIN: 190 case SIGTTOU: 191 need_restart = 1; 192 } 193 } 194 } 195 if (need_restart) 196 goto restart; 197 198 if (save_errno) 199 errno = save_errno; 200 return(nr == -1 ? NULL : buf); 201 } 202 DEF_WEAK(readpassphrase); 203 204 #if 0 205 char * 206 getpass(const char *prompt) 207 { 208 static char buf[_PASSWORD_LEN + 1]; 209 210 return(readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF)); 211 } 212 #endif 213 214 static void handler(int s) 215 { 216 217 signo[s] = 1; 218 } 219 #endif /* HAVE_READPASSPHRASE */ 220