113d98e8cSBrian Feldman /* 213d98e8cSBrian Feldman * Copyright (c) 2000 Todd C. Miller <Todd.Miller@courtesan.com> 313d98e8cSBrian Feldman * All rights reserved. 413d98e8cSBrian Feldman * 513d98e8cSBrian Feldman * Redistribution and use in source and binary forms, with or without 613d98e8cSBrian Feldman * modification, are permitted provided that the following conditions 713d98e8cSBrian Feldman * are met: 813d98e8cSBrian Feldman * 1. Redistributions of source code must retain the above copyright 913d98e8cSBrian Feldman * notice, this list of conditions and the following disclaimer. 1013d98e8cSBrian Feldman * 2. Redistributions in binary form must reproduce the above copyright 1113d98e8cSBrian Feldman * notice, this list of conditions and the following disclaimer in the 1213d98e8cSBrian Feldman * documentation and/or other materials provided with the distribution. 1313d98e8cSBrian Feldman * 3. The name of the author may not be used to endorse or promote products 1413d98e8cSBrian Feldman * derived from this software without specific prior written permission. 1513d98e8cSBrian Feldman * 1613d98e8cSBrian Feldman * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 1713d98e8cSBrian Feldman * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 1813d98e8cSBrian Feldman * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 1913d98e8cSBrian Feldman * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 2013d98e8cSBrian Feldman * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2113d98e8cSBrian Feldman * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 2213d98e8cSBrian Feldman * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2313d98e8cSBrian Feldman * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2413d98e8cSBrian Feldman * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 2513d98e8cSBrian Feldman * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2613d98e8cSBrian Feldman */ 2713d98e8cSBrian Feldman 2813d98e8cSBrian Feldman #if defined(LIBC_SCCS) && !defined(lint) 2913d98e8cSBrian Feldman static const char rcsid[] = "$OpenBSD: readpassphrase.c,v 1.7 2001/08/07 19:34:11 millert Exp $"; 3013d98e8cSBrian Feldman #endif /* LIBC_SCCS and not lint */ 3113d98e8cSBrian Feldman #include <sys/cdefs.h> 3213d98e8cSBrian Feldman __FBSDID("$FreeBSD$"); 3313d98e8cSBrian Feldman 3413d98e8cSBrian Feldman #include <ctype.h> 3513d98e8cSBrian Feldman #include <errno.h> 3613d98e8cSBrian Feldman #include <fcntl.h> 3713d98e8cSBrian Feldman #include <paths.h> 3813d98e8cSBrian Feldman #include <pwd.h> 3913d98e8cSBrian Feldman #include <signal.h> 4013d98e8cSBrian Feldman #include <string.h> 4113d98e8cSBrian Feldman #include <termios.h> 4213d98e8cSBrian Feldman #include <unistd.h> 4313d98e8cSBrian Feldman #include <readpassphrase.h> 4413d98e8cSBrian Feldman 4513d98e8cSBrian Feldman char * 4613d98e8cSBrian Feldman readpassphrase(prompt, buf, bufsiz, flags) 4713d98e8cSBrian Feldman const char *prompt; 4813d98e8cSBrian Feldman char *buf; 4913d98e8cSBrian Feldman size_t bufsiz; 5013d98e8cSBrian Feldman int flags; 5113d98e8cSBrian Feldman { 5213d98e8cSBrian Feldman struct termios term, oterm; 5313d98e8cSBrian Feldman char ch, *p, *end; 5413d98e8cSBrian Feldman int input, output; 5513d98e8cSBrian Feldman sigset_t oset, nset; 5613d98e8cSBrian Feldman 5713d98e8cSBrian Feldman /* I suppose we could alloc on demand in this case (XXX). */ 5813d98e8cSBrian Feldman if (bufsiz == 0) { 5913d98e8cSBrian Feldman errno = EINVAL; 6013d98e8cSBrian Feldman return(NULL); 6113d98e8cSBrian Feldman } 6213d98e8cSBrian Feldman 6313d98e8cSBrian Feldman /* 6413d98e8cSBrian Feldman * Read and write to /dev/tty if available. If not, read from 6513d98e8cSBrian Feldman * stdin and write to stderr unless a tty is required. 6613d98e8cSBrian Feldman */ 6713d98e8cSBrian Feldman if ((input = output = open(_PATH_TTY, O_RDWR)) == -1) { 6813d98e8cSBrian Feldman if (flags & RPP_REQUIRE_TTY) { 6913d98e8cSBrian Feldman errno = ENOTTY; 7013d98e8cSBrian Feldman return(NULL); 7113d98e8cSBrian Feldman } 7213d98e8cSBrian Feldman input = STDIN_FILENO; 7313d98e8cSBrian Feldman output = STDERR_FILENO; 7413d98e8cSBrian Feldman } 7513d98e8cSBrian Feldman 7613d98e8cSBrian Feldman /* 7713d98e8cSBrian Feldman * We block SIGINT and SIGTSTP so the terminal is not left 7813d98e8cSBrian Feldman * in an inconsistent state (ie: no echo). It would probably 7913d98e8cSBrian Feldman * be better to simply catch these though. 8013d98e8cSBrian Feldman */ 8113d98e8cSBrian Feldman sigemptyset(&nset); 8213d98e8cSBrian Feldman sigaddset(&nset, SIGINT); 8313d98e8cSBrian Feldman sigaddset(&nset, SIGTSTP); 8413d98e8cSBrian Feldman (void)sigprocmask(SIG_BLOCK, &nset, &oset); 8513d98e8cSBrian Feldman 8613d98e8cSBrian Feldman /* Turn off echo if possible. */ 8713d98e8cSBrian Feldman if (tcgetattr(input, &oterm) == 0) { 8813d98e8cSBrian Feldman memcpy(&term, &oterm, sizeof(term)); 8913d98e8cSBrian Feldman if (!(flags & RPP_ECHO_ON) && (term.c_lflag & ECHO)) 9013d98e8cSBrian Feldman term.c_lflag &= ~ECHO; 9113d98e8cSBrian Feldman if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) 9213d98e8cSBrian Feldman term.c_cc[VSTATUS] = _POSIX_VDISABLE; 9313d98e8cSBrian Feldman (void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term); 9413d98e8cSBrian Feldman } else { 9513d98e8cSBrian Feldman memset(&term, 0, sizeof(term)); 9613d98e8cSBrian Feldman memset(&oterm, 0, sizeof(oterm)); 9713d98e8cSBrian Feldman } 9813d98e8cSBrian Feldman 9913d98e8cSBrian Feldman (void)write(output, prompt, strlen(prompt)); 10013d98e8cSBrian Feldman end = buf + bufsiz - 1; 10113d98e8cSBrian Feldman for (p = buf; read(input, &ch, 1) == 1 && ch != '\n' && ch != '\r';) { 10213d98e8cSBrian Feldman if (p < end) { 10313d98e8cSBrian Feldman if ((flags & RPP_SEVENBIT)) 10413d98e8cSBrian Feldman ch &= 0x7f; 10513d98e8cSBrian Feldman if (isalpha(ch)) { 10613d98e8cSBrian Feldman if ((flags & RPP_FORCELOWER)) 10713d98e8cSBrian Feldman ch = tolower(ch); 10813d98e8cSBrian Feldman if ((flags & RPP_FORCEUPPER)) 10913d98e8cSBrian Feldman ch = toupper(ch); 11013d98e8cSBrian Feldman } 11113d98e8cSBrian Feldman *p++ = ch; 11213d98e8cSBrian Feldman } 11313d98e8cSBrian Feldman } 11413d98e8cSBrian Feldman *p = '\0'; 11513d98e8cSBrian Feldman if (!(term.c_lflag & ECHO)) 11613d98e8cSBrian Feldman (void)write(output, "\n", 1); 11713d98e8cSBrian Feldman 11813d98e8cSBrian Feldman /* Restore old terminal settings and signal mask. */ 11913d98e8cSBrian Feldman if (memcmp(&term, &oterm, sizeof(term)) != 0) 12013d98e8cSBrian Feldman (void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm); 12113d98e8cSBrian Feldman (void)sigprocmask(SIG_SETMASK, &oset, NULL); 12213d98e8cSBrian Feldman if (input != STDIN_FILENO) 12313d98e8cSBrian Feldman (void)close(input); 12413d98e8cSBrian Feldman return(buf); 12513d98e8cSBrian Feldman } 12613d98e8cSBrian Feldman 12713d98e8cSBrian Feldman char * 12813d98e8cSBrian Feldman getpass(prompt) 12913d98e8cSBrian Feldman const char *prompt; 13013d98e8cSBrian Feldman { 13113d98e8cSBrian Feldman static char buf[_PASSWORD_LEN + 1]; 13213d98e8cSBrian Feldman 13313d98e8cSBrian Feldman return(readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF)); 13413d98e8cSBrian Feldman } 135