1*6b384f39SPeter Avalos /*- 2*6b384f39SPeter Avalos * Copyright (c) 2014 Michihiro NAKAJIMA 3*6b384f39SPeter Avalos * All rights reserved. 4*6b384f39SPeter Avalos * 5*6b384f39SPeter Avalos * Redistribution and use in source and binary forms, with or without 6*6b384f39SPeter Avalos * modification, are permitted provided that the following conditions 7*6b384f39SPeter Avalos * are met: 8*6b384f39SPeter Avalos * 1. Redistributions of source code must retain the above copyright 9*6b384f39SPeter Avalos * notice, this list of conditions and the following disclaimer 10*6b384f39SPeter Avalos * in this position and unchanged. 11*6b384f39SPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright 12*6b384f39SPeter Avalos * notice, this list of conditions and the following disclaimer in the 13*6b384f39SPeter Avalos * documentation and/or other materials provided with the distribution. 14*6b384f39SPeter Avalos * 15*6b384f39SPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16*6b384f39SPeter Avalos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17*6b384f39SPeter Avalos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18*6b384f39SPeter Avalos * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19*6b384f39SPeter Avalos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20*6b384f39SPeter Avalos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21*6b384f39SPeter Avalos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22*6b384f39SPeter Avalos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23*6b384f39SPeter Avalos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24*6b384f39SPeter Avalos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25*6b384f39SPeter Avalos */ 26*6b384f39SPeter Avalos /* $OpenBSD: readpassphrase.c,v 1.22 2010/01/13 10:20:54 dtucker Exp $ */ 27*6b384f39SPeter Avalos /* 28*6b384f39SPeter Avalos * Copyright (c) 2000-2002, 2007 Todd C. Miller <Todd.Miller@courtesan.com> 29*6b384f39SPeter Avalos * 30*6b384f39SPeter Avalos * Permission to use, copy, modify, and distribute this software for any 31*6b384f39SPeter Avalos * purpose with or without fee is hereby granted, provided that the above 32*6b384f39SPeter Avalos * copyright notice and this permission notice appear in all copies. 33*6b384f39SPeter Avalos * 34*6b384f39SPeter Avalos * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 35*6b384f39SPeter Avalos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 36*6b384f39SPeter Avalos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 37*6b384f39SPeter Avalos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 38*6b384f39SPeter Avalos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 39*6b384f39SPeter Avalos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 40*6b384f39SPeter Avalos * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 41*6b384f39SPeter Avalos * 42*6b384f39SPeter Avalos * Sponsored in part by the Defense Advanced Research Projects 43*6b384f39SPeter Avalos * Agency (DARPA) and Air Force Research Laboratory, Air Force 44*6b384f39SPeter Avalos * Materiel Command, USAF, under agreement number F39502-99-1-0512. 45*6b384f39SPeter Avalos */ 46*6b384f39SPeter Avalos 47*6b384f39SPeter Avalos /* OPENBSD ORIGINAL: lib/libc/gen/readpassphrase.c */ 48*6b384f39SPeter Avalos 49*6b384f39SPeter Avalos 50*6b384f39SPeter Avalos #include "lafe_platform.h" 51*6b384f39SPeter Avalos __FBSDID("$FreeBSD$"); 52*6b384f39SPeter Avalos 53*6b384f39SPeter Avalos #include <errno.h> 54*6b384f39SPeter Avalos #ifdef HAVE_STDLIB_H 55*6b384f39SPeter Avalos #include <stdlib.h> 56*6b384f39SPeter Avalos #endif 57*6b384f39SPeter Avalos #ifdef HAVE_UNISTD_H 58*6b384f39SPeter Avalos #include <unistd.h> 59*6b384f39SPeter Avalos #endif 60*6b384f39SPeter Avalos #ifdef HAVE_READPASSPHRASE_H 61*6b384f39SPeter Avalos #include <readpassphrase.h> 62*6b384f39SPeter Avalos #endif 63*6b384f39SPeter Avalos 64*6b384f39SPeter Avalos #include "err.h" 65*6b384f39SPeter Avalos #include "passphrase.h" 66*6b384f39SPeter Avalos 67*6b384f39SPeter Avalos #ifndef HAVE_READPASSPHRASE 68*6b384f39SPeter Avalos 69*6b384f39SPeter Avalos #define RPP_ECHO_OFF 0x00 /* Turn off echo (default). */ 70*6b384f39SPeter Avalos #define RPP_ECHO_ON 0x01 /* Leave echo on. */ 71*6b384f39SPeter Avalos #define RPP_REQUIRE_TTY 0x02 /* Fail if there is no tty. */ 72*6b384f39SPeter Avalos #define RPP_FORCELOWER 0x04 /* Force input to lower case. */ 73*6b384f39SPeter Avalos #define RPP_FORCEUPPER 0x08 /* Force input to upper case. */ 74*6b384f39SPeter Avalos #define RPP_SEVENBIT 0x10 /* Strip the high bit from input. */ 75*6b384f39SPeter Avalos #define RPP_STDIN 0x20 /* Read from stdin, not /dev/tty */ 76*6b384f39SPeter Avalos 77*6b384f39SPeter Avalos 78*6b384f39SPeter Avalos #if defined(_WIN32) && !defined(__CYGWIN__) 79*6b384f39SPeter Avalos #include <windows.h> 80*6b384f39SPeter Avalos 81*6b384f39SPeter Avalos static char * 82*6b384f39SPeter Avalos readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) 83*6b384f39SPeter Avalos { 84*6b384f39SPeter Avalos HANDLE hStdin, hStdout; 85*6b384f39SPeter Avalos DWORD mode, rbytes; 86*6b384f39SPeter Avalos BOOL success; 87*6b384f39SPeter Avalos 88*6b384f39SPeter Avalos (void)flags; 89*6b384f39SPeter Avalos 90*6b384f39SPeter Avalos hStdin = GetStdHandle(STD_INPUT_HANDLE); 91*6b384f39SPeter Avalos if (hStdin == INVALID_HANDLE_VALUE) 92*6b384f39SPeter Avalos return (NULL); 93*6b384f39SPeter Avalos hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 94*6b384f39SPeter Avalos if (hStdout == INVALID_HANDLE_VALUE) 95*6b384f39SPeter Avalos return (NULL); 96*6b384f39SPeter Avalos 97*6b384f39SPeter Avalos success = GetConsoleMode(hStdin, &mode); 98*6b384f39SPeter Avalos if (!success) 99*6b384f39SPeter Avalos return (NULL); 100*6b384f39SPeter Avalos mode &= ~ENABLE_ECHO_INPUT; 101*6b384f39SPeter Avalos mode |= ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; 102*6b384f39SPeter Avalos success = SetConsoleMode(hStdin, mode); 103*6b384f39SPeter Avalos if (!success) 104*6b384f39SPeter Avalos return (NULL); 105*6b384f39SPeter Avalos 106*6b384f39SPeter Avalos success = WriteFile(hStdout, prompt, (DWORD)strlen(prompt), 107*6b384f39SPeter Avalos NULL, NULL); 108*6b384f39SPeter Avalos if (!success) 109*6b384f39SPeter Avalos return (NULL); 110*6b384f39SPeter Avalos success = ReadFile(hStdin, buf, (DWORD)bufsiz - 1, &rbytes, NULL); 111*6b384f39SPeter Avalos if (!success) 112*6b384f39SPeter Avalos return (NULL); 113*6b384f39SPeter Avalos WriteFile(hStdout, "\r\n", 2, NULL, NULL); 114*6b384f39SPeter Avalos buf[rbytes] = '\0'; 115*6b384f39SPeter Avalos /* Remove trailing carriage return(s). */ 116*6b384f39SPeter Avalos if (rbytes > 2 && buf[rbytes - 2] == '\r' && buf[rbytes - 1] == '\n') 117*6b384f39SPeter Avalos buf[rbytes - 2] = '\0'; 118*6b384f39SPeter Avalos 119*6b384f39SPeter Avalos return (buf); 120*6b384f39SPeter Avalos } 121*6b384f39SPeter Avalos 122*6b384f39SPeter Avalos #else /* _WIN32 && !__CYGWIN__ */ 123*6b384f39SPeter Avalos 124*6b384f39SPeter Avalos #include <termios.h> 125*6b384f39SPeter Avalos #include <signal.h> 126*6b384f39SPeter Avalos #include <ctype.h> 127*6b384f39SPeter Avalos #include <fcntl.h> 128*6b384f39SPeter Avalos #ifdef HAVE_PATHS_H 129*6b384f39SPeter Avalos #include <paths.h> 130*6b384f39SPeter Avalos #endif 131*6b384f39SPeter Avalos #include <string.h> 132*6b384f39SPeter Avalos #include <unistd.h> 133*6b384f39SPeter Avalos 134*6b384f39SPeter Avalos #ifdef TCSASOFT 135*6b384f39SPeter Avalos # define _T_FLUSH (TCSAFLUSH|TCSASOFT) 136*6b384f39SPeter Avalos #else 137*6b384f39SPeter Avalos # define _T_FLUSH (TCSAFLUSH) 138*6b384f39SPeter Avalos #endif 139*6b384f39SPeter Avalos 140*6b384f39SPeter Avalos /* SunOS 4.x which lacks _POSIX_VDISABLE, but has VDISABLE */ 141*6b384f39SPeter Avalos #if !defined(_POSIX_VDISABLE) && defined(VDISABLE) 142*6b384f39SPeter Avalos # define _POSIX_VDISABLE VDISABLE 143*6b384f39SPeter Avalos #endif 144*6b384f39SPeter Avalos 145*6b384f39SPeter Avalos static volatile sig_atomic_t *signo; 146*6b384f39SPeter Avalos 147*6b384f39SPeter Avalos static void 148*6b384f39SPeter Avalos handler(int s) 149*6b384f39SPeter Avalos { 150*6b384f39SPeter Avalos signo[s] = 1; 151*6b384f39SPeter Avalos } 152*6b384f39SPeter Avalos 153*6b384f39SPeter Avalos static char * 154*6b384f39SPeter Avalos readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) 155*6b384f39SPeter Avalos { 156*6b384f39SPeter Avalos ssize_t nr; 157*6b384f39SPeter Avalos int input, output, save_errno, i, need_restart; 158*6b384f39SPeter Avalos char ch, *p, *end; 159*6b384f39SPeter Avalos struct termios term, oterm; 160*6b384f39SPeter Avalos struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm; 161*6b384f39SPeter Avalos struct sigaction savetstp, savettin, savettou, savepipe; 162*6b384f39SPeter Avalos 163*6b384f39SPeter Avalos /* I suppose we could alloc on demand in this case (XXX). */ 164*6b384f39SPeter Avalos if (bufsiz == 0) { 165*6b384f39SPeter Avalos errno = EINVAL; 166*6b384f39SPeter Avalos return(NULL); 167*6b384f39SPeter Avalos } 168*6b384f39SPeter Avalos 169*6b384f39SPeter Avalos if (signo == NULL) { 170*6b384f39SPeter Avalos signo = calloc(SIGRTMAX, sizeof(sig_atomic_t)); 171*6b384f39SPeter Avalos } 172*6b384f39SPeter Avalos 173*6b384f39SPeter Avalos restart: 174*6b384f39SPeter Avalos for (i = 0; i < SIGRTMAX; i++) 175*6b384f39SPeter Avalos signo[i] = 0; 176*6b384f39SPeter Avalos nr = -1; 177*6b384f39SPeter Avalos save_errno = 0; 178*6b384f39SPeter Avalos need_restart = 0; 179*6b384f39SPeter Avalos /* 180*6b384f39SPeter Avalos * Read and write to /dev/tty if available. If not, read from 181*6b384f39SPeter Avalos * stdin and write to stderr unless a tty is required. 182*6b384f39SPeter Avalos */ 183*6b384f39SPeter Avalos if ((flags & RPP_STDIN) || 184*6b384f39SPeter Avalos (input = output = open(_PATH_TTY, O_RDWR)) == -1) { 185*6b384f39SPeter Avalos if (flags & RPP_REQUIRE_TTY) { 186*6b384f39SPeter Avalos errno = ENOTTY; 187*6b384f39SPeter Avalos return(NULL); 188*6b384f39SPeter Avalos } 189*6b384f39SPeter Avalos input = STDIN_FILENO; 190*6b384f39SPeter Avalos output = STDERR_FILENO; 191*6b384f39SPeter Avalos } 192*6b384f39SPeter Avalos 193*6b384f39SPeter Avalos /* 194*6b384f39SPeter Avalos * Catch signals that would otherwise cause the user to end 195*6b384f39SPeter Avalos * up with echo turned off in the shell. Don't worry about 196*6b384f39SPeter Avalos * things like SIGXCPU and SIGVTALRM for now. 197*6b384f39SPeter Avalos */ 198*6b384f39SPeter Avalos sigemptyset(&sa.sa_mask); 199*6b384f39SPeter Avalos sa.sa_flags = 0; /* don't restart system calls */ 200*6b384f39SPeter Avalos sa.sa_handler = handler; 201*6b384f39SPeter Avalos (void)sigaction(SIGALRM, &sa, &savealrm); 202*6b384f39SPeter Avalos (void)sigaction(SIGHUP, &sa, &savehup); 203*6b384f39SPeter Avalos (void)sigaction(SIGINT, &sa, &saveint); 204*6b384f39SPeter Avalos (void)sigaction(SIGPIPE, &sa, &savepipe); 205*6b384f39SPeter Avalos (void)sigaction(SIGQUIT, &sa, &savequit); 206*6b384f39SPeter Avalos (void)sigaction(SIGTERM, &sa, &saveterm); 207*6b384f39SPeter Avalos (void)sigaction(SIGTSTP, &sa, &savetstp); 208*6b384f39SPeter Avalos (void)sigaction(SIGTTIN, &sa, &savettin); 209*6b384f39SPeter Avalos (void)sigaction(SIGTTOU, &sa, &savettou); 210*6b384f39SPeter Avalos 211*6b384f39SPeter Avalos /* Turn off echo if possible. */ 212*6b384f39SPeter Avalos if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) { 213*6b384f39SPeter Avalos memcpy(&term, &oterm, sizeof(term)); 214*6b384f39SPeter Avalos if (!(flags & RPP_ECHO_ON)) 215*6b384f39SPeter Avalos term.c_lflag &= ~(ECHO | ECHONL); 216*6b384f39SPeter Avalos #ifdef VSTATUS 217*6b384f39SPeter Avalos if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) 218*6b384f39SPeter Avalos term.c_cc[VSTATUS] = _POSIX_VDISABLE; 219*6b384f39SPeter Avalos #endif 220*6b384f39SPeter Avalos (void)tcsetattr(input, _T_FLUSH, &term); 221*6b384f39SPeter Avalos } else { 222*6b384f39SPeter Avalos memset(&term, 0, sizeof(term)); 223*6b384f39SPeter Avalos term.c_lflag |= ECHO; 224*6b384f39SPeter Avalos memset(&oterm, 0, sizeof(oterm)); 225*6b384f39SPeter Avalos oterm.c_lflag |= ECHO; 226*6b384f39SPeter Avalos } 227*6b384f39SPeter Avalos 228*6b384f39SPeter Avalos /* No I/O if we are already backgrounded. */ 229*6b384f39SPeter Avalos if (signo[SIGTTOU] != 1 && signo[SIGTTIN] != 1) { 230*6b384f39SPeter Avalos if (!(flags & RPP_STDIN)) { 231*6b384f39SPeter Avalos int r = write(output, prompt, strlen(prompt)); 232*6b384f39SPeter Avalos (void)r; 233*6b384f39SPeter Avalos } 234*6b384f39SPeter Avalos end = buf + bufsiz - 1; 235*6b384f39SPeter Avalos p = buf; 236*6b384f39SPeter Avalos while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') { 237*6b384f39SPeter Avalos if (p < end) { 238*6b384f39SPeter Avalos if ((flags & RPP_SEVENBIT)) 239*6b384f39SPeter Avalos ch &= 0x7f; 240*6b384f39SPeter Avalos if (isalpha(ch)) { 241*6b384f39SPeter Avalos if ((flags & RPP_FORCELOWER)) 242*6b384f39SPeter Avalos ch = (char)tolower(ch); 243*6b384f39SPeter Avalos if ((flags & RPP_FORCEUPPER)) 244*6b384f39SPeter Avalos ch = (char)toupper(ch); 245*6b384f39SPeter Avalos } 246*6b384f39SPeter Avalos *p++ = ch; 247*6b384f39SPeter Avalos } 248*6b384f39SPeter Avalos } 249*6b384f39SPeter Avalos *p = '\0'; 250*6b384f39SPeter Avalos save_errno = errno; 251*6b384f39SPeter Avalos if (!(term.c_lflag & ECHO)) { 252*6b384f39SPeter Avalos int r = write(output, "\n", 1); 253*6b384f39SPeter Avalos (void)r; 254*6b384f39SPeter Avalos } 255*6b384f39SPeter Avalos } 256*6b384f39SPeter Avalos 257*6b384f39SPeter Avalos /* Restore old terminal settings and signals. */ 258*6b384f39SPeter Avalos if (memcmp(&term, &oterm, sizeof(term)) != 0) { 259*6b384f39SPeter Avalos while (tcsetattr(input, _T_FLUSH, &oterm) == -1 && 260*6b384f39SPeter Avalos errno == EINTR) 261*6b384f39SPeter Avalos continue; 262*6b384f39SPeter Avalos } 263*6b384f39SPeter Avalos (void)sigaction(SIGALRM, &savealrm, NULL); 264*6b384f39SPeter Avalos (void)sigaction(SIGHUP, &savehup, NULL); 265*6b384f39SPeter Avalos (void)sigaction(SIGINT, &saveint, NULL); 266*6b384f39SPeter Avalos (void)sigaction(SIGQUIT, &savequit, NULL); 267*6b384f39SPeter Avalos (void)sigaction(SIGPIPE, &savepipe, NULL); 268*6b384f39SPeter Avalos (void)sigaction(SIGTERM, &saveterm, NULL); 269*6b384f39SPeter Avalos (void)sigaction(SIGTSTP, &savetstp, NULL); 270*6b384f39SPeter Avalos (void)sigaction(SIGTTIN, &savettin, NULL); 271*6b384f39SPeter Avalos (void)sigaction(SIGTTOU, &savettou, NULL); 272*6b384f39SPeter Avalos if (input != STDIN_FILENO) 273*6b384f39SPeter Avalos (void)close(input); 274*6b384f39SPeter Avalos 275*6b384f39SPeter Avalos /* 276*6b384f39SPeter Avalos * If we were interrupted by a signal, resend it to ourselves 277*6b384f39SPeter Avalos * now that we have restored the signal handlers. 278*6b384f39SPeter Avalos */ 279*6b384f39SPeter Avalos for (i = 0; i < SIGRTMAX; i++) { 280*6b384f39SPeter Avalos if (signo[i]) { 281*6b384f39SPeter Avalos kill(getpid(), i); 282*6b384f39SPeter Avalos switch (i) { 283*6b384f39SPeter Avalos case SIGTSTP: 284*6b384f39SPeter Avalos case SIGTTIN: 285*6b384f39SPeter Avalos case SIGTTOU: 286*6b384f39SPeter Avalos need_restart = 1; 287*6b384f39SPeter Avalos } 288*6b384f39SPeter Avalos } 289*6b384f39SPeter Avalos } 290*6b384f39SPeter Avalos if (need_restart) 291*6b384f39SPeter Avalos goto restart; 292*6b384f39SPeter Avalos 293*6b384f39SPeter Avalos if (save_errno) 294*6b384f39SPeter Avalos errno = save_errno; 295*6b384f39SPeter Avalos return(nr == -1 ? NULL : buf); 296*6b384f39SPeter Avalos } 297*6b384f39SPeter Avalos #endif /* _WIN32 && !__CYGWIN__ */ 298*6b384f39SPeter Avalos #endif /* HAVE_READPASSPHRASE */ 299*6b384f39SPeter Avalos 300*6b384f39SPeter Avalos char * 301*6b384f39SPeter Avalos lafe_readpassphrase(const char *prompt, char *buf, size_t bufsiz) 302*6b384f39SPeter Avalos { 303*6b384f39SPeter Avalos char *p; 304*6b384f39SPeter Avalos 305*6b384f39SPeter Avalos p = readpassphrase(prompt, buf, bufsiz, RPP_ECHO_OFF); 306*6b384f39SPeter Avalos if (p == NULL) { 307*6b384f39SPeter Avalos switch (errno) { 308*6b384f39SPeter Avalos case EINTR: 309*6b384f39SPeter Avalos break; 310*6b384f39SPeter Avalos default: 311*6b384f39SPeter Avalos lafe_errc(1, errno, "Couldn't read passphrase"); 312*6b384f39SPeter Avalos break; 313*6b384f39SPeter Avalos } 314*6b384f39SPeter Avalos } 315*6b384f39SPeter Avalos return (p); 316*6b384f39SPeter Avalos } 317*6b384f39SPeter Avalos 318