1 /* $NetBSD: readpassphrase.c,v 1.3 2012/04/14 01:34:37 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 #ifdef GETPASS_ECHO 53 int gflags = GETPASS_ECHO_NL; 54 55 if (flags & RPP_ECHO_ON) 56 gflags |= GETPASS_ECHO; 57 if (flags & RPP_REQUIRE_TTY) 58 gflags |= GETPASS_NEED_TTY; 59 if (flags & RPP_FORCELOWER) 60 gflags |= GETPASS_FORCE_LOWER; 61 if (flags & RPP_FORCEUPPER) 62 gflags |= GETPASS_FORCE_UPPER; 63 if (flags & RPP_SEVENBIT) 64 gflags |= GETPASS_7BIT; 65 66 return getpassfd(prompt, buf, bufsiz, NULL, gflags, 0); 67 #else 68 struct termios term, oterm; 69 char ch, *p, *end; 70 int input, output; 71 sigset_t oset, nset; 72 73 /* I suppose we could alloc on demand in this case (XXX). */ 74 if (bufsiz == 0) { 75 errno = EINVAL; 76 return(NULL); 77 } 78 79 /* 80 * Read and write to /dev/tty if available. If not, read from 81 * stdin and write to stderr unless a tty is required. 82 */ 83 if ((input = output = open(_PATH_TTY, O_RDWR)) == -1) { 84 if (flags & RPP_REQUIRE_TTY) { 85 errno = ENOTTY; 86 return(NULL); 87 } 88 input = STDIN_FILENO; 89 output = STDERR_FILENO; 90 } 91 92 /* 93 * We block SIGINT and SIGTSTP so the terminal is not left 94 * in an inconsistent state (ie: no echo). It would probably 95 * be better to simply catch these though. 96 */ 97 sigemptyset(&nset); 98 sigaddset(&nset, SIGINT); 99 sigaddset(&nset, SIGTSTP); 100 (void)sigprocmask(SIG_BLOCK, &nset, &oset); 101 102 /* Turn off echo if possible. */ 103 if (tcgetattr(input, &oterm) == 0) { 104 memcpy(&term, &oterm, sizeof(term)); 105 if (!(flags & RPP_ECHO_ON) && (term.c_lflag & ECHO)) 106 term.c_lflag &= ~ECHO; 107 if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) 108 term.c_cc[VSTATUS] = _POSIX_VDISABLE; 109 (void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term); 110 } else { 111 memset(&term, 0, sizeof(term)); 112 memset(&oterm, 0, sizeof(oterm)); 113 } 114 115 (void)write(output, prompt, strlen(prompt)); 116 end = buf + bufsiz - 1; 117 for (p = buf; read(input, &ch, 1) == 1 && ch != '\n' && ch != '\r';) { 118 if (p < end) { 119 if ((flags & RPP_SEVENBIT)) 120 ch &= 0x7f; 121 if (isalpha((unsigned char)ch)) { 122 if ((flags & RPP_FORCELOWER)) 123 ch = tolower((unsigned char)ch); 124 if ((flags & RPP_FORCEUPPER)) 125 ch = toupper((unsigned char)ch); 126 } 127 *p++ = ch; 128 } 129 } 130 *p = '\0'; 131 if (!(term.c_lflag & ECHO)) 132 (void)write(output, "\n", 1); 133 134 /* Restore old terminal settings and signal mask. */ 135 if (memcmp(&term, &oterm, sizeof(term)) != 0) 136 (void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm); 137 (void)sigprocmask(SIG_SETMASK, &oset, NULL); 138 if (input != STDIN_FILENO) 139 (void)close(input); 140 return(buf); 141 #endif 142 } 143 144 char * 145 getpass(prompt) 146 const char *prompt; 147 { 148 static char buf[_PASSWORD_LEN + 1]; 149 150 return(readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF)); 151 } 152