xref: /dflybsd-src/contrib/libarchive/libarchive_fe/passphrase.c (revision 6b384f3989c11f4c0078ee986d3d85a2da3bf92a)
1*6b384f39SPeter Avalos /*-
2*6b384f39SPeter Avalos  * Copyright (c) 2014 Michihiro NAKAJIMA
3*6b384f39SPeter Avalos  * All rights reserved.
4*6b384f39SPeter Avalos  *
5*6b384f39SPeter Avalos  * Redistribution and use in source and binary forms, with or without
6*6b384f39SPeter Avalos  * modification, are permitted provided that the following conditions
7*6b384f39SPeter Avalos  * are met:
8*6b384f39SPeter Avalos  * 1. Redistributions of source code must retain the above copyright
9*6b384f39SPeter Avalos  *    notice, this list of conditions and the following disclaimer
10*6b384f39SPeter Avalos  *    in this position and unchanged.
11*6b384f39SPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
12*6b384f39SPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
13*6b384f39SPeter Avalos  *    documentation and/or other materials provided with the distribution.
14*6b384f39SPeter Avalos  *
15*6b384f39SPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16*6b384f39SPeter Avalos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17*6b384f39SPeter Avalos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18*6b384f39SPeter Avalos  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19*6b384f39SPeter Avalos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20*6b384f39SPeter Avalos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21*6b384f39SPeter Avalos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22*6b384f39SPeter Avalos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23*6b384f39SPeter Avalos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24*6b384f39SPeter Avalos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*6b384f39SPeter Avalos  */
26*6b384f39SPeter Avalos /*	$OpenBSD: readpassphrase.c,v 1.22 2010/01/13 10:20:54 dtucker Exp $	*/
27*6b384f39SPeter Avalos /*
28*6b384f39SPeter Avalos  * Copyright (c) 2000-2002, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
29*6b384f39SPeter Avalos  *
30*6b384f39SPeter Avalos  * Permission to use, copy, modify, and distribute this software for any
31*6b384f39SPeter Avalos  * purpose with or without fee is hereby granted, provided that the above
32*6b384f39SPeter Avalos  * copyright notice and this permission notice appear in all copies.
33*6b384f39SPeter Avalos  *
34*6b384f39SPeter Avalos  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
35*6b384f39SPeter Avalos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
36*6b384f39SPeter Avalos  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
37*6b384f39SPeter Avalos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
38*6b384f39SPeter Avalos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
39*6b384f39SPeter Avalos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
40*6b384f39SPeter Avalos  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
41*6b384f39SPeter Avalos  *
42*6b384f39SPeter Avalos  * Sponsored in part by the Defense Advanced Research Projects
43*6b384f39SPeter Avalos  * Agency (DARPA) and Air Force Research Laboratory, Air Force
44*6b384f39SPeter Avalos  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
45*6b384f39SPeter Avalos  */
46*6b384f39SPeter Avalos 
47*6b384f39SPeter Avalos /* OPENBSD ORIGINAL: lib/libc/gen/readpassphrase.c */
48*6b384f39SPeter Avalos 
49*6b384f39SPeter Avalos 
50*6b384f39SPeter Avalos #include "lafe_platform.h"
51*6b384f39SPeter Avalos __FBSDID("$FreeBSD$");
52*6b384f39SPeter Avalos 
53*6b384f39SPeter Avalos #include <errno.h>
54*6b384f39SPeter Avalos #ifdef HAVE_STDLIB_H
55*6b384f39SPeter Avalos #include <stdlib.h>
56*6b384f39SPeter Avalos #endif
57*6b384f39SPeter Avalos #ifdef HAVE_UNISTD_H
58*6b384f39SPeter Avalos #include <unistd.h>
59*6b384f39SPeter Avalos #endif
60*6b384f39SPeter Avalos #ifdef HAVE_READPASSPHRASE_H
61*6b384f39SPeter Avalos #include <readpassphrase.h>
62*6b384f39SPeter Avalos #endif
63*6b384f39SPeter Avalos 
64*6b384f39SPeter Avalos #include "err.h"
65*6b384f39SPeter Avalos #include "passphrase.h"
66*6b384f39SPeter Avalos 
67*6b384f39SPeter Avalos #ifndef HAVE_READPASSPHRASE
68*6b384f39SPeter Avalos 
69*6b384f39SPeter Avalos #define RPP_ECHO_OFF    0x00		/* Turn off echo (default). */
70*6b384f39SPeter Avalos #define RPP_ECHO_ON     0x01		/* Leave echo on. */
71*6b384f39SPeter Avalos #define RPP_REQUIRE_TTY 0x02		/* Fail if there is no tty. */
72*6b384f39SPeter Avalos #define RPP_FORCELOWER  0x04		/* Force input to lower case. */
73*6b384f39SPeter Avalos #define RPP_FORCEUPPER  0x08		/* Force input to upper case. */
74*6b384f39SPeter Avalos #define RPP_SEVENBIT    0x10		/* Strip the high bit from input. */
75*6b384f39SPeter Avalos #define RPP_STDIN       0x20		/* Read from stdin, not /dev/tty */
76*6b384f39SPeter Avalos 
77*6b384f39SPeter Avalos 
78*6b384f39SPeter Avalos #if defined(_WIN32) && !defined(__CYGWIN__)
79*6b384f39SPeter Avalos #include <windows.h>
80*6b384f39SPeter Avalos 
81*6b384f39SPeter Avalos static char *
82*6b384f39SPeter Avalos readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
83*6b384f39SPeter Avalos {
84*6b384f39SPeter Avalos 	HANDLE hStdin, hStdout;
85*6b384f39SPeter Avalos 	DWORD mode, rbytes;
86*6b384f39SPeter Avalos 	BOOL success;
87*6b384f39SPeter Avalos 
88*6b384f39SPeter Avalos 	(void)flags;
89*6b384f39SPeter Avalos 
90*6b384f39SPeter Avalos 	hStdin = GetStdHandle(STD_INPUT_HANDLE);
91*6b384f39SPeter Avalos 	if (hStdin == INVALID_HANDLE_VALUE)
92*6b384f39SPeter Avalos 		return (NULL);
93*6b384f39SPeter Avalos 	hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
94*6b384f39SPeter Avalos 	if (hStdout == INVALID_HANDLE_VALUE)
95*6b384f39SPeter Avalos 		return (NULL);
96*6b384f39SPeter Avalos 
97*6b384f39SPeter Avalos 	success = GetConsoleMode(hStdin, &mode);
98*6b384f39SPeter Avalos 	if (!success)
99*6b384f39SPeter Avalos 		return (NULL);
100*6b384f39SPeter Avalos 	mode &= ~ENABLE_ECHO_INPUT;
101*6b384f39SPeter Avalos 	mode |= ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
102*6b384f39SPeter Avalos 	success = SetConsoleMode(hStdin, mode);
103*6b384f39SPeter Avalos 	if (!success)
104*6b384f39SPeter Avalos 		return (NULL);
105*6b384f39SPeter Avalos 
106*6b384f39SPeter Avalos 	success = WriteFile(hStdout, prompt, (DWORD)strlen(prompt),
107*6b384f39SPeter Avalos 		NULL, NULL);
108*6b384f39SPeter Avalos 	if (!success)
109*6b384f39SPeter Avalos 		return (NULL);
110*6b384f39SPeter Avalos 	success = ReadFile(hStdin, buf, (DWORD)bufsiz - 1, &rbytes, NULL);
111*6b384f39SPeter Avalos 	if (!success)
112*6b384f39SPeter Avalos 		return (NULL);
113*6b384f39SPeter Avalos 	WriteFile(hStdout, "\r\n", 2, NULL, NULL);
114*6b384f39SPeter Avalos 	buf[rbytes] = '\0';
115*6b384f39SPeter Avalos 	/* Remove trailing carriage return(s). */
116*6b384f39SPeter Avalos 	if (rbytes > 2 && buf[rbytes - 2] == '\r' && buf[rbytes - 1] == '\n')
117*6b384f39SPeter Avalos 		buf[rbytes - 2] = '\0';
118*6b384f39SPeter Avalos 
119*6b384f39SPeter Avalos 	return (buf);
120*6b384f39SPeter Avalos }
121*6b384f39SPeter Avalos 
122*6b384f39SPeter Avalos #else /* _WIN32 && !__CYGWIN__ */
123*6b384f39SPeter Avalos 
124*6b384f39SPeter Avalos #include <termios.h>
125*6b384f39SPeter Avalos #include <signal.h>
126*6b384f39SPeter Avalos #include <ctype.h>
127*6b384f39SPeter Avalos #include <fcntl.h>
128*6b384f39SPeter Avalos #ifdef HAVE_PATHS_H
129*6b384f39SPeter Avalos #include <paths.h>
130*6b384f39SPeter Avalos #endif
131*6b384f39SPeter Avalos #include <string.h>
132*6b384f39SPeter Avalos #include <unistd.h>
133*6b384f39SPeter Avalos 
134*6b384f39SPeter Avalos #ifdef TCSASOFT
135*6b384f39SPeter Avalos # define _T_FLUSH	(TCSAFLUSH|TCSASOFT)
136*6b384f39SPeter Avalos #else
137*6b384f39SPeter Avalos # define _T_FLUSH	(TCSAFLUSH)
138*6b384f39SPeter Avalos #endif
139*6b384f39SPeter Avalos 
140*6b384f39SPeter Avalos /* SunOS 4.x which lacks _POSIX_VDISABLE, but has VDISABLE */
141*6b384f39SPeter Avalos #if !defined(_POSIX_VDISABLE) && defined(VDISABLE)
142*6b384f39SPeter Avalos #  define _POSIX_VDISABLE       VDISABLE
143*6b384f39SPeter Avalos #endif
144*6b384f39SPeter Avalos 
145*6b384f39SPeter Avalos static volatile sig_atomic_t *signo;
146*6b384f39SPeter Avalos 
147*6b384f39SPeter Avalos static void
148*6b384f39SPeter Avalos handler(int s)
149*6b384f39SPeter Avalos {
150*6b384f39SPeter Avalos 	signo[s] = 1;
151*6b384f39SPeter Avalos }
152*6b384f39SPeter Avalos 
153*6b384f39SPeter Avalos static char *
154*6b384f39SPeter Avalos readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
155*6b384f39SPeter Avalos {
156*6b384f39SPeter Avalos 	ssize_t nr;
157*6b384f39SPeter Avalos 	int input, output, save_errno, i, need_restart;
158*6b384f39SPeter Avalos 	char ch, *p, *end;
159*6b384f39SPeter Avalos 	struct termios term, oterm;
160*6b384f39SPeter Avalos 	struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm;
161*6b384f39SPeter Avalos 	struct sigaction savetstp, savettin, savettou, savepipe;
162*6b384f39SPeter Avalos 
163*6b384f39SPeter Avalos 	/* I suppose we could alloc on demand in this case (XXX). */
164*6b384f39SPeter Avalos 	if (bufsiz == 0) {
165*6b384f39SPeter Avalos 		errno = EINVAL;
166*6b384f39SPeter Avalos 		return(NULL);
167*6b384f39SPeter Avalos 	}
168*6b384f39SPeter Avalos 
169*6b384f39SPeter Avalos 	if (signo == NULL) {
170*6b384f39SPeter Avalos 		signo = calloc(SIGRTMAX, sizeof(sig_atomic_t));
171*6b384f39SPeter Avalos 	}
172*6b384f39SPeter Avalos 
173*6b384f39SPeter Avalos restart:
174*6b384f39SPeter Avalos 	for (i = 0; i < SIGRTMAX; i++)
175*6b384f39SPeter Avalos 		signo[i] = 0;
176*6b384f39SPeter Avalos 	nr = -1;
177*6b384f39SPeter Avalos 	save_errno = 0;
178*6b384f39SPeter Avalos 	need_restart = 0;
179*6b384f39SPeter Avalos 	/*
180*6b384f39SPeter Avalos 	 * Read and write to /dev/tty if available.  If not, read from
181*6b384f39SPeter Avalos 	 * stdin and write to stderr unless a tty is required.
182*6b384f39SPeter Avalos 	 */
183*6b384f39SPeter Avalos 	if ((flags & RPP_STDIN) ||
184*6b384f39SPeter Avalos 	    (input = output = open(_PATH_TTY, O_RDWR)) == -1) {
185*6b384f39SPeter Avalos 		if (flags & RPP_REQUIRE_TTY) {
186*6b384f39SPeter Avalos 			errno = ENOTTY;
187*6b384f39SPeter Avalos 			return(NULL);
188*6b384f39SPeter Avalos 		}
189*6b384f39SPeter Avalos 		input = STDIN_FILENO;
190*6b384f39SPeter Avalos 		output = STDERR_FILENO;
191*6b384f39SPeter Avalos 	}
192*6b384f39SPeter Avalos 
193*6b384f39SPeter Avalos 	/*
194*6b384f39SPeter Avalos 	 * Catch signals that would otherwise cause the user to end
195*6b384f39SPeter Avalos 	 * up with echo turned off in the shell.  Don't worry about
196*6b384f39SPeter Avalos 	 * things like SIGXCPU and SIGVTALRM for now.
197*6b384f39SPeter Avalos 	 */
198*6b384f39SPeter Avalos 	sigemptyset(&sa.sa_mask);
199*6b384f39SPeter Avalos 	sa.sa_flags = 0;		/* don't restart system calls */
200*6b384f39SPeter Avalos 	sa.sa_handler = handler;
201*6b384f39SPeter Avalos 	(void)sigaction(SIGALRM, &sa, &savealrm);
202*6b384f39SPeter Avalos 	(void)sigaction(SIGHUP, &sa, &savehup);
203*6b384f39SPeter Avalos 	(void)sigaction(SIGINT, &sa, &saveint);
204*6b384f39SPeter Avalos 	(void)sigaction(SIGPIPE, &sa, &savepipe);
205*6b384f39SPeter Avalos 	(void)sigaction(SIGQUIT, &sa, &savequit);
206*6b384f39SPeter Avalos 	(void)sigaction(SIGTERM, &sa, &saveterm);
207*6b384f39SPeter Avalos 	(void)sigaction(SIGTSTP, &sa, &savetstp);
208*6b384f39SPeter Avalos 	(void)sigaction(SIGTTIN, &sa, &savettin);
209*6b384f39SPeter Avalos 	(void)sigaction(SIGTTOU, &sa, &savettou);
210*6b384f39SPeter Avalos 
211*6b384f39SPeter Avalos 	/* Turn off echo if possible. */
212*6b384f39SPeter Avalos 	if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) {
213*6b384f39SPeter Avalos 		memcpy(&term, &oterm, sizeof(term));
214*6b384f39SPeter Avalos 		if (!(flags & RPP_ECHO_ON))
215*6b384f39SPeter Avalos 			term.c_lflag &= ~(ECHO | ECHONL);
216*6b384f39SPeter Avalos #ifdef VSTATUS
217*6b384f39SPeter Avalos 		if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
218*6b384f39SPeter Avalos 			term.c_cc[VSTATUS] = _POSIX_VDISABLE;
219*6b384f39SPeter Avalos #endif
220*6b384f39SPeter Avalos 		(void)tcsetattr(input, _T_FLUSH, &term);
221*6b384f39SPeter Avalos 	} else {
222*6b384f39SPeter Avalos 		memset(&term, 0, sizeof(term));
223*6b384f39SPeter Avalos 		term.c_lflag |= ECHO;
224*6b384f39SPeter Avalos 		memset(&oterm, 0, sizeof(oterm));
225*6b384f39SPeter Avalos 		oterm.c_lflag |= ECHO;
226*6b384f39SPeter Avalos 	}
227*6b384f39SPeter Avalos 
228*6b384f39SPeter Avalos 	/* No I/O if we are already backgrounded. */
229*6b384f39SPeter Avalos 	if (signo[SIGTTOU] != 1 && signo[SIGTTIN] != 1) {
230*6b384f39SPeter Avalos 		if (!(flags & RPP_STDIN)) {
231*6b384f39SPeter Avalos 			int r = write(output, prompt, strlen(prompt));
232*6b384f39SPeter Avalos 			(void)r;
233*6b384f39SPeter Avalos 		}
234*6b384f39SPeter Avalos 		end = buf + bufsiz - 1;
235*6b384f39SPeter Avalos 		p = buf;
236*6b384f39SPeter Avalos 		while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') {
237*6b384f39SPeter Avalos 			if (p < end) {
238*6b384f39SPeter Avalos 				if ((flags & RPP_SEVENBIT))
239*6b384f39SPeter Avalos 					ch &= 0x7f;
240*6b384f39SPeter Avalos 				if (isalpha(ch)) {
241*6b384f39SPeter Avalos 					if ((flags & RPP_FORCELOWER))
242*6b384f39SPeter Avalos 						ch = (char)tolower(ch);
243*6b384f39SPeter Avalos 					if ((flags & RPP_FORCEUPPER))
244*6b384f39SPeter Avalos 						ch = (char)toupper(ch);
245*6b384f39SPeter Avalos 				}
246*6b384f39SPeter Avalos 				*p++ = ch;
247*6b384f39SPeter Avalos 			}
248*6b384f39SPeter Avalos 		}
249*6b384f39SPeter Avalos 		*p = '\0';
250*6b384f39SPeter Avalos 		save_errno = errno;
251*6b384f39SPeter Avalos 		if (!(term.c_lflag & ECHO)) {
252*6b384f39SPeter Avalos 			int r = write(output, "\n", 1);
253*6b384f39SPeter Avalos 			(void)r;
254*6b384f39SPeter Avalos 		}
255*6b384f39SPeter Avalos 	}
256*6b384f39SPeter Avalos 
257*6b384f39SPeter Avalos 	/* Restore old terminal settings and signals. */
258*6b384f39SPeter Avalos 	if (memcmp(&term, &oterm, sizeof(term)) != 0) {
259*6b384f39SPeter Avalos 		while (tcsetattr(input, _T_FLUSH, &oterm) == -1 &&
260*6b384f39SPeter Avalos 		    errno == EINTR)
261*6b384f39SPeter Avalos 			continue;
262*6b384f39SPeter Avalos 	}
263*6b384f39SPeter Avalos 	(void)sigaction(SIGALRM, &savealrm, NULL);
264*6b384f39SPeter Avalos 	(void)sigaction(SIGHUP, &savehup, NULL);
265*6b384f39SPeter Avalos 	(void)sigaction(SIGINT, &saveint, NULL);
266*6b384f39SPeter Avalos 	(void)sigaction(SIGQUIT, &savequit, NULL);
267*6b384f39SPeter Avalos 	(void)sigaction(SIGPIPE, &savepipe, NULL);
268*6b384f39SPeter Avalos 	(void)sigaction(SIGTERM, &saveterm, NULL);
269*6b384f39SPeter Avalos 	(void)sigaction(SIGTSTP, &savetstp, NULL);
270*6b384f39SPeter Avalos 	(void)sigaction(SIGTTIN, &savettin, NULL);
271*6b384f39SPeter Avalos 	(void)sigaction(SIGTTOU, &savettou, NULL);
272*6b384f39SPeter Avalos 	if (input != STDIN_FILENO)
273*6b384f39SPeter Avalos 		(void)close(input);
274*6b384f39SPeter Avalos 
275*6b384f39SPeter Avalos 	/*
276*6b384f39SPeter Avalos 	 * If we were interrupted by a signal, resend it to ourselves
277*6b384f39SPeter Avalos 	 * now that we have restored the signal handlers.
278*6b384f39SPeter Avalos 	 */
279*6b384f39SPeter Avalos 	for (i = 0; i < SIGRTMAX; i++) {
280*6b384f39SPeter Avalos 		if (signo[i]) {
281*6b384f39SPeter Avalos 			kill(getpid(), i);
282*6b384f39SPeter Avalos 			switch (i) {
283*6b384f39SPeter Avalos 			case SIGTSTP:
284*6b384f39SPeter Avalos 			case SIGTTIN:
285*6b384f39SPeter Avalos 			case SIGTTOU:
286*6b384f39SPeter Avalos 				need_restart = 1;
287*6b384f39SPeter Avalos 			}
288*6b384f39SPeter Avalos 		}
289*6b384f39SPeter Avalos 	}
290*6b384f39SPeter Avalos 	if (need_restart)
291*6b384f39SPeter Avalos 		goto restart;
292*6b384f39SPeter Avalos 
293*6b384f39SPeter Avalos 	if (save_errno)
294*6b384f39SPeter Avalos 		errno = save_errno;
295*6b384f39SPeter Avalos 	return(nr == -1 ? NULL : buf);
296*6b384f39SPeter Avalos }
297*6b384f39SPeter Avalos #endif /* _WIN32 && !__CYGWIN__ */
298*6b384f39SPeter Avalos #endif /* HAVE_READPASSPHRASE */
299*6b384f39SPeter Avalos 
300*6b384f39SPeter Avalos char *
301*6b384f39SPeter Avalos lafe_readpassphrase(const char *prompt, char *buf, size_t bufsiz)
302*6b384f39SPeter Avalos {
303*6b384f39SPeter Avalos 	char *p;
304*6b384f39SPeter Avalos 
305*6b384f39SPeter Avalos 	p = readpassphrase(prompt, buf, bufsiz, RPP_ECHO_OFF);
306*6b384f39SPeter Avalos 	if (p == NULL) {
307*6b384f39SPeter Avalos 		switch (errno) {
308*6b384f39SPeter Avalos 		case EINTR:
309*6b384f39SPeter Avalos 			break;
310*6b384f39SPeter Avalos 		default:
311*6b384f39SPeter Avalos 			lafe_errc(1, errno, "Couldn't read passphrase");
312*6b384f39SPeter Avalos 			break;
313*6b384f39SPeter Avalos 		}
314*6b384f39SPeter Avalos 	}
315*6b384f39SPeter Avalos 	return (p);
316*6b384f39SPeter Avalos }
317*6b384f39SPeter Avalos 
318