1*f29af3b2SXin LI /* $OpenBSD: readpassphrase.c,v 1.23 2010/05/14 13:30:34 millert Exp $ */ 2a7a8a766SBrian Feldman 313d98e8cSBrian Feldman /* 4*f29af3b2SXin LI * Copyright (c) 2000-2002, 2007, 2010 5*f29af3b2SXin LI * Todd C. Miller <Todd.Miller@courtesan.com> 613d98e8cSBrian Feldman * 7*f29af3b2SXin LI * Permission to use, copy, modify, and distribute this software for any 8*f29af3b2SXin LI * purpose with or without fee is hereby granted, provided that the above 9*f29af3b2SXin LI * copyright notice and this permission notice appear in all copies. 1013d98e8cSBrian Feldman * 11*f29af3b2SXin LI * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12*f29af3b2SXin LI * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13*f29af3b2SXin LI * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14*f29af3b2SXin LI * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15*f29af3b2SXin LI * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16*f29af3b2SXin LI * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17*f29af3b2SXin LI * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18*f29af3b2SXin LI * 19*f29af3b2SXin LI * Sponsored in part by the Defense Advanced Research Projects 20*f29af3b2SXin LI * Agency (DARPA) and Air Force Research Laboratory, Air Force 21*f29af3b2SXin LI * Materiel Command, USAF, under agreement number F39502-99-1-0512. 2213d98e8cSBrian Feldman */ 2313d98e8cSBrian Feldman 241e450813SMax Khon #include <sys/cdefs.h> 2513d98e8cSBrian Feldman __FBSDID("$FreeBSD$"); 2613d98e8cSBrian Feldman 2770d2a9e1SBrian Feldman #include "namespace.h" 2813d98e8cSBrian Feldman #include <ctype.h> 2913d98e8cSBrian Feldman #include <errno.h> 3013d98e8cSBrian Feldman #include <fcntl.h> 3113d98e8cSBrian Feldman #include <paths.h> 3213d98e8cSBrian Feldman #include <pwd.h> 3313d98e8cSBrian Feldman #include <signal.h> 3413d98e8cSBrian Feldman #include <string.h> 3513d98e8cSBrian Feldman #include <termios.h> 3613d98e8cSBrian Feldman #include <unistd.h> 3713d98e8cSBrian Feldman #include <readpassphrase.h> 3870d2a9e1SBrian Feldman #include "un-namespace.h" 3913d98e8cSBrian Feldman 40*f29af3b2SXin LI static volatile sig_atomic_t signo[NSIG]; 41a7a8a766SBrian Feldman 42a7a8a766SBrian Feldman static void handler(int); 43a7a8a766SBrian Feldman 4413d98e8cSBrian Feldman char * 45a7a8a766SBrian Feldman readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) 4613d98e8cSBrian Feldman { 47a7a8a766SBrian Feldman ssize_t nr; 48*f29af3b2SXin LI int input, output, save_errno, i, need_restart; 4913d98e8cSBrian Feldman char ch, *p, *end; 50a7a8a766SBrian Feldman struct termios term, oterm; 51*f29af3b2SXin LI struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm; 52*f29af3b2SXin LI struct sigaction savetstp, savettin, savettou, savepipe; 5313d98e8cSBrian Feldman 5413d98e8cSBrian Feldman /* I suppose we could alloc on demand in this case (XXX). */ 5513d98e8cSBrian Feldman if (bufsiz == 0) { 5613d98e8cSBrian Feldman errno = EINVAL; 5713d98e8cSBrian Feldman return(NULL); 5813d98e8cSBrian Feldman } 5913d98e8cSBrian Feldman 60a7a8a766SBrian Feldman restart: 61*f29af3b2SXin LI for (i = 0; i < NSIG; i++) 62*f29af3b2SXin LI signo[i] = 0; 63*f29af3b2SXin LI nr = -1; 64*f29af3b2SXin LI save_errno = 0; 65*f29af3b2SXin LI need_restart = 0; 6613d98e8cSBrian Feldman /* 6713d98e8cSBrian Feldman * Read and write to /dev/tty if available. If not, read from 6813d98e8cSBrian Feldman * stdin and write to stderr unless a tty is required. 6913d98e8cSBrian Feldman */ 70*f29af3b2SXin LI if ((flags & RPP_STDIN) || 71*f29af3b2SXin LI (input = output = _open(_PATH_TTY, O_RDWR)) == -1) { 7213d98e8cSBrian Feldman if (flags & RPP_REQUIRE_TTY) { 7313d98e8cSBrian Feldman errno = ENOTTY; 7413d98e8cSBrian Feldman return(NULL); 7513d98e8cSBrian Feldman } 7613d98e8cSBrian Feldman input = STDIN_FILENO; 7713d98e8cSBrian Feldman output = STDERR_FILENO; 7813d98e8cSBrian Feldman } 7913d98e8cSBrian Feldman 8013d98e8cSBrian Feldman /* 81*f29af3b2SXin LI * Turn off echo if possible. 82*f29af3b2SXin LI * If we are using a tty but are not the foreground pgrp this will 83*f29af3b2SXin LI * generate SIGTTOU, so do it *before* installing the signal handlers. 8413d98e8cSBrian Feldman */ 85*f29af3b2SXin LI if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) { 8613d98e8cSBrian Feldman memcpy(&term, &oterm, sizeof(term)); 87a7a8a766SBrian Feldman if (!(flags & RPP_ECHO_ON)) 88a7a8a766SBrian Feldman term.c_lflag &= ~(ECHO | ECHONL); 8913d98e8cSBrian Feldman if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) 9013d98e8cSBrian Feldman term.c_cc[VSTATUS] = _POSIX_VDISABLE; 9113d98e8cSBrian Feldman (void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term); 9213d98e8cSBrian Feldman } else { 9313d98e8cSBrian Feldman memset(&term, 0, sizeof(term)); 94*f29af3b2SXin LI term.c_lflag |= ECHO; 9513d98e8cSBrian Feldman memset(&oterm, 0, sizeof(oterm)); 96*f29af3b2SXin LI oterm.c_lflag |= ECHO; 9713d98e8cSBrian Feldman } 9813d98e8cSBrian Feldman 99*f29af3b2SXin LI /* 100*f29af3b2SXin LI * Catch signals that would otherwise cause the user to end 101*f29af3b2SXin LI * up with echo turned off in the shell. Don't worry about 102*f29af3b2SXin LI * things like SIGXCPU and SIGVTALRM for now. 103*f29af3b2SXin LI */ 104*f29af3b2SXin LI sigemptyset(&sa.sa_mask); 105*f29af3b2SXin LI sa.sa_flags = 0; /* don't restart system calls */ 106*f29af3b2SXin LI sa.sa_handler = handler; 107*f29af3b2SXin LI (void)_sigaction(SIGALRM, &sa, &savealrm); 108*f29af3b2SXin LI (void)_sigaction(SIGHUP, &sa, &savehup); 109*f29af3b2SXin LI (void)_sigaction(SIGINT, &sa, &saveint); 110*f29af3b2SXin LI (void)_sigaction(SIGPIPE, &sa, &savepipe); 111*f29af3b2SXin LI (void)_sigaction(SIGQUIT, &sa, &savequit); 112*f29af3b2SXin LI (void)_sigaction(SIGTERM, &sa, &saveterm); 113*f29af3b2SXin LI (void)_sigaction(SIGTSTP, &sa, &savetstp); 114*f29af3b2SXin LI (void)_sigaction(SIGTTIN, &sa, &savettin); 115*f29af3b2SXin LI (void)_sigaction(SIGTTOU, &sa, &savettou); 116*f29af3b2SXin LI 117*f29af3b2SXin LI if (!(flags & RPP_STDIN)) 118a939ced8SBrian Feldman (void)_write(output, prompt, strlen(prompt)); 11913d98e8cSBrian Feldman end = buf + bufsiz - 1; 120*f29af3b2SXin LI p = buf; 121*f29af3b2SXin LI while ((nr = _read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') { 12213d98e8cSBrian Feldman if (p < end) { 12313d98e8cSBrian Feldman if ((flags & RPP_SEVENBIT)) 12413d98e8cSBrian Feldman ch &= 0x7f; 12513d98e8cSBrian Feldman if (isalpha(ch)) { 12613d98e8cSBrian Feldman if ((flags & RPP_FORCELOWER)) 127*f29af3b2SXin LI ch = (char)tolower(ch); 12813d98e8cSBrian Feldman if ((flags & RPP_FORCEUPPER)) 129*f29af3b2SXin LI ch = (char)toupper(ch); 13013d98e8cSBrian Feldman } 13113d98e8cSBrian Feldman *p++ = ch; 13213d98e8cSBrian Feldman } 13313d98e8cSBrian Feldman } 13413d98e8cSBrian Feldman *p = '\0'; 135a7a8a766SBrian Feldman save_errno = errno; 13613d98e8cSBrian Feldman if (!(term.c_lflag & ECHO)) 137a939ced8SBrian Feldman (void)_write(output, "\n", 1); 13813d98e8cSBrian Feldman 139a7a8a766SBrian Feldman /* Restore old terminal settings and signals. */ 140*f29af3b2SXin LI if (memcmp(&term, &oterm, sizeof(term)) != 0) { 141*f29af3b2SXin LI while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 && 142*f29af3b2SXin LI errno == EINTR && !signo[SIGTTOU]) 143*f29af3b2SXin LI continue; 144*f29af3b2SXin LI } 145*f29af3b2SXin LI (void)_sigaction(SIGALRM, &savealrm, NULL); 146a7a8a766SBrian Feldman (void)_sigaction(SIGHUP, &savehup, NULL); 147*f29af3b2SXin LI (void)_sigaction(SIGINT, &saveint, NULL); 148a7a8a766SBrian Feldman (void)_sigaction(SIGQUIT, &savequit, NULL); 149*f29af3b2SXin LI (void)_sigaction(SIGPIPE, &savepipe, NULL); 150a7a8a766SBrian Feldman (void)_sigaction(SIGTERM, &saveterm, NULL); 151a7a8a766SBrian Feldman (void)_sigaction(SIGTSTP, &savetstp, NULL); 152a7a8a766SBrian Feldman (void)_sigaction(SIGTTIN, &savettin, NULL); 153a7a8a766SBrian Feldman (void)_sigaction(SIGTTOU, &savettou, NULL); 15413d98e8cSBrian Feldman if (input != STDIN_FILENO) 155a939ced8SBrian Feldman (void)_close(input); 156a7a8a766SBrian Feldman 157a7a8a766SBrian Feldman /* 158a7a8a766SBrian Feldman * If we were interrupted by a signal, resend it to ourselves 159a7a8a766SBrian Feldman * now that we have restored the signal handlers. 160a7a8a766SBrian Feldman */ 161*f29af3b2SXin LI for (i = 0; i < NSIG; i++) { 162*f29af3b2SXin LI if (signo[i]) { 163*f29af3b2SXin LI kill(getpid(), i); 164*f29af3b2SXin LI switch (i) { 165a7a8a766SBrian Feldman case SIGTSTP: 166a7a8a766SBrian Feldman case SIGTTIN: 167a7a8a766SBrian Feldman case SIGTTOU: 168*f29af3b2SXin LI need_restart = 1; 169*f29af3b2SXin LI } 170*f29af3b2SXin LI } 171*f29af3b2SXin LI } 172*f29af3b2SXin LI if (need_restart) 173a7a8a766SBrian Feldman goto restart; 17413d98e8cSBrian Feldman 175*f29af3b2SXin LI if (save_errno) 176a7a8a766SBrian Feldman errno = save_errno; 177a7a8a766SBrian Feldman return(nr == -1 ? NULL : buf); 178a7a8a766SBrian Feldman } 179a7a8a766SBrian Feldman 18013d98e8cSBrian Feldman char * 181a7a8a766SBrian Feldman getpass(const char *prompt) 18213d98e8cSBrian Feldman { 18313d98e8cSBrian Feldman static char buf[_PASSWORD_LEN + 1]; 18413d98e8cSBrian Feldman 18544f7d6afSBrian Feldman if (readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF) == NULL) 18644f7d6afSBrian Feldman buf[0] = '\0'; 18744f7d6afSBrian Feldman return(buf); 18813d98e8cSBrian Feldman } 189a7a8a766SBrian Feldman 190a7a8a766SBrian Feldman static void handler(int s) 191a7a8a766SBrian Feldman { 192a7a8a766SBrian Feldman 193*f29af3b2SXin LI signo[s] = 1; 194a7a8a766SBrian Feldman } 195