"Fossies" - the Fresh Open Source Software Archive

Member "putty-0.73/windows/wincons.c" (22 Sep 2019, 16916 Bytes) of package /linux/misc/putty-0.73.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "wincons.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.72_vs_0.73.

    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 
   14 bool console_batch_mode = false;
   15 
   16 /*
   17  * Clean up and exit.
   18  */
   19 void cleanup_exit(int code)
   20 {
   21     /*
   22      * Clean up.
   23      */
   24     sk_cleanup();
   25 
   26     random_save_seed();
   27 
   28     exit(code);
   29 }
   30 
   31 /*
   32  * Various error message and/or fatal exit functions.
   33  */
   34 void console_print_error_msg(const char *prefix, const char *msg)
   35 {
   36     fputs(prefix, stderr);
   37     fputs(": ", stderr);
   38     fputs(msg, stderr);
   39     fputc('\n', stderr);
   40     fflush(stderr);
   41 }
   42 
   43 void console_print_error_msg_fmt_v(
   44     const char *prefix, const char *fmt, va_list ap)
   45 {
   46     char *msg = dupvprintf(fmt, ap);
   47     console_print_error_msg(prefix, msg);
   48     sfree(msg);
   49 }
   50 
   51 void console_print_error_msg_fmt(const char *prefix, const char *fmt, ...)
   52 {
   53     va_list ap;
   54     va_start(ap, fmt);
   55     console_print_error_msg_fmt_v(prefix, fmt, ap);
   56     va_end(ap);
   57 }
   58 
   59 void modalfatalbox(const char *fmt, ...)
   60 {
   61     va_list ap;
   62     va_start(ap, fmt);
   63     console_print_error_msg_fmt_v("FATAL ERROR", fmt, ap);
   64     va_end(ap);
   65     cleanup_exit(1);
   66 }
   67 
   68 void nonfatal(const char *fmt, ...)
   69 {
   70     va_list ap;
   71     va_start(ap, fmt);
   72     console_print_error_msg_fmt_v("ERROR", fmt, ap);
   73     va_end(ap);
   74 }
   75 
   76 void console_connection_fatal(Seat *seat, const char *msg)
   77 {
   78     console_print_error_msg("FATAL ERROR", msg);
   79     cleanup_exit(1);
   80 }
   81 
   82 void timer_change_notify(unsigned long next)
   83 {
   84 }
   85 
   86 int console_verify_ssh_host_key(
   87     Seat *seat, const char *host, int port,
   88     const char *keytype, char *keystr, char *fingerprint,
   89     void (*callback)(void *ctx, int result), void *ctx)
   90 {
   91     int ret;
   92     HANDLE hin;
   93     DWORD savemode, i;
   94 
   95     static const char absentmsg_batch[] =
   96         "The server's host key is not cached in the registry. You\n"
   97         "have no guarantee that the server is the computer you\n"
   98         "think it is.\n"
   99         "The server's %s key fingerprint is:\n"
  100         "%s\n"
  101         "Connection abandoned.\n";
  102     static const char absentmsg[] =
  103         "The server's host key is not cached in the registry. You\n"
  104         "have no guarantee that the server is the computer you\n"
  105         "think it is.\n"
  106         "The server's %s key fingerprint is:\n"
  107         "%s\n"
  108         "If you trust this host, enter \"y\" to add the key to\n"
  109         "PuTTY's cache and carry on connecting.\n"
  110         "If you want to carry on connecting just once, without\n"
  111         "adding the key to the cache, enter \"n\".\n"
  112         "If you do not trust this host, press Return to abandon the\n"
  113         "connection.\n"
  114         "Store key in cache? (y/n) ";
  115 
  116     static const char wrongmsg_batch[] =
  117         "WARNING - POTENTIAL SECURITY BREACH!\n"
  118         "The server's host key does not match the one PuTTY has\n"
  119         "cached in the registry. This means that either the\n"
  120         "server administrator has changed the host key, or you\n"
  121         "have actually connected to another computer pretending\n"
  122         "to be the server.\n"
  123         "The new %s key fingerprint is:\n"
  124         "%s\n"
  125         "Connection abandoned.\n";
  126     static const char wrongmsg[] =
  127         "WARNING - POTENTIAL SECURITY BREACH!\n"
  128         "The server's host key does not match the one PuTTY has\n"
  129         "cached in the registry. This means that either the\n"
  130         "server administrator has changed the host key, or you\n"
  131         "have actually connected to another computer pretending\n"
  132         "to be the server.\n"
  133         "The new %s key fingerprint is:\n"
  134         "%s\n"
  135         "If you were expecting this change and trust the new key,\n"
  136         "enter \"y\" to update PuTTY's cache and continue connecting.\n"
  137         "If you want to carry on connecting but without updating\n"
  138         "the cache, enter \"n\".\n"
  139         "If you want to abandon the connection completely, press\n"
  140         "Return to cancel. Pressing Return is the ONLY guaranteed\n"
  141         "safe choice.\n"
  142         "Update cached key? (y/n, Return cancels connection) ";
  143 
  144     static const char abandoned[] = "Connection abandoned.\n";
  145 
  146     char line[32];
  147 
  148     /*
  149      * Verify the key against the registry.
  150      */
  151     ret = verify_host_key(host, port, keytype, keystr);
  152 
  153     if (ret == 0)                      /* success - key matched OK */
  154         return 1;
  155 
  156     if (ret == 2) {                    /* key was different */
  157         if (console_batch_mode) {
  158             fprintf(stderr, wrongmsg_batch, keytype, fingerprint);
  159             return 0;
  160         }
  161         fprintf(stderr, wrongmsg, keytype, fingerprint);
  162         fflush(stderr);
  163     }
  164     if (ret == 1) {                    /* key was absent */
  165         if (console_batch_mode) {
  166             fprintf(stderr, absentmsg_batch, keytype, fingerprint);
  167             return 0;
  168         }
  169         fprintf(stderr, absentmsg, keytype, fingerprint);
  170         fflush(stderr);
  171     }
  172 
  173     line[0] = '\0';         /* fail safe if ReadFile returns no data */
  174 
  175     hin = GetStdHandle(STD_INPUT_HANDLE);
  176     GetConsoleMode(hin, &savemode);
  177     SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
  178                          ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
  179     ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
  180     SetConsoleMode(hin, savemode);
  181 
  182     if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') {
  183         if (line[0] == 'y' || line[0] == 'Y')
  184             store_host_key(host, port, keytype, keystr);
  185         return 1;
  186     } else {
  187         fprintf(stderr, abandoned);
  188         return 0;
  189     }
  190 }
  191 
  192 int console_confirm_weak_crypto_primitive(
  193     Seat *seat, const char *algtype, const char *algname,
  194     void (*callback)(void *ctx, int result), void *ctx)
  195 {
  196     HANDLE hin;
  197     DWORD savemode, i;
  198 
  199     static const char msg[] =
  200         "The first %s supported by the server is\n"
  201         "%s, which is below the configured warning threshold.\n"
  202         "Continue with connection? (y/n) ";
  203     static const char msg_batch[] =
  204         "The first %s supported by the server is\n"
  205         "%s, which is below the configured warning threshold.\n"
  206         "Connection abandoned.\n";
  207     static const char abandoned[] = "Connection abandoned.\n";
  208 
  209     char line[32];
  210 
  211     if (console_batch_mode) {
  212         fprintf(stderr, msg_batch, algtype, algname);
  213         return 0;
  214     }
  215 
  216     fprintf(stderr, msg, algtype, algname);
  217     fflush(stderr);
  218 
  219     hin = GetStdHandle(STD_INPUT_HANDLE);
  220     GetConsoleMode(hin, &savemode);
  221     SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
  222                          ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
  223     ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
  224     SetConsoleMode(hin, savemode);
  225 
  226     if (line[0] == 'y' || line[0] == 'Y') {
  227         return 1;
  228     } else {
  229         fprintf(stderr, abandoned);
  230         return 0;
  231     }
  232 }
  233 
  234 int console_confirm_weak_cached_hostkey(
  235     Seat *seat, const char *algname, const char *betteralgs,
  236     void (*callback)(void *ctx, int result), void *ctx)
  237 {
  238     HANDLE hin;
  239     DWORD savemode, i;
  240 
  241     static const char msg[] =
  242         "The first host key type we have stored for this server\n"
  243         "is %s, which is below the configured warning threshold.\n"
  244         "The server also provides the following types of host key\n"
  245         "above the threshold, which we do not have stored:\n"
  246         "%s\n"
  247         "Continue with connection? (y/n) ";
  248     static const char msg_batch[] =
  249         "The first host key type we have stored for this server\n"
  250         "is %s, which is below the configured warning threshold.\n"
  251         "The server also provides the following types of host key\n"
  252         "above the threshold, which we do not have stored:\n"
  253         "%s\n"
  254         "Connection abandoned.\n";
  255     static const char abandoned[] = "Connection abandoned.\n";
  256 
  257     char line[32];
  258 
  259     if (console_batch_mode) {
  260         fprintf(stderr, msg_batch, algname, betteralgs);
  261         return 0;
  262     }
  263 
  264     fprintf(stderr, msg, algname, betteralgs);
  265     fflush(stderr);
  266 
  267     hin = GetStdHandle(STD_INPUT_HANDLE);
  268     GetConsoleMode(hin, &savemode);
  269     SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
  270                          ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
  271     ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
  272     SetConsoleMode(hin, savemode);
  273 
  274     if (line[0] == 'y' || line[0] == 'Y') {
  275         return 1;
  276     } else {
  277         fprintf(stderr, abandoned);
  278         return 0;
  279     }
  280 }
  281 
  282 bool is_interactive(void)
  283 {
  284     return is_console_handle(GetStdHandle(STD_INPUT_HANDLE));
  285 }
  286 
  287 bool console_antispoof_prompt = true;
  288 bool console_set_trust_status(Seat *seat, bool trusted)
  289 {
  290     if (console_batch_mode || !is_interactive() || !console_antispoof_prompt) {
  291         /*
  292          * In batch mode, we don't need to worry about the server
  293          * mimicking our interactive authentication, because the user
  294          * already knows not to expect any.
  295          *
  296          * If standard input isn't connected to a terminal, likewise,
  297          * because even if the server did send a spoof authentication
  298          * prompt, the user couldn't respond to it via the terminal
  299          * anyway.
  300          *
  301          * We also vacuously return success if the user has purposely
  302          * disabled the antispoof prompt.
  303          */
  304         return true;
  305     }
  306 
  307     return false;
  308 }
  309 
  310 /*
  311  * Ask whether to wipe a session log file before writing to it.
  312  * Returns 2 for wipe, 1 for append, 0 for cancel (don't log).
  313  */
  314 static int console_askappend(LogPolicy *lp, Filename *filename,
  315                              void (*callback)(void *ctx, int result),
  316                              void *ctx)
  317 {
  318     HANDLE hin;
  319     DWORD savemode, i;
  320 
  321     static const char msgtemplate[] =
  322         "The session log file \"%.*s\" already exists.\n"
  323         "You can overwrite it with a new session log,\n"
  324         "append your session log to the end of it,\n"
  325         "or disable session logging for this session.\n"
  326         "Enter \"y\" to wipe the file, \"n\" to append to it,\n"
  327         "or just press Return to disable logging.\n"
  328         "Wipe the log file? (y/n, Return cancels logging) ";
  329 
  330     static const char msgtemplate_batch[] =
  331         "The session log file \"%.*s\" already exists.\n"
  332         "Logging will not be enabled.\n";
  333 
  334     char line[32];
  335 
  336     if (console_batch_mode) {
  337         fprintf(stderr, msgtemplate_batch, FILENAME_MAX, filename->path);
  338         fflush(stderr);
  339         return 0;
  340     }
  341     fprintf(stderr, msgtemplate, FILENAME_MAX, filename->path);
  342     fflush(stderr);
  343 
  344     hin = GetStdHandle(STD_INPUT_HANDLE);
  345     GetConsoleMode(hin, &savemode);
  346     SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
  347                          ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
  348     ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
  349     SetConsoleMode(hin, savemode);
  350 
  351     if (line[0] == 'y' || line[0] == 'Y')
  352         return 2;
  353     else if (line[0] == 'n' || line[0] == 'N')
  354         return 1;
  355     else
  356         return 0;
  357 }
  358 
  359 /*
  360  * Warn about the obsolescent key file format.
  361  *
  362  * Uniquely among these functions, this one does _not_ expect a
  363  * frontend handle. This means that if PuTTY is ported to a
  364  * platform which requires frontend handles, this function will be
  365  * an anomaly. Fortunately, the problem it addresses will not have
  366  * been present on that platform, so it can plausibly be
  367  * implemented as an empty function.
  368  */
  369 void old_keyfile_warning(void)
  370 {
  371     static const char message[] =
  372         "You are loading an SSH-2 private key which has an\n"
  373         "old version of the file format. This means your key\n"
  374         "file is not fully tamperproof. Future versions of\n"
  375         "PuTTY may stop supporting this private key format,\n"
  376         "so we recommend you convert your key to the new\n"
  377         "format.\n"
  378         "\n"
  379         "Once the key is loaded into PuTTYgen, you can perform\n"
  380         "this conversion simply by saving it again.\n";
  381 
  382     fputs(message, stderr);
  383 }
  384 
  385 /*
  386  * Display the fingerprints of the PGP Master Keys to the user.
  387  */
  388 void pgp_fingerprints(void)
  389 {
  390     fputs("These are the fingerprints of the PuTTY PGP Master Keys. They can\n"
  391           "be used to establish a trust path from this executable to another\n"
  392           "one. See the manual for more information.\n"
  393           "(Note: these fingerprints have nothing to do with SSH!)\n"
  394           "\n"
  395           "PuTTY Master Key as of " PGP_MASTER_KEY_YEAR
  396           " (" PGP_MASTER_KEY_DETAILS "):\n"
  397           "  " PGP_MASTER_KEY_FP "\n\n"
  398           "Previous Master Key (" PGP_PREV_MASTER_KEY_YEAR
  399           ", " PGP_PREV_MASTER_KEY_DETAILS "):\n"
  400           "  " PGP_PREV_MASTER_KEY_FP "\n", stdout);
  401 }
  402 
  403 static void console_logging_error(LogPolicy *lp, const char *string)
  404 {
  405     /* Ordinary Event Log entries are displayed in the same way as
  406      * logging errors, but only in verbose mode */
  407     fprintf(stderr, "%s\n", string);
  408     fflush(stderr);
  409 }
  410 
  411 static void console_eventlog(LogPolicy *lp, const char *string)
  412 {
  413     /* Ordinary Event Log entries are displayed in the same way as
  414      * logging errors, but only in verbose mode */
  415     if (flags & FLAG_VERBOSE)
  416         console_logging_error(lp, string);
  417 }
  418 
  419 StripCtrlChars *console_stripctrl_new(
  420     Seat *seat, BinarySink *bs_out, SeatInteractionContext sic)
  421 {
  422     return stripctrl_new(bs_out, false, 0);
  423 }
  424 
  425 static void console_write(HANDLE hout, ptrlen data)
  426 {
  427     DWORD dummy;
  428     WriteFile(hout, data.ptr, data.len, &dummy, NULL);
  429 }
  430 
  431 int console_get_userpass_input(prompts_t *p)
  432 {
  433     HANDLE hin = INVALID_HANDLE_VALUE, hout = INVALID_HANDLE_VALUE;
  434     size_t curr_prompt;
  435 
  436     /*
  437      * Zero all the results, in case we abort half-way through.
  438      */
  439     {
  440         int i;
  441         for (i = 0; i < (int)p->n_prompts; i++)
  442             prompt_set_result(p->prompts[i], "");
  443     }
  444 
  445     /*
  446      * The prompts_t might contain a message to be displayed but no
  447      * actual prompt. More usually, though, it will contain
  448      * questions that the user needs to answer, in which case we
  449      * need to ensure that we're able to get the answers.
  450      */
  451     if (p->n_prompts) {
  452         if (console_batch_mode)
  453             return 0;
  454         hin = GetStdHandle(STD_INPUT_HANDLE);
  455         if (hin == INVALID_HANDLE_VALUE) {
  456             fprintf(stderr, "Cannot get standard input handle\n");
  457             cleanup_exit(1);
  458         }
  459     }
  460 
  461     /*
  462      * And if we have anything to print, we need standard output.
  463      */
  464     if ((p->name_reqd && p->name) || p->instruction || p->n_prompts) {
  465         hout = GetStdHandle(STD_OUTPUT_HANDLE);
  466         if (hout == INVALID_HANDLE_VALUE) {
  467             fprintf(stderr, "Cannot get standard output handle\n");
  468             cleanup_exit(1);
  469         }
  470     }
  471 
  472     /*
  473      * Preamble.
  474      */
  475     /* We only print the `name' caption if we have to... */
  476     if (p->name_reqd && p->name) {
  477         ptrlen plname = ptrlen_from_asciz(p->name);
  478         console_write(hout, plname);
  479         if (!ptrlen_endswith(plname, PTRLEN_LITERAL("\n"), NULL))
  480             console_write(hout, PTRLEN_LITERAL("\n"));
  481     }
  482     /* ...but we always print any `instruction'. */
  483     if (p->instruction) {
  484         ptrlen plinst = ptrlen_from_asciz(p->instruction);
  485         console_write(hout, plinst);
  486         if (!ptrlen_endswith(plinst, PTRLEN_LITERAL("\n"), NULL))
  487             console_write(hout, PTRLEN_LITERAL("\n"));
  488     }
  489 
  490     for (curr_prompt = 0; curr_prompt < p->n_prompts; curr_prompt++) {
  491 
  492         DWORD savemode, newmode;
  493         size_t len;
  494         prompt_t *pr = p->prompts[curr_prompt];
  495 
  496         GetConsoleMode(hin, &savemode);
  497         newmode = savemode | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT;
  498         if (!pr->echo)
  499             newmode &= ~ENABLE_ECHO_INPUT;
  500         else
  501             newmode |= ENABLE_ECHO_INPUT;
  502         SetConsoleMode(hin, newmode);
  503 
  504         console_write(hout, ptrlen_from_asciz(pr->prompt));
  505 
  506         len = 0;
  507         while (1) {
  508             DWORD ret = 0;
  509 
  510             prompt_ensure_result_size(pr, len * 5 / 4 + 512);
  511 
  512             if (!ReadFile(hin, pr->result + len, pr->resultsize - len - 1,
  513                           &ret, NULL) || ret == 0) {
  514                 len = (size_t)-1;
  515                 break;
  516             }
  517             len += ret;
  518             if (pr->result[len - 1] == '\n') {
  519                 len--;
  520                 if (pr->result[len - 1] == '\r')
  521                     len--;
  522                 break;
  523             }
  524         }
  525 
  526         SetConsoleMode(hin, savemode);
  527 
  528         if (!pr->echo)
  529             console_write(hout, PTRLEN_LITERAL("\r\n"));
  530 
  531         if (len == (size_t)-1) {
  532             return 0;                  /* failure due to read error */
  533         }
  534 
  535         pr->result[len] = '\0';
  536     }
  537 
  538     return 1; /* success */
  539 }
  540 
  541 static const LogPolicyVtable default_logpolicy_vt = {
  542     console_eventlog,
  543     console_askappend,
  544     console_logging_error,
  545 };
  546 LogPolicy default_logpolicy[1] = {{ &default_logpolicy_vt }};