]>
Commit | Line | Data |
---|---|---|
9e9bd8c0 | 1 | /* $OpenBSD: cli.c,v 1.12 2001/05/06 17:52:07 mouring Exp $ */ |
4371658c | 2 | |
3 | /* | |
4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * | |
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
25 | */ | |
26 | ||
94ec8c6b | 27 | #include "includes.h" |
9e9bd8c0 | 28 | RCSID("$OpenBSD: cli.c,v 1.12 2001/05/06 17:52:07 mouring Exp $"); |
94ec8c6b | 29 | |
30 | #include "xmalloc.h" | |
42f11eb2 | 31 | #include "log.h" |
5ca51e19 | 32 | #include "cli.h" |
94ec8c6b | 33 | |
34 | static int cli_input = -1; | |
35 | static int cli_output = -1; | |
36 | static int cli_from_stdin = 0; | |
37 | ||
38 | sigset_t oset; | |
39 | sigset_t nset; | |
40 | struct sigaction nsa; | |
41 | struct sigaction osa; | |
42 | struct termios ntio; | |
43 | struct termios otio; | |
44 | int echo_modified; | |
45 | ||
46 | volatile int intr; | |
47 | ||
48 | static int | |
49 | cli_open(int from_stdin) | |
50 | { | |
51 | if (cli_input >= 0 && cli_output >= 0 && cli_from_stdin == from_stdin) | |
52 | return 1; | |
53 | ||
54 | if (from_stdin) { | |
55 | if (!cli_from_stdin && cli_input >= 0) { | |
56 | (void)close(cli_input); | |
57 | } | |
58 | cli_input = STDIN_FILENO; | |
59 | cli_output = STDERR_FILENO; | |
60 | } else { | |
5ca51e19 | 61 | cli_input = cli_output = open(_PATH_TTY, O_RDWR); |
94ec8c6b | 62 | if (cli_input < 0) |
63 | fatal("You have no controlling tty. Cannot read passphrase."); | |
64 | } | |
65 | ||
66 | cli_from_stdin = from_stdin; | |
67 | ||
68 | return cli_input >= 0 && cli_output >= 0 && cli_from_stdin == from_stdin; | |
69 | } | |
70 | ||
71 | static void | |
5ca51e19 | 72 | cli_close(void) |
94ec8c6b | 73 | { |
74 | if (!cli_from_stdin && cli_input >= 0) | |
75 | close(cli_input); | |
76 | cli_input = -1; | |
77 | cli_output = -1; | |
78 | cli_from_stdin = 0; | |
79 | return; | |
80 | } | |
81 | ||
82 | void | |
5ca51e19 | 83 | intrcatch(int sig) |
94ec8c6b | 84 | { |
85 | intr = 1; | |
86 | } | |
87 | ||
88 | static void | |
5ca51e19 | 89 | cli_echo_disable(void) |
94ec8c6b | 90 | { |
91 | sigemptyset(&nset); | |
92 | sigaddset(&nset, SIGTSTP); | |
93 | (void) sigprocmask(SIG_BLOCK, &nset, &oset); | |
94 | ||
95 | intr = 0; | |
96 | ||
97 | memset(&nsa, 0, sizeof(nsa)); | |
98 | nsa.sa_handler = intrcatch; | |
99 | (void) sigaction(SIGINT, &nsa, &osa); | |
100 | ||
101 | echo_modified = 0; | |
102 | if (tcgetattr(cli_input, &otio) == 0 && (otio.c_lflag & ECHO)) { | |
103 | echo_modified = 1; | |
104 | ntio = otio; | |
105 | ntio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); | |
106 | (void) tcsetattr(cli_input, TCSANOW, &ntio); | |
107 | } | |
108 | return; | |
109 | } | |
110 | ||
111 | static void | |
5ca51e19 | 112 | cli_echo_restore(void) |
94ec8c6b | 113 | { |
114 | if (echo_modified != 0) { | |
115 | tcsetattr(cli_input, TCSANOW, &otio); | |
116 | echo_modified = 0; | |
117 | } | |
118 | ||
119 | (void) sigprocmask(SIG_SETMASK, &oset, NULL); | |
120 | (void) sigaction(SIGINT, &osa, NULL); | |
121 | ||
122 | if (intr != 0) { | |
123 | kill(getpid(), SIGINT); | |
124 | sigemptyset(&nset); | |
125 | /* XXX tty has not neccessarily drained by now? */ | |
126 | sigsuspend(&nset); | |
127 | intr = 0; | |
128 | } | |
129 | return; | |
130 | } | |
131 | ||
132 | static int | |
133 | cli_read(char* buf, int size, int echo) | |
134 | { | |
135 | char ch = 0; | |
136 | int i = 0; | |
bbc62e59 | 137 | int n; |
94ec8c6b | 138 | |
139 | if (!echo) | |
140 | cli_echo_disable(); | |
141 | ||
142 | while (ch != '\n') { | |
bbc62e59 | 143 | n = read(cli_input, &ch, 1); |
144 | if (n == -1 && (errno == EAGAIN || errno == EINTR)) | |
145 | continue; | |
146 | if (n != 1) | |
94ec8c6b | 147 | break; |
148 | if (ch == '\n' || intr != 0) | |
149 | break; | |
150 | if (i < size) | |
151 | buf[i++] = ch; | |
152 | } | |
153 | buf[i] = '\0'; | |
154 | ||
155 | if (!echo) | |
156 | cli_echo_restore(); | |
157 | if (!intr && !echo) | |
158 | (void) write(cli_output, "\n", 1); | |
159 | return i; | |
160 | } | |
161 | ||
162 | static int | |
8694a1ce | 163 | cli_write(const char* buf, int size) |
94ec8c6b | 164 | { |
165 | int i, len, pos, ret = 0; | |
166 | char *output, *p; | |
167 | ||
168 | output = xmalloc(4*size); | |
169 | for (p = output, i = 0; i < size; i++) { | |
7f8ea238 | 170 | if (buf[i] == '\n' || buf[i] == '\r') |
2b87da3b | 171 | *p++ = buf[i]; |
172 | else | |
173 | p = vis(p, buf[i], 0, 0); | |
174 | } | |
94ec8c6b | 175 | len = p - output; |
176 | ||
177 | for (pos = 0; pos < len; pos += ret) { | |
178 | ret = write(cli_output, output + pos, len - pos); | |
bbcf899f | 179 | if (ret == -1) { |
180 | xfree(output); | |
94ec8c6b | 181 | return -1; |
bbcf899f | 182 | } |
94ec8c6b | 183 | } |
bbcf899f | 184 | xfree(output); |
94ec8c6b | 185 | return 0; |
186 | } | |
187 | ||
188 | /* | |
189 | * Presents a prompt and returns the response allocated with xmalloc(). | |
190 | * Uses /dev/tty or stdin/out depending on arg. Optionally disables echo | |
191 | * of response depending on arg. Tries to ensure that no other userland | |
192 | * buffer is storing the response. | |
193 | */ | |
194 | char* | |
8694a1ce | 195 | cli_read_passphrase(const char* prompt, int from_stdin, int echo_enable) |
94ec8c6b | 196 | { |
197 | char buf[BUFSIZ]; | |
198 | char* p; | |
199 | ||
200 | if (!cli_open(from_stdin)) | |
201 | fatal("Cannot read passphrase."); | |
202 | ||
203 | fflush(stdout); | |
204 | ||
205 | cli_write(prompt, strlen(prompt)); | |
206 | cli_read(buf, sizeof buf, echo_enable); | |
207 | ||
208 | cli_close(); | |
209 | ||
210 | p = xstrdup(buf); | |
211 | memset(buf, 0, sizeof(buf)); | |
212 | return (p); | |
213 | } | |
214 | ||
215 | char* | |
216 | cli_prompt(char* prompt, int echo_enable) | |
217 | { | |
218 | return cli_read_passphrase(prompt, 0, echo_enable); | |
219 | } | |
220 | ||
221 | void | |
222 | cli_mesg(char* mesg) | |
223 | { | |
224 | cli_open(0); | |
225 | cli_write(mesg, strlen(mesg)); | |
226 | cli_write("\n", strlen("\n")); | |
227 | cli_close(); | |
228 | return; | |
229 | } |