1299425Smm/*- 2299425Smm * Copyright (c) 2014 Michihiro NAKAJIMA 3299425Smm * All rights reserved. 4299425Smm * 5299425Smm * Redistribution and use in source and binary forms, with or without 6299425Smm * modification, are permitted provided that the following conditions 7299425Smm * are met: 8299425Smm * 1. Redistributions of source code must retain the above copyright 9299425Smm * notice, this list of conditions and the following disclaimer 10299425Smm * in this position and unchanged. 11299425Smm * 2. Redistributions in binary form must reproduce the above copyright 12299425Smm * notice, this list of conditions and the following disclaimer in the 13299425Smm * documentation and/or other materials provided with the distribution. 14299425Smm * 15299425Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16299425Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17299425Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18299425Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19299425Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20299425Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21299425Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22299425Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23299425Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24299425Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25299425Smm */ 26349524Smm/* $OpenBSD: readpassphrase.c,v 1.27 2019/01/25 00:19:25 millert Exp $ */ 27349524Smm 28299425Smm/* 29349524Smm * Copyright (c) 2000-2002, 2007, 2010 30349524Smm * Todd C. Miller <millert@openbsd.org> 31299425Smm * 32299425Smm * Permission to use, copy, modify, and distribute this software for any 33299425Smm * purpose with or without fee is hereby granted, provided that the above 34299425Smm * copyright notice and this permission notice appear in all copies. 35299425Smm * 36299425Smm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 37299425Smm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 38299425Smm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 39299425Smm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 40299425Smm * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 41299425Smm * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 42299425Smm * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 43299425Smm * 44299425Smm * Sponsored in part by the Defense Advanced Research Projects 45299425Smm * Agency (DARPA) and Air Force Research Laboratory, Air Force 46299425Smm * Materiel Command, USAF, under agreement number F39502-99-1-0512. 47299425Smm */ 48299425Smm 49299425Smm/* OPENBSD ORIGINAL: lib/libc/gen/readpassphrase.c */ 50299425Smm 51299425Smm 52299425Smm#include "lafe_platform.h" 53299425Smm__FBSDID("$FreeBSD: stable/11/contrib/libarchive/libarchive_fe/passphrase.c 349524 2019-06-28 22:33:44Z mm $"); 54299425Smm 55299425Smm#include <errno.h> 56299425Smm#ifdef HAVE_STDLIB_H 57299425Smm#include <stdlib.h> 58299425Smm#endif 59299425Smm#ifdef HAVE_UNISTD_H 60299425Smm#include <unistd.h> 61299425Smm#endif 62299425Smm#ifdef HAVE_READPASSPHRASE_H 63299425Smm#include <readpassphrase.h> 64299425Smm#endif 65299425Smm 66299425Smm#include "err.h" 67299425Smm#include "passphrase.h" 68299425Smm 69299425Smm#ifndef HAVE_READPASSPHRASE 70299425Smm 71299425Smm#define RPP_ECHO_OFF 0x00 /* Turn off echo (default). */ 72299425Smm#define RPP_ECHO_ON 0x01 /* Leave echo on. */ 73299425Smm#define RPP_REQUIRE_TTY 0x02 /* Fail if there is no tty. */ 74299425Smm#define RPP_FORCELOWER 0x04 /* Force input to lower case. */ 75299425Smm#define RPP_FORCEUPPER 0x08 /* Force input to upper case. */ 76299425Smm#define RPP_SEVENBIT 0x10 /* Strip the high bit from input. */ 77299425Smm#define RPP_STDIN 0x20 /* Read from stdin, not /dev/tty */ 78299425Smm 79299425Smm 80299425Smm#if defined(_WIN32) && !defined(__CYGWIN__) 81299425Smm#include <windows.h> 82299425Smm 83299425Smmstatic char * 84299425Smmreadpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) 85299425Smm{ 86299425Smm HANDLE hStdin, hStdout; 87299425Smm DWORD mode, rbytes; 88299425Smm BOOL success; 89299425Smm 90299425Smm (void)flags; 91299425Smm 92299425Smm hStdin = GetStdHandle(STD_INPUT_HANDLE); 93299425Smm if (hStdin == INVALID_HANDLE_VALUE) 94299425Smm return (NULL); 95299425Smm hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 96299425Smm if (hStdout == INVALID_HANDLE_VALUE) 97299425Smm return (NULL); 98299425Smm 99299425Smm success = GetConsoleMode(hStdin, &mode); 100299425Smm if (!success) 101299425Smm return (NULL); 102299425Smm mode &= ~ENABLE_ECHO_INPUT; 103299425Smm mode |= ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; 104299425Smm success = SetConsoleMode(hStdin, mode); 105299425Smm if (!success) 106299425Smm return (NULL); 107299425Smm 108299425Smm success = WriteFile(hStdout, prompt, (DWORD)strlen(prompt), 109299425Smm NULL, NULL); 110299425Smm if (!success) 111299425Smm return (NULL); 112299425Smm success = ReadFile(hStdin, buf, (DWORD)bufsiz - 1, &rbytes, NULL); 113299425Smm if (!success) 114299425Smm return (NULL); 115299425Smm WriteFile(hStdout, "\r\n", 2, NULL, NULL); 116299425Smm buf[rbytes] = '\0'; 117299425Smm /* Remove trailing carriage return(s). */ 118299425Smm if (rbytes > 2 && buf[rbytes - 2] == '\r' && buf[rbytes - 1] == '\n') 119299425Smm buf[rbytes - 2] = '\0'; 120299425Smm 121299425Smm return (buf); 122299425Smm} 123299425Smm 124299425Smm#else /* _WIN32 && !__CYGWIN__ */ 125299425Smm 126302075Smm#include <assert.h> 127299425Smm#include <ctype.h> 128299425Smm#include <fcntl.h> 129299425Smm#ifdef HAVE_PATHS_H 130299425Smm#include <paths.h> 131299425Smm#endif 132302075Smm#include <signal.h> 133299425Smm#include <string.h> 134302075Smm#include <termios.h> 135299425Smm#include <unistd.h> 136299425Smm 137302294Smm#ifndef _PATH_TTY 138302294Smm#define _PATH_TTY "/dev/tty" 139302294Smm#endif 140302294Smm 141299425Smm#ifdef TCSASOFT 142299425Smm# define _T_FLUSH (TCSAFLUSH|TCSASOFT) 143299425Smm#else 144299425Smm# define _T_FLUSH (TCSAFLUSH) 145299425Smm#endif 146299425Smm 147299425Smm/* SunOS 4.x which lacks _POSIX_VDISABLE, but has VDISABLE */ 148299425Smm#if !defined(_POSIX_VDISABLE) && defined(VDISABLE) 149299425Smm# define _POSIX_VDISABLE VDISABLE 150299425Smm#endif 151299425Smm 152302075Smm#define M(a,b) (a > b ? a : b) 153302075Smm#define MAX_SIGNO M(M(M(SIGALRM, SIGHUP), \ 154302075Smm M(SIGINT, SIGPIPE)), \ 155302075Smm M(M(SIGQUIT, SIGTERM), \ 156302075Smm M(M(SIGTSTP, SIGTTIN), SIGTTOU))) 157299425Smm 158302075Smmstatic volatile sig_atomic_t signo[MAX_SIGNO + 1]; 159302075Smm 160299425Smmstatic void 161299425Smmhandler(int s) 162299425Smm{ 163302075Smm assert(s <= MAX_SIGNO); 164299425Smm signo[s] = 1; 165299425Smm} 166299425Smm 167299425Smmstatic char * 168299425Smmreadpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) 169299425Smm{ 170299425Smm ssize_t nr; 171299425Smm int input, output, save_errno, i, need_restart; 172299425Smm char ch, *p, *end; 173299425Smm struct termios term, oterm; 174299425Smm struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm; 175299425Smm struct sigaction savetstp, savettin, savettou, savepipe; 176299425Smm 177299425Smm /* I suppose we could alloc on demand in this case (XXX). */ 178299425Smm if (bufsiz == 0) { 179299425Smm errno = EINVAL; 180299425Smm return(NULL); 181299425Smm } 182299425Smm 183299425Smmrestart: 184302075Smm for (i = 0; i <= MAX_SIGNO; i++) 185299425Smm signo[i] = 0; 186299425Smm nr = -1; 187299425Smm save_errno = 0; 188299425Smm need_restart = 0; 189299425Smm /* 190299425Smm * Read and write to /dev/tty if available. If not, read from 191299425Smm * stdin and write to stderr unless a tty is required. 192299425Smm */ 193299425Smm if ((flags & RPP_STDIN) || 194299425Smm (input = output = open(_PATH_TTY, O_RDWR)) == -1) { 195299425Smm if (flags & RPP_REQUIRE_TTY) { 196299425Smm errno = ENOTTY; 197299425Smm return(NULL); 198299425Smm } 199299425Smm input = STDIN_FILENO; 200299425Smm output = STDERR_FILENO; 201299425Smm } 202299425Smm 203299425Smm /* 204349524Smm * Turn off echo if possible. 205349524Smm * If we are using a tty but are not the foreground pgrp this will 206349524Smm * generate SIGTTOU, so do it *before* installing the signal handlers. 207349524Smm */ 208349524Smm if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) { 209349524Smm memcpy(&term, &oterm, sizeof(term)); 210349524Smm if (!(flags & RPP_ECHO_ON)) 211349524Smm term.c_lflag &= ~(ECHO | ECHONL); 212349524Smm#ifdef VSTATUS 213349524Smm if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) 214349524Smm term.c_cc[VSTATUS] = _POSIX_VDISABLE; 215349524Smm#endif 216349524Smm (void)tcsetattr(input, _T_FLUSH, &term); 217349524Smm } else { 218349524Smm memset(&term, 0, sizeof(term)); 219349524Smm term.c_lflag |= ECHO; 220349524Smm memset(&oterm, 0, sizeof(oterm)); 221349524Smm oterm.c_lflag |= ECHO; 222349524Smm } 223349524Smm 224349524Smm /* 225299425Smm * Catch signals that would otherwise cause the user to end 226299425Smm * up with echo turned off in the shell. Don't worry about 227299425Smm * things like SIGXCPU and SIGVTALRM for now. 228299425Smm */ 229299425Smm sigemptyset(&sa.sa_mask); 230299425Smm sa.sa_flags = 0; /* don't restart system calls */ 231299425Smm sa.sa_handler = handler; 232302075Smm /* Keep this list in sync with MAX_SIGNO! */ 233299425Smm (void)sigaction(SIGALRM, &sa, &savealrm); 234299425Smm (void)sigaction(SIGHUP, &sa, &savehup); 235299425Smm (void)sigaction(SIGINT, &sa, &saveint); 236299425Smm (void)sigaction(SIGPIPE, &sa, &savepipe); 237299425Smm (void)sigaction(SIGQUIT, &sa, &savequit); 238299425Smm (void)sigaction(SIGTERM, &sa, &saveterm); 239299425Smm (void)sigaction(SIGTSTP, &sa, &savetstp); 240299425Smm (void)sigaction(SIGTTIN, &sa, &savettin); 241299425Smm (void)sigaction(SIGTTOU, &sa, &savettou); 242299425Smm 243349524Smm if (!(flags & RPP_STDIN)) { 244349524Smm int r = write(output, prompt, strlen(prompt)); 245349524Smm (void)r; 246299425Smm } 247349524Smm end = buf + bufsiz - 1; 248349524Smm p = buf; 249349524Smm while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') { 250349524Smm if (p < end) { 251349524Smm if ((flags & RPP_SEVENBIT)) 252349524Smm ch &= 0x7f; 253349524Smm if (isalpha((unsigned char)ch)) { 254349524Smm if ((flags & RPP_FORCELOWER)) 255349524Smm ch = (char)tolower((unsigned char)ch); 256349524Smm if ((flags & RPP_FORCEUPPER)) 257349524Smm ch = (char)toupper((unsigned char)ch); 258299425Smm } 259349524Smm *p++ = ch; 260299425Smm } 261299425Smm } 262349524Smm *p = '\0'; 263349524Smm save_errno = errno; 264349524Smm if (!(term.c_lflag & ECHO)) { 265349524Smm int r = write(output, "\n", 1); 266349524Smm (void)r; 267349524Smm } 268299425Smm 269299425Smm /* Restore old terminal settings and signals. */ 270299425Smm if (memcmp(&term, &oterm, sizeof(term)) != 0) { 271349524Smm const int sigttou = signo[SIGTTOU]; 272349524Smm 273349524Smm /* Ignore SIGTTOU generated when we are not the fg pgrp. */ 274299425Smm while (tcsetattr(input, _T_FLUSH, &oterm) == -1 && 275349524Smm errno == EINTR && !signo[SIGTTOU]) 276299425Smm continue; 277349524Smm signo[SIGTTOU] = sigttou; 278299425Smm } 279299425Smm (void)sigaction(SIGALRM, &savealrm, NULL); 280299425Smm (void)sigaction(SIGHUP, &savehup, NULL); 281299425Smm (void)sigaction(SIGINT, &saveint, NULL); 282299425Smm (void)sigaction(SIGQUIT, &savequit, NULL); 283299425Smm (void)sigaction(SIGPIPE, &savepipe, NULL); 284299425Smm (void)sigaction(SIGTERM, &saveterm, NULL); 285299425Smm (void)sigaction(SIGTSTP, &savetstp, NULL); 286299425Smm (void)sigaction(SIGTTIN, &savettin, NULL); 287299425Smm (void)sigaction(SIGTTOU, &savettou, NULL); 288299425Smm if (input != STDIN_FILENO) 289299425Smm (void)close(input); 290299425Smm 291299425Smm /* 292299425Smm * If we were interrupted by a signal, resend it to ourselves 293299425Smm * now that we have restored the signal handlers. 294299425Smm */ 295302075Smm for (i = 0; i <= MAX_SIGNO; i++) { 296299425Smm if (signo[i]) { 297299425Smm kill(getpid(), i); 298299425Smm switch (i) { 299299425Smm case SIGTSTP: 300299425Smm case SIGTTIN: 301299425Smm case SIGTTOU: 302299425Smm need_restart = 1; 303299425Smm } 304299425Smm } 305299425Smm } 306299425Smm if (need_restart) 307299425Smm goto restart; 308299425Smm 309299425Smm if (save_errno) 310299425Smm errno = save_errno; 311299425Smm return(nr == -1 ? NULL : buf); 312299425Smm} 313299425Smm#endif /* _WIN32 && !__CYGWIN__ */ 314299425Smm#endif /* HAVE_READPASSPHRASE */ 315299425Smm 316299425Smmchar * 317299425Smmlafe_readpassphrase(const char *prompt, char *buf, size_t bufsiz) 318299425Smm{ 319299425Smm char *p; 320299425Smm 321299425Smm p = readpassphrase(prompt, buf, bufsiz, RPP_ECHO_OFF); 322299425Smm if (p == NULL) { 323299425Smm switch (errno) { 324299425Smm case EINTR: 325299425Smm break; 326299425Smm default: 327299425Smm lafe_errc(1, errno, "Couldn't read passphrase"); 328299425Smm break; 329299425Smm } 330299425Smm } 331299425Smm return (p); 332299425Smm} 333299425Smm 334