1215236Sdelphij/* $OpenBSD: readpassphrase.c,v 1.23 2010/05/14 13:30:34 millert Exp $ */ 291913Sgreen 386669Sgreen/* 4215236Sdelphij * Copyright (c) 2000-2002, 2007, 2010 5215236Sdelphij * Todd C. Miller <Todd.Miller@courtesan.com> 686669Sgreen * 7215236Sdelphij * Permission to use, copy, modify, and distribute this software for any 8215236Sdelphij * purpose with or without fee is hereby granted, provided that the above 9215236Sdelphij * copyright notice and this permission notice appear in all copies. 1086669Sgreen * 11215236Sdelphij * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12215236Sdelphij * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13215236Sdelphij * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14215236Sdelphij * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15215236Sdelphij * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16215236Sdelphij * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17215236Sdelphij * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18215236Sdelphij * 19215236Sdelphij * Sponsored in part by the Defense Advanced Research Projects 20215236Sdelphij * Agency (DARPA) and Air Force Research Laboratory, Air Force 21215236Sdelphij * Materiel Command, USAF, under agreement number F39502-99-1-0512. 2286669Sgreen */ 2386669Sgreen 2486750Sfjoe#include <sys/cdefs.h> 2586669Sgreen__FBSDID("$FreeBSD$"); 2686669Sgreen 2786733Sgreen#include "namespace.h" 2886669Sgreen#include <ctype.h> 2986669Sgreen#include <errno.h> 3086669Sgreen#include <fcntl.h> 3186669Sgreen#include <paths.h> 3286669Sgreen#include <pwd.h> 3386669Sgreen#include <signal.h> 3486669Sgreen#include <string.h> 3586669Sgreen#include <termios.h> 3686669Sgreen#include <unistd.h> 3786669Sgreen#include <readpassphrase.h> 3886733Sgreen#include "un-namespace.h" 3986669Sgreen 40215236Sdelphijstatic volatile sig_atomic_t signo[NSIG]; 4191913Sgreen 4291913Sgreenstatic void handler(int); 4391913Sgreen 4486669Sgreenchar * 4591913Sgreenreadpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) 4686669Sgreen{ 4791913Sgreen ssize_t nr; 48215236Sdelphij int input, output, save_errno, i, need_restart; 4991913Sgreen char ch, *p, *end; 5086669Sgreen struct termios term, oterm; 51215236Sdelphij struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm; 52215236Sdelphij struct sigaction savetstp, savettin, savettou, savepipe; 5386669Sgreen 5486669Sgreen /* I suppose we could alloc on demand in this case (XXX). */ 5586669Sgreen if (bufsiz == 0) { 5686669Sgreen errno = EINVAL; 5786669Sgreen return(NULL); 5886669Sgreen } 5986669Sgreen 6091913Sgreenrestart: 61215236Sdelphij for (i = 0; i < NSIG; i++) 62215236Sdelphij signo[i] = 0; 63215236Sdelphij nr = -1; 64215236Sdelphij save_errno = 0; 65215236Sdelphij need_restart = 0; 6686669Sgreen /* 6786669Sgreen * Read and write to /dev/tty if available. If not, read from 6886669Sgreen * stdin and write to stderr unless a tty is required. 6986669Sgreen */ 70215236Sdelphij if ((flags & RPP_STDIN) || 71261813Sjilles (input = output = _open(_PATH_TTY, O_RDWR | O_CLOEXEC)) == -1) { 7286669Sgreen if (flags & RPP_REQUIRE_TTY) { 7386669Sgreen errno = ENOTTY; 7486669Sgreen return(NULL); 7586669Sgreen } 7686669Sgreen input = STDIN_FILENO; 7786669Sgreen output = STDERR_FILENO; 7886669Sgreen } 7986669Sgreen 8086669Sgreen /* 81215236Sdelphij * Turn off echo if possible. 82215236Sdelphij * If we are using a tty but are not the foreground pgrp this will 83215236Sdelphij * generate SIGTTOU, so do it *before* installing the signal handlers. 84215236Sdelphij */ 85215236Sdelphij if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) { 86215236Sdelphij memcpy(&term, &oterm, sizeof(term)); 87215236Sdelphij if (!(flags & RPP_ECHO_ON)) 88215236Sdelphij term.c_lflag &= ~(ECHO | ECHONL); 89215236Sdelphij if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) 90215236Sdelphij term.c_cc[VSTATUS] = _POSIX_VDISABLE; 91215236Sdelphij (void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term); 92215236Sdelphij } else { 93215236Sdelphij memset(&term, 0, sizeof(term)); 94215236Sdelphij term.c_lflag |= ECHO; 95215236Sdelphij memset(&oterm, 0, sizeof(oterm)); 96215236Sdelphij oterm.c_lflag |= ECHO; 97215236Sdelphij } 98215236Sdelphij 99215236Sdelphij /* 10091913Sgreen * Catch signals that would otherwise cause the user to end 10191913Sgreen * up with echo turned off in the shell. Don't worry about 102215236Sdelphij * things like SIGXCPU and SIGVTALRM for now. 10386669Sgreen */ 10491913Sgreen sigemptyset(&sa.sa_mask); 10591913Sgreen sa.sa_flags = 0; /* don't restart system calls */ 10691913Sgreen sa.sa_handler = handler; 107215236Sdelphij (void)_sigaction(SIGALRM, &sa, &savealrm); 108215236Sdelphij (void)_sigaction(SIGHUP, &sa, &savehup); 10991913Sgreen (void)_sigaction(SIGINT, &sa, &saveint); 110215236Sdelphij (void)_sigaction(SIGPIPE, &sa, &savepipe); 11191913Sgreen (void)_sigaction(SIGQUIT, &sa, &savequit); 11291913Sgreen (void)_sigaction(SIGTERM, &sa, &saveterm); 11391913Sgreen (void)_sigaction(SIGTSTP, &sa, &savetstp); 11491913Sgreen (void)_sigaction(SIGTTIN, &sa, &savettin); 11591913Sgreen (void)_sigaction(SIGTTOU, &sa, &savettou); 11686669Sgreen 117215236Sdelphij if (!(flags & RPP_STDIN)) 118215236Sdelphij (void)_write(output, prompt, strlen(prompt)); 11986669Sgreen end = buf + bufsiz - 1; 120215236Sdelphij p = buf; 121215236Sdelphij while ((nr = _read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') { 12286669Sgreen if (p < end) { 12386669Sgreen if ((flags & RPP_SEVENBIT)) 12486669Sgreen ch &= 0x7f; 12586669Sgreen if (isalpha(ch)) { 12686669Sgreen if ((flags & RPP_FORCELOWER)) 127215236Sdelphij ch = (char)tolower(ch); 12886669Sgreen if ((flags & RPP_FORCEUPPER)) 129215236Sdelphij ch = (char)toupper(ch); 13086669Sgreen } 13186669Sgreen *p++ = ch; 13286669Sgreen } 13386669Sgreen } 13486669Sgreen *p = '\0'; 13591913Sgreen save_errno = errno; 13686669Sgreen if (!(term.c_lflag & ECHO)) 13786732Sgreen (void)_write(output, "\n", 1); 13886669Sgreen 13991913Sgreen /* Restore old terminal settings and signals. */ 140215236Sdelphij if (memcmp(&term, &oterm, sizeof(term)) != 0) { 141215236Sdelphij while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 && 142215236Sdelphij errno == EINTR && !signo[SIGTTOU]) 143215236Sdelphij continue; 144215236Sdelphij } 145215236Sdelphij (void)_sigaction(SIGALRM, &savealrm, NULL); 146215236Sdelphij (void)_sigaction(SIGHUP, &savehup, NULL); 14791913Sgreen (void)_sigaction(SIGINT, &saveint, NULL); 14891913Sgreen (void)_sigaction(SIGQUIT, &savequit, NULL); 149215236Sdelphij (void)_sigaction(SIGPIPE, &savepipe, NULL); 15091913Sgreen (void)_sigaction(SIGTERM, &saveterm, NULL); 15191913Sgreen (void)_sigaction(SIGTSTP, &savetstp, NULL); 15291913Sgreen (void)_sigaction(SIGTTIN, &savettin, NULL); 15391913Sgreen (void)_sigaction(SIGTTOU, &savettou, NULL); 15486669Sgreen if (input != STDIN_FILENO) 15586732Sgreen (void)_close(input); 15691913Sgreen 15791913Sgreen /* 15891913Sgreen * If we were interrupted by a signal, resend it to ourselves 15991913Sgreen * now that we have restored the signal handlers. 16091913Sgreen */ 161215236Sdelphij for (i = 0; i < NSIG; i++) { 162215236Sdelphij if (signo[i]) { 163215236Sdelphij kill(getpid(), i); 164215236Sdelphij switch (i) { 165215236Sdelphij case SIGTSTP: 166215236Sdelphij case SIGTTIN: 167215236Sdelphij case SIGTTOU: 168215236Sdelphij need_restart = 1; 169215236Sdelphij } 17091913Sgreen } 17191913Sgreen } 172215236Sdelphij if (need_restart) 173215236Sdelphij goto restart; 17491913Sgreen 175215236Sdelphij if (save_errno) 176215236Sdelphij errno = save_errno; 17791913Sgreen return(nr == -1 ? NULL : buf); 17886669Sgreen} 17986669Sgreen 18086669Sgreenchar * 18191913Sgreengetpass(const char *prompt) 18286669Sgreen{ 18386669Sgreen static char buf[_PASSWORD_LEN + 1]; 18486669Sgreen 18591922Sgreen if (readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF) == NULL) 18691922Sgreen buf[0] = '\0'; 18791922Sgreen return(buf); 18886669Sgreen} 18991913Sgreen 19091913Sgreenstatic void handler(int s) 19191913Sgreen{ 19291913Sgreen 193215236Sdelphij signo[s] = 1; 19491913Sgreen} 195