source: filezilla/trunk/fuentes/src/putty/windows/wincons.c @ 130

Last change on this file since 130 was 130, checked in by jrpelegrina, 3 years ago

First release to xenial

File size: 10.8 KB
Line 
1/*
2 * wincons.c - various interactive-prompt routines shared between
3 * the Windows console PuTTY tools
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <stdarg.h>
9
10#include "putty.h"
11#include "storage.h"
12#include "ssh.h"
13
14int console_batch_mode = FALSE;
15
16static void *console_logctx = NULL;
17
18/*
19 * Clean up and exit.
20 */
21void cleanup_exit(int code)
22{
23    /*
24     * Clean up.
25     */
26    sk_cleanup();
27
28    random_save_seed();
29#ifdef MSCRYPTOAPI
30    crypto_wrapup();
31#endif
32
33    exit(code);
34}
35
36void set_busy_status(void *frontend, int status)
37{
38}
39
40void notify_remote_exit(void *frontend)
41{
42}
43
44void timer_change_notify(unsigned long next)
45{
46}
47
48int verify_ssh_host_key(void *frontend, char *host, int port,
49                        const char *keytype, char *keystr, char *fingerprint,
50                        void (*callback)(void *ctx, int result), void *ctx)
51{
52    int ret;
53    HANDLE hin;
54    DWORD savemode, i;
55
56    /*static const char absentmsg_batch[] =
57        "The server's host key is not cached in the registry. You\n"
58        "have no guarantee that the server is the computer you\n"
59        "think it is.\n"
60        "The server's %s key fingerprint is:\n"
61        "%s\n"
62        "Connection abandoned.\n";
63    static const char absentmsg[] =
64        "The server's host key is not cached in the registry. You\n"
65        "have no guarantee that the server is the computer you\n"
66        "think it is.\n"
67        "The server's %s key fingerprint is:\n"
68        "%s\n"
69        "If you trust this host, enter \"y\" to add the key to\n"
70        "PuTTY's cache and carry on connecting.\n"
71        "If you want to carry on connecting just once, without\n"
72        "adding the key to the cache, enter \"n\".\n"
73        "If you do not trust this host, press Return to abandon the\n"
74        "connection.\n"
75        "Store key in cache? (y/n) ";*/
76
77    static const char wrongmsg_batch[] =
78        "WARNING - POTENTIAL SECURITY BREACH!\n"
79        "The server's host key does not match the one PuTTY has\n"
80        "cached in the registry. This means that either the\n"
81        "server administrator has changed the host key, or you\n"
82        "have actually connected to another computer pretending\n"
83        "to be the server.\n"
84        "The new %s key fingerprint is:\n"
85        "%s\n"
86        "Connection abandoned.\n";
87    /*static const char wrongmsg[] =
88        "WARNING - POTENTIAL SECURITY BREACH!\n"
89        "The server's host key does not match the one PuTTY has\n"
90        "cached in the registry. This means that either the\n"
91        "server administrator has changed the host key, or you\n"
92        "have actually connected to another computer pretending\n"
93        "to be the server.\n"
94        "The new %s key fingerprint is:\n"
95        "%s\n"
96        "If you were expecting this change and trust the new key,\n"
97        "enter \"y\" to update PuTTY's cache and continue connecting.\n"
98        "If you want to carry on connecting but without updating\n"
99        "the cache, enter \"n\".\n"
100        "If you want to abandon the connection completely, press\n"
101        "Return to cancel. Pressing Return is the ONLY guaranteed\n"
102        "safe choice.\n"
103        "Update cached key? (y/n, Return cancels connection) ";*/
104
105    static const char abandoned[] = "Connection abandoned.";
106
107    char line[32];
108
109    /*
110     * Verify the key against the registry.
111     */
112    ret = verify_host_key(host, port, keytype, keystr);
113
114    if (ret == 0)                      /* success - key matched OK */
115        return 1;
116
117    if (ret == 2) {                    /* key was different */
118        if (console_batch_mode) {
119            fprintf(stderr, wrongmsg_batch, keytype, fingerprint);
120            return 0;
121        }
122        fzprintf_raw(sftpRequest, "%d%s\n%d\n%s\n", (int)sftpReqHostkeyChanged, host, port, fingerprint);
123    }
124    if (ret == 1) {                    /* key was absent */
125        fzprintf_raw(sftpRequest, "%d%s\n%d\n%s\n", (int)sftpReqHostkey, host, port, fingerprint);
126    }
127
128    hin = GetStdHandle(STD_INPUT_HANDLE);
129    GetConsoleMode(hin, &savemode);
130    SetConsoleMode(hin, (savemode | 
131                         ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
132    ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
133    SetConsoleMode(hin, savemode);
134
135    if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') {
136        if (line[0] == 'y' || line[0] == 'Y')
137            store_host_key(host, port, keytype, keystr);
138        return 1;
139    } else {
140        fzprintf(sftpError, abandoned);
141        return 0;
142    }
143}
144
145void update_specials_menu(void *frontend)
146{
147}
148
149/*
150 * Ask whether the selected algorithm is acceptable (since it was
151 * below the configured 'warn' threshold).
152 */
153int askalg(void *frontend, const char *algtype, const char *algname,
154           void (*callback)(void *ctx, int result), void *ctx)
155{
156    fzprintf(sftpError, "The first %s supported by the server is %s, which is no longer secure. Aborting connection.", algtype, algname);
157    return 0;
158}
159
160/*
161 * Ask whether to wipe a session log file before writing to it.
162 * Returns 2 for wipe, 1 for append, 0 for cancel (don't log).
163 */
164int askappend(void *frontend, Filename *filename,
165              void (*callback)(void *ctx, int result), void *ctx)
166{
167    HANDLE hin;
168    DWORD savemode, i;
169
170    static const char msgtemplate[] =
171        "The session log file \"%.*s\" already exists.\n"
172        "You can overwrite it with a new session log,\n"
173        "append your session log to the end of it,\n"
174        "or disable session logging for this session.\n"
175        "Enter \"y\" to wipe the file, \"n\" to append to it,\n"
176        "or just press Return to disable logging.\n"
177        "Wipe the log file? (y/n, Return cancels logging) ";
178
179    static const char msgtemplate_batch[] =
180        "The session log file \"%.*s\" already exists.\n"
181        "Logging will not be enabled.\n";
182
183    char line[32];
184
185    if (console_batch_mode) {
186        fprintf(stderr, msgtemplate_batch, FILENAME_MAX, filename->path);
187        fflush(stderr);
188        return 0;
189    }
190    fprintf(stderr, msgtemplate, FILENAME_MAX, filename->path);
191    fflush(stderr);
192
193    hin = GetStdHandle(STD_INPUT_HANDLE);
194    GetConsoleMode(hin, &savemode);
195    SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
196                         ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
197    ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
198    SetConsoleMode(hin, savemode);
199
200    if (line[0] == 'y' || line[0] == 'Y')
201        return 2;
202    else if (line[0] == 'n' || line[0] == 'N')
203        return 1;
204    else
205        return 0;
206}
207
208/*
209 * Warn about the obsolescent key file format.
210 *
211 * Uniquely among these functions, this one does _not_ expect a
212 * frontend handle. This means that if PuTTY is ported to a
213 * platform which requires frontend handles, this function will be
214 * an anomaly. Fortunately, the problem it addresses will not have
215 * been present on that platform, so it can plausibly be
216 * implemented as an empty function.
217 */
218void old_keyfile_warning(void)
219{
220    static const char message[] =
221        "You are loading an SSH-2 private key which has an\n"
222        "old version of the file format. This means your key\n"
223        "file is not fully tamperproof. Future versions of\n"
224        "PuTTY may stop supporting this private key format,\n"
225        "so we recommend you convert your key to the new\n"
226        "format.\n"
227        "\n"
228        "Once the key is loaded into PuTTYgen, you can perform\n"
229        "this conversion simply by saving it again.\n";
230
231    fputs(message, stderr);
232}
233
234/*
235 * Display the fingerprints of the PGP Master Keys to the user.
236 */
237void pgp_fingerprints(void)
238{
239    fputs("These are the fingerprints of the PuTTY PGP Master Keys. They can\n"
240          "be used to establish a trust path from this executable to another\n"
241          "one. See the manual for more information.\n"
242          "(Note: these fingerprints have nothing to do with SSH!)\n"
243          "\n"
244          "PuTTY Master Key as of 2015 (RSA, 4096-bit):\n"
245          "  " PGP_MASTER_KEY_FP "\n\n"
246          "Original PuTTY Master Key (RSA, 1024-bit):\n"
247          "  " PGP_RSA_MASTER_KEY_FP "\n"
248          "Original PuTTY Master Key (DSA, 1024-bit):\n"
249          "  " PGP_DSA_MASTER_KEY_FP "\n", stdout);
250}
251
252void console_provide_logctx(void *logctx)
253{
254    console_logctx = logctx;
255}
256
257void logevent(void *frontend, const char *string)
258{
259    log_eventlog(console_logctx, string);
260}
261
262/*static void console_data_untrusted(HANDLE hout, const char *data, int len)
263{
264    DWORD dummy;
265    *//* FIXME: control-character filtering *//*
266    WriteFile(hout, data, len, &dummy, NULL);
267}*/
268
269int console_get_userpass_input(prompts_t *p,
270                               const unsigned char *in, int inlen)
271{
272    HANDLE hin, hout;
273    size_t curr_prompt;
274
275    /*
276     * Zero all the results, in case we abort half-way through.
277     */
278    {
279        int i;
280        for (i = 0; i < (int)p->n_prompts; i++)
281            prompt_set_result(p->prompts[i], "");
282    }
283
284    /*
285     * The prompts_t might contain a message to be displayed but no
286     * actual prompt. More usually, though, it will contain
287     * questions that the user needs to answer, in which case we
288     * need to ensure that we're able to get the answers.
289     */
290    if (p->n_prompts) {
291        if (console_batch_mode)
292            return 0;
293        hin = GetStdHandle(STD_INPUT_HANDLE);
294        if (hin == INVALID_HANDLE_VALUE) {
295            fprintf(stderr, "Cannot get standard input handle\n");
296            cleanup_exit(1);
297        }
298    }
299
300    /*
301     * And if we have anything to print, we need standard output.
302     */
303    if ((p->name) || p->instruction || p->n_prompts) {
304        hout = GetStdHandle(STD_OUTPUT_HANDLE);
305        if (hout == INVALID_HANDLE_VALUE) {
306            fprintf(stderr, "Cannot get standard output handle\n");
307            cleanup_exit(1);
308        }
309    }
310
311    /*
312     * Preamble.
313     */
314    /* We only print the `name' caption if we have to... */
315    if (p->name)
316        fzprintf_raw_untrusted(sftpRequestPreamble, p->name);
317    else
318        fzprintf_raw_untrusted(sftpRequestPreamble, "");
319
320    /* ...but we always print any `instruction'. */
321    if (p->instruction)
322        fzprintf_raw_untrusted(sftpRequestInstruction, p->instruction);
323    else
324        fzprintf_raw_untrusted(sftpRequestInstruction, "");
325
326    for (curr_prompt = 0; curr_prompt < p->n_prompts; curr_prompt++) {
327
328        DWORD savemode, newmode;
329        int len;
330        prompt_t *pr = p->prompts[curr_prompt];
331
332        GetConsoleMode(hin, &savemode);
333        newmode = savemode | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT;
334        //if (!pr->echo)
335            newmode &= ~ENABLE_ECHO_INPUT;
336        //else
337        //    newmode |= ENABLE_ECHO_INPUT;
338        SetConsoleMode(hin, newmode);
339
340        fzprintf_raw_untrusted(sftpRequest, "%d%s\n", (int)sftpReqPassword, pr->prompt);
341       
342        len = 0;
343        while (1) {
344            DWORD ret = 0;
345            BOOL r;
346
347            prompt_ensure_result_size(pr, len * 5 / 4 + 512);
348
349            r = ReadFile(hin, pr->result + len, pr->resultsize - len - 1,
350                         &ret, NULL);
351
352            if (!r || ret == 0) {
353                len = -1;
354                break;
355            }
356            len += ret;
357            if (pr->result[len - 1] == '\n') {
358                len--;
359                if (pr->result[len - 1] == '\r')
360                    len--;
361                break;
362            }
363        }
364
365        SetConsoleMode(hin, savemode);
366
367/*      if (!pr->echo) {
368            DWORD dummy;
369            WriteFile(hout, "\r\n", 2, &dummy, NULL);
370        }*/
371
372        if (len < 0) {
373            return 0;                  /* failure due to read error */
374        }
375
376        do {
377            pr->result[len--] = 0;
378        } while (len >= 0 && (pr->result[len] == '\r' || pr->result[len] == '\n'));
379    }
380
381    return 1; /* success */
382}
383
384void frontend_keypress(void *handle)
385{
386    /*
387     * This is nothing but a stub, in console code.
388     */
389    return;
390}
Note: See TracBrowser for help on using the repository browser.