X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/8d5de7770cde9b808c276bd86a0214189a8f7578..27be44524b0e41e95ce86831b885e1e1ed16886f:/plink.c diff --git a/plink.c b/plink.c index fd9d36dd..6ac5e0ac 100644 --- a/plink.c +++ b/plink.c @@ -2,7 +2,9 @@ * PLink - a command-line (stdin/stdout) variant of PuTTY. */ +#ifndef AUTO_WINSOCK #include +#endif #include #include #include @@ -31,13 +33,28 @@ void connection_fatal (char *p, ...) { exit(1); } +static char *password = NULL; + +/* + * Stubs for linking with other modules. + */ +void write_clip (void *data, int len) { } +void term_deselect(void) { } + HANDLE outhandle; +DWORD orig_console_mode; + +void begin_session(void) { + if (!cfg.ldisc_term) + SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_PROCESSED_INPUT); + else + SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), orig_console_mode); +} void term_out(void) { int reap; DWORD ret; - reap = 0; while (reap < inbuf_head) { if (!WriteFile(outhandle, inbuf+reap, inbuf_head-reap, &ret, NULL)) @@ -58,7 +75,6 @@ static int get_password(const char *prompt, char *str, int maxlen) HANDLE hin, hout; DWORD savemode, i; -#if 0 /* this allows specifying a password some other way */ if (password) { static int tried_once = 0; @@ -71,7 +87,6 @@ static int get_password(const char *prompt, char *str, int maxlen) return 1; } } -#endif hin = GetStdHandle(STD_INPUT_HANDLE); hout = GetStdHandle(STD_OUTPUT_HANDLE); @@ -114,6 +129,22 @@ int WINAPI stdin_read_thread(void *param) { return 0; } +/* + * Short description of parameters. + */ +static void usage(void) +{ + printf("PuTTY Link: command-line connection utility\n"); + printf("%s\n", ver); + printf("Usage: plink [options] [user@]host [command]\n"); + printf("Options:\n"); + printf(" -v show verbose messages\n"); + printf(" -ssh force use of ssh protocol\n"); + printf(" -P port connect to specified port\n"); + printf(" -pw passw login with specified password\n"); + exit(1); +} + int main(int argc, char **argv) { WSADATA wsadata; WORD winsock_ver; @@ -123,6 +154,7 @@ int main(int argc, char **argv) { DWORD threadid; struct input_data idata; int sending; + int portnumber = -1; ssh_get_password = get_password; @@ -130,20 +162,50 @@ int main(int argc, char **argv) { /* * Process the command line. */ - default_protocol = DEFAULT_PROTOCOL; - default_port = DEFAULT_PORT; do_defaults(NULL); + 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 == '-') { if (!strcmp(p, "-ssh")) { default_protocol = cfg.protocol = PROT_SSH; default_port = cfg.port = 22; + } else if (!strcmp(p, "-telnet")) { + default_protocol = cfg.protocol = PROT_TELNET; + default_port = cfg.port = 23; + } else if (!strcmp(p, "-raw")) { + default_protocol = cfg.protocol = PROT_RAW; } else if (!strcmp(p, "-v")) { flags |= FLAG_VERBOSE; } else if (!strcmp(p, "-log")) { logfile = "putty.log"; - } + } else if (!strcmp(p, "-pw") && argc > 1) { + --argc, password = *++argv; + } else if (!strcmp(p, "-l") && argc > 1) { + char *username; + --argc, username = *++argv; + strncpy(cfg.username, username, sizeof(cfg.username)); + cfg.username[sizeof(cfg.username)-1] = '\0'; + } else if (!strcmp(p, "-P") && argc > 1) { + --argc, portnumber = atoi(*++argv); + } } else if (*p) { if (!*cfg.host) { char *q = p; @@ -171,6 +233,27 @@ int main(int argc, char **argv) { strncpy (cfg.host, q, sizeof(cfg.host)-1); cfg.host[sizeof(cfg.host)-1] = '\0'; } else { + char *r; + /* + * Before we process the [user@]host string, we + * first check for the presence of a protocol + * prefix (a protocol name followed by ","). + */ + r = strchr(p, ','); + if (r) { + int i, j; + for (i = 0; backends[i].backend != NULL; i++) { + j = strlen(backends[i].name); + if (j == r-p && + !memcmp(backends[i].name, p, j)) { + default_protocol = cfg.protocol = backends[i].protocol; + portnumber = backends[i].backend->default_port; + p = r+1; + break; + } + } + } + /* * Three cases. Either (a) there's a nonzero * length string followed by an @, in which @@ -181,7 +264,7 @@ int main(int argc, char **argv) { * string and it _doesn't_ exist in the * database. */ - char *r = strrchr(p, '@'); + r = strrchr(p, '@'); if (r == p) p++, r = NULL; /* discount initial @ */ if (r == NULL) { /* @@ -223,6 +306,10 @@ int main(int argc, char **argv) { } } + if (!*cfg.host) { + usage(); + } + if (!*cfg.remote_cmd) flags |= FLAG_INTERACTIVE; @@ -245,6 +332,12 @@ int main(int argc, char **argv) { } /* + * Select port. + */ + if (portnumber != -1) + cfg.port = portnumber; + + /* * Initialise WinSock. */ winsock_ver = MAKEWORD(2, 0); @@ -277,8 +370,8 @@ int main(int argc, char **argv) { netevent = CreateEvent(NULL, FALSE, FALSE, NULL); stdinevent = CreateEvent(NULL, FALSE, FALSE, NULL); - if (!cfg.ldisc_term) - SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_PROCESSED_INPUT); + GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &orig_console_mode); + SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_PROCESSED_INPUT); outhandle = GetStdHandle(STD_OUTPUT_HANDLE); /* @@ -296,6 +389,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; @@ -308,34 +428,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);