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