X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/c6ccd5c22a25aca610b0120b3eec1e6efd1aab97..985b644054f5e0d777184c48bfd8a97e824705fd:/ssh.c diff --git a/ssh.c b/ssh.c index f26eafd2..e0556a62 100644 --- a/ssh.c +++ b/ssh.c @@ -721,6 +721,7 @@ struct ssh_tag { struct ssh_channel *mainchan; /* primary session channel */ int exitcode; int close_expected; + int clean_exit; tree234 *rportfwds, *portfwds; @@ -748,6 +749,7 @@ struct ssh_tag { */ int fallback_cmd; + bufchain banner; /* accumulates banners during do_ssh2_authconn */ /* * Used for username and password input. */ @@ -1265,7 +1267,8 @@ static struct Packet *ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen) * _Completely_ silly lengths should be stomped on before they * do us any more damage. */ - if (st->len < 0 || st->pad < 0 || st->len + st->pad < 0) { + if (st->len < 0 || st->len > 35000 || st->pad < 4 || + st->len - st->pad < 1 || (st->len + 4) % st->cipherblk != 0) { bombout(("Incoming packet was garbled on decryption")); ssh_free_packet(st->pktin); crStop(NULL); @@ -1650,8 +1653,6 @@ static unsigned char *ssh2_mpint_fmt(Bignum b, int *len) unsigned char *p; int i, n = (bignum_bitcount(b) + 7) / 8; p = snewn(n + 1, unsigned char); - if (!p) - fatalbox("out of memory"); p[0] = 0; for (i = 1; i <= n; i++) p[i] = bignum_byte(b, n - i); @@ -1797,8 +1798,19 @@ static int ssh2_pkt_construct(Ssh ssh, struct Packet *pkt) * ssh2_pkt_send() or ssh2_pkt_defer() either go straight to one of * these or get queued, and then when the queue is later emptied * the packets are all passed to defer_noqueue(). + * + * When using a CBC-mode cipher, it's necessary to ensure that an + * attacker can't provide data to be encrypted using an IV that they + * know. We ensure this by prefixing each packet that might contain + * user data with an SSH_MSG_IGNORE. This is done using the deferral + * mechanism, so in this case send_noqueue() ends up redirecting to + * defer_noqueue(). If you don't like this inefficiency, don't use + * CBC. */ +static void ssh2_pkt_defer_noqueue(Ssh, struct Packet *, int); +static void ssh_pkt_defersend(Ssh); + /* * Send an SSH-2 packet immediately, without queuing or deferring. */ @@ -1806,6 +1818,12 @@ static void ssh2_pkt_send_noqueue(Ssh ssh, struct Packet *pkt) { int len; int backlog; + if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC)) { + /* We need to send two packets, so use the deferral mechanism. */ + ssh2_pkt_defer_noqueue(ssh, pkt, FALSE); + ssh_pkt_defersend(ssh); + return; + } len = ssh2_pkt_construct(ssh, pkt); backlog = sk_write(ssh->s, (char *)pkt->data, len); if (backlog > SSH_MAX_BACKLOG) @@ -1823,9 +1841,19 @@ static void ssh2_pkt_send_noqueue(Ssh ssh, struct Packet *pkt) /* * Defer an SSH-2 packet. */ -static void ssh2_pkt_defer_noqueue(Ssh ssh, struct Packet *pkt) +static void ssh2_pkt_defer_noqueue(Ssh ssh, struct Packet *pkt, int noignore) { - int len = ssh2_pkt_construct(ssh, pkt); + int len; + if (ssh->cscipher != NULL && (ssh->cscipher->flags & SSH_CIPHER_IS_CBC) && + ssh->deferred_len == 0 && !noignore) { + /* + * Interpose an SSH_MSG_IGNORE to ensure that user data don't + * get encrypted with a known IV. + */ + struct Packet *ipkt = ssh2_pkt_init(SSH2_MSG_IGNORE); + ssh2_pkt_defer_noqueue(ssh, ipkt, TRUE); + } + len = ssh2_pkt_construct(ssh, pkt); if (ssh->deferred_len + len > ssh->deferred_size) { ssh->deferred_size = ssh->deferred_len + len + 128; ssh->deferred_send_data = sresize(ssh->deferred_send_data, @@ -1875,7 +1903,7 @@ static void ssh2_pkt_defer(Ssh ssh, struct Packet *pkt) if (ssh->queueing) ssh2_pkt_queue(ssh, pkt); else - ssh2_pkt_defer_noqueue(ssh, pkt); + ssh2_pkt_defer_noqueue(ssh, pkt, FALSE); } #endif @@ -1923,7 +1951,7 @@ static void ssh2_pkt_queuesend(Ssh ssh) assert(!ssh->queueing); for (i = 0; i < ssh->queuelen; i++) - ssh2_pkt_defer_noqueue(ssh, ssh->queue[i]); + ssh2_pkt_defer_noqueue(ssh, ssh->queue[i], FALSE); ssh->queuelen = 0; ssh_pkt_defersend(ssh); @@ -2217,10 +2245,12 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) if (ssh->cfg.sshbug_rekey2 == FORCE_ON || (ssh->cfg.sshbug_rekey2 == AUTO && - (wc_match("OpenSSH_2.[0-4]*", imp) || + (wc_match("DigiSSH_2.0", imp) || + wc_match("OpenSSH_2.[0-4]*", imp) || wc_match("OpenSSH_2.5.[0-3]*", imp) || wc_match("Sun_SSH_1.0", imp) || - wc_match("Sun_SSH_1.0.1", imp)))) { + wc_match("Sun_SSH_1.0.1", imp) || + wc_match("WeOnlyDo-1.2.6", imp)))) { /* * These versions have the SSH-2 rekey bug. */ @@ -2266,23 +2296,20 @@ static int do_ssh_init(Ssh ssh, unsigned char c) crBegin(ssh->do_ssh_init_crstate); - /* Search for the string "SSH-" in the input. */ - s->i = 0; - while (1) { - static const int transS[] = { 1, 2, 2, 1 }; - static const int transH[] = { 0, 0, 3, 0 }; - static const int transminus[] = { 0, 0, 0, -1 }; - if (c == 'S') - s->i = transS[s->i]; - else if (c == 'H') - s->i = transH[s->i]; - else if (c == '-') - s->i = transminus[s->i]; - else - s->i = 0; - if (s->i < 0) - break; - crReturn(1); /* get another character */ + /* Search for a line beginning with the string "SSH-" in the input. */ + for (;;) { + if (c != 'S') goto no; + crReturn(1); + if (c != 'S') goto no; + crReturn(1); + if (c != 'H') goto no; + crReturn(1); + if (c != '-') goto no; + break; + no: + while (c != '\012') + crReturn(1); + crReturn(1); } s->vstrsize = 16; @@ -2383,6 +2410,8 @@ static int do_ssh_init(Ssh ssh, unsigned char c) strcspn(verstring, "\015\012"), verstring); sk_write(ssh->s, verstring, strlen(verstring)); sfree(verstring); + if (ssh->version == 2) + do_ssh2_transport(ssh, NULL, -1, NULL); } logeventf(ssh, "Using SSH protocol version %d", ssh->version); @@ -2566,20 +2595,20 @@ static int ssh_closing(Plug plug, const char *error_msg, int error_code, Ssh ssh = (Ssh) plug; int need_notify = ssh_do_close(ssh, FALSE); - if (!error_msg && !ssh->close_expected) { - error_msg = "Server unexpectedly closed network connection"; + if (!error_msg) { + if (!ssh->close_expected) + error_msg = "Server unexpectedly closed network connection"; + else + error_msg = "Server closed network connection"; } if (need_notify) notify_remote_exit(ssh->frontend); - if (error_msg) { - /* A socket error has occurred. */ + if (error_msg) logevent(error_msg); + if (!ssh->close_expected || !ssh->clean_exit) connection_fatal(ssh->frontend, "%s", error_msg); - } else { - logevent("Server closed network connection"); - } return 0; } @@ -2626,8 +2655,6 @@ static const char *connect_to_host(Ssh ssh, char *host, int port, const char *err; ssh->savedhost = snewn(1 + strlen(host), char); - if (!ssh->savedhost) - fatalbox("Out of memory"); strcpy(ssh->savedhost, host); if (port < 0) @@ -2843,6 +2870,39 @@ static void ssh_agentf_callback(void *cv, void *reply, int replylen) } /* + * Client-initiated disconnection. Send a DISCONNECT if `wire_reason' + * non-NULL, otherwise just close the connection. `client_reason' == NULL + * => log `wire_reason'. + */ +static void ssh_disconnect(Ssh ssh, char *client_reason, char *wire_reason, + int code, int clean_exit) +{ + char *error; + if (!client_reason) + client_reason = wire_reason; + if (client_reason) + error = dupprintf("Disconnected: %s", client_reason); + else + error = dupstr("Disconnected"); + if (wire_reason) { + if (ssh->version == 1) { + send_packet(ssh, SSH1_MSG_DISCONNECT, PKT_STR, wire_reason, + PKT_END); + } else if (ssh->version == 2) { + struct Packet *pktout = ssh2_pkt_init(SSH2_MSG_DISCONNECT); + ssh2_pkt_adduint32(pktout, code); + ssh2_pkt_addstring(pktout, wire_reason); + ssh2_pkt_addstring(pktout, "en"); /* language tag */ + ssh2_pkt_send_noqueue(ssh, pktout); + } + } + ssh->close_expected = TRUE; + ssh->clean_exit = clean_exit; + ssh_closing((Plug)ssh, error, 0, 0); + sfree(error); +} + +/* * Handle the key exchange and user authentication phases. */ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, @@ -2947,8 +3007,6 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, s->len = (hostkey.bytes > servkey.bytes ? hostkey.bytes : servkey.bytes); s->rsabuf = snewn(s->len, unsigned char); - if (!s->rsabuf) - fatalbox("Out of memory"); /* * Verify the host key. @@ -2960,8 +3018,6 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int len = rsastr_len(&hostkey); char fingerprint[100]; char *keystr = snewn(len, char); - if (!keystr) - fatalbox("Out of memory"); rsastr_fmt(keystr, &hostkey); rsa_fingerprint(fingerprint, sizeof(fingerprint), &hostkey); @@ -2985,8 +3041,8 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, ssh_set_frozen(ssh, 0); if (s->dlgret == 0) { - ssh->close_expected = TRUE; - ssh_closing((Plug)ssh, NULL, 0, 0); + ssh_disconnect(ssh, "User aborted at host key verification", + NULL, 0, TRUE); crStop(0); } } @@ -3066,8 +3122,8 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, } ssh_set_frozen(ssh, 0); if (s->dlgret == 0) { - ssh->close_expected = TRUE; - ssh_closing((Plug)ssh, NULL, 0, 0); + ssh_disconnect(ssh, "User aborted at cipher warning", NULL, + 0, TRUE); crStop(0); } } @@ -3141,9 +3197,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, * get_line failed to get a username. * Terminate. */ - logevent("No username provided. Abandoning session."); - ssh->close_expected = TRUE; - ssh_closing((Plug)ssh, NULL, 0, 0); + ssh_disconnect(ssh, "No username provided", NULL, 0, TRUE); crStop(1); } } else { @@ -3480,13 +3534,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, * because one was supplied on the command line * which has already failed to work). Terminate. */ - send_packet(ssh, SSH1_MSG_DISCONNECT, - PKT_STR, "No more passwords available to try", - PKT_END); - logevent("Unable to authenticate"); - connection_fatal(ssh->frontend, "Unable to authenticate"); - ssh->close_expected = TRUE; - ssh_closing((Plug)ssh, NULL, 0, 0); + ssh_disconnect(ssh, NULL, "Unable to authenticate", 0, FALSE); crStop(1); } } else { @@ -4534,8 +4582,7 @@ static void ssh1_smsg_exit_status(Ssh ssh, struct Packet *pktin) * encrypted packet, we close the session once * we've sent EXIT_CONFIRMATION. */ - ssh->close_expected = TRUE; - ssh_closing((Plug)ssh, NULL, 0, 0); + ssh_disconnect(ssh, NULL, NULL, 0, TRUE); } /* Helper function to deal with sending tty modes for REQUEST_PTY */ @@ -4603,14 +4650,23 @@ static void do_ssh1_connection(Ssh ssh, unsigned char *in, int inlen, ssh->x11auth = x11_invent_auth(proto, sizeof(proto), data, sizeof(data), ssh->cfg.x11_auth); x11_get_real_auth(ssh->x11auth, ssh->cfg.x11_display); + /* + * Note that while we blank the X authentication data here, we don't + * take any special action to blank the start of an X11 channel, + * so using MIT-MAGIC-COOKIE-1 and actually opening an X connection + * without having session blanking enabled is likely to leak your + * cookie into the log. + */ if (ssh->v1_local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) { send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING, - PKT_STR, proto, PKT_STR, data, + PKT_STR, proto, + PKTT_PASSWORD, PKT_STR, data, PKTT_OTHER, PKT_INT, x11_get_screen_number(ssh->cfg.x11_display), PKT_END); } else { send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING, - PKT_STR, proto, PKT_STR, data, PKT_END); + PKT_STR, proto, + PKTT_PASSWORD, PKT_STR, data, PKTT_OTHER, PKT_END); } do { crReturnV; @@ -5301,8 +5357,8 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, } ssh_set_frozen(ssh, 0); if (s->dlgret == 0) { - ssh->close_expected = TRUE; - ssh_closing((Plug)ssh, NULL, 0, 0); + ssh_disconnect(ssh, "User aborted at kex warning", NULL, + 0, TRUE); crStop(0); } } @@ -5326,8 +5382,8 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, } ssh_set_frozen(ssh, 0); if (s->dlgret == 0) { - ssh->close_expected = TRUE; - ssh_closing((Plug)ssh, NULL, 0, 0); + ssh_disconnect(ssh, "User aborted at cipher warning", NULL, + 0, TRUE); crStop(0); } } @@ -5351,8 +5407,8 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, } ssh_set_frozen(ssh, 0); if (s->dlgret == 0) { - ssh->close_expected = TRUE; - ssh_closing((Plug)ssh, NULL, 0, 0); + ssh_disconnect(ssh, "User aborted at cipher warning", NULL, + 0, TRUE); crStop(0); } } @@ -5500,8 +5556,8 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, } ssh_set_frozen(ssh, 0); if (s->dlgret == 0) { - ssh->close_expected = TRUE; - ssh_closing((Plug)ssh, NULL, 0, 0); + ssh_disconnect(ssh, "User aborted at host key verification", NULL, + 0, TRUE); crStop(0); } if (!s->got_session_id) { /* don't bother logging this in rekeys */ @@ -5667,7 +5723,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, * it would only confuse the layer above. */ if (s->activated_authconn) { - crReturn(1); + crReturn(0); } s->activated_authconn = TRUE; @@ -5982,8 +6038,6 @@ static void ssh2_msg_channel_close(Ssh ssh, struct Packet *pktin) * not running in -N mode.) */ if (!ssh->cfg.ssh_no_shell && count234(ssh->channels) == 0) { - logevent("All channels closed. Disconnecting"); -#if 0 /* * We used to send SSH_MSG_DISCONNECT here, * because I'd believed that _every_ conforming @@ -5995,14 +6049,7 @@ static void ssh2_msg_channel_close(Ssh ssh, struct Packet *pktin) * this is more polite than sending a * DISCONNECT. So now we don't. */ - s->pktout = ssh2_pkt_init(SSH2_MSG_DISCONNECT); - ssh2_pkt_adduint32(s->pktout, SSH2_DISCONNECT_BY_APPLICATION); - ssh2_pkt_addstring(s->pktout, "All open channels closed"); - ssh2_pkt_addstring(s->pktout, "en"); /* language tag */ - ssh2_pkt_send_noqueue(ssh, s->pktout); -#endif - ssh->close_expected = TRUE; - ssh_closing((Plug)ssh, NULL, 0, 0); + ssh_disconnect(ssh, "All channels closed", NULL, 0, TRUE); } } @@ -6089,18 +6136,10 @@ static void ssh2_msg_channel_request(Ssh ssh, struct Packet *pktin) */ c = find234(ssh->channels, &localid, ssh_channelfind); if (!c) { - char buf[80]; - sprintf(buf, "Received channel request for nonexistent" - " channel %d", localid); - logevent(buf); - pktout = ssh2_pkt_init(SSH2_MSG_DISCONNECT); - ssh2_pkt_adduint32(pktout, SSH2_DISCONNECT_BY_APPLICATION); - ssh2_pkt_addstring(pktout, buf); - ssh2_pkt_addstring(pktout, "en"); /* language tag */ - ssh2_pkt_send_noqueue(ssh, pktout); - connection_fatal(ssh->frontend, "%s", buf); - ssh->close_expected = TRUE; - ssh_closing((Plug)ssh, NULL, 0, 0); + char *buf = dupprintf("Received channel request for nonexistent" + " channel %d", localid); + ssh_disconnect(ssh, NULL, buf, SSH2_DISCONNECT_PROTOCOL_ERROR, FALSE); + sfree(buf); return; } @@ -6310,7 +6349,7 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin) } } } else if (typelen == 22 && - !memcmp(type, "auth-agent@openssh.com", 3)) { + !memcmp(type, "auth-agent@openssh.com", 22)) { if (!ssh->agentfwd_enabled) error = "Agent forwarding is not enabled"; else { @@ -6349,6 +6388,21 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin) } } +/* + * Buffer banner messages for later display at some convenient point. + */ +static void ssh2_msg_userauth_banner(Ssh ssh, struct Packet *pktin) +{ + /* Arbitrary limit to prevent unbounded inflation of buffer */ + if (bufchain_size(&ssh->banner) <= 131072) { + char *banner = NULL; + int size = 0; + ssh_pkt_getstring(pktin, &banner, &size); + if (banner) + bufchain_add(&ssh->banner, banner, size); + } +} + /* Helper function to deal with sending tty modes for "pty-req" */ static void ssh2_send_ttymode(void *data, char *mode, char *val) { @@ -6390,6 +6444,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, AUTH_TYPE_KEYBOARD_INTERACTIVE, AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET } type; + int done_service_req; int gotit, need_pw, can_pubkey, can_passwd, can_keyb_inter; int tried_pubkey_config, tried_agent; int kbd_inter_running, kbd_inter_refused; @@ -6417,16 +6472,33 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, crBegin(ssh->do_ssh2_authconn_crstate); - /* - * Request userauth protocol, and await a response to it. - */ - s->pktout = ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST); - ssh2_pkt_addstring(s->pktout, "ssh-userauth"); - ssh2_pkt_send(ssh, s->pktout); - crWaitUntilV(pktin); - if (pktin->type != SSH2_MSG_SERVICE_ACCEPT) { - bombout(("Server refused user authentication protocol")); - crStopV; + s->done_service_req = FALSE; + s->we_are_in = FALSE; + if (!ssh->cfg.ssh_no_userauth) { + /* + * Request userauth protocol, and await a response to it. + */ + s->pktout = ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST); + ssh2_pkt_addstring(s->pktout, "ssh-userauth"); + ssh2_pkt_send(ssh, s->pktout); + crWaitUntilV(pktin); + if (pktin->type == SSH2_MSG_SERVICE_ACCEPT) + s->done_service_req = TRUE; + } + if (!s->done_service_req) { + /* + * Request connection protocol directly, without authentication. + */ + s->pktout = ssh2_pkt_init(SSH2_MSG_SERVICE_REQUEST); + ssh2_pkt_addstring(s->pktout, "ssh-connection"); + ssh2_pkt_send(ssh, s->pktout); + crWaitUntilV(pktin); + if (pktin->type == SSH2_MSG_SERVICE_ACCEPT) { + s->we_are_in = TRUE; /* no auth required */ + } else { + bombout(("Server refused service request")); + crStopV; + } } /* @@ -6455,7 +6527,10 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, */ s->username[0] = '\0'; s->got_username = FALSE; - do { + bufchain_init(&ssh->banner); + ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = + ssh2_msg_userauth_banner; + while (!s->we_are_in) { /* * Get a username. */ @@ -6473,9 +6548,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, * get_line failed to get a username. * Terminate. */ - logevent("No username provided. Abandoning session."); - ssh->close_expected = TRUE; - ssh_closing((Plug)ssh, NULL, 0, 0); + ssh_disconnect(ssh, "No username provided", NULL, 0, TRUE); crStopV; } } else { @@ -6555,9 +6628,14 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, */ if (!s->gotit) crWaitUntilV(pktin); - while (pktin->type == SSH2_MSG_USERAUTH_BANNER) { - char *banner; - int size; + /* + * Now is a convenient point to spew any banner material + * that we've accumulated. (This should ensure that when + * we exit the auth loop, we haven't any left to deal + * with.) + */ + { + int size = bufchain_size(&ssh->banner); /* * Don't show the banner if we're operating in * non-verbose non-interactive mode. (It's probably @@ -6566,12 +6644,13 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, * the banner will screw up processing on the * output of (say) plink.) */ - if (flags & (FLAG_VERBOSE | FLAG_INTERACTIVE)) { - ssh_pkt_getstring(pktin, &banner, &size); - if (banner) - c_write_untrusted(ssh, banner, size); + if (size && (flags & (FLAG_VERBOSE | FLAG_INTERACTIVE))) { + char *banner = snewn(size, char); + bufchain_fetch(&ssh->banner, banner, size); + c_write_untrusted(ssh, banner, size); + sfree(banner); } - crWaitUntilV(pktin); + bufchain_clear(&ssh->banner); } if (pktin->type == SSH2_MSG_USERAUTH_SUCCESS) { logevent("Access granted"); @@ -7020,17 +7099,9 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, * command line which has already failed to * work). Terminate. */ - s->pktout = ssh2_pkt_init(SSH2_MSG_DISCONNECT); - ssh2_pkt_adduint32(s->pktout,SSH2_DISCONNECT_BY_APPLICATION); - ssh2_pkt_addstring(s->pktout, "No more passwords available" - " to try"); - ssh2_pkt_addstring(s->pktout, "en"); /* language tag */ - ssh2_pkt_send_noqueue(ssh, s->pktout); - logevent("Unable to authenticate"); - connection_fatal(ssh->frontend, - "Unable to authenticate"); - ssh->close_expected = TRUE; - ssh_closing((Plug)ssh, NULL, 0, 0); + ssh_disconnect(ssh, NULL, "Unable to authenticate", + SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER, + FALSE); crStopV; } } else { @@ -7181,27 +7252,18 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, } s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE; } else { - c_write_str(ssh, "No supported authentication methods" - " left to try!\r\n"); - logevent("No supported authentications offered." - " Disconnecting"); - s->pktout = ssh2_pkt_init(SSH2_MSG_DISCONNECT); - ssh2_pkt_adduint32(s->pktout, SSH2_DISCONNECT_BY_APPLICATION); - ssh2_pkt_addstring(s->pktout, "No supported authentication" - " methods available"); - ssh2_pkt_addstring(s->pktout, "en"); /* language tag */ - ssh2_pkt_send_noqueue(ssh, s->pktout); - ssh->close_expected = TRUE; - ssh_closing((Plug)ssh, NULL, 0, 0); + ssh_disconnect(ssh, NULL, + "No supported authentication methods available", + SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, + FALSE); crStopV; } } - } while (!s->we_are_in); + } + ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = NULL; /* - * Now we're authenticated for the connection protocol. The - * connection protocol will automatically have started at this - * point; there's no need to send SERVICE_REQUEST. + * Now the connection protocol has started, one way or another. */ ssh->channels = newtree234(ssh_channelcmp); @@ -7285,7 +7347,16 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, ssh2_pkt_addbool(s->pktout, 1); /* want reply */ ssh2_pkt_addbool(s->pktout, 0); /* many connections */ ssh2_pkt_addstring(s->pktout, proto); + /* + * Note that while we blank the X authentication data here, we don't + * take any special action to blank the start of an X11 channel, + * so using MIT-MAGIC-COOKIE-1 and actually opening an X connection + * without having session blanking enabled is likely to leak your + * cookie into the log. + */ + dont_log_password(ssh, s->pktout, PKTLOG_BLANK); ssh2_pkt_addstring(s->pktout, data); + end_log_omission(ssh, s->pktout); ssh2_pkt_adduint32(s->pktout, x11_get_screen_number(ssh->cfg.x11_display)); ssh2_pkt_send(ssh, s->pktout); @@ -7758,6 +7829,7 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle, ssh->hostkey = NULL; ssh->exitcode = -1; ssh->close_expected = FALSE; + ssh->clean_exit = FALSE; ssh->state = SSH_STATE_PREPACKET; ssh->size_needed = FALSE; ssh->eof_needed = FALSE; @@ -7935,7 +8007,8 @@ static void ssh_reconfig(void *handle, Config *cfg) unsigned long old_max_data_size; pinger_reconfig(ssh->pinger, &ssh->cfg, cfg); - ssh_setup_portfwd(ssh, cfg); + if (ssh->portfwds) + ssh_setup_portfwd(ssh, cfg); if (ssh->cfg.ssh_rekey_time != cfg->ssh_rekey_time && cfg->ssh_rekey_time != 0) { @@ -7982,7 +8055,7 @@ static void ssh_reconfig(void *handle, Config *cfg) } /* - * Called to send data down the Telnet connection. + * Called to send data down the SSH connection. */ static int ssh_send(void *handle, char *buf, int len) { @@ -8139,7 +8212,7 @@ static const struct telnet_special *ssh_get_specials(void *handle) } /* - * Send Telnet special codes. TS_EOF is useful for `plink', so you + * Send special codes. TS_EOF is useful for `plink', so you * can send an EOF and collect resulting output (e.g. `plink * hostname sort'). */