1*ca86bcf2SDag-Erling Smørgrav /* $OpenBSD: readpassphrase.c,v 1.26 2016/10/18 12:47:18 millert Exp $ */
283d2307dSDag-Erling Smørgrav
383d2307dSDag-Erling Smørgrav /*
4*ca86bcf2SDag-Erling Smørgrav * Copyright (c) 2000-2002, 2007, 2010
5*ca86bcf2SDag-Erling Smørgrav * Todd C. Miller <Todd.Miller@courtesan.com>
683d2307dSDag-Erling Smørgrav *
7d95e11bfSDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any
8d95e11bfSDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above
9d95e11bfSDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies.
1083d2307dSDag-Erling Smørgrav *
11d95e11bfSDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12d95e11bfSDag-Erling Smørgrav * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13d95e11bfSDag-Erling Smørgrav * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14d95e11bfSDag-Erling Smørgrav * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15d95e11bfSDag-Erling Smørgrav * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16d95e11bfSDag-Erling Smørgrav * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17d95e11bfSDag-Erling Smørgrav * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18d95e11bfSDag-Erling Smørgrav *
19d95e11bfSDag-Erling Smørgrav * Sponsored in part by the Defense Advanced Research Projects
20d95e11bfSDag-Erling Smørgrav * Agency (DARPA) and Air Force Research Laboratory, Air Force
21d95e11bfSDag-Erling Smørgrav * Materiel Command, USAF, under agreement number F39502-99-1-0512.
2283d2307dSDag-Erling Smørgrav */
2383d2307dSDag-Erling Smørgrav
24021d409fSDag-Erling Smørgrav /* OPENBSD ORIGINAL: lib/libc/gen/readpassphrase.c */
2583d2307dSDag-Erling Smørgrav
2683d2307dSDag-Erling Smørgrav #include "includes.h"
2783d2307dSDag-Erling Smørgrav
2883d2307dSDag-Erling Smørgrav #ifndef HAVE_READPASSPHRASE
2983d2307dSDag-Erling Smørgrav
3083d2307dSDag-Erling Smørgrav #include <termios.h>
31761efaa7SDag-Erling Smørgrav #include <signal.h>
32761efaa7SDag-Erling Smørgrav #include <ctype.h>
33761efaa7SDag-Erling Smørgrav #include <fcntl.h>
3483d2307dSDag-Erling Smørgrav #include <readpassphrase.h>
35761efaa7SDag-Erling Smørgrav #include <errno.h>
36761efaa7SDag-Erling Smørgrav #include <string.h>
37761efaa7SDag-Erling Smørgrav #include <unistd.h>
3883d2307dSDag-Erling Smørgrav
39*ca86bcf2SDag-Erling Smørgrav #ifndef TCSASOFT
40*ca86bcf2SDag-Erling Smørgrav /* If we don't have TCSASOFT define it so that ORing it it below is a no-op. */
41*ca86bcf2SDag-Erling Smørgrav # define TCSASOFT 0
4283d2307dSDag-Erling Smørgrav #endif
4383d2307dSDag-Erling Smørgrav
4483d2307dSDag-Erling Smørgrav /* SunOS 4.x which lacks _POSIX_VDISABLE, but has VDISABLE */
4583d2307dSDag-Erling Smørgrav #if !defined(_POSIX_VDISABLE) && defined(VDISABLE)
4683d2307dSDag-Erling Smørgrav # define _POSIX_VDISABLE VDISABLE
4783d2307dSDag-Erling Smørgrav #endif
4883d2307dSDag-Erling Smørgrav
49b15c8340SDag-Erling Smørgrav static volatile sig_atomic_t signo[_NSIG];
5083d2307dSDag-Erling Smørgrav
5183d2307dSDag-Erling Smørgrav static void handler(int);
5283d2307dSDag-Erling Smørgrav
5383d2307dSDag-Erling Smørgrav char *
readpassphrase(const char * prompt,char * buf,size_t bufsiz,int flags)5483d2307dSDag-Erling Smørgrav readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
5583d2307dSDag-Erling Smørgrav {
5683d2307dSDag-Erling Smørgrav ssize_t nr;
57b15c8340SDag-Erling Smørgrav int input, output, save_errno, i, need_restart;
5883d2307dSDag-Erling Smørgrav char ch, *p, *end;
5983d2307dSDag-Erling Smørgrav struct termios term, oterm;
604b17dab0SDag-Erling Smørgrav struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm;
614b17dab0SDag-Erling Smørgrav struct sigaction savetstp, savettin, savettou, savepipe;
6283d2307dSDag-Erling Smørgrav
6383d2307dSDag-Erling Smørgrav /* I suppose we could alloc on demand in this case (XXX). */
6483d2307dSDag-Erling Smørgrav if (bufsiz == 0) {
6583d2307dSDag-Erling Smørgrav errno = EINVAL;
6683d2307dSDag-Erling Smørgrav return(NULL);
6783d2307dSDag-Erling Smørgrav }
6883d2307dSDag-Erling Smørgrav
6983d2307dSDag-Erling Smørgrav restart:
70b15c8340SDag-Erling Smørgrav for (i = 0; i < _NSIG; i++)
71b15c8340SDag-Erling Smørgrav signo[i] = 0;
72b15c8340SDag-Erling Smørgrav nr = -1;
73b15c8340SDag-Erling Smørgrav save_errno = 0;
74b15c8340SDag-Erling Smørgrav need_restart = 0;
7583d2307dSDag-Erling Smørgrav /*
7683d2307dSDag-Erling Smørgrav * Read and write to /dev/tty if available. If not, read from
7783d2307dSDag-Erling Smørgrav * stdin and write to stderr unless a tty is required.
7883d2307dSDag-Erling Smørgrav */
794b17dab0SDag-Erling Smørgrav if ((flags & RPP_STDIN) ||
804b17dab0SDag-Erling Smørgrav (input = output = open(_PATH_TTY, O_RDWR)) == -1) {
8183d2307dSDag-Erling Smørgrav if (flags & RPP_REQUIRE_TTY) {
8283d2307dSDag-Erling Smørgrav errno = ENOTTY;
8383d2307dSDag-Erling Smørgrav return(NULL);
8483d2307dSDag-Erling Smørgrav }
8583d2307dSDag-Erling Smørgrav input = STDIN_FILENO;
8683d2307dSDag-Erling Smørgrav output = STDERR_FILENO;
8783d2307dSDag-Erling Smørgrav }
8883d2307dSDag-Erling Smørgrav
8983d2307dSDag-Erling Smørgrav /*
90*ca86bcf2SDag-Erling Smørgrav * Turn off echo if possible.
91*ca86bcf2SDag-Erling Smørgrav * If we are using a tty but are not the foreground pgrp this will
92*ca86bcf2SDag-Erling Smørgrav * generate SIGTTOU, so do it *before* installing the signal handlers.
93*ca86bcf2SDag-Erling Smørgrav */
94*ca86bcf2SDag-Erling Smørgrav if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) {
95*ca86bcf2SDag-Erling Smørgrav memcpy(&term, &oterm, sizeof(term));
96*ca86bcf2SDag-Erling Smørgrav if (!(flags & RPP_ECHO_ON))
97*ca86bcf2SDag-Erling Smørgrav term.c_lflag &= ~(ECHO | ECHONL);
98*ca86bcf2SDag-Erling Smørgrav #ifdef VSTATUS
99*ca86bcf2SDag-Erling Smørgrav if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
100*ca86bcf2SDag-Erling Smørgrav term.c_cc[VSTATUS] = _POSIX_VDISABLE;
101*ca86bcf2SDag-Erling Smørgrav #endif
102*ca86bcf2SDag-Erling Smørgrav (void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
103*ca86bcf2SDag-Erling Smørgrav } else {
104*ca86bcf2SDag-Erling Smørgrav memset(&term, 0, sizeof(term));
105*ca86bcf2SDag-Erling Smørgrav term.c_lflag |= ECHO;
106*ca86bcf2SDag-Erling Smørgrav memset(&oterm, 0, sizeof(oterm));
107*ca86bcf2SDag-Erling Smørgrav oterm.c_lflag |= ECHO;
108*ca86bcf2SDag-Erling Smørgrav }
109*ca86bcf2SDag-Erling Smørgrav
110*ca86bcf2SDag-Erling Smørgrav /*
11183d2307dSDag-Erling Smørgrav * Catch signals that would otherwise cause the user to end
11283d2307dSDag-Erling Smørgrav * up with echo turned off in the shell. Don't worry about
1134b17dab0SDag-Erling Smørgrav * things like SIGXCPU and SIGVTALRM for now.
11483d2307dSDag-Erling Smørgrav */
11583d2307dSDag-Erling Smørgrav sigemptyset(&sa.sa_mask);
11683d2307dSDag-Erling Smørgrav sa.sa_flags = 0; /* don't restart system calls */
11783d2307dSDag-Erling Smørgrav sa.sa_handler = handler;
1184b17dab0SDag-Erling Smørgrav (void)sigaction(SIGALRM, &sa, &savealrm);
11983d2307dSDag-Erling Smørgrav (void)sigaction(SIGHUP, &sa, &savehup);
1204b17dab0SDag-Erling Smørgrav (void)sigaction(SIGINT, &sa, &saveint);
1214b17dab0SDag-Erling Smørgrav (void)sigaction(SIGPIPE, &sa, &savepipe);
12283d2307dSDag-Erling Smørgrav (void)sigaction(SIGQUIT, &sa, &savequit);
12383d2307dSDag-Erling Smørgrav (void)sigaction(SIGTERM, &sa, &saveterm);
12483d2307dSDag-Erling Smørgrav (void)sigaction(SIGTSTP, &sa, &savetstp);
12583d2307dSDag-Erling Smørgrav (void)sigaction(SIGTTIN, &sa, &savettin);
12683d2307dSDag-Erling Smørgrav (void)sigaction(SIGTTOU, &sa, &savettou);
12783d2307dSDag-Erling Smørgrav
1284b17dab0SDag-Erling Smørgrav if (!(flags & RPP_STDIN))
12983d2307dSDag-Erling Smørgrav (void)write(output, prompt, strlen(prompt));
13083d2307dSDag-Erling Smørgrav end = buf + bufsiz - 1;
131b15c8340SDag-Erling Smørgrav p = buf;
132b15c8340SDag-Erling Smørgrav while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') {
13383d2307dSDag-Erling Smørgrav if (p < end) {
13483d2307dSDag-Erling Smørgrav if ((flags & RPP_SEVENBIT))
13583d2307dSDag-Erling Smørgrav ch &= 0x7f;
136*ca86bcf2SDag-Erling Smørgrav if (isalpha((unsigned char)ch)) {
13783d2307dSDag-Erling Smørgrav if ((flags & RPP_FORCELOWER))
138*ca86bcf2SDag-Erling Smørgrav ch = (char)tolower((unsigned char)ch);
13983d2307dSDag-Erling Smørgrav if ((flags & RPP_FORCEUPPER))
140*ca86bcf2SDag-Erling Smørgrav ch = (char)toupper((unsigned char)ch);
14183d2307dSDag-Erling Smørgrav }
14283d2307dSDag-Erling Smørgrav *p++ = ch;
14383d2307dSDag-Erling Smørgrav }
14483d2307dSDag-Erling Smørgrav }
14583d2307dSDag-Erling Smørgrav *p = '\0';
14683d2307dSDag-Erling Smørgrav save_errno = errno;
14783d2307dSDag-Erling Smørgrav if (!(term.c_lflag & ECHO))
14883d2307dSDag-Erling Smørgrav (void)write(output, "\n", 1);
14983d2307dSDag-Erling Smørgrav
15083d2307dSDag-Erling Smørgrav /* Restore old terminal settings and signals. */
1514518870cSDag-Erling Smørgrav if (memcmp(&term, &oterm, sizeof(term)) != 0) {
152*ca86bcf2SDag-Erling Smørgrav const int sigttou = signo[SIGTTOU];
153*ca86bcf2SDag-Erling Smørgrav
154*ca86bcf2SDag-Erling Smørgrav /* Ignore SIGTTOU generated when we are not the fg pgrp. */
155*ca86bcf2SDag-Erling Smørgrav while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 &&
156*ca86bcf2SDag-Erling Smørgrav errno == EINTR && !signo[SIGTTOU])
1574518870cSDag-Erling Smørgrav continue;
158*ca86bcf2SDag-Erling Smørgrav signo[SIGTTOU] = sigttou;
1594518870cSDag-Erling Smørgrav }
1604b17dab0SDag-Erling Smørgrav (void)sigaction(SIGALRM, &savealrm, NULL);
16183d2307dSDag-Erling Smørgrav (void)sigaction(SIGHUP, &savehup, NULL);
1624b17dab0SDag-Erling Smørgrav (void)sigaction(SIGINT, &saveint, NULL);
16383d2307dSDag-Erling Smørgrav (void)sigaction(SIGQUIT, &savequit, NULL);
1644b17dab0SDag-Erling Smørgrav (void)sigaction(SIGPIPE, &savepipe, NULL);
16583d2307dSDag-Erling Smørgrav (void)sigaction(SIGTERM, &saveterm, NULL);
16683d2307dSDag-Erling Smørgrav (void)sigaction(SIGTSTP, &savetstp, NULL);
16783d2307dSDag-Erling Smørgrav (void)sigaction(SIGTTIN, &savettin, NULL);
168b15c8340SDag-Erling Smørgrav (void)sigaction(SIGTTOU, &savettou, NULL);
16983d2307dSDag-Erling Smørgrav if (input != STDIN_FILENO)
17083d2307dSDag-Erling Smørgrav (void)close(input);
17183d2307dSDag-Erling Smørgrav
17283d2307dSDag-Erling Smørgrav /*
17383d2307dSDag-Erling Smørgrav * If we were interrupted by a signal, resend it to ourselves
17483d2307dSDag-Erling Smørgrav * now that we have restored the signal handlers.
17583d2307dSDag-Erling Smørgrav */
176b15c8340SDag-Erling Smørgrav for (i = 0; i < _NSIG; i++) {
177b15c8340SDag-Erling Smørgrav if (signo[i]) {
178b15c8340SDag-Erling Smørgrav kill(getpid(), i);
179b15c8340SDag-Erling Smørgrav switch (i) {
18083d2307dSDag-Erling Smørgrav case SIGTSTP:
18183d2307dSDag-Erling Smørgrav case SIGTTIN:
18283d2307dSDag-Erling Smørgrav case SIGTTOU:
183b15c8340SDag-Erling Smørgrav need_restart = 1;
184b15c8340SDag-Erling Smørgrav }
185b15c8340SDag-Erling Smørgrav }
186b15c8340SDag-Erling Smørgrav }
187b15c8340SDag-Erling Smørgrav if (need_restart)
18883d2307dSDag-Erling Smørgrav goto restart;
18983d2307dSDag-Erling Smørgrav
190b15c8340SDag-Erling Smørgrav if (save_errno)
19183d2307dSDag-Erling Smørgrav errno = save_errno;
19283d2307dSDag-Erling Smørgrav return(nr == -1 ? NULL : buf);
19383d2307dSDag-Erling Smørgrav }
194*ca86bcf2SDag-Erling Smørgrav DEF_WEAK(readpassphrase);
19583d2307dSDag-Erling Smørgrav
19683d2307dSDag-Erling Smørgrav #if 0
19783d2307dSDag-Erling Smørgrav char *
19883d2307dSDag-Erling Smørgrav getpass(const char *prompt)
19983d2307dSDag-Erling Smørgrav {
20083d2307dSDag-Erling Smørgrav static char buf[_PASSWORD_LEN + 1];
20183d2307dSDag-Erling Smørgrav
20283d2307dSDag-Erling Smørgrav return(readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF));
20383d2307dSDag-Erling Smørgrav }
20483d2307dSDag-Erling Smørgrav #endif
20583d2307dSDag-Erling Smørgrav
handler(int s)20683d2307dSDag-Erling Smørgrav static void handler(int s)
20783d2307dSDag-Erling Smørgrav {
208d95e11bfSDag-Erling Smørgrav
209b15c8340SDag-Erling Smørgrav signo[s] = 1;
21083d2307dSDag-Erling Smørgrav }
21183d2307dSDag-Erling Smørgrav #endif /* HAVE_READPASSPHRASE */
212