source: filezilla/trunk/fuentes/src/putty/unix/uxcons.c @ 130

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

First release to xenial

File size: 12.0 KB
Line 
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 <errno.h>
11
12#include <termios.h>
13#include <unistd.h>
14#include <fcntl.h>
15
16#include "putty.h"
17#include "storage.h"
18#include "ssh.h"
19
20int console_batch_mode = FALSE;
21
22static void *console_logctx = NULL;
23
24static struct termios orig_termios_stderr;
25static int stderr_is_a_tty;
26
27void stderr_tty_init()
28{
29    /* Ensure that if stderr is a tty, we can get it back to a sane state. */
30    if ((flags & FLAG_STDERR_TTY) && isatty(STDERR_FILENO)) {
31        stderr_is_a_tty = TRUE;
32        tcgetattr(STDERR_FILENO, &orig_termios_stderr);
33    }
34}
35
36void premsg(struct termios *cf)
37{
38    if (stderr_is_a_tty) {
39        tcgetattr(STDERR_FILENO, cf);
40        tcsetattr(STDERR_FILENO, TCSADRAIN, &orig_termios_stderr);
41    }
42}
43void postmsg(struct termios *cf)
44{
45    if (stderr_is_a_tty)
46        tcsetattr(STDERR_FILENO, TCSADRAIN, cf);
47}
48
49/*
50 * Clean up and exit.
51 */
52void cleanup_exit(int code)
53{
54    /*
55     * Clean up.
56     */
57    sk_cleanup();
58    random_save_seed();
59    exit(code);
60}
61
62void set_busy_status(void *frontend, int status)
63{
64}
65
66void update_specials_menu(void *frontend)
67{
68}
69
70void notify_remote_exit(void *frontend)
71{
72}
73
74void timer_change_notify(unsigned long next)
75{
76}
77
78/*
79 * Wrapper around Unix read(2), suitable for use on a file descriptor
80 * that's been set into nonblocking mode. Handles EAGAIN/EWOULDBLOCK
81 * by means of doing a one-fd select and then trying again; all other
82 * errors (including errors from select) are returned to the caller.
83 */
84static int block_and_read(int fd, void *buf, size_t len)
85{
86    int ret;
87
88    while ((ret = read(fd, buf, len)) < 0 && (
89#ifdef EAGAIN
90               (errno == EAGAIN) ||
91#endif
92#ifdef EWOULDBLOCK
93               (errno == EWOULDBLOCK) ||
94#endif
95               0)) {
96
97        fd_set rfds;
98        FD_ZERO(&rfds);
99        FD_SET(fd, &rfds);
100        ret = select(fd+1, &rfds, NULL, NULL, NULL);
101        assert(ret != 0);
102        if (ret < 0)
103            return ret;
104        assert(FD_ISSET(fd, &rfds));
105    }
106
107    return ret;
108}
109
110int verify_ssh_host_key(void *frontend, char *host, int port,
111                        const char *keytype, char *keystr, char *fingerprint,
112                        void (*callback)(void *ctx, int result), void *ctx)
113{
114    int ret;
115
116    static const char absentmsg_batch[] =
117        "The server's host key is not cached. You have no guarantee\n"
118        "that the server is the computer you think it is.\n"
119        "The server's %s key fingerprint is:\n"
120        "%s\n"
121        "Connection abandoned.\n";
122/*    static const char absentmsg[] =
123        "The server's host key is not cached. You have no guarantee\n"
124        "that the server is the computer you think it is.\n"
125        "The server's %s key fingerprint is:\n"
126        "%s\n"
127        "If you trust this host, enter \"y\" to add the key to\n"
128        "PuTTY's cache and carry on connecting.\n"
129        "If you want to carry on connecting just once, without\n"
130        "adding the key to the cache, enter \"n\".\n"
131        "If you do not trust this host, press Return to abandon the\n"
132        "connection.\n"
133        "Store key in cache? (y/n) ";
134*/
135    static const char wrongmsg_batch[] =
136        "WARNING - POTENTIAL SECURITY BREACH!\n"
137        "The server's host key does not match the one PuTTY has\n"
138        "cached. This means that either the server administrator\n"
139        "has changed the host key, or you have actually connected\n"
140        "to another computer pretending to be the server.\n"
141        "The new %s key fingerprint is:\n"
142        "%s\n"
143        "Connection abandoned.\n";
144/*    static const char wrongmsg[] =
145        "WARNING - POTENTIAL SECURITY BREACH!\n"
146        "The server's host key does not match the one PuTTY has\n"
147        "cached. This means that either the server administrator\n"
148        "has changed the host key, or you have actually connected\n"
149        "to another computer pretending to be the server.\n"
150        "The new %s key fingerprint is:\n"
151        "%s\n"
152        "If you were expecting this change and trust the new key,\n"
153        "enter \"y\" to update PuTTY's cache and continue connecting.\n"
154        "If you want to carry on connecting but without updating\n"
155        "the cache, enter \"n\".\n"
156        "If you want to abandon the connection completely, press\n"
157        "Return to cancel. Pressing Return is the ONLY guaranteed\n"
158        "safe choice.\n"
159        "Update cached key? (y/n, Return cancels connection) ";
160*/
161    static const char abandoned[] = "Connection abandoned.\n";
162
163    char line[32];
164//FZ struct termios cf;
165
166    /*
167     * Verify the key.
168     */
169    ret = verify_host_key(host, port, keytype, keystr);
170
171    if (ret == 0)                      /* success - key matched OK */
172        return 1;
173
174//FZ premsg(&cf);
175    if (ret == 2) {                    /* key was different */
176        if (console_batch_mode) {
177            fprintf(stderr, wrongmsg_batch, keytype, fingerprint);
178            return 0;
179        }
180        fzprintf_raw(sftpRequest, "%d%s\n%d\n%s\n", (int)sftpReqHostkeyChanged, host, port, fingerprint);
181    }
182    if (ret == 1) {                    /* key was absent */
183        if (console_batch_mode) {
184            fprintf(stderr, absentmsg_batch, keytype, fingerprint);
185            return 0;
186        }
187        fzprintf_raw(sftpRequest, "%d%s\n%d\n%s\n", (int)sftpReqHostkey, host, port, fingerprint);
188    }
189
190    {
191        struct termios oldmode, newmode;
192        tcgetattr(0, &oldmode);
193        newmode = oldmode;
194        newmode.c_lflag |= ISIG | ICANON;
195        tcsetattr(0, TCSANOW, &newmode);
196        line[0] = '\0';
197        int ret;
198        do
199        {
200            ret = read(0, line, sizeof(line) - 1);
201        } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
202
203        tcsetattr(0, TCSANOW, &oldmode);
204    }
205
206    if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') {
207        if (line[0] == 'y' || line[0] == 'Y')
208            store_host_key(host, port, keytype, keystr);
209//FZ    postmsg(&cf);
210        return 1;
211    } else {
212        fprintf(stderr, abandoned);
213//FZ    postmsg(&cf);
214        return 0;
215    }
216}
217
218/*
219 * Ask whether the selected algorithm is acceptable (since it was
220 * below the configured 'warn' threshold).
221 */
222int askalg(void *frontend, const char *algtype, const char *algname,
223           void (*callback)(void *ctx, int result), void *ctx)
224{
225    fzprintf(sftpError, "The first %s supported by the server is %s, which is no longer secure. Aborting connection.", algtype, algname);
226    return 0;
227}
228
229/*
230 * Ask whether to wipe a session log file before writing to it.
231 * Returns 2 for wipe, 1 for append, 0 for cancel (don't log).
232 */
233int askappend(void *frontend, Filename *filename,
234              void (*callback)(void *ctx, int result), void *ctx)
235{
236    static const char msgtemplate[] =
237        "The session log file \"%.*s\" already exists.\n"
238        "You can overwrite it with a new session log,\n"
239        "append your session log to the end of it,\n"
240        "or disable session logging for this session.\n"
241        "Enter \"y\" to wipe the file, \"n\" to append to it,\n"
242        "or just press Return to disable logging.\n"
243        "Wipe the log file? (y/n, Return cancels logging) ";
244
245    static const char msgtemplate_batch[] =
246        "The session log file \"%.*s\" already exists.\n"
247        "Logging will not be enabled.\n";
248
249    char line[32];
250//FZ struct termios cf;
251
252//FZ premsg(&cf);
253    if (console_batch_mode) {
254        fprintf(stderr, msgtemplate_batch, FILENAME_MAX, filename->path);
255        fflush(stderr);
256        return 0;
257    }
258    fprintf(stderr, msgtemplate, FILENAME_MAX, filename->path);
259    fflush(stderr);
260
261    {
262        struct termios oldmode, newmode;
263        tcgetattr(0, &oldmode);
264        newmode = oldmode;
265        newmode.c_lflag |= ECHO | ISIG | ICANON;
266        tcsetattr(0, TCSANOW, &newmode);
267        line[0] = '\0';
268        if (block_and_read(0, line, sizeof(line) - 1) <= 0)
269            /* handled below */;
270        tcsetattr(0, TCSANOW, &oldmode);
271    }
272
273//FZ postmsg(&cf);
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[] =
295        "You are loading an SSH-2 private key which has an\n"
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
305//FZ struct termios cf;
306//FZ premsg(&cf);
307    fzprintf(sftpStatus, message);
308//FZ postmsg(&cf);
309}
310
311void console_provide_logctx(void *logctx)
312{
313    console_logctx = logctx;
314}
315
316void logevent(void *frontend, const char *string)
317{
318//FZ struct termios cf;
319//FZ premsg(&cf);
320    if (console_logctx)
321        log_eventlog(console_logctx, string);
322//FZ postmsg(&cf);
323}
324
325/*
326 * Special functions to read and print to the console for password
327 * prompts and the like. Uses /dev/tty or stdin/stderr, in that order
328 * of preference; also sanitises escape sequences out of the text, on
329 * the basis that it might have been sent by a hostile SSH server
330 * doing malicious keyboard-interactive.
331 */
332
333static void console_open(FILE **outfp, int *infd)
334{
335    /*int fd;
336
337    if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
338        *infd = fd;
339        *outfp = fdopen(*infd, "w");
340    } else*/ {
341        *infd = 0;
342        *outfp = stderr;
343    }
344}
345static void console_close(FILE *outfp, int infd)
346{
347    if (outfp != stderr)
348        fclose(outfp);             /* will automatically close infd too */
349}
350/*
351static void console_prompt_text(FILE *outfp, const char *data, int len)
352{
353    int i;
354
355    for (i = 0; i < len; i++)
356        if ((data[i] & 0x60) || (data[i] == '\n'))
357            fputc(data[i], outfp);
358    fflush(outfp);
359}*/
360
361int console_get_userpass_input(prompts_t *p, const unsigned char *in,
362                               int inlen)
363{
364    size_t curr_prompt;
365    FILE *outfp = NULL;
366    int infd;
367
368    /*
369     * Zero all the results, in case we abort half-way through.
370     */
371    {
372        int i;
373        for (i = 0; i < p->n_prompts; i++)
374            prompt_set_result(p->prompts[i], "");
375    }
376
377    if (p->n_prompts && console_batch_mode)
378        return 0;
379
380    console_open(&outfp, &infd);
381
382    /*
383     * Preamble.
384     */
385    /* We only print the `name' caption if we have to... */
386    if (p->name)
387        fzprintf_raw_untrusted(sftpRequestPreamble, p->name);
388    else
389        fzprintf_raw_untrusted(sftpRequestPreamble, "");
390
391    /* ...but we always print any `instruction'. */
392    if (p->instruction)
393        fzprintf_raw_untrusted(sftpRequestInstruction, p->instruction);
394    else
395        fzprintf_raw_untrusted(sftpRequestInstruction, "");
396
397    for (curr_prompt = 0; curr_prompt < p->n_prompts; curr_prompt++) {
398
399        struct termios oldmode, newmode;
400        int len;
401        prompt_t *pr = p->prompts[curr_prompt];
402
403        tcgetattr(infd, &oldmode);
404        newmode = oldmode;
405        newmode.c_lflag |= ISIG | ICANON;
406//      if (!pr->echo)
407            newmode.c_lflag &= ~ECHO;
408//      else
409//          newmode.c_lflag |= ECHO;
410        tcsetattr(infd, TCSANOW, &newmode);
411
412        fzprintf_raw_untrusted(sftpRequest, "%d%s\n", (int)sftpReqPassword, pr->prompt);
413
414        len = 0;
415        while (1) {
416            int ret;
417
418            prompt_ensure_result_size(pr, len * 5 / 4 + 512);
419            ret = read(infd, pr->result + len, pr->resultsize - len - 1);
420            if (ret <= 0) {
421                len = -1;
422                break;
423            }
424            len += ret;
425            if (pr->result[len - 1] == '\n') {
426                len--;
427                break;
428            }
429        }
430
431        tcsetattr(infd, TCSANOW, &oldmode);
432
433        //if (!pr->echo)
434        //    console_prompt_text(outfp, "\n", 1);
435
436        if (len < 0) {
437            console_close(outfp, infd);
438            return 0;                  /* failure due to read error */
439        }
440
441        pr->result[len--] = 0;
442        while (len >= 0 && (pr->result[len] == '\r' || pr->result[len] == '\n'))
443            pr->result[len--] = '\0';
444    }
445
446    console_close(outfp, infd);
447
448    return 1; /* success */
449}
450
451void frontend_keypress(void *handle)
452{
453    /*
454     * This is nothing but a stub, in console code.
455     */
456    return;
457}
458
459int is_interactive(void)
460{
461    return isatty(0);
462}
463
464/*
465 * X11-forwarding-related things suitable for console.
466 */
467
468char *platform_get_x_display(void) {
469    return dupstr(getenv("DISPLAY"));
470}
Note: See TracBrowser for help on using the repository browser.