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