r8305 made platform_x11_best_transport[] obsolete, but there still seem to be a
[u/mdw/putty] / unix / uxcons.c
CommitLineData
c5e438ec 1/*
2 * uxcons.c: various interactive-prompt routines shared between the
3 * Unix console PuTTY tools
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <stdarg.h>
9#include <assert.h>
10#include <termios.h>
11#include <unistd.h>
12
13#include "putty.h"
14#include "storage.h"
15#include "ssh.h"
16
17int console_batch_mode = FALSE;
18
b51259f6 19static void *console_logctx = NULL;
20
f7397dc6 21static struct termios orig_termios_stderr;
22static int stderr_is_a_tty;
23
24void stderr_tty_init()
25{
26 /* Ensure that if stderr is a tty, we can get it back to a sane state. */
27 if ((flags & FLAG_STDERR_TTY) && isatty(STDERR_FILENO)) {
28 stderr_is_a_tty = TRUE;
29 tcgetattr(STDERR_FILENO, &orig_termios_stderr);
30 }
31}
32
33void premsg(struct termios *cf)
34{
35 if (stderr_is_a_tty) {
36 tcgetattr(STDERR_FILENO, cf);
37 tcsetattr(STDERR_FILENO, TCSADRAIN, &orig_termios_stderr);
38 }
39}
40void postmsg(struct termios *cf)
41{
42 if (stderr_is_a_tty)
43 tcsetattr(STDERR_FILENO, TCSADRAIN, cf);
44}
45
c5e438ec 46/*
47 * Clean up and exit.
48 */
49void cleanup_exit(int code)
50{
51 /*
52 * Clean up.
53 */
54 sk_cleanup();
e85da6a5 55 random_save_seed();
c5e438ec 56 exit(code);
57}
58
755e0524 59void set_busy_status(void *frontend, int status)
60{
61}
62
125105d1 63void update_specials_menu(void *frontend)
64{
65}
66
39934deb 67void notify_remote_exit(void *frontend)
68{
69}
70
71void timer_change_notify(long next)
72{
73}
74
3d9449a1 75int verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
76 char *keystr, char *fingerprint,
77 void (*callback)(void *ctx, int result), void *ctx)
c5e438ec 78{
79 int ret;
80
81 static const char absentmsg_batch[] =
82 "The server's host key is not cached. You have no guarantee\n"
83 "that the server is the computer you think it is.\n"
65f66c88 84 "The server's %s key fingerprint is:\n"
c5e438ec 85 "%s\n"
86 "Connection abandoned.\n";
87 static const char absentmsg[] =
88 "The server's host key is not cached. You have no guarantee\n"
89 "that the server is the computer you think it is.\n"
65f66c88 90 "The server's %s key fingerprint is:\n"
c5e438ec 91 "%s\n"
92 "If you trust this host, enter \"y\" to add the key to\n"
93 "PuTTY's cache and carry on connecting.\n"
94 "If you want to carry on connecting just once, without\n"
95 "adding the key to the cache, enter \"n\".\n"
96 "If you do not trust this host, press Return to abandon the\n"
97 "connection.\n"
98 "Store key in cache? (y/n) ";
99
100 static const char wrongmsg_batch[] =
101 "WARNING - POTENTIAL SECURITY BREACH!\n"
102 "The server's host key does not match the one PuTTY has\n"
103 "cached. This means that either the server administrator\n"
104 "has changed the host key, or you have actually connected\n"
105 "to another computer pretending to be the server.\n"
65f66c88 106 "The new %s key fingerprint is:\n"
c5e438ec 107 "%s\n"
108 "Connection abandoned.\n";
109 static const char wrongmsg[] =
110 "WARNING - POTENTIAL SECURITY BREACH!\n"
111 "The server's host key does not match the one PuTTY has\n"
112 "cached. This means that either the server administrator\n"
113 "has changed the host key, or you have actually connected\n"
114 "to another computer pretending to be the server.\n"
65f66c88 115 "The new %s key fingerprint is:\n"
c5e438ec 116 "%s\n"
117 "If you were expecting this change and trust the new key,\n"
118 "enter \"y\" to update PuTTY's cache and continue connecting.\n"
119 "If you want to carry on connecting but without updating\n"
120 "the cache, enter \"n\".\n"
121 "If you want to abandon the connection completely, press\n"
122 "Return to cancel. Pressing Return is the ONLY guaranteed\n"
123 "safe choice.\n"
124 "Update cached key? (y/n, Return cancels connection) ";
125
126 static const char abandoned[] = "Connection abandoned.\n";
127
128 char line[32];
f7397dc6 129 struct termios cf;
c5e438ec 130
131 /*
132 * Verify the key.
133 */
134 ret = verify_host_key(host, port, keytype, keystr);
135
136 if (ret == 0) /* success - key matched OK */
3d9449a1 137 return 1;
c5e438ec 138
f7397dc6 139 premsg(&cf);
c5e438ec 140 if (ret == 2) { /* key was different */
141 if (console_batch_mode) {
65f66c88 142 fprintf(stderr, wrongmsg_batch, keytype, fingerprint);
3d9449a1 143 return 0;
c5e438ec 144 }
65f66c88 145 fprintf(stderr, wrongmsg, keytype, fingerprint);
c5e438ec 146 fflush(stderr);
147 }
148 if (ret == 1) { /* key was absent */
149 if (console_batch_mode) {
65f66c88 150 fprintf(stderr, absentmsg_batch, keytype, fingerprint);
3d9449a1 151 return 0;
c5e438ec 152 }
65f66c88 153 fprintf(stderr, absentmsg, keytype, fingerprint);
c5e438ec 154 fflush(stderr);
155 }
156
157 {
158 struct termios oldmode, newmode;
159 tcgetattr(0, &oldmode);
160 newmode = oldmode;
161 newmode.c_lflag |= ECHO | ISIG | ICANON;
162 tcsetattr(0, TCSANOW, &newmode);
163 line[0] = '\0';
164 read(0, line, sizeof(line) - 1);
165 tcsetattr(0, TCSANOW, &oldmode);
166 }
167
168 if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') {
169 if (line[0] == 'y' || line[0] == 'Y')
170 store_host_key(host, port, keytype, keystr);
f7397dc6 171 postmsg(&cf);
3d9449a1 172 return 1;
c5e438ec 173 } else {
174 fprintf(stderr, abandoned);
f7397dc6 175 postmsg(&cf);
3d9449a1 176 return 0;
c5e438ec 177 }
178}
179
180/*
83e7d008 181 * Ask whether the selected algorithm is acceptable (since it was
c5e438ec 182 * below the configured 'warn' threshold).
c5e438ec 183 */
3d9449a1 184int askalg(void *frontend, const char *algtype, const char *algname,
185 void (*callback)(void *ctx, int result), void *ctx)
c5e438ec 186{
187 static const char msg[] =
83e7d008 188 "The first %s supported by the server is\n"
c5e438ec 189 "%s, which is below the configured warning threshold.\n"
190 "Continue with connection? (y/n) ";
191 static const char msg_batch[] =
83e7d008 192 "The first %s supported by the server is\n"
c5e438ec 193 "%s, which is below the configured warning threshold.\n"
194 "Connection abandoned.\n";
195 static const char abandoned[] = "Connection abandoned.\n";
196
197 char line[32];
f7397dc6 198 struct termios cf;
c5e438ec 199
f7397dc6 200 premsg(&cf);
c5e438ec 201 if (console_batch_mode) {
83e7d008 202 fprintf(stderr, msg_batch, algtype, algname);
3d9449a1 203 return 0;
c5e438ec 204 }
205
83e7d008 206 fprintf(stderr, msg, algtype, algname);
c5e438ec 207 fflush(stderr);
208
209 {
210 struct termios oldmode, newmode;
211 tcgetattr(0, &oldmode);
212 newmode = oldmode;
213 newmode.c_lflag |= ECHO | ISIG | ICANON;
214 tcsetattr(0, TCSANOW, &newmode);
215 line[0] = '\0';
216 read(0, line, sizeof(line) - 1);
217 tcsetattr(0, TCSANOW, &oldmode);
218 }
219
220 if (line[0] == 'y' || line[0] == 'Y') {
f7397dc6 221 postmsg(&cf);
3d9449a1 222 return 1;
c5e438ec 223 } else {
224 fprintf(stderr, abandoned);
f7397dc6 225 postmsg(&cf);
3d9449a1 226 return 0;
c5e438ec 227 }
228}
229
230/*
231 * Ask whether to wipe a session log file before writing to it.
232 * Returns 2 for wipe, 1 for append, 0 for cancel (don't log).
233 */
919baedb 234int askappend(void *frontend, Filename filename,
235 void (*callback)(void *ctx, int result), void *ctx)
c5e438ec 236{
237 static const char msgtemplate[] =
238 "The session log file \"%.*s\" already exists.\n"
239 "You can overwrite it with a new session log,\n"
240 "append your session log to the end of it,\n"
241 "or disable session logging for this session.\n"
242 "Enter \"y\" to wipe the file, \"n\" to append to it,\n"
243 "or just press Return to disable logging.\n"
244 "Wipe the log file? (y/n, Return cancels logging) ";
245
246 static const char msgtemplate_batch[] =
247 "The session log file \"%.*s\" already exists.\n"
248 "Logging will not be enabled.\n";
249
250 char line[32];
f7397dc6 251 struct termios cf;
c5e438ec 252
f7397dc6 253 premsg(&cf);
c5e438ec 254 if (console_batch_mode) {
9a30e26b 255 fprintf(stderr, msgtemplate_batch, FILENAME_MAX, filename.path);
c5e438ec 256 fflush(stderr);
257 return 0;
258 }
9a30e26b 259 fprintf(stderr, msgtemplate, FILENAME_MAX, filename.path);
c5e438ec 260 fflush(stderr);
261
262 {
263 struct termios oldmode, newmode;
264 tcgetattr(0, &oldmode);
265 newmode = oldmode;
266 newmode.c_lflag |= ECHO | ISIG | ICANON;
267 tcsetattr(0, TCSANOW, &newmode);
268 line[0] = '\0';
269 read(0, line, sizeof(line) - 1);
270 tcsetattr(0, TCSANOW, &oldmode);
271 }
272
f7397dc6 273 postmsg(&cf);
c5e438ec 274 if (line[0] == 'y' || line[0] == 'Y')
275 return 2;
276 else if (line[0] == 'n' || line[0] == 'N')
277 return 1;
278 else
279 return 0;
280}
281
282/*
283 * Warn about the obsolescent key file format.
284 *
285 * Uniquely among these functions, this one does _not_ expect a
286 * frontend handle. This means that if PuTTY is ported to a
287 * platform which requires frontend handles, this function will be
288 * an anomaly. Fortunately, the problem it addresses will not have
289 * been present on that platform, so it can plausibly be
290 * implemented as an empty function.
291 */
292void old_keyfile_warning(void)
293{
294 static const char message[] =
2e85c969 295 "You are loading an SSH-2 private key which has an\n"
c5e438ec 296 "old version of the file format. This means your key\n"
297 "file is not fully tamperproof. Future versions of\n"
298 "PuTTY may stop supporting this private key format,\n"
299 "so we recommend you convert your key to the new\n"
300 "format.\n"
301 "\n"
302 "Once the key is loaded into PuTTYgen, you can perform\n"
303 "this conversion simply by saving it again.\n";
304
f7397dc6 305 struct termios cf;
306 premsg(&cf);
c5e438ec 307 fputs(message, stderr);
f7397dc6 308 postmsg(&cf);
c5e438ec 309}
310
b51259f6 311void console_provide_logctx(void *logctx)
312{
313 console_logctx = logctx;
314}
315
cbe2d68f 316void logevent(void *frontend, const char *string)
c5e438ec 317{
f7397dc6 318 struct termios cf;
319 premsg(&cf);
b51259f6 320 if (console_logctx)
321 log_eventlog(console_logctx, string);
f7397dc6 322 postmsg(&cf);
c5e438ec 323}
324
edd0cb8a 325static void console_data_untrusted(const char *data, int len)
c5e438ec 326{
c5e438ec 327 int i;
edd0cb8a 328 for (i = 0; i < len; i++)
329 if ((data[i] & 0x60) || (data[i] == '\n'))
330 fputc(data[i], stdout);
331 fflush(stdout);
332}
c5e438ec 333
edd0cb8a 334int console_get_userpass_input(prompts_t *p, unsigned char *in, int inlen)
335{
336 size_t curr_prompt;
337
338 /*
339 * Zero all the results, in case we abort half-way through.
340 */
341 {
342 int i;
343 for (i = 0; i < p->n_prompts; i++)
344 memset(p->prompts[i]->result, 0, p->prompts[i]->result_len);
345 }
346
347 if (console_batch_mode)
a21a6a9a 348 return 0;
edd0cb8a 349
350 /*
351 * Preamble.
352 */
353 /* We only print the `name' caption if we have to... */
354 if (p->name_reqd && p->name) {
355 size_t l = strlen(p->name);
356 console_data_untrusted(p->name, l);
357 if (p->name[l-1] != '\n')
358 console_data_untrusted("\n", 1);
359 }
360 /* ...but we always print any `instruction'. */
361 if (p->instruction) {
362 size_t l = strlen(p->instruction);
363 console_data_untrusted(p->instruction, l);
364 if (p->instruction[l-1] != '\n')
365 console_data_untrusted("\n", 1);
366 }
367
368 for (curr_prompt = 0; curr_prompt < p->n_prompts; curr_prompt++) {
369
370 struct termios oldmode, newmode;
371 int i;
372 prompt_t *pr = p->prompts[curr_prompt];
373
c5e438ec 374 tcgetattr(0, &oldmode);
375 newmode = oldmode;
376 newmode.c_lflag |= ISIG | ICANON;
edd0cb8a 377 if (!pr->echo)
c5e438ec 378 newmode.c_lflag &= ~ECHO;
379 else
380 newmode.c_lflag |= ECHO;
381 tcsetattr(0, TCSANOW, &newmode);
382
edd0cb8a 383 console_data_untrusted(pr->prompt, strlen(pr->prompt));
384
385 i = read(0, pr->result, pr->result_len - 1);
c5e438ec 386
387 tcsetattr(0, TCSANOW, &oldmode);
388
edd0cb8a 389 if (i > 0 && pr->result[i-1] == '\n')
c5e438ec 390 i--;
edd0cb8a 391 pr->result[i] = '\0';
c5e438ec 392
edd0cb8a 393 if (!pr->echo)
8d69b472 394 fputs("\n", stdout);
a21a6a9a 395
c5e438ec 396 }
edd0cb8a 397
398 return 1; /* success */
399
c5e438ec 400}
401
402void frontend_keypress(void *handle)
403{
404 /*
405 * This is nothing but a stub, in console code.
406 */
407 return;
408}
47a6b94c 409
410int is_interactive(void)
411{
412 return isatty(0);
413}
46ed7b64 414
415/*
416 * X11-forwarding-related things suitable for console.
417 */
418
46ed7b64 419char *platform_get_x_display(void) {
420 return dupstr(getenv("DISPLAY"));
421}