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