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