X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/9d33ebddc777e92a92d57f91a9d7f325d36aa422..052f07e466e1f69b8c14bc1bbbe8a1df7e38cccc:/plink.c diff --git a/plink.c b/plink.c index 19b94b29..938bcb75 100644 --- a/plink.c +++ b/plink.c @@ -11,6 +11,7 @@ #define PUTTY_DO_GLOBALS /* actually _define_ globals */ #include "putty.h" +#include "storage.h" void fatalbox (char *p, ...) { va_list ap; @@ -35,11 +36,75 @@ void connection_fatal (char *p, ...) { static char *password = NULL; -/* - * Stubs for linking with other modules. - */ -void write_clip (void *data, int len) { } -void term_deselect(void) { } +void logevent(char *string) { } + +void verify_ssh_host_key(char *host, int port, char *keytype, + char *keystr, char *fingerprint) { + int ret; + + static const char absentmsg[] = + "The server's host key is not cached in the registry. You\n" + "have no guarantee that the server is the computer you\n" + "think it is.\n" + "The server's key fingerprint is:\n" + "%s\n" + "If you trust this host, enter \"y\" to add the key to\n" + "PuTTY's cache and carry on connecting.\n" + "If you do not trust this host, enter \"n\" to abandon the\n" + "connection.\n" + "Continue connecting? (y/n) "; + + static const char wrongmsg[] = + "WARNING - POTENTIAL SECURITY BREACH!\n" + "The server's host key does not match the one PuTTY has\n" + "cached in the registry. This means that either the\n" + "server administrator has changed the host key, or you\n" + "have actually connected to another computer pretending\n" + "to be the server.\n" + "The new key fingerprint is:\n" + "%s\n" + "If you were expecting this change and trust the new key,\n" + "enter \"y\" to update PuTTY's cache and continue connecting.\n" + "If you want to carry on connecting but without updating\n" + "the cache, enter \"n\".\n" + "If you want to abandon the connection completely, press\n" + "Return to cancel. Pressing Return is the ONLY guaranteed\n" + "safe choice.\n" + "Update cached key? (y/n, Return cancels connection) "; + + static const char abandoned[] = "Connection abandoned.\n"; + + char line[32]; + + /* + * Verify the key against the registry. + */ + ret = verify_host_key(host, port, keytype, keystr); + + if (ret == 0) /* success - key matched OK */ + return; + if (ret == 2) { /* key was different */ + fprintf(stderr, wrongmsg, fingerprint); + if (fgets(line, sizeof(line), stdin) && + line[0] != '\0' && line[0] != '\n') { + if (line[0] == 'y' || line[0] == 'Y') + store_host_key(host, port, keytype, keystr); + } else { + fprintf(stderr, abandoned); + exit(0); + } + } + if (ret == 1) { /* key was absent */ + fprintf(stderr, absentmsg, fingerprint); + if (fgets(line, sizeof(line), stdin) && + (line[0] == 'y' || line[0] == 'Y')) + store_host_key(host, port, keytype, keystr); + else { + fprintf(stderr, abandoned); + exit(0); + } + } +} HANDLE outhandle; DWORD orig_console_mode; @@ -112,7 +177,7 @@ static int get_password(const char *prompt, char *str, int maxlen) return 1; } -int WINAPI stdin_read_thread(void *param) { +static DWORD WINAPI stdin_read_thread(void *param) { struct input_data *idata = (struct input_data *)param; HANDLE inhandle; @@ -162,9 +227,25 @@ int main(int argc, char **argv) { /* * Process the command line. */ - do_defaults(NULL); + do_defaults(NULL, &cfg); default_protocol = cfg.protocol; default_port = cfg.port; + { + /* + * Override the default protocol if PLINK_PROTOCOL is set. + */ + char *p = getenv("PLINK_PROTOCOL"); + int i; + if (p) { + for (i = 0; backends[i].backend != NULL; i++) { + if (!strcmp(backends[i].name, p)) { + default_protocol = cfg.protocol = backends[i].protocol; + default_port = cfg.port = backends[i].backend->default_port; + break; + } + } + } + } while (--argc) { char *p = *++argv; if (*p == '-') { @@ -254,7 +335,7 @@ int main(int argc, char **argv) { /* * One string. */ - do_defaults (p); + do_defaults (p, &cfg); if (cfg.host[0] == '\0') { /* No settings for this host; use defaults */ strncpy(cfg.host, p, sizeof(cfg.host)-1); @@ -293,8 +374,6 @@ int main(int argc, char **argv) { if (!*cfg.host) { usage(); } - if (portnumber != -1) - cfg.port = portnumber; if (!*cfg.remote_cmd) flags |= FLAG_INTERACTIVE; @@ -318,6 +397,12 @@ int main(int argc, char **argv) { } /* + * Select port. + */ + if (portnumber != -1) + cfg.port = portnumber; + + /* * Initialise WinSock. */ winsock_ver = MAKEWORD(2, 0); @@ -369,6 +454,33 @@ int main(int argc, char **argv) { sending = FALSE; while (1) { int n; + + if (!sending && back->sendok()) { + /* + * Create a separate thread to read from stdin. This is + * a total pain, but I can't find another way to do it: + * + * - an overlapped ReadFile or ReadFileEx just doesn't + * happen; we get failure from ReadFileEx, and + * ReadFile blocks despite being given an OVERLAPPED + * structure. Perhaps we can't do overlapped reads + * on consoles. WHY THE HELL NOT? + * + * - WaitForMultipleObjects(netevent, console) doesn't + * work, because it signals the console when + * _anything_ happens, including mouse motions and + * other things that don't cause data to be readable + * - so we're back to ReadFile blocking. + */ + idata.event = stdinevent; + if (!CreateThread(NULL, 0, stdin_read_thread, + &idata, 0, &threadid)) { + fprintf(stderr, "Unable to create second thread\n"); + exit(1); + } + sending = TRUE; + } + n = WaitForMultipleObjects(2, handles, FALSE, INFINITE); if (n == 0) { WSANETWORKEVENTS things; @@ -381,34 +493,6 @@ int main(int argc, char **argv) { } } term_out(); - if (!sending && back->sendok()) { - /* - * Create a separate thread to read from stdin. - * This is a total pain, but I can't find another - * way to do it: - * - * - an overlapped ReadFile or ReadFileEx just - * doesn't happen; we get failure from - * ReadFileEx, and ReadFile blocks despite being - * given an OVERLAPPED structure. Perhaps we - * can't do overlapped reads on consoles. WHY - * THE HELL NOT? - * - * - WaitForMultipleObjects(netevent, console) - * doesn't work, because it signals the console - * when _anything_ happens, including mouse - * motions and other things that don't cause - * data to be readable - so we're back to - * ReadFile blocking. - */ - idata.event = stdinevent; - if (!CreateThread(NULL, 0, stdin_read_thread, - &idata, 0, &threadid)) { - fprintf(stderr, "Unable to create second thread\n"); - exit(1); - } - sending = TRUE; - } } else if (n == 1) { if (idata.len > 0) { back->send(idata.buffer, idata.len);