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 124f061a221SMartin 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 130f061a221SMartin Matuska #include <signal.h> 131cdf63a70SMartin Matuska #include <string.h> 132f061a221SMartin Matuska #include <termios.h> 133cdf63a70SMartin Matuska #include <unistd.h> 134cdf63a70SMartin Matuska 135*ae5876eaSMartin Matuska #ifndef _PATH_TTY 136*ae5876eaSMartin Matuska #define _PATH_TTY "/dev/tty" 137*ae5876eaSMartin Matuska #endif 138*ae5876eaSMartin Matuska 139cdf63a70SMartin Matuska #ifdef TCSASOFT 140cdf63a70SMartin Matuska # define _T_FLUSH (TCSAFLUSH|TCSASOFT) 141cdf63a70SMartin Matuska #else 142cdf63a70SMartin Matuska # define _T_FLUSH (TCSAFLUSH) 143cdf63a70SMartin Matuska #endif 144cdf63a70SMartin Matuska 145cdf63a70SMartin Matuska /* SunOS 4.x which lacks _POSIX_VDISABLE, but has VDISABLE */ 146cdf63a70SMartin Matuska #if !defined(_POSIX_VDISABLE) && defined(VDISABLE) 147cdf63a70SMartin Matuska # define _POSIX_VDISABLE VDISABLE 148cdf63a70SMartin Matuska #endif 149cdf63a70SMartin Matuska 150f061a221SMartin Matuska #define M(a,b) (a > b ? a : b) 151f061a221SMartin Matuska #define MAX_SIGNO M(M(M(SIGALRM, SIGHUP), \ 152f061a221SMartin Matuska M(SIGINT, SIGPIPE)), \ 153f061a221SMartin Matuska M(M(SIGQUIT, SIGTERM), \ 154f061a221SMartin Matuska M(M(SIGTSTP, SIGTTIN), SIGTTOU))) 155f061a221SMartin Matuska 156f061a221SMartin Matuska static volatile sig_atomic_t signo[MAX_SIGNO + 1]; 157cdf63a70SMartin Matuska 158cdf63a70SMartin Matuska static void 159cdf63a70SMartin Matuska handler(int s) 160cdf63a70SMartin Matuska { 161f061a221SMartin Matuska assert(s <= MAX_SIGNO); 162cdf63a70SMartin Matuska signo[s] = 1; 163cdf63a70SMartin Matuska } 164cdf63a70SMartin Matuska 165cdf63a70SMartin Matuska static char * 166cdf63a70SMartin Matuska readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) 167cdf63a70SMartin Matuska { 168cdf63a70SMartin Matuska ssize_t nr; 169cdf63a70SMartin Matuska int input, output, save_errno, i, need_restart; 170cdf63a70SMartin Matuska char ch, *p, *end; 171cdf63a70SMartin Matuska struct termios term, oterm; 172cdf63a70SMartin Matuska struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm; 173cdf63a70SMartin Matuska struct sigaction savetstp, savettin, savettou, savepipe; 174cdf63a70SMartin Matuska 175cdf63a70SMartin Matuska /* I suppose we could alloc on demand in this case (XXX). */ 176cdf63a70SMartin Matuska if (bufsiz == 0) { 177cdf63a70SMartin Matuska errno = EINVAL; 178cdf63a70SMartin Matuska return(NULL); 179cdf63a70SMartin Matuska } 180cdf63a70SMartin Matuska 181cdf63a70SMartin Matuska restart: 182f061a221SMartin Matuska for (i = 0; i <= MAX_SIGNO; i++) 183cdf63a70SMartin Matuska signo[i] = 0; 184cdf63a70SMartin Matuska nr = -1; 185cdf63a70SMartin Matuska save_errno = 0; 186cdf63a70SMartin Matuska need_restart = 0; 187cdf63a70SMartin Matuska /* 188cdf63a70SMartin Matuska * Read and write to /dev/tty if available. If not, read from 189cdf63a70SMartin Matuska * stdin and write to stderr unless a tty is required. 190cdf63a70SMartin Matuska */ 191cdf63a70SMartin Matuska if ((flags & RPP_STDIN) || 192cdf63a70SMartin Matuska (input = output = open(_PATH_TTY, O_RDWR)) == -1) { 193cdf63a70SMartin Matuska if (flags & RPP_REQUIRE_TTY) { 194cdf63a70SMartin Matuska errno = ENOTTY; 195cdf63a70SMartin Matuska return(NULL); 196cdf63a70SMartin Matuska } 197cdf63a70SMartin Matuska input = STDIN_FILENO; 198cdf63a70SMartin Matuska output = STDERR_FILENO; 199cdf63a70SMartin Matuska } 200cdf63a70SMartin Matuska 201cdf63a70SMartin Matuska /* 202cdf63a70SMartin Matuska * Catch signals that would otherwise cause the user to end 203cdf63a70SMartin Matuska * up with echo turned off in the shell. Don't worry about 204cdf63a70SMartin Matuska * things like SIGXCPU and SIGVTALRM for now. 205cdf63a70SMartin Matuska */ 206cdf63a70SMartin Matuska sigemptyset(&sa.sa_mask); 207cdf63a70SMartin Matuska sa.sa_flags = 0; /* don't restart system calls */ 208cdf63a70SMartin Matuska sa.sa_handler = handler; 209f061a221SMartin Matuska /* Keep this list in sync with MAX_SIGNO! */ 210cdf63a70SMartin Matuska (void)sigaction(SIGALRM, &sa, &savealrm); 211cdf63a70SMartin Matuska (void)sigaction(SIGHUP, &sa, &savehup); 212cdf63a70SMartin Matuska (void)sigaction(SIGINT, &sa, &saveint); 213cdf63a70SMartin Matuska (void)sigaction(SIGPIPE, &sa, &savepipe); 214cdf63a70SMartin Matuska (void)sigaction(SIGQUIT, &sa, &savequit); 215cdf63a70SMartin Matuska (void)sigaction(SIGTERM, &sa, &saveterm); 216cdf63a70SMartin Matuska (void)sigaction(SIGTSTP, &sa, &savetstp); 217cdf63a70SMartin Matuska (void)sigaction(SIGTTIN, &sa, &savettin); 218cdf63a70SMartin Matuska (void)sigaction(SIGTTOU, &sa, &savettou); 219cdf63a70SMartin Matuska 220cdf63a70SMartin Matuska /* Turn off echo if possible. */ 221cdf63a70SMartin Matuska if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) { 222cdf63a70SMartin Matuska memcpy(&term, &oterm, sizeof(term)); 223cdf63a70SMartin Matuska if (!(flags & RPP_ECHO_ON)) 224cdf63a70SMartin Matuska term.c_lflag &= ~(ECHO | ECHONL); 225cdf63a70SMartin Matuska #ifdef VSTATUS 226cdf63a70SMartin Matuska if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) 227cdf63a70SMartin Matuska term.c_cc[VSTATUS] = _POSIX_VDISABLE; 228cdf63a70SMartin Matuska #endif 229cdf63a70SMartin Matuska (void)tcsetattr(input, _T_FLUSH, &term); 230cdf63a70SMartin Matuska } else { 231cdf63a70SMartin Matuska memset(&term, 0, sizeof(term)); 232cdf63a70SMartin Matuska term.c_lflag |= ECHO; 233cdf63a70SMartin Matuska memset(&oterm, 0, sizeof(oterm)); 234cdf63a70SMartin Matuska oterm.c_lflag |= ECHO; 235cdf63a70SMartin Matuska } 236cdf63a70SMartin Matuska 237cdf63a70SMartin Matuska /* No I/O if we are already backgrounded. */ 238cdf63a70SMartin Matuska if (signo[SIGTTOU] != 1 && signo[SIGTTIN] != 1) { 239cdf63a70SMartin Matuska if (!(flags & RPP_STDIN)) { 240cdf63a70SMartin Matuska int r = write(output, prompt, strlen(prompt)); 241cdf63a70SMartin Matuska (void)r; 242cdf63a70SMartin Matuska } 243cdf63a70SMartin Matuska end = buf + bufsiz - 1; 244cdf63a70SMartin Matuska p = buf; 245cdf63a70SMartin Matuska while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') { 246cdf63a70SMartin Matuska if (p < end) { 247cdf63a70SMartin Matuska if ((flags & RPP_SEVENBIT)) 248cdf63a70SMartin Matuska ch &= 0x7f; 249f061a221SMartin Matuska if (isalpha((unsigned char)ch)) { 250cdf63a70SMartin Matuska if ((flags & RPP_FORCELOWER)) 251f061a221SMartin Matuska ch = (char)tolower((unsigned char)ch); 252cdf63a70SMartin Matuska if ((flags & RPP_FORCEUPPER)) 253f061a221SMartin Matuska ch = (char)toupper((unsigned char)ch); 254cdf63a70SMartin Matuska } 255cdf63a70SMartin Matuska *p++ = ch; 256cdf63a70SMartin Matuska } 257cdf63a70SMartin Matuska } 258cdf63a70SMartin Matuska *p = '\0'; 259cdf63a70SMartin Matuska save_errno = errno; 260cdf63a70SMartin Matuska if (!(term.c_lflag & ECHO)) { 261cdf63a70SMartin Matuska int r = write(output, "\n", 1); 262cdf63a70SMartin Matuska (void)r; 263cdf63a70SMartin Matuska } 264cdf63a70SMartin Matuska } 265cdf63a70SMartin Matuska 266cdf63a70SMartin Matuska /* Restore old terminal settings and signals. */ 267cdf63a70SMartin Matuska if (memcmp(&term, &oterm, sizeof(term)) != 0) { 268cdf63a70SMartin Matuska while (tcsetattr(input, _T_FLUSH, &oterm) == -1 && 269cdf63a70SMartin Matuska errno == EINTR) 270cdf63a70SMartin Matuska continue; 271cdf63a70SMartin Matuska } 272cdf63a70SMartin Matuska (void)sigaction(SIGALRM, &savealrm, NULL); 273cdf63a70SMartin Matuska (void)sigaction(SIGHUP, &savehup, NULL); 274cdf63a70SMartin Matuska (void)sigaction(SIGINT, &saveint, NULL); 275cdf63a70SMartin Matuska (void)sigaction(SIGQUIT, &savequit, NULL); 276cdf63a70SMartin Matuska (void)sigaction(SIGPIPE, &savepipe, NULL); 277cdf63a70SMartin Matuska (void)sigaction(SIGTERM, &saveterm, NULL); 278cdf63a70SMartin Matuska (void)sigaction(SIGTSTP, &savetstp, NULL); 279cdf63a70SMartin Matuska (void)sigaction(SIGTTIN, &savettin, NULL); 280cdf63a70SMartin Matuska (void)sigaction(SIGTTOU, &savettou, NULL); 281cdf63a70SMartin Matuska if (input != STDIN_FILENO) 282cdf63a70SMartin Matuska (void)close(input); 283cdf63a70SMartin Matuska 284cdf63a70SMartin Matuska /* 285cdf63a70SMartin Matuska * If we were interrupted by a signal, resend it to ourselves 286cdf63a70SMartin Matuska * now that we have restored the signal handlers. 287cdf63a70SMartin Matuska */ 288f061a221SMartin Matuska for (i = 0; i <= MAX_SIGNO; i++) { 289cdf63a70SMartin Matuska if (signo[i]) { 290cdf63a70SMartin Matuska kill(getpid(), i); 291cdf63a70SMartin Matuska switch (i) { 292cdf63a70SMartin Matuska case SIGTSTP: 293cdf63a70SMartin Matuska case SIGTTIN: 294cdf63a70SMartin Matuska case SIGTTOU: 295cdf63a70SMartin Matuska need_restart = 1; 296cdf63a70SMartin Matuska } 297cdf63a70SMartin Matuska } 298cdf63a70SMartin Matuska } 299cdf63a70SMartin Matuska if (need_restart) 300cdf63a70SMartin Matuska goto restart; 301cdf63a70SMartin Matuska 302cdf63a70SMartin Matuska if (save_errno) 303cdf63a70SMartin Matuska errno = save_errno; 304cdf63a70SMartin Matuska return(nr == -1 ? NULL : buf); 305cdf63a70SMartin Matuska } 306cdf63a70SMartin Matuska #endif /* _WIN32 && !__CYGWIN__ */ 307cdf63a70SMartin Matuska #endif /* HAVE_READPASSPHRASE */ 308cdf63a70SMartin Matuska 309cdf63a70SMartin Matuska char * 310cdf63a70SMartin Matuska lafe_readpassphrase(const char *prompt, char *buf, size_t bufsiz) 311cdf63a70SMartin Matuska { 312cdf63a70SMartin Matuska char *p; 313cdf63a70SMartin Matuska 314cdf63a70SMartin Matuska p = readpassphrase(prompt, buf, bufsiz, RPP_ECHO_OFF); 315cdf63a70SMartin Matuska if (p == NULL) { 316cdf63a70SMartin Matuska switch (errno) { 317cdf63a70SMartin Matuska case EINTR: 318cdf63a70SMartin Matuska break; 319cdf63a70SMartin Matuska default: 320cdf63a70SMartin Matuska lafe_errc(1, errno, "Couldn't read passphrase"); 321cdf63a70SMartin Matuska break; 322cdf63a70SMartin Matuska } 323cdf63a70SMartin Matuska } 324cdf63a70SMartin Matuska return (p); 325cdf63a70SMartin Matuska } 326cdf63a70SMartin Matuska 327