OSDN Git Service

Add PuTTY 0.61 to contrib directory.
[ffftp/ffftp.git] / contrib / putty / UNIX / UXCONS.C
diff --git a/contrib/putty/UNIX/UXCONS.C b/contrib/putty/UNIX/UXCONS.C
new file mode 100644 (file)
index 0000000..2e71df4
--- /dev/null
@@ -0,0 +1,440 @@
+/*\r
+ * uxcons.c: various interactive-prompt routines shared between the\r
+ * Unix console PuTTY tools\r
+ */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <stdarg.h>\r
+#include <assert.h>\r
+#include <termios.h>\r
+#include <unistd.h>\r
+\r
+#include "putty.h"\r
+#include "storage.h"\r
+#include "ssh.h"\r
+\r
+int console_batch_mode = FALSE;\r
+\r
+static void *console_logctx = NULL;\r
+\r
+static struct termios orig_termios_stderr;\r
+static int stderr_is_a_tty;\r
+\r
+void stderr_tty_init()\r
+{\r
+    /* Ensure that if stderr is a tty, we can get it back to a sane state. */\r
+    if ((flags & FLAG_STDERR_TTY) && isatty(STDERR_FILENO)) {\r
+       stderr_is_a_tty = TRUE;\r
+       tcgetattr(STDERR_FILENO, &orig_termios_stderr);\r
+    }\r
+}\r
+\r
+void premsg(struct termios *cf)\r
+{\r
+    if (stderr_is_a_tty) {\r
+       tcgetattr(STDERR_FILENO, cf);\r
+       tcsetattr(STDERR_FILENO, TCSADRAIN, &orig_termios_stderr);\r
+    }\r
+}\r
+void postmsg(struct termios *cf)\r
+{\r
+    if (stderr_is_a_tty)\r
+       tcsetattr(STDERR_FILENO, TCSADRAIN, cf);\r
+}\r
+\r
+/*\r
+ * Clean up and exit.\r
+ */\r
+void cleanup_exit(int code)\r
+{\r
+    /*\r
+     * Clean up.\r
+     */\r
+    sk_cleanup();\r
+    random_save_seed();\r
+    exit(code);\r
+}\r
+\r
+void set_busy_status(void *frontend, int status)\r
+{\r
+}\r
+\r
+void update_specials_menu(void *frontend)\r
+{\r
+}\r
+\r
+void notify_remote_exit(void *frontend)\r
+{\r
+}\r
+\r
+void timer_change_notify(long next)\r
+{\r
+}\r
+\r
+int verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,\r
+                        char *keystr, char *fingerprint,\r
+                        void (*callback)(void *ctx, int result), void *ctx)\r
+{\r
+    int ret;\r
+\r
+    static const char absentmsg_batch[] =\r
+       "The server's host key is not cached. You have no guarantee\n"\r
+       "that the server is the computer you think it is.\n"\r
+       "The server's %s key fingerprint is:\n"\r
+       "%s\n"\r
+       "Connection abandoned.\n";\r
+    static const char absentmsg[] =\r
+       "The server's host key is not cached. You have no guarantee\n"\r
+       "that the server is the computer you think it is.\n"\r
+       "The server's %s key fingerprint is:\n"\r
+       "%s\n"\r
+       "If you trust this host, enter \"y\" to add the key to\n"\r
+       "PuTTY's cache and carry on connecting.\n"\r
+       "If you want to carry on connecting just once, without\n"\r
+       "adding the key to the cache, enter \"n\".\n"\r
+       "If you do not trust this host, press Return to abandon the\n"\r
+       "connection.\n"\r
+       "Store key in cache? (y/n) ";\r
+\r
+    static const char wrongmsg_batch[] =\r
+       "WARNING - POTENTIAL SECURITY BREACH!\n"\r
+       "The server's host key does not match the one PuTTY has\n"\r
+       "cached. This means that either the server administrator\n"\r
+       "has changed the host key, or you have actually connected\n"\r
+       "to another computer pretending to be the server.\n"\r
+       "The new %s key fingerprint is:\n"\r
+       "%s\n"\r
+       "Connection abandoned.\n";\r
+    static const char wrongmsg[] =\r
+       "WARNING - POTENTIAL SECURITY BREACH!\n"\r
+       "The server's host key does not match the one PuTTY has\n"\r
+       "cached. This means that either the server administrator\n"\r
+       "has changed the host key, or you have actually connected\n"\r
+       "to another computer pretending to be the server.\n"\r
+       "The new %s key fingerprint is:\n"\r
+       "%s\n"\r
+       "If you were expecting this change and trust the new key,\n"\r
+       "enter \"y\" to update PuTTY's cache and continue connecting.\n"\r
+       "If you want to carry on connecting but without updating\n"\r
+       "the cache, enter \"n\".\n"\r
+       "If you want to abandon the connection completely, press\n"\r
+       "Return to cancel. Pressing Return is the ONLY guaranteed\n"\r
+       "safe choice.\n"\r
+       "Update cached key? (y/n, Return cancels connection) ";\r
+\r
+    static const char abandoned[] = "Connection abandoned.\n";\r
+\r
+    char line[32];\r
+    struct termios cf;\r
+\r
+    /*\r
+     * Verify the key.\r
+     */\r
+    ret = verify_host_key(host, port, keytype, keystr);\r
+\r
+    if (ret == 0)                     /* success - key matched OK */\r
+       return 1;\r
+\r
+    premsg(&cf);\r
+    if (ret == 2) {                   /* key was different */\r
+       if (console_batch_mode) {\r
+           fprintf(stderr, wrongmsg_batch, keytype, fingerprint);\r
+           return 0;\r
+       }\r
+       fprintf(stderr, wrongmsg, keytype, fingerprint);\r
+       fflush(stderr);\r
+    }\r
+    if (ret == 1) {                   /* key was absent */\r
+       if (console_batch_mode) {\r
+           fprintf(stderr, absentmsg_batch, keytype, fingerprint);\r
+           return 0;\r
+       }\r
+       fprintf(stderr, absentmsg, keytype, fingerprint);\r
+       fflush(stderr);\r
+    }\r
+\r
+    {\r
+       struct termios oldmode, newmode;\r
+       tcgetattr(0, &oldmode);\r
+       newmode = oldmode;\r
+       newmode.c_lflag |= ECHO | ISIG | ICANON;\r
+       tcsetattr(0, TCSANOW, &newmode);\r
+       line[0] = '\0';\r
+       if (read(0, line, sizeof(line) - 1) <= 0)\r
+           /* handled below */;\r
+       tcsetattr(0, TCSANOW, &oldmode);\r
+    }\r
+\r
+    if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') {\r
+       if (line[0] == 'y' || line[0] == 'Y')\r
+           store_host_key(host, port, keytype, keystr);\r
+       postmsg(&cf);\r
+        return 1;\r
+    } else {\r
+       fprintf(stderr, abandoned);\r
+       postmsg(&cf);\r
+        return 0;\r
+    }\r
+}\r
+\r
+/*\r
+ * Ask whether the selected algorithm is acceptable (since it was\r
+ * below the configured 'warn' threshold).\r
+ */\r
+int askalg(void *frontend, const char *algtype, const char *algname,\r
+          void (*callback)(void *ctx, int result), void *ctx)\r
+{\r
+    static const char msg[] =\r
+       "The first %s supported by the server is\n"\r
+       "%s, which is below the configured warning threshold.\n"\r
+       "Continue with connection? (y/n) ";\r
+    static const char msg_batch[] =\r
+       "The first %s supported by the server is\n"\r
+       "%s, which is below the configured warning threshold.\n"\r
+       "Connection abandoned.\n";\r
+    static const char abandoned[] = "Connection abandoned.\n";\r
+\r
+    char line[32];\r
+    struct termios cf;\r
+\r
+    premsg(&cf);\r
+    if (console_batch_mode) {\r
+       fprintf(stderr, msg_batch, algtype, algname);\r
+       return 0;\r
+    }\r
+\r
+    fprintf(stderr, msg, algtype, algname);\r
+    fflush(stderr);\r
+\r
+    {\r
+       struct termios oldmode, newmode;\r
+       tcgetattr(0, &oldmode);\r
+       newmode = oldmode;\r
+       newmode.c_lflag |= ECHO | ISIG | ICANON;\r
+       tcsetattr(0, TCSANOW, &newmode);\r
+       line[0] = '\0';\r
+       if (read(0, line, sizeof(line) - 1) <= 0)\r
+           /* handled below */;\r
+       tcsetattr(0, TCSANOW, &oldmode);\r
+    }\r
+\r
+    if (line[0] == 'y' || line[0] == 'Y') {\r
+       postmsg(&cf);\r
+       return 1;\r
+    } else {\r
+       fprintf(stderr, abandoned);\r
+       postmsg(&cf);\r
+       return 0;\r
+    }\r
+}\r
+\r
+/*\r
+ * Ask whether to wipe a session log file before writing to it.\r
+ * Returns 2 for wipe, 1 for append, 0 for cancel (don't log).\r
+ */\r
+int askappend(void *frontend, Filename filename,\r
+             void (*callback)(void *ctx, int result), void *ctx)\r
+{\r
+    static const char msgtemplate[] =\r
+       "The session log file \"%.*s\" already exists.\n"\r
+       "You can overwrite it with a new session log,\n"\r
+       "append your session log to the end of it,\n"\r
+       "or disable session logging for this session.\n"\r
+       "Enter \"y\" to wipe the file, \"n\" to append to it,\n"\r
+       "or just press Return to disable logging.\n"\r
+       "Wipe the log file? (y/n, Return cancels logging) ";\r
+\r
+    static const char msgtemplate_batch[] =\r
+       "The session log file \"%.*s\" already exists.\n"\r
+       "Logging will not be enabled.\n";\r
+\r
+    char line[32];\r
+    struct termios cf;\r
+\r
+    premsg(&cf);\r
+    if (console_batch_mode) {\r
+       fprintf(stderr, msgtemplate_batch, FILENAME_MAX, filename.path);\r
+       fflush(stderr);\r
+       return 0;\r
+    }\r
+    fprintf(stderr, msgtemplate, FILENAME_MAX, filename.path);\r
+    fflush(stderr);\r
+\r
+    {\r
+       struct termios oldmode, newmode;\r
+       tcgetattr(0, &oldmode);\r
+       newmode = oldmode;\r
+       newmode.c_lflag |= ECHO | ISIG | ICANON;\r
+       tcsetattr(0, TCSANOW, &newmode);\r
+       line[0] = '\0';\r
+       if (read(0, line, sizeof(line) - 1) <= 0)\r
+           /* handled below */;\r
+       tcsetattr(0, TCSANOW, &oldmode);\r
+    }\r
+\r
+    postmsg(&cf);\r
+    if (line[0] == 'y' || line[0] == 'Y')\r
+       return 2;\r
+    else if (line[0] == 'n' || line[0] == 'N')\r
+       return 1;\r
+    else\r
+       return 0;\r
+}\r
+\r
+/*\r
+ * Warn about the obsolescent key file format.\r
+ * \r
+ * Uniquely among these functions, this one does _not_ expect a\r
+ * frontend handle. This means that if PuTTY is ported to a\r
+ * platform which requires frontend handles, this function will be\r
+ * an anomaly. Fortunately, the problem it addresses will not have\r
+ * been present on that platform, so it can plausibly be\r
+ * implemented as an empty function.\r
+ */\r
+void old_keyfile_warning(void)\r
+{\r
+    static const char message[] =\r
+       "You are loading an SSH-2 private key which has an\n"\r
+       "old version of the file format. This means your key\n"\r
+       "file is not fully tamperproof. Future versions of\n"\r
+       "PuTTY may stop supporting this private key format,\n"\r
+       "so we recommend you convert your key to the new\n"\r
+       "format.\n"\r
+       "\n"\r
+       "Once the key is loaded into PuTTYgen, you can perform\n"\r
+       "this conversion simply by saving it again.\n";\r
+\r
+    struct termios cf;\r
+    premsg(&cf);\r
+    fputs(message, stderr);\r
+    postmsg(&cf);\r
+}\r
+\r
+void console_provide_logctx(void *logctx)\r
+{\r
+    console_logctx = logctx;\r
+}\r
+\r
+void logevent(void *frontend, const char *string)\r
+{\r
+    struct termios cf;\r
+    premsg(&cf);\r
+    if (console_logctx)\r
+       log_eventlog(console_logctx, string);\r
+    postmsg(&cf);\r
+}\r
+\r
+/*\r
+ * Special function to print text to the console for password\r
+ * prompts and the like. Uses /dev/tty or stderr, in that order of\r
+ * preference; also sanitises escape sequences out of the text, on\r
+ * the basis that it might have been sent by a hostile SSH server\r
+ * doing malicious keyboard-interactive.\r
+ */\r
+static void console_prompt_text(FILE **confp, const char *data, int len)\r
+{\r
+    int i;\r
+\r
+    if (!*confp) {\r
+       if ((*confp = fopen("/dev/tty", "w")) == NULL)\r
+           *confp = stderr;\r
+    }\r
+\r
+    for (i = 0; i < len; i++)\r
+       if ((data[i] & 0x60) || (data[i] == '\n'))\r
+           fputc(data[i], *confp);\r
+    fflush(*confp);\r
+}\r
+\r
+int console_get_userpass_input(prompts_t *p, unsigned char *in, int inlen)\r
+{\r
+    size_t curr_prompt;\r
+    FILE *confp = NULL;\r
+\r
+    /*\r
+     * Zero all the results, in case we abort half-way through.\r
+     */\r
+    {\r
+       int i;\r
+       for (i = 0; i < p->n_prompts; i++)\r
+           memset(p->prompts[i]->result, 0, p->prompts[i]->result_len);\r
+    }\r
+\r
+    if (p->n_prompts && console_batch_mode)\r
+       return 0;\r
+\r
+    /*\r
+     * Preamble.\r
+     */\r
+    /* We only print the `name' caption if we have to... */\r
+    if (p->name_reqd && p->name) {\r
+       size_t l = strlen(p->name);\r
+       console_prompt_text(&confp, p->name, l);\r
+       if (p->name[l-1] != '\n')\r
+           console_prompt_text(&confp, "\n", 1);\r
+    }\r
+    /* ...but we always print any `instruction'. */\r
+    if (p->instruction) {\r
+       size_t l = strlen(p->instruction);\r
+       console_prompt_text(&confp, p->instruction, l);\r
+       if (p->instruction[l-1] != '\n')\r
+           console_prompt_text(&confp, "\n", 1);\r
+    }\r
+\r
+    for (curr_prompt = 0; curr_prompt < p->n_prompts; curr_prompt++) {\r
+\r
+       struct termios oldmode, newmode;\r
+       int i;\r
+       prompt_t *pr = p->prompts[curr_prompt];\r
+\r
+       tcgetattr(0, &oldmode);\r
+       newmode = oldmode;\r
+       newmode.c_lflag |= ISIG | ICANON;\r
+       if (!pr->echo)\r
+           newmode.c_lflag &= ~ECHO;\r
+       else\r
+           newmode.c_lflag |= ECHO;\r
+       tcsetattr(0, TCSANOW, &newmode);\r
+\r
+       console_prompt_text(&confp, pr->prompt, strlen(pr->prompt));\r
+\r
+       i = read(0, pr->result, pr->result_len - 1);\r
+\r
+       tcsetattr(0, TCSANOW, &oldmode);\r
+\r
+       if (i > 0 && pr->result[i-1] == '\n')\r
+           i--;\r
+       pr->result[i] = '\0';\r
+\r
+       if (!pr->echo)\r
+           console_prompt_text(&confp, "\n", 1);\r
+\r
+    }\r
+\r
+    if (confp && confp != stderr)\r
+       fclose(confp);\r
+\r
+    return 1; /* success */\r
+}\r
+\r
+void frontend_keypress(void *handle)\r
+{\r
+    /*\r
+     * This is nothing but a stub, in console code.\r
+     */\r
+    return;\r
+}\r
+\r
+int is_interactive(void)\r
+{\r
+    return isatty(0);\r
+}\r
+\r
+/*\r
+ * X11-forwarding-related things suitable for console.\r
+ */\r
+\r
+char *platform_get_x_display(void) {\r
+    return dupstr(getenv("DISPLAY"));\r
+}\r