1 /* $NetBSD: readpassphrase.c,v 1.1 2009/06/07 22:38:47 christos Exp $ */ 2 /* 3 * Copyright (c) 2000 Todd C. Miller <Todd.Miller@courtesan.com> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 19 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 20 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "includes.h" 30 #if defined(LIBC_SCCS) && !defined(lint) 31 static const char rcsid[] = "$OpenBSD: readpassphrase.c,v 1.7 2001/08/07 19:34:11 millert Exp $"; 32 #endif /* LIBC_SCCS and not lint */ 33 34 #include <ctype.h> 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <paths.h> 38 #include <pwd.h> 39 #include <signal.h> 40 #include <string.h> 41 #include <termios.h> 42 #include <unistd.h> 43 #include <readpassphrase.h> 44 45 char * 46 readpassphrase(prompt, buf, bufsiz, flags) 47 const char *prompt; 48 char *buf; 49 size_t bufsiz; 50 int flags; 51 { 52 struct termios term, oterm; 53 char ch, *p, *end; 54 int input, output; 55 sigset_t oset, nset; 56 57 /* I suppose we could alloc on demand in this case (XXX). */ 58 if (bufsiz == 0) { 59 errno = EINVAL; 60 return(NULL); 61 } 62 63 /* 64 * Read and write to /dev/tty if available. If not, read from 65 * stdin and write to stderr unless a tty is required. 66 */ 67 if ((input = output = open(_PATH_TTY, O_RDWR)) == -1) { 68 if (flags & RPP_REQUIRE_TTY) { 69 errno = ENOTTY; 70 return(NULL); 71 } 72 input = STDIN_FILENO; 73 output = STDERR_FILENO; 74 } 75 76 /* 77 * We block SIGINT and SIGTSTP so the terminal is not left 78 * in an inconsistent state (ie: no echo). It would probably 79 * be better to simply catch these though. 80 */ 81 sigemptyset(&nset); 82 sigaddset(&nset, SIGINT); 83 sigaddset(&nset, SIGTSTP); 84 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 85 86 /* Turn off echo if possible. */ 87 if (tcgetattr(input, &oterm) == 0) { 88 memcpy(&term, &oterm, sizeof(term)); 89 if (!(flags & RPP_ECHO_ON) && (term.c_lflag & ECHO)) 90 term.c_lflag &= ~ECHO; 91 if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) 92 term.c_cc[VSTATUS] = _POSIX_VDISABLE; 93 (void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term); 94 } else { 95 memset(&term, 0, sizeof(term)); 96 memset(&oterm, 0, sizeof(oterm)); 97 } 98 99 (void)write(output, prompt, strlen(prompt)); 100 end = buf + bufsiz - 1; 101 for (p = buf; read(input, &ch, 1) == 1 && ch != '\n' && ch != '\r';) { 102 if (p < end) { 103 if ((flags & RPP_SEVENBIT)) 104 ch &= 0x7f; 105 if (isalpha((unsigned char)ch)) { 106 if ((flags & RPP_FORCELOWER)) 107 ch = tolower((unsigned char)ch); 108 if ((flags & RPP_FORCEUPPER)) 109 ch = toupper((unsigned char)ch); 110 } 111 *p++ = ch; 112 } 113 } 114 *p = '\0'; 115 if (!(term.c_lflag & ECHO)) 116 (void)write(output, "\n", 1); 117 118 /* Restore old terminal settings and signal mask. */ 119 if (memcmp(&term, &oterm, sizeof(term)) != 0) 120 (void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm); 121 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 122 if (input != STDIN_FILENO) 123 (void)close(input); 124 return(buf); 125 } 126 127 char * 128 getpass(prompt) 129 const char *prompt; 130 { 131 static char buf[_PASSWORD_LEN + 1]; 132 133 return(readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF)); 134 } 135