1dad64c97SPedro F. Giffuni /* $OpenBSD: readpassphrase.c,v 1.24 2013/11/24 23:51:29 deraadt Exp $ */ 2a7a8a766SBrian Feldman 313d98e8cSBrian Feldman /* 4f29af3b2SXin LI * Copyright (c) 2000-2002, 2007, 2010 5f29af3b2SXin LI * Todd C. Miller <Todd.Miller@courtesan.com> 613d98e8cSBrian Feldman * 7f29af3b2SXin LI * Permission to use, copy, modify, and distribute this software for any 8f29af3b2SXin LI * purpose with or without fee is hereby granted, provided that the above 9f29af3b2SXin LI * copyright notice and this permission notice appear in all copies. 1013d98e8cSBrian Feldman * 11f29af3b2SXin LI * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12f29af3b2SXin LI * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13f29af3b2SXin LI * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14f29af3b2SXin LI * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15f29af3b2SXin LI * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16f29af3b2SXin LI * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17f29af3b2SXin LI * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18f29af3b2SXin LI * 19f29af3b2SXin LI * Sponsored in part by the Defense Advanced Research Projects 20f29af3b2SXin LI * Agency (DARPA) and Air Force Research Laboratory, Air Force 21f29af3b2SXin 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" 39bd6060a1SKonstantin Belousov #include "libc_private.h" 4013d98e8cSBrian Feldman 41f29af3b2SXin LI static volatile sig_atomic_t signo[NSIG]; 42a7a8a766SBrian Feldman 43a7a8a766SBrian Feldman static void handler(int); 44a7a8a766SBrian Feldman 4513d98e8cSBrian Feldman char * 46a7a8a766SBrian Feldman readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) 4713d98e8cSBrian Feldman { 48a7a8a766SBrian Feldman ssize_t nr; 49*18a2ccd2SMaxim Sobolev int input, output, save_errno, i, need_restart, input_is_tty; 5013d98e8cSBrian Feldman char ch, *p, *end; 51a7a8a766SBrian Feldman struct termios term, oterm; 52f29af3b2SXin LI struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm; 53f29af3b2SXin LI struct sigaction savetstp, savettin, savettou, savepipe; 5413d98e8cSBrian Feldman 5513d98e8cSBrian Feldman /* I suppose we could alloc on demand in this case (XXX). */ 5613d98e8cSBrian Feldman if (bufsiz == 0) { 5713d98e8cSBrian Feldman errno = EINVAL; 5813d98e8cSBrian Feldman return(NULL); 5913d98e8cSBrian Feldman } 6013d98e8cSBrian Feldman 61a7a8a766SBrian Feldman restart: 62f29af3b2SXin LI for (i = 0; i < NSIG; i++) 63f29af3b2SXin LI signo[i] = 0; 64f29af3b2SXin LI nr = -1; 65f29af3b2SXin LI save_errno = 0; 66f29af3b2SXin LI need_restart = 0; 6713d98e8cSBrian Feldman /* 6813d98e8cSBrian Feldman * Read and write to /dev/tty if available. If not, read from 6913d98e8cSBrian Feldman * stdin and write to stderr unless a tty is required. 7013d98e8cSBrian Feldman */ 71*18a2ccd2SMaxim Sobolev input_is_tty = 0; 72*18a2ccd2SMaxim Sobolev if (!(flags & RPP_STDIN)) { 73*18a2ccd2SMaxim Sobolev input = output = _open(_PATH_TTY, O_RDWR | O_CLOEXEC); 74*18a2ccd2SMaxim Sobolev if (input == -1) { 7513d98e8cSBrian Feldman if (flags & RPP_REQUIRE_TTY) { 7613d98e8cSBrian Feldman errno = ENOTTY; 7713d98e8cSBrian Feldman return(NULL); 7813d98e8cSBrian Feldman } 7913d98e8cSBrian Feldman input = STDIN_FILENO; 8013d98e8cSBrian Feldman output = STDERR_FILENO; 81*18a2ccd2SMaxim Sobolev } else { 82*18a2ccd2SMaxim Sobolev input_is_tty = 1; 83*18a2ccd2SMaxim Sobolev } 84*18a2ccd2SMaxim Sobolev } else { 85*18a2ccd2SMaxim Sobolev input = STDIN_FILENO; 86*18a2ccd2SMaxim Sobolev output = STDERR_FILENO; 8713d98e8cSBrian Feldman } 8813d98e8cSBrian Feldman 8913d98e8cSBrian Feldman /* 90f29af3b2SXin LI * Turn off echo if possible. 91f29af3b2SXin LI * If we are using a tty but are not the foreground pgrp this will 92f29af3b2SXin LI * generate SIGTTOU, so do it *before* installing the signal handlers. 9313d98e8cSBrian Feldman */ 94*18a2ccd2SMaxim Sobolev if (input_is_tty && tcgetattr(input, &oterm) == 0) { 9513d98e8cSBrian Feldman memcpy(&term, &oterm, sizeof(term)); 96a7a8a766SBrian Feldman if (!(flags & RPP_ECHO_ON)) 97a7a8a766SBrian Feldman term.c_lflag &= ~(ECHO | ECHONL); 9813d98e8cSBrian Feldman if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) 9913d98e8cSBrian Feldman term.c_cc[VSTATUS] = _POSIX_VDISABLE; 10013d98e8cSBrian Feldman (void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term); 10113d98e8cSBrian Feldman } else { 10213d98e8cSBrian Feldman memset(&term, 0, sizeof(term)); 103f29af3b2SXin LI term.c_lflag |= ECHO; 10413d98e8cSBrian Feldman memset(&oterm, 0, sizeof(oterm)); 105f29af3b2SXin LI oterm.c_lflag |= ECHO; 10613d98e8cSBrian Feldman } 10713d98e8cSBrian Feldman 108f29af3b2SXin LI /* 109f29af3b2SXin LI * Catch signals that would otherwise cause the user to end 110f29af3b2SXin LI * up with echo turned off in the shell. Don't worry about 111f29af3b2SXin LI * things like SIGXCPU and SIGVTALRM for now. 112f29af3b2SXin LI */ 113f29af3b2SXin LI sigemptyset(&sa.sa_mask); 114f29af3b2SXin LI sa.sa_flags = 0; /* don't restart system calls */ 115f29af3b2SXin LI sa.sa_handler = handler; 116bd6060a1SKonstantin Belousov (void)__libc_sigaction(SIGALRM, &sa, &savealrm); 117bd6060a1SKonstantin Belousov (void)__libc_sigaction(SIGHUP, &sa, &savehup); 118bd6060a1SKonstantin Belousov (void)__libc_sigaction(SIGINT, &sa, &saveint); 119bd6060a1SKonstantin Belousov (void)__libc_sigaction(SIGPIPE, &sa, &savepipe); 120bd6060a1SKonstantin Belousov (void)__libc_sigaction(SIGQUIT, &sa, &savequit); 121bd6060a1SKonstantin Belousov (void)__libc_sigaction(SIGTERM, &sa, &saveterm); 122bd6060a1SKonstantin Belousov (void)__libc_sigaction(SIGTSTP, &sa, &savetstp); 123bd6060a1SKonstantin Belousov (void)__libc_sigaction(SIGTTIN, &sa, &savettin); 124bd6060a1SKonstantin Belousov (void)__libc_sigaction(SIGTTOU, &sa, &savettou); 125f29af3b2SXin LI 126f29af3b2SXin LI if (!(flags & RPP_STDIN)) 127a939ced8SBrian Feldman (void)_write(output, prompt, strlen(prompt)); 12813d98e8cSBrian Feldman end = buf + bufsiz - 1; 129f29af3b2SXin LI p = buf; 130f29af3b2SXin LI while ((nr = _read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') { 13113d98e8cSBrian Feldman if (p < end) { 13213d98e8cSBrian Feldman if ((flags & RPP_SEVENBIT)) 13313d98e8cSBrian Feldman ch &= 0x7f; 134dad64c97SPedro F. Giffuni if (isalpha((unsigned char)ch)) { 13513d98e8cSBrian Feldman if ((flags & RPP_FORCELOWER)) 136dad64c97SPedro F. Giffuni ch = (char)tolower((unsigned char)ch); 13713d98e8cSBrian Feldman if ((flags & RPP_FORCEUPPER)) 138dad64c97SPedro F. Giffuni ch = (char)toupper((unsigned char)ch); 13913d98e8cSBrian Feldman } 14013d98e8cSBrian Feldman *p++ = ch; 14113d98e8cSBrian Feldman } 14213d98e8cSBrian Feldman } 14313d98e8cSBrian Feldman *p = '\0'; 144a7a8a766SBrian Feldman save_errno = errno; 14513d98e8cSBrian Feldman if (!(term.c_lflag & ECHO)) 146a939ced8SBrian Feldman (void)_write(output, "\n", 1); 14713d98e8cSBrian Feldman 148a7a8a766SBrian Feldman /* Restore old terminal settings and signals. */ 149f29af3b2SXin LI if (memcmp(&term, &oterm, sizeof(term)) != 0) { 150f29af3b2SXin LI while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 && 151f29af3b2SXin LI errno == EINTR && !signo[SIGTTOU]) 152f29af3b2SXin LI continue; 153f29af3b2SXin LI } 154bd6060a1SKonstantin Belousov (void)__libc_sigaction(SIGALRM, &savealrm, NULL); 155bd6060a1SKonstantin Belousov (void)__libc_sigaction(SIGHUP, &savehup, NULL); 156bd6060a1SKonstantin Belousov (void)__libc_sigaction(SIGINT, &saveint, NULL); 157bd6060a1SKonstantin Belousov (void)__libc_sigaction(SIGQUIT, &savequit, NULL); 158bd6060a1SKonstantin Belousov (void)__libc_sigaction(SIGPIPE, &savepipe, NULL); 159bd6060a1SKonstantin Belousov (void)__libc_sigaction(SIGTERM, &saveterm, NULL); 160bd6060a1SKonstantin Belousov (void)__libc_sigaction(SIGTSTP, &savetstp, NULL); 161bd6060a1SKonstantin Belousov (void)__libc_sigaction(SIGTTIN, &savettin, NULL); 162bd6060a1SKonstantin Belousov (void)__libc_sigaction(SIGTTOU, &savettou, NULL); 163*18a2ccd2SMaxim Sobolev if (input_is_tty) 164a939ced8SBrian Feldman (void)_close(input); 165a7a8a766SBrian Feldman 166a7a8a766SBrian Feldman /* 167a7a8a766SBrian Feldman * If we were interrupted by a signal, resend it to ourselves 168a7a8a766SBrian Feldman * now that we have restored the signal handlers. 169a7a8a766SBrian Feldman */ 170f29af3b2SXin LI for (i = 0; i < NSIG; i++) { 171f29af3b2SXin LI if (signo[i]) { 172f29af3b2SXin LI kill(getpid(), i); 173f29af3b2SXin LI switch (i) { 174a7a8a766SBrian Feldman case SIGTSTP: 175a7a8a766SBrian Feldman case SIGTTIN: 176a7a8a766SBrian Feldman case SIGTTOU: 177f29af3b2SXin LI need_restart = 1; 178f29af3b2SXin LI } 179f29af3b2SXin LI } 180f29af3b2SXin LI } 181f29af3b2SXin LI if (need_restart) 182a7a8a766SBrian Feldman goto restart; 18313d98e8cSBrian Feldman 184f29af3b2SXin LI if (save_errno) 185a7a8a766SBrian Feldman errno = save_errno; 186a7a8a766SBrian Feldman return(nr == -1 ? NULL : buf); 187a7a8a766SBrian Feldman } 188a7a8a766SBrian Feldman 18913d98e8cSBrian Feldman char * 190a7a8a766SBrian Feldman getpass(const char *prompt) 19113d98e8cSBrian Feldman { 19213d98e8cSBrian Feldman static char buf[_PASSWORD_LEN + 1]; 19313d98e8cSBrian Feldman 19444f7d6afSBrian Feldman if (readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF) == NULL) 19544f7d6afSBrian Feldman buf[0] = '\0'; 19644f7d6afSBrian Feldman return(buf); 19713d98e8cSBrian Feldman } 198a7a8a766SBrian Feldman 199a7a8a766SBrian Feldman static void handler(int s) 200a7a8a766SBrian Feldman { 201a7a8a766SBrian Feldman 202f29af3b2SXin LI signo[s] = 1; 203a7a8a766SBrian Feldman } 204