]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - console.c
Create the long-awaited console.c, and move the common routines out
[PuTTY.git] / console.c
1 /*
2  * console.c: various interactive-prompt routines shared between
3  * the console PuTTY tools
4  */
5
6 #include <windows.h>
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stdarg.h>
11
12 #include "putty.h"
13 #include "storage.h"
14 #include "ssh.h"
15
16 int console_batch_mode = FALSE;
17
18 void verify_ssh_host_key(char *host, int port, char *keytype,
19                          char *keystr, char *fingerprint)
20 {
21     int ret;
22     HANDLE hin;
23     DWORD savemode, i;
24
25     static const char absentmsg_batch[] =
26         "The server's host key is not cached in the registry. You\n"
27         "have no guarantee that the server is the computer you\n"
28         "think it is.\n"
29         "The server's key fingerprint is:\n"
30         "%s\n"
31         "Connection abandoned.\n";
32     static const char absentmsg[] =
33         "The server's host key is not cached in the registry. You\n"
34         "have no guarantee that the server is the computer you\n"
35         "think it is.\n"
36         "The server's key fingerprint is:\n"
37         "%s\n"
38         "If you trust this host, enter \"y\" to add the key to\n"
39         "PuTTY's cache and carry on connecting.\n"
40         "If you want to carry on connecting just once, without\n"
41         "adding the key to the cache, enter \"n\".\n"
42         "If you do not trust this host, press Return to abandon the\n"
43         "connection.\n"
44         "Store key in cache? (y/n) ";
45
46     static const char wrongmsg_batch[] =
47         "WARNING - POTENTIAL SECURITY BREACH!\n"
48         "The server's host key does not match the one PuTTY has\n"
49         "cached in the registry. This means that either the\n"
50         "server administrator has changed the host key, or you\n"
51         "have actually connected to another computer pretending\n"
52         "to be the server.\n"
53         "The new key fingerprint is:\n"
54         "%s\n"
55         "Connection abandoned.\n";
56     static const char wrongmsg[] =
57         "WARNING - POTENTIAL SECURITY BREACH!\n"
58         "The server's host key does not match the one PuTTY has\n"
59         "cached in the registry. This means that either the\n"
60         "server administrator has changed the host key, or you\n"
61         "have actually connected to another computer pretending\n"
62         "to be the server.\n"
63         "The new key fingerprint is:\n"
64         "%s\n"
65         "If you were expecting this change and trust the new key,\n"
66         "enter \"y\" to update PuTTY's cache and continue connecting.\n"
67         "If you want to carry on connecting but without updating\n"
68         "the cache, enter \"n\".\n"
69         "If you want to abandon the connection completely, press\n"
70         "Return to cancel. Pressing Return is the ONLY guaranteed\n"
71         "safe choice.\n"
72         "Update cached key? (y/n, Return cancels connection) ";
73
74     static const char abandoned[] = "Connection abandoned.\n";
75
76     char line[32];
77
78     /*
79      * Verify the key against the registry.
80      */
81     ret = verify_host_key(host, port, keytype, keystr);
82
83     if (ret == 0)                      /* success - key matched OK */
84         return;
85
86     if (ret == 2) {                    /* key was different */
87         if (console_batch_mode) {
88             fprintf(stderr, wrongmsg_batch, fingerprint);
89             exit(1);
90         }
91         fprintf(stderr, wrongmsg, fingerprint);
92         fflush(stderr);
93     }
94     if (ret == 1) {                    /* key was absent */
95         if (console_batch_mode) {
96             fprintf(stderr, absentmsg_batch, fingerprint);
97             exit(1);
98         }
99         fprintf(stderr, absentmsg, fingerprint);
100         fflush(stderr);
101     }
102
103     hin = GetStdHandle(STD_INPUT_HANDLE);
104     GetConsoleMode(hin, &savemode);
105     SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
106                          ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
107     ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
108     SetConsoleMode(hin, savemode);
109
110     if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') {
111         if (line[0] == 'y' || line[0] == 'Y')
112             store_host_key(host, port, keytype, keystr);
113     } else {
114         fprintf(stderr, abandoned);
115         exit(0);
116     }
117 }
118
119 /*
120  * Ask whether the selected cipher is acceptable (since it was
121  * below the configured 'warn' threshold).
122  * cs: 0 = both ways, 1 = client->server, 2 = server->client
123  */
124 void askcipher(char *ciphername, int cs)
125 {
126     HANDLE hin;
127     DWORD savemode, i;
128
129     static const char msg[] =
130         "The first %scipher supported by the server is\n"
131         "%s, which is below the configured warning threshold.\n"
132         "Continue with connection? (y/n) ";
133     static const char msg_batch[] =
134         "The first %scipher supported by the server is\n"
135         "%s, which is below the configured warning threshold.\n"
136         "Connection abandoned.\n";
137     static const char abandoned[] = "Connection abandoned.\n";
138
139     char line[32];
140
141     if (console_batch_mode) {
142         fprintf(stderr, msg_batch,
143                 (cs == 0) ? "" :
144                 (cs == 1) ? "client-to-server " : "server-to-client ",
145                 ciphername);
146         exit(1);
147     }
148
149     fprintf(stderr, msg,
150             (cs == 0) ? "" :
151             (cs == 1) ? "client-to-server " : "server-to-client ",
152             ciphername);
153     fflush(stderr);
154
155     hin = GetStdHandle(STD_INPUT_HANDLE);
156     GetConsoleMode(hin, &savemode);
157     SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
158                          ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
159     ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
160     SetConsoleMode(hin, savemode);
161
162     if (line[0] == 'y' || line[0] == 'Y') {
163         return;
164     } else {
165         fprintf(stderr, abandoned);
166         exit(0);
167     }
168 }
169
170 /*
171  * Ask whether to wipe a session log file before writing to it.
172  * Returns 2 for wipe, 1 for append, 0 for cancel (don't log).
173  */
174 int askappend(char *filename)
175 {
176     HANDLE hin;
177     DWORD savemode, i;
178
179     static const char msgtemplate[] =
180         "The session log file \"%.*s\" already exists.\n"
181         "You can overwrite it with a new session log,\n"
182         "append your session log to the end of it,\n"
183         "or disable session logging for this session.\n"
184         "Enter \"y\" to wipe the file, \"n\" to append to it,\n"
185         "or just press Return to disable logging.\n"
186         "Wipe the log file? (y/n, Return cancels logging) ";
187
188     static const char msgtemplate_batch[] =
189         "The session log file \"%.*s\" already exists.\n"
190         "Logging will not be enabled.\n";
191
192     char line[32];
193
194     if (console_batch_mode) {
195         fprintf(stderr, msgtemplate_batch, FILENAME_MAX, filename);
196         fflush(stderr);
197         return 0;
198     }
199     fprintf(stderr, msgtemplate, FILENAME_MAX, filename);
200     fflush(stderr);
201
202     hin = GetStdHandle(STD_INPUT_HANDLE);
203     GetConsoleMode(hin, &savemode);
204     SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
205                          ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
206     ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
207     SetConsoleMode(hin, savemode);
208
209     if (line[0] == 'y' || line[0] == 'Y')
210         return 2;
211     else if (line[0] == 'n' || line[0] == 'N')
212         return 1;
213     else
214         return 0;
215 }
216
217 /*
218  * Warn about the obsolescent key file format.
219  */
220 void old_keyfile_warning(void)
221 {
222     static const char message[] =
223         "You are loading an SSH 2 private key which has an\n"
224         "old version of the file format. This means your key\n"
225         "file is not fully tamperproof. Future versions of\n"
226         "PuTTY may stop supporting this private key format,\n"
227         "so we recommend you convert your key to the new\n"
228         "format.\n"
229         "\n"
230         "Once the key is loaded into PuTTYgen, you can perform\n"
231         "this conversion simply by saving it again.\n";
232
233     fputs(message, stderr);
234 }
235
236 void logevent(char *string)
237 {
238 }
239
240 char *console_password = NULL;
241
242 int console_get_line(const char *prompt, char *str,
243                             int maxlen, int is_pw)
244 {
245     HANDLE hin, hout;
246     DWORD savemode, newmode, i;
247
248     if (is_pw && console_password) {
249         static int tried_once = 0;
250
251         if (tried_once) {
252             return 0;
253         } else {
254             strncpy(str, console_password, maxlen);
255             str[maxlen - 1] = '\0';
256             tried_once = 1;
257             return 1;
258         }
259     }
260
261     if (console_batch_mode) {
262         if (maxlen > 0)
263             str[0] = '\0';
264     } else {
265         hin = GetStdHandle(STD_INPUT_HANDLE);
266         hout = GetStdHandle(STD_OUTPUT_HANDLE);
267         if (hin == INVALID_HANDLE_VALUE || hout == INVALID_HANDLE_VALUE) {
268             fprintf(stderr, "Cannot get standard input/output handles\n");
269             exit(1);
270         }
271
272         GetConsoleMode(hin, &savemode);
273         newmode = savemode | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT;
274         if (is_pw)
275             newmode &= ~ENABLE_ECHO_INPUT;
276         else
277             newmode |= ENABLE_ECHO_INPUT;
278         SetConsoleMode(hin, newmode);
279
280         WriteFile(hout, prompt, strlen(prompt), &i, NULL);
281         ReadFile(hin, str, maxlen - 1, &i, NULL);
282
283         SetConsoleMode(hin, savemode);
284
285         if ((int) i > maxlen)
286             i = maxlen - 1;
287         else
288             i = i - 2;
289         str[i] = '\0';
290
291         if (is_pw)
292             WriteFile(hout, "\r\n", 2, &i, NULL);
293
294     }
295     return 1;
296 }