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