]>
Commit | Line | Data |
---|---|---|
94ec8c6b | 1 | #include "includes.h" |
5ca51e19 | 2 | RCSID("$OpenBSD: cli.c,v 1.8 2001/02/08 19:30:51 itojun Exp $"); |
94ec8c6b | 3 | |
4 | #include "xmalloc.h" | |
42f11eb2 | 5 | #include "log.h" |
5ca51e19 | 6 | #include "cli.h" |
94ec8c6b | 7 | |
8 | static int cli_input = -1; | |
9 | static int cli_output = -1; | |
10 | static int cli_from_stdin = 0; | |
11 | ||
12 | sigset_t oset; | |
13 | sigset_t nset; | |
14 | struct sigaction nsa; | |
15 | struct sigaction osa; | |
16 | struct termios ntio; | |
17 | struct termios otio; | |
18 | int echo_modified; | |
19 | ||
20 | volatile int intr; | |
21 | ||
22 | static int | |
23 | cli_open(int from_stdin) | |
24 | { | |
25 | if (cli_input >= 0 && cli_output >= 0 && cli_from_stdin == from_stdin) | |
26 | return 1; | |
27 | ||
28 | if (from_stdin) { | |
29 | if (!cli_from_stdin && cli_input >= 0) { | |
30 | (void)close(cli_input); | |
31 | } | |
32 | cli_input = STDIN_FILENO; | |
33 | cli_output = STDERR_FILENO; | |
34 | } else { | |
5ca51e19 | 35 | cli_input = cli_output = open(_PATH_TTY, O_RDWR); |
94ec8c6b | 36 | if (cli_input < 0) |
37 | fatal("You have no controlling tty. Cannot read passphrase."); | |
38 | } | |
39 | ||
40 | cli_from_stdin = from_stdin; | |
41 | ||
42 | return cli_input >= 0 && cli_output >= 0 && cli_from_stdin == from_stdin; | |
43 | } | |
44 | ||
45 | static void | |
5ca51e19 | 46 | cli_close(void) |
94ec8c6b | 47 | { |
48 | if (!cli_from_stdin && cli_input >= 0) | |
49 | close(cli_input); | |
50 | cli_input = -1; | |
51 | cli_output = -1; | |
52 | cli_from_stdin = 0; | |
53 | return; | |
54 | } | |
55 | ||
56 | void | |
5ca51e19 | 57 | intrcatch(int sig) |
94ec8c6b | 58 | { |
59 | intr = 1; | |
60 | } | |
61 | ||
62 | static void | |
5ca51e19 | 63 | cli_echo_disable(void) |
94ec8c6b | 64 | { |
65 | sigemptyset(&nset); | |
66 | sigaddset(&nset, SIGTSTP); | |
67 | (void) sigprocmask(SIG_BLOCK, &nset, &oset); | |
68 | ||
69 | intr = 0; | |
70 | ||
71 | memset(&nsa, 0, sizeof(nsa)); | |
72 | nsa.sa_handler = intrcatch; | |
73 | (void) sigaction(SIGINT, &nsa, &osa); | |
74 | ||
75 | echo_modified = 0; | |
76 | if (tcgetattr(cli_input, &otio) == 0 && (otio.c_lflag & ECHO)) { | |
77 | echo_modified = 1; | |
78 | ntio = otio; | |
79 | ntio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); | |
80 | (void) tcsetattr(cli_input, TCSANOW, &ntio); | |
81 | } | |
82 | return; | |
83 | } | |
84 | ||
85 | static void | |
5ca51e19 | 86 | cli_echo_restore(void) |
94ec8c6b | 87 | { |
88 | if (echo_modified != 0) { | |
89 | tcsetattr(cli_input, TCSANOW, &otio); | |
90 | echo_modified = 0; | |
91 | } | |
92 | ||
93 | (void) sigprocmask(SIG_SETMASK, &oset, NULL); | |
94 | (void) sigaction(SIGINT, &osa, NULL); | |
95 | ||
96 | if (intr != 0) { | |
97 | kill(getpid(), SIGINT); | |
98 | sigemptyset(&nset); | |
99 | /* XXX tty has not neccessarily drained by now? */ | |
100 | sigsuspend(&nset); | |
101 | intr = 0; | |
102 | } | |
103 | return; | |
104 | } | |
105 | ||
106 | static int | |
107 | cli_read(char* buf, int size, int echo) | |
108 | { | |
109 | char ch = 0; | |
110 | int i = 0; | |
111 | ||
112 | if (!echo) | |
113 | cli_echo_disable(); | |
114 | ||
115 | while (ch != '\n') { | |
116 | if (read(cli_input, &ch, 1) != 1) | |
117 | break; | |
118 | if (ch == '\n' || intr != 0) | |
119 | break; | |
120 | if (i < size) | |
121 | buf[i++] = ch; | |
122 | } | |
123 | buf[i] = '\0'; | |
124 | ||
125 | if (!echo) | |
126 | cli_echo_restore(); | |
127 | if (!intr && !echo) | |
128 | (void) write(cli_output, "\n", 1); | |
129 | return i; | |
130 | } | |
131 | ||
132 | static int | |
8694a1ce | 133 | cli_write(const char* buf, int size) |
94ec8c6b | 134 | { |
135 | int i, len, pos, ret = 0; | |
136 | char *output, *p; | |
137 | ||
138 | output = xmalloc(4*size); | |
139 | for (p = output, i = 0; i < size; i++) { | |
2b87da3b | 140 | if (buf[i] == '\n') |
141 | *p++ = buf[i]; | |
142 | else | |
143 | p = vis(p, buf[i], 0, 0); | |
144 | } | |
94ec8c6b | 145 | len = p - output; |
146 | ||
147 | for (pos = 0; pos < len; pos += ret) { | |
148 | ret = write(cli_output, output + pos, len - pos); | |
bbcf899f | 149 | if (ret == -1) { |
150 | xfree(output); | |
94ec8c6b | 151 | return -1; |
bbcf899f | 152 | } |
94ec8c6b | 153 | } |
bbcf899f | 154 | xfree(output); |
94ec8c6b | 155 | return 0; |
156 | } | |
157 | ||
158 | /* | |
159 | * Presents a prompt and returns the response allocated with xmalloc(). | |
160 | * Uses /dev/tty or stdin/out depending on arg. Optionally disables echo | |
161 | * of response depending on arg. Tries to ensure that no other userland | |
162 | * buffer is storing the response. | |
163 | */ | |
164 | char* | |
8694a1ce | 165 | cli_read_passphrase(const char* prompt, int from_stdin, int echo_enable) |
94ec8c6b | 166 | { |
167 | char buf[BUFSIZ]; | |
168 | char* p; | |
169 | ||
170 | if (!cli_open(from_stdin)) | |
171 | fatal("Cannot read passphrase."); | |
172 | ||
173 | fflush(stdout); | |
174 | ||
175 | cli_write(prompt, strlen(prompt)); | |
176 | cli_read(buf, sizeof buf, echo_enable); | |
177 | ||
178 | cli_close(); | |
179 | ||
180 | p = xstrdup(buf); | |
181 | memset(buf, 0, sizeof(buf)); | |
182 | return (p); | |
183 | } | |
184 | ||
185 | char* | |
186 | cli_prompt(char* prompt, int echo_enable) | |
187 | { | |
188 | return cli_read_passphrase(prompt, 0, echo_enable); | |
189 | } | |
190 | ||
191 | void | |
192 | cli_mesg(char* mesg) | |
193 | { | |
194 | cli_open(0); | |
195 | cli_write(mesg, strlen(mesg)); | |
196 | cli_write("\n", strlen("\n")); | |
197 | cli_close(); | |
198 | return; | |
199 | } |