xref: /netbsd-src/crypto/external/bsd/openssh/dist/readpassphrase.c (revision d91f98a8715141154279122ae81737cb65179572)
1*d91f98a8Spgoyette /*	$NetBSD: readpassphrase.c,v 1.9 2019/01/27 02:08:33 pgoyette Exp $	*/
2313c6c94Schristos /*
3313c6c94Schristos  * Copyright (c) 2000 Todd C. Miller <Todd.Miller@courtesan.com>
4313c6c94Schristos  * All rights reserved.
5313c6c94Schristos  *
6313c6c94Schristos  * Redistribution and use in source and binary forms, with or without
7313c6c94Schristos  * modification, are permitted provided that the following conditions
8313c6c94Schristos  * are met:
9313c6c94Schristos  * 1. Redistributions of source code must retain the above copyright
10313c6c94Schristos  *    notice, this list of conditions and the following disclaimer.
11313c6c94Schristos  * 2. Redistributions in binary form must reproduce the above copyright
12313c6c94Schristos  *    notice, this list of conditions and the following disclaimer in the
13313c6c94Schristos  *    documentation and/or other materials provided with the distribution.
14313c6c94Schristos  * 3. The name of the author may not be used to endorse or promote products
15313c6c94Schristos  *    derived from this software without specific prior written permission.
16313c6c94Schristos  *
17313c6c94Schristos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18313c6c94Schristos  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19313c6c94Schristos  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
20313c6c94Schristos  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21313c6c94Schristos  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22313c6c94Schristos  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23313c6c94Schristos  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24313c6c94Schristos  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25313c6c94Schristos  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26313c6c94Schristos  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27313c6c94Schristos  */
28313c6c94Schristos 
29313c6c94Schristos #include "includes.h"
30313c6c94Schristos #if defined(LIBC_SCCS) && !defined(lint)
31313c6c94Schristos static const char rcsid[] = "$OpenBSD: readpassphrase.c,v 1.7 2001/08/07 19:34:11 millert Exp $";
32313c6c94Schristos #endif /* LIBC_SCCS and not lint */
33*d91f98a8Spgoyette __RCSID("$NetBSD: readpassphrase.c,v 1.9 2019/01/27 02:08:33 pgoyette Exp $");
34313c6c94Schristos 
35313c6c94Schristos #include <ctype.h>
36313c6c94Schristos #include <errno.h>
37313c6c94Schristos #include <fcntl.h>
38313c6c94Schristos #include <paths.h>
39313c6c94Schristos #include <pwd.h>
40313c6c94Schristos #include <signal.h>
41313c6c94Schristos #include <string.h>
42313c6c94Schristos #include <termios.h>
43313c6c94Schristos #include <unistd.h>
44313c6c94Schristos #include <readpassphrase.h>
45313c6c94Schristos 
46313c6c94Schristos char *
readpassphrase(prompt,buf,bufsiz,flags)4707636659Schristos readpassphrase(prompt, buf, bufsiz, flags)
4807636659Schristos 	const char *prompt;
4907636659Schristos 	char *buf;
5007636659Schristos 	size_t bufsiz;
5107636659Schristos 	int flags;
52313c6c94Schristos {
5307636659Schristos #ifdef GETPASS_ECHO
5407636659Schristos 	int gflags = GETPASS_ECHO_NL;
5507636659Schristos 
5607636659Schristos 	if (flags & RPP_ECHO_ON)
5707636659Schristos 		gflags |= GETPASS_ECHO;
5807636659Schristos 	if (flags & RPP_REQUIRE_TTY)
5907636659Schristos 		gflags |= GETPASS_NEED_TTY;
6007636659Schristos 	if (flags & RPP_FORCELOWER)
6107636659Schristos 		gflags |= GETPASS_FORCE_LOWER;
6207636659Schristos 	if (flags & RPP_FORCEUPPER)
6307636659Schristos 		gflags |= GETPASS_FORCE_UPPER;
6407636659Schristos 	if (flags & RPP_SEVENBIT)
6507636659Schristos 		gflags |= GETPASS_7BIT;
6607636659Schristos 
6707636659Schristos 	return getpassfd(prompt, buf, bufsiz, NULL, gflags, 0);
6807636659Schristos #else
6907636659Schristos 	struct termios term, oterm;
7007636659Schristos 	char ch, *p, *end;
71313c6c94Schristos 	int input, output;
7207636659Schristos 	sigset_t oset, nset;
73313c6c94Schristos 
74313c6c94Schristos 	/* I suppose we could alloc on demand in this case (XXX). */
75313c6c94Schristos 	if (bufsiz == 0) {
76313c6c94Schristos 		errno = EINVAL;
77313c6c94Schristos 		return(NULL);
78313c6c94Schristos 	}
79313c6c94Schristos 
80313c6c94Schristos 	/*
81313c6c94Schristos 	 * Read and write to /dev/tty if available.  If not, read from
82313c6c94Schristos 	 * stdin and write to stderr unless a tty is required.
83313c6c94Schristos 	 */
84313c6c94Schristos 	if ((input = output = open(_PATH_TTY, O_RDWR)) == -1) {
85313c6c94Schristos 		if (flags & RPP_REQUIRE_TTY) {
86313c6c94Schristos 			errno = ENOTTY;
87313c6c94Schristos 			return(NULL);
88313c6c94Schristos 		}
89313c6c94Schristos 		input = STDIN_FILENO;
90313c6c94Schristos 		output = STDERR_FILENO;
91313c6c94Schristos 	}
92313c6c94Schristos 
93313c6c94Schristos 	/*
94313c6c94Schristos 	 * We block SIGINT and SIGTSTP so the terminal is not left
95313c6c94Schristos 	 * in an inconsistent state (ie: no echo).  It would probably
96313c6c94Schristos 	 * be better to simply catch these though.
97313c6c94Schristos 	 */
98313c6c94Schristos 	sigemptyset(&nset);
99313c6c94Schristos 	sigaddset(&nset, SIGINT);
100313c6c94Schristos 	sigaddset(&nset, SIGTSTP);
101313c6c94Schristos 	(void)sigprocmask(SIG_BLOCK, &nset, &oset);
102313c6c94Schristos 
103313c6c94Schristos 	/* Turn off echo if possible. */
104313c6c94Schristos 	if (tcgetattr(input, &oterm) == 0) {
105313c6c94Schristos 		memcpy(&term, &oterm, sizeof(term));
106313c6c94Schristos 		if (!(flags & RPP_ECHO_ON) && (term.c_lflag & ECHO))
107313c6c94Schristos 			term.c_lflag &= ~ECHO;
108313c6c94Schristos 		if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
109313c6c94Schristos 			term.c_cc[VSTATUS] = _POSIX_VDISABLE;
110313c6c94Schristos 		(void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
111313c6c94Schristos 	} else {
112313c6c94Schristos 		memset(&term, 0, sizeof(term));
113313c6c94Schristos 		memset(&oterm, 0, sizeof(oterm));
114313c6c94Schristos 	}
115313c6c94Schristos 
116313c6c94Schristos 	(void)write(output, prompt, strlen(prompt));
117313c6c94Schristos 	end = buf + bufsiz - 1;
118313c6c94Schristos 	for (p = buf; read(input, &ch, 1) == 1 && ch != '\n' && ch != '\r';) {
119313c6c94Schristos 		if (p < end) {
120313c6c94Schristos 			if ((flags & RPP_SEVENBIT))
121313c6c94Schristos 				ch &= 0x7f;
122313c6c94Schristos 			if (isalpha((unsigned char)ch)) {
123313c6c94Schristos 				if ((flags & RPP_FORCELOWER))
124313c6c94Schristos 					ch = tolower((unsigned char)ch);
125313c6c94Schristos 				if ((flags & RPP_FORCEUPPER))
126313c6c94Schristos 					ch = toupper((unsigned char)ch);
127313c6c94Schristos 			}
128313c6c94Schristos 			*p++ = ch;
129313c6c94Schristos 		}
130313c6c94Schristos 	}
131313c6c94Schristos 	*p = '\0';
132313c6c94Schristos 	if (!(term.c_lflag & ECHO))
133313c6c94Schristos 		(void)write(output, "\n", 1);
134313c6c94Schristos 
135313c6c94Schristos 	/* Restore old terminal settings and signal mask. */
136313c6c94Schristos 	if (memcmp(&term, &oterm, sizeof(term)) != 0)
137313c6c94Schristos 		(void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm);
138313c6c94Schristos 	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
139313c6c94Schristos 	if (input != STDIN_FILENO)
140313c6c94Schristos 		(void)close(input);
14107636659Schristos 	return(buf);
14207636659Schristos #endif
143313c6c94Schristos }
144313c6c94Schristos 
145313c6c94Schristos char *
getpass(prompt)146313c6c94Schristos getpass(prompt)
147313c6c94Schristos         const char *prompt;
148313c6c94Schristos {
149313c6c94Schristos 	static char buf[_PASSWORD_LEN + 1];
150313c6c94Schristos 
151313c6c94Schristos 	return(readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF));
152313c6c94Schristos }
153