1/* $NetBSD: readpassphrase.c,v 1.14 2009/02/16 20:55:22 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) 31static 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 45char * 46readpassphrase(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 127char * 128getpass(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