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