X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/c44bf5bd7bf680c21356864ac5ae72ab29e55ce6..f33ba69e92f389f5884eae5a586858a629a5260b:/plink.c diff --git a/plink.c b/plink.c index 0f764cf3..307d7298 100644 --- a/plink.c +++ b/plink.c @@ -1,11 +1,7 @@ /* - * PLink - a command-line (stdin/stdout) variant of PuTTY. + * PLink - a Windows command-line (stdin/stdout) variant of PuTTY. */ -#ifndef AUTO_WINSOCK -#include -#endif -#include #include #include #include @@ -35,7 +31,6 @@ void fatalbox(char *p, ...) vfprintf(stderr, p, ap); va_end(ap); fputc('\n', stderr); - WSACleanup(); cleanup_exit(1); } void modalfatalbox(char *p, ...) @@ -46,7 +41,6 @@ void modalfatalbox(char *p, ...) vfprintf(stderr, p, ap); va_end(ap); fputc('\n', stderr); - WSACleanup(); cleanup_exit(1); } void connection_fatal(void *frontend, char *p, ...) @@ -57,7 +51,6 @@ void connection_fatal(void *frontend, char *p, ...) vfprintf(stderr, p, ap); va_end(ap); fputc('\n', stderr); - WSACleanup(); cleanup_exit(1); } void cmdline_error(char *p, ...) @@ -180,8 +173,6 @@ int from_backend(void *frontend_handle, int is_stderr, { int osize, esize; - assert(len > 0); - if (is_stderr) { bufchain_add(&stderr_data, data, len); try_output(1); @@ -219,27 +210,36 @@ static void usage(void) printf("Usage: plink [options] [user@]host [command]\n"); printf(" (\"host\" can also be a PuTTY saved session name)\n"); printf("Options:\n"); + printf(" -V print version information\n"); printf(" -v show verbose messages\n"); printf(" -load sessname Load settings from saved session\n"); printf(" -ssh -telnet -rlogin -raw\n"); - printf(" force use of a particular protocol (default SSH)\n"); + printf(" force use of a particular protocol\n"); printf(" -P port connect to specified port\n"); printf(" -l user connect with specified username\n"); printf(" -m file read remote command(s) from file\n"); printf(" -batch disable all interactive prompts\n"); printf("The following options only apply to SSH connections:\n"); printf(" -pw passw login with specified password\n"); - printf(" -D listen-port Dynamic SOCKS-based port forwarding\n"); - printf(" -L listen-port:host:port Forward local port to " - "remote address\n"); - printf(" -R listen-port:host:port Forward remote port to" - " local address\n"); + printf(" -D [listen-IP:]listen-port\n"); + printf(" Dynamic SOCKS-based port forwarding\n"); + printf(" -L [listen-IP:]listen-port:host:port\n"); + printf(" Forward local port to remote address\n"); + printf(" -R [listen-IP:]listen-port:host:port\n"); + printf(" Forward remote port to local address\n"); printf(" -X -x enable / disable X11 forwarding\n"); printf(" -A -a enable / disable agent forwarding\n"); printf(" -t -T enable / disable pty allocation\n"); printf(" -1 -2 force use of particular protocol version\n"); printf(" -C enable compression\n"); printf(" -i key private key file for authentication\n"); + printf(" -s remote command is an SSH subsystem (SSH-2 only)\n"); + exit(1); +} + +static void version(void) +{ + printf("plink: %s\n", ver); exit(1); } @@ -252,12 +252,12 @@ char *do_select(SOCKET skt, int startup) } else { events = 0; } - if (WSAEventSelect(skt, netevent, events) == SOCKET_ERROR) { - switch (WSAGetLastError()) { + if (p_WSAEventSelect(skt, netevent, events) == SOCKET_ERROR) { + switch (p_WSAGetLastError()) { case WSAENETDOWN: return "Network is down"; default: - return "WSAAsyncSelect(): unknown error"; + return "WSAEventSelect(): unknown error"; } } return NULL; @@ -265,8 +265,6 @@ char *do_select(SOCKET skt, int startup) int main(int argc, char **argv) { - WSADATA wsadata; - WORD winsock_ver; WSAEVENT stdinevent, stdoutevent, stderrevent; HANDLE handles[4]; DWORD in_threadid, out_threadid, err_threadid; @@ -279,6 +277,7 @@ int main(int argc, char **argv) int connopen; int exitcode; int errors; + int use_subsystem = 0; ssh_get_line = console_get_line; @@ -296,6 +295,7 @@ int main(int argc, char **argv) * Process the command line. */ do_defaults(NULL, &cfg); + loaded_session = FALSE; default_protocol = cfg.protocol; default_port = cfg.port; errors = 0; @@ -331,6 +331,11 @@ int main(int argc, char **argv) continue; } else if (!strcmp(p, "-batch")) { console_batch_mode = 1; + } else if (!strcmp(p, "-s")) { + /* Save status to write to cfg later. */ + use_subsystem = 1; + } else if (!strcmp(p, "-V")) { + version(); } else { fprintf(stderr, "plink: unknown option \"%s\"\n", p); errors = 1; @@ -363,7 +368,7 @@ int main(int argc, char **argv) strncpy(cfg.host, q, sizeof(cfg.host) - 1); cfg.host[sizeof(cfg.host) - 1] = '\0'; } else { - char *r; + char *r, *user, *host; /* * Before we process the [user@]host string, we * first check for the presence of a protocol @@ -387,41 +392,48 @@ int main(int argc, char **argv) } /* - * Three cases. Either (a) there's a nonzero - * length string followed by an @, in which - * case that's user and the remainder is host. - * Or (b) there's only one string, not counting - * a potential initial @, and it exists in the - * saved-sessions database. Or (c) only one - * string and it _doesn't_ exist in the - * database. + * A nonzero length string followed by an @ is treated + * as a username. (We discount an _initial_ @.) The + * rest of the string (or the whole string if no @) + * is treated as a session name and/or hostname. */ r = strrchr(p, '@'); if (r == p) p++, r = NULL; /* discount initial @ */ - if (r == NULL) { - /* - * One string. - */ + if (r) { + *r++ = '\0'; + user = p, host = r; + } else { + user = NULL, host = p; + } + + /* + * Now attempt to load a saved session with the + * same name as the hostname. + */ + { Config cfg2; - do_defaults(p, &cfg2); - if (cfg2.host[0] == '\0') { + do_defaults(host, &cfg2); + if (loaded_session || cfg2.host[0] == '\0') { /* No settings for this host; use defaults */ - strncpy(cfg.host, p, sizeof(cfg.host) - 1); + /* (or session was already loaded with -load) */ + strncpy(cfg.host, host, sizeof(cfg.host) - 1); cfg.host[sizeof(cfg.host) - 1] = '\0'; cfg.port = default_port; } else { cfg = cfg2; + /* Ick: patch up internal pointer after copy */ cfg.remote_cmd_ptr = cfg.remote_cmd; } - } else { - *r++ = '\0'; - strncpy(cfg.username, p, sizeof(cfg.username) - 1); + } + + if (user) { + /* Patch in specified username. */ + strncpy(cfg.username, user, + sizeof(cfg.username) - 1); cfg.username[sizeof(cfg.username) - 1] = '\0'; - strncpy(cfg.host, r, sizeof(cfg.host) - 1); - cfg.host[sizeof(cfg.host) - 1] = '\0'; - cfg.port = default_port; } + } } else { char *command; @@ -489,6 +501,12 @@ int main(int argc, char **argv) cmdline_run_saved(&cfg); /* + * Apply subsystem status. + */ + if (use_subsystem) + cfg.ssh_subsys = TRUE; + + /* * Trim a colon suffix off the hostname if it's there. */ cfg.host[strcspn(cfg.host, ":")] = '\0'; @@ -536,36 +554,25 @@ int main(int argc, char **argv) if (portnumber != -1) cfg.port = portnumber; - /* - * Initialise WinSock. - */ - winsock_ver = MAKEWORD(2, 0); - if (WSAStartup(winsock_ver, &wsadata)) { - MessageBox(NULL, "Unable to initialise WinSock", "WinSock Error", - MB_OK | MB_ICONEXCLAMATION); - return 1; - } - if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wVersion) != 0) { - MessageBox(NULL, "WinSock version is incompatible with 2.0", - "WinSock Error", MB_OK | MB_ICONEXCLAMATION); - WSACleanup(); + sk_init(); + if (p_WSAEventSelect == NULL) { + fprintf(stderr, "Plink requires WinSock 2\n"); return 1; } - sk_init(); /* * Start up the connection. */ netevent = CreateEvent(NULL, FALSE, FALSE, NULL); { - char *error; + const char *error; char *realhost; /* nodelay is only useful if stdin is a character device (console) */ int nodelay = cfg.tcp_nodelay && (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR); error = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port, - &realhost, nodelay); + &realhost, nodelay, cfg.tcp_keepalives); if (error) { fprintf(stderr, "Unable to open connection:\n%s", error); return 1; @@ -693,7 +700,7 @@ int main(int argc, char **argv) WPARAM wp; socket = sklist[i]; wp = (WPARAM) socket; - if (!WSAEnumNetworkEvents(socket, NULL, &things)) { + if (!p_WSAEnumNetworkEvents(socket, NULL, &things)) { static const struct { int bit, mask; } eventtypes[] = { {FD_CONNECT_BIT, FD_CONNECT}, {FD_READ_BIT, FD_READ}, @@ -771,11 +778,11 @@ int main(int argc, char **argv) bufchain_size(&stderr_data) == 0) break; /* we closed the connection */ } - WSACleanup(); exitcode = back->exitcode(backhandle); if (exitcode < 0) { fprintf(stderr, "Remote process exit code unavailable\n"); exitcode = 1; /* this is an error condition */ } - return exitcode; + cleanup_exit(exitcode); + return 0; /* placate compiler warning */ }