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