1*0afa8e06SEd Maste /* $OpenBSD: readpassphrase.c,v 1.26 2016/10/18 12:47:18 millert Exp $ */
2*0afa8e06SEd Maste
3*0afa8e06SEd Maste /*
4*0afa8e06SEd Maste * Copyright (c) 2000-2002, 2007, 2010
5*0afa8e06SEd Maste * Todd C. Miller <Todd.Miller@courtesan.com>
6*0afa8e06SEd Maste *
7*0afa8e06SEd Maste * Permission to use, copy, modify, and distribute this software for any
8*0afa8e06SEd Maste * purpose with or without fee is hereby granted, provided that the above
9*0afa8e06SEd Maste * copyright notice and this permission notice appear in all copies.
10*0afa8e06SEd Maste *
11*0afa8e06SEd Maste * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12*0afa8e06SEd Maste * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13*0afa8e06SEd Maste * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14*0afa8e06SEd Maste * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15*0afa8e06SEd Maste * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16*0afa8e06SEd Maste * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17*0afa8e06SEd Maste * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18*0afa8e06SEd Maste *
19*0afa8e06SEd Maste * Sponsored in part by the Defense Advanced Research Projects
20*0afa8e06SEd Maste * Agency (DARPA) and Air Force Research Laboratory, Air Force
21*0afa8e06SEd Maste * Materiel Command, USAF, under agreement number F39502-99-1-0512.
22*0afa8e06SEd Maste */
23*0afa8e06SEd Maste
24*0afa8e06SEd Maste /* OPENBSD ORIGINAL: lib/libc/gen/readpassphrase.c */
25*0afa8e06SEd Maste
26*0afa8e06SEd Maste #include "openbsd-compat.h"
27*0afa8e06SEd Maste
28*0afa8e06SEd Maste #ifndef HAVE_READPASSPHRASE
29*0afa8e06SEd Maste
30*0afa8e06SEd Maste #include <termios.h>
31*0afa8e06SEd Maste #include <signal.h>
32*0afa8e06SEd Maste #include <ctype.h>
33*0afa8e06SEd Maste #include <fcntl.h>
34*0afa8e06SEd Maste #include <errno.h>
35*0afa8e06SEd Maste #include <string.h>
36*0afa8e06SEd Maste #ifdef HAVE_UNISTD_H
37*0afa8e06SEd Maste #include <unistd.h>
38*0afa8e06SEd Maste #endif
39*0afa8e06SEd Maste #include <paths.h>
40*0afa8e06SEd Maste
41*0afa8e06SEd Maste #ifndef _PATH_TTY
42*0afa8e06SEd Maste # define _PATH_TTY "/dev/tty"
43*0afa8e06SEd Maste #endif
44*0afa8e06SEd Maste
45*0afa8e06SEd Maste #ifndef TCSASOFT
46*0afa8e06SEd Maste /* If we don't have TCSASOFT define it so that ORing it it below is a no-op. */
47*0afa8e06SEd Maste # define TCSASOFT 0
48*0afa8e06SEd Maste #endif
49*0afa8e06SEd Maste
50*0afa8e06SEd Maste /* SunOS 4.x which lacks _POSIX_VDISABLE, but has VDISABLE */
51*0afa8e06SEd Maste #if !defined(_POSIX_VDISABLE) && defined(VDISABLE)
52*0afa8e06SEd Maste # define _POSIX_VDISABLE VDISABLE
53*0afa8e06SEd Maste #endif
54*0afa8e06SEd Maste
55*0afa8e06SEd Maste static volatile sig_atomic_t signo[NSIG];
56*0afa8e06SEd Maste
57*0afa8e06SEd Maste static void handler(int);
58*0afa8e06SEd Maste
59*0afa8e06SEd Maste char *
readpassphrase(const char * prompt,char * buf,size_t bufsiz,int flags)60*0afa8e06SEd Maste readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
61*0afa8e06SEd Maste {
62*0afa8e06SEd Maste ssize_t nr;
63*0afa8e06SEd Maste int input, output, save_errno, i, need_restart;
64*0afa8e06SEd Maste char ch, *p, *end;
65*0afa8e06SEd Maste struct termios term, oterm;
66*0afa8e06SEd Maste struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm;
67*0afa8e06SEd Maste struct sigaction savetstp, savettin, savettou, savepipe;
68*0afa8e06SEd Maste
69*0afa8e06SEd Maste /* I suppose we could alloc on demand in this case (XXX). */
70*0afa8e06SEd Maste if (bufsiz == 0) {
71*0afa8e06SEd Maste errno = EINVAL;
72*0afa8e06SEd Maste return(NULL);
73*0afa8e06SEd Maste }
74*0afa8e06SEd Maste
75*0afa8e06SEd Maste restart:
76*0afa8e06SEd Maste for (i = 0; i < NSIG; i++)
77*0afa8e06SEd Maste signo[i] = 0;
78*0afa8e06SEd Maste need_restart = 0;
79*0afa8e06SEd Maste /*
80*0afa8e06SEd Maste * Read and write to /dev/tty if available. If not, read from
81*0afa8e06SEd Maste * stdin and write to stderr unless a tty is required.
82*0afa8e06SEd Maste */
83*0afa8e06SEd Maste if ((flags & RPP_STDIN) ||
84*0afa8e06SEd Maste (input = output = open(_PATH_TTY, O_RDWR)) == -1) {
85*0afa8e06SEd Maste if (flags & RPP_REQUIRE_TTY) {
86*0afa8e06SEd Maste errno = ENOTTY;
87*0afa8e06SEd Maste return(NULL);
88*0afa8e06SEd Maste }
89*0afa8e06SEd Maste input = STDIN_FILENO;
90*0afa8e06SEd Maste output = STDERR_FILENO;
91*0afa8e06SEd Maste }
92*0afa8e06SEd Maste
93*0afa8e06SEd Maste /*
94*0afa8e06SEd Maste * Turn off echo if possible.
95*0afa8e06SEd Maste * If we are using a tty but are not the foreground pgrp this will
96*0afa8e06SEd Maste * generate SIGTTOU, so do it *before* installing the signal handlers.
97*0afa8e06SEd Maste */
98*0afa8e06SEd Maste if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) {
99*0afa8e06SEd Maste memcpy(&term, &oterm, sizeof(term));
100*0afa8e06SEd Maste if (!(flags & RPP_ECHO_ON))
101*0afa8e06SEd Maste term.c_lflag &= ~(ECHO | ECHONL);
102*0afa8e06SEd Maste #ifdef VSTATUS
103*0afa8e06SEd Maste if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
104*0afa8e06SEd Maste term.c_cc[VSTATUS] = _POSIX_VDISABLE;
105*0afa8e06SEd Maste #endif
106*0afa8e06SEd Maste (void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
107*0afa8e06SEd Maste } else {
108*0afa8e06SEd Maste memset(&term, 0, sizeof(term));
109*0afa8e06SEd Maste term.c_lflag |= ECHO;
110*0afa8e06SEd Maste memset(&oterm, 0, sizeof(oterm));
111*0afa8e06SEd Maste oterm.c_lflag |= ECHO;
112*0afa8e06SEd Maste }
113*0afa8e06SEd Maste
114*0afa8e06SEd Maste /*
115*0afa8e06SEd Maste * Catch signals that would otherwise cause the user to end
116*0afa8e06SEd Maste * up with echo turned off in the shell. Don't worry about
117*0afa8e06SEd Maste * things like SIGXCPU and SIGVTALRM for now.
118*0afa8e06SEd Maste */
119*0afa8e06SEd Maste sigemptyset(&sa.sa_mask);
120*0afa8e06SEd Maste sa.sa_flags = 0; /* don't restart system calls */
121*0afa8e06SEd Maste sa.sa_handler = handler;
122*0afa8e06SEd Maste (void)sigaction(SIGALRM, &sa, &savealrm);
123*0afa8e06SEd Maste (void)sigaction(SIGHUP, &sa, &savehup);
124*0afa8e06SEd Maste (void)sigaction(SIGINT, &sa, &saveint);
125*0afa8e06SEd Maste (void)sigaction(SIGPIPE, &sa, &savepipe);
126*0afa8e06SEd Maste (void)sigaction(SIGQUIT, &sa, &savequit);
127*0afa8e06SEd Maste (void)sigaction(SIGTERM, &sa, &saveterm);
128*0afa8e06SEd Maste (void)sigaction(SIGTSTP, &sa, &savetstp);
129*0afa8e06SEd Maste (void)sigaction(SIGTTIN, &sa, &savettin);
130*0afa8e06SEd Maste (void)sigaction(SIGTTOU, &sa, &savettou);
131*0afa8e06SEd Maste
132*0afa8e06SEd Maste if (!(flags & RPP_STDIN))
133*0afa8e06SEd Maste (void)write(output, prompt, strlen(prompt));
134*0afa8e06SEd Maste end = buf + bufsiz - 1;
135*0afa8e06SEd Maste p = buf;
136*0afa8e06SEd Maste while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') {
137*0afa8e06SEd Maste if (p < end) {
138*0afa8e06SEd Maste if ((flags & RPP_SEVENBIT))
139*0afa8e06SEd Maste ch &= 0x7f;
140*0afa8e06SEd Maste if (isalpha((unsigned char)ch)) {
141*0afa8e06SEd Maste if ((flags & RPP_FORCELOWER))
142*0afa8e06SEd Maste ch = (char)tolower((unsigned char)ch);
143*0afa8e06SEd Maste if ((flags & RPP_FORCEUPPER))
144*0afa8e06SEd Maste ch = (char)toupper((unsigned char)ch);
145*0afa8e06SEd Maste }
146*0afa8e06SEd Maste *p++ = ch;
147*0afa8e06SEd Maste }
148*0afa8e06SEd Maste }
149*0afa8e06SEd Maste *p = '\0';
150*0afa8e06SEd Maste save_errno = errno;
151*0afa8e06SEd Maste if (!(term.c_lflag & ECHO))
152*0afa8e06SEd Maste (void)write(output, "\n", 1);
153*0afa8e06SEd Maste
154*0afa8e06SEd Maste /* Restore old terminal settings and signals. */
155*0afa8e06SEd Maste if (memcmp(&term, &oterm, sizeof(term)) != 0) {
156*0afa8e06SEd Maste const int sigttou = signo[SIGTTOU];
157*0afa8e06SEd Maste
158*0afa8e06SEd Maste /* Ignore SIGTTOU generated when we are not the fg pgrp. */
159*0afa8e06SEd Maste while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 &&
160*0afa8e06SEd Maste errno == EINTR && !signo[SIGTTOU])
161*0afa8e06SEd Maste continue;
162*0afa8e06SEd Maste signo[SIGTTOU] = sigttou;
163*0afa8e06SEd Maste }
164*0afa8e06SEd Maste (void)sigaction(SIGALRM, &savealrm, NULL);
165*0afa8e06SEd Maste (void)sigaction(SIGHUP, &savehup, NULL);
166*0afa8e06SEd Maste (void)sigaction(SIGINT, &saveint, NULL);
167*0afa8e06SEd Maste (void)sigaction(SIGQUIT, &savequit, NULL);
168*0afa8e06SEd Maste (void)sigaction(SIGPIPE, &savepipe, NULL);
169*0afa8e06SEd Maste (void)sigaction(SIGTERM, &saveterm, NULL);
170*0afa8e06SEd Maste (void)sigaction(SIGTSTP, &savetstp, NULL);
171*0afa8e06SEd Maste (void)sigaction(SIGTTIN, &savettin, NULL);
172*0afa8e06SEd Maste (void)sigaction(SIGTTOU, &savettou, NULL);
173*0afa8e06SEd Maste if (input != STDIN_FILENO)
174*0afa8e06SEd Maste (void)close(input);
175*0afa8e06SEd Maste
176*0afa8e06SEd Maste /*
177*0afa8e06SEd Maste * If we were interrupted by a signal, resend it to ourselves
178*0afa8e06SEd Maste * now that we have restored the signal handlers.
179*0afa8e06SEd Maste */
180*0afa8e06SEd Maste for (i = 0; i < NSIG; i++) {
181*0afa8e06SEd Maste if (signo[i]) {
182*0afa8e06SEd Maste kill(getpid(), i);
183*0afa8e06SEd Maste switch (i) {
184*0afa8e06SEd Maste case SIGTSTP:
185*0afa8e06SEd Maste case SIGTTIN:
186*0afa8e06SEd Maste case SIGTTOU:
187*0afa8e06SEd Maste need_restart = 1;
188*0afa8e06SEd Maste }
189*0afa8e06SEd Maste }
190*0afa8e06SEd Maste }
191*0afa8e06SEd Maste if (need_restart)
192*0afa8e06SEd Maste goto restart;
193*0afa8e06SEd Maste
194*0afa8e06SEd Maste if (save_errno)
195*0afa8e06SEd Maste errno = save_errno;
196*0afa8e06SEd Maste return(nr == -1 ? NULL : buf);
197*0afa8e06SEd Maste }
198*0afa8e06SEd Maste
199*0afa8e06SEd Maste #if 0
200*0afa8e06SEd Maste char *
201*0afa8e06SEd Maste getpass(const char *prompt)
202*0afa8e06SEd Maste {
203*0afa8e06SEd Maste static char buf[_PASSWORD_LEN + 1];
204*0afa8e06SEd Maste
205*0afa8e06SEd Maste return(readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF));
206*0afa8e06SEd Maste }
207*0afa8e06SEd Maste #endif
208*0afa8e06SEd Maste
handler(int s)209*0afa8e06SEd Maste static void handler(int s)
210*0afa8e06SEd Maste {
211*0afa8e06SEd Maste
212*0afa8e06SEd Maste signo[s] = 1;
213*0afa8e06SEd Maste }
214*0afa8e06SEd Maste #endif /* HAVE_READPASSPHRASE */
215