static char *password = NULL;
-void logevent(char *string)
-{
-}
-
-void verify_ssh_host_key(char *host, int port, char *keytype,
- char *keystr, char *fingerprint)
-{
- int ret;
- HANDLE hin;
- DWORD savemode, i;
-
- 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 want to carry on connecting just once, without\n"
- "adding the key to the cache, enter \"n\".\n"
- "If you do not trust this host, press Return to abandon the\n"
- "connection.\n"
- "Store key in cache? (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);
- fflush(stderr);
- }
- if (ret == 1) { /* key was absent */
- fprintf(stderr, absentmsg, fingerprint);
- fflush(stderr);
- }
-
- hin = GetStdHandle(STD_INPUT_HANDLE);
- GetConsoleMode(hin, &savemode);
- SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
- ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
- ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
- SetConsoleMode(hin, savemode);
-
- if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') {
- if (line[0] == 'y' || line[0] == 'Y')
- store_host_key(host, port, keytype, keystr);
- } else {
- fprintf(stderr, abandoned);
- exit(0);
- }
-}
-
-/*
- * Ask whether the selected cipher is acceptable (since it was
- * below the configured 'warn' threshold).
- * cs: 0 = both ways, 1 = client->server, 2 = server->client
- */
-void askcipher(char *ciphername, int cs)
-{
- HANDLE hin;
- DWORD savemode, i;
-
- static const char msg[] =
- "The first %scipher supported by the server is\n"
- "%s, which is below the configured warning threshold.\n"
- "Continue with connection? (y/n) ";
- static const char abandoned[] = "Connection abandoned.\n";
-
- char line[32];
-
- fprintf(stderr, msg,
- (cs == 0) ? "" :
- (cs == 1) ? "client-to-server " :
- "server-to-client ",
- ciphername);
- fflush(stderr);
-
- hin = GetStdHandle(STD_INPUT_HANDLE);
- GetConsoleMode(hin, &savemode);
- SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
- ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
- ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
- SetConsoleMode(hin, savemode);
-
- if (line[0] == 'y' || line[0] == 'Y') {
- return;
- } else {
- fprintf(stderr, abandoned);
- exit(0);
- }
-}
-
HANDLE inhandle, outhandle, errhandle;
DWORD orig_console_mode;
SetConsoleMode(inhandle, mode);
}
-static int get_line(const char *prompt, char *str, int maxlen, int is_pw)
-{
- HANDLE hin, hout;
- DWORD savemode, newmode, i;
-
- if (is_pw && password) {
- static int tried_once = 0;
-
- if (tried_once) {
- return 0;
- } else {
- strncpy(str, password, maxlen);
- str[maxlen - 1] = '\0';
- tried_once = 1;
- return 1;
- }
- }
-
- hin = GetStdHandle(STD_INPUT_HANDLE);
- hout = GetStdHandle(STD_OUTPUT_HANDLE);
- if (hin == INVALID_HANDLE_VALUE || hout == INVALID_HANDLE_VALUE) {
- fprintf(stderr, "Cannot get standard input/output handles");
- return 0;
- }
-
- GetConsoleMode(hin, &savemode);
- newmode = savemode | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT;
- if (is_pw)
- newmode &= ~ENABLE_ECHO_INPUT;
- else
- newmode |= ENABLE_ECHO_INPUT;
- SetConsoleMode(hin, newmode);
-
- WriteFile(hout, prompt, strlen(prompt), &i, NULL);
- ReadFile(hin, str, maxlen - 1, &i, NULL);
-
- SetConsoleMode(hin, savemode);
-
- if ((int) i > maxlen)
- i = maxlen - 1;
- else
- i = i - 2;
- str[i] = '\0';
-
- if (is_pw)
- WriteFile(hout, "\r\n", 2, &i, NULL);
-
- return 1;
-}
-
struct input_data {
DWORD len;
char buffer[4096];
SOCKET *sklist;
int skcount, sksize;
int connopen;
+ int exitcode;
char extra_portfwd[sizeof(cfg.portfwd)];
- ssh_get_line = get_line;
+ ssh_get_line = console_get_line;
sklist = NULL;
skcount = sksize = 0;
} else if (!strcmp(p, "-telnet")) {
default_protocol = cfg.protocol = PROT_TELNET;
default_port = cfg.port = 23;
+ } else if (!strcmp(p, "-rlogin")) {
+ default_protocol = cfg.protocol = PROT_RLOGIN;
+ default_port = cfg.port = 513;
} else if (!strcmp(p, "-raw")) {
default_protocol = cfg.protocol = PROT_RAW;
+ } else if (!strcmp(p, "-batch")) {
+ console_batch_mode = TRUE;
} 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;
+ --argc, console_password = *++argv;
} else if (!strcmp(p, "-l") && argc > 1) {
char *username;
--argc, username = *++argv;
{
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(cfg.host, cfg.port, &realhost);
+ error = back->init(cfg.host, cfg.port, &realhost, nodelay);
if (error) {
fprintf(stderr, "Unable to open connection:\n%s", error);
return 1;
socket = sklist[i];
wp = (WPARAM) socket;
if (!WSAEnumNetworkEvents(socket, NULL, &things)) {
+ static const struct { int bit, mask; } eventtypes[] = {
+ {FD_CONNECT_BIT, FD_CONNECT},
+ {FD_READ_BIT, FD_READ},
+ {FD_CLOSE_BIT, FD_CLOSE},
+ {FD_OOB_BIT, FD_OOB},
+ {FD_WRITE_BIT, FD_WRITE},
+ {FD_ACCEPT_BIT, FD_ACCEPT},
+ };
+ int e;
+
noise_ultralight(socket);
noise_ultralight(things.lNetworkEvents);
- if (things.lNetworkEvents & FD_CONNECT)
- connopen &= select_result(wp, (LPARAM) FD_CONNECT);
- if (things.lNetworkEvents & FD_READ)
- connopen &= select_result(wp, (LPARAM) FD_READ);
- if (things.lNetworkEvents & FD_CLOSE)
- connopen &= select_result(wp, (LPARAM) FD_CLOSE);
- if (things.lNetworkEvents & FD_OOB)
- connopen &= select_result(wp, (LPARAM) FD_OOB);
- if (things.lNetworkEvents & FD_WRITE)
- connopen &= select_result(wp, (LPARAM) FD_WRITE);
- if (things.lNetworkEvents & FD_ACCEPT)
- connopen &= select_result(wp, (LPARAM) FD_ACCEPT);
+ for (e = 0; e < lenof(eventtypes); e++)
+ if (things.lNetworkEvents & eventtypes[e].mask) {
+ LPARAM lp;
+ int err = things.iErrorCode[eventtypes[e].bit];
+ lp = WSAMAKESELECTREPLY(eventtypes[e].mask, err);
+ connopen &= select_result(wp, lp);
+ }
}
}
} else if (n == 1) {
break; /* we closed the connection */
}
WSACleanup();
- return 0;
+ exitcode = back->exitcode();
+ if (exitcode < 0) {
+ fprintf(stderr, "Remote process exit code unavailable\n");
+ exitcode = 1; /* this is an error condition */
+ }
+ return exitcode;
}