X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/cdcbdf3b83c8a1e4db0b149e818cd24e3596cf2c..4252c9cc7d88ca10cfaeaea2dd2510aabfdc0f38:/ssh.c diff --git a/ssh.c b/ssh.c index b0f16518..4a6db9f6 100644 --- a/ssh.c +++ b/ssh.c @@ -607,12 +607,6 @@ static int ssh1_rdpkt(unsigned char **data, int *datalen) (*data)++, (*datalen)--; } -#ifdef FWHACK - if (st->len == 0x52656d6f) { /* "Remo"te server has closed ... */ - st->len = 0x300; /* big enough to carry to end */ - } -#endif - st->pad = 8 - (st->len % 8); st->biglen = st->len + st->pad; pktin.length = st->len - 5; @@ -725,6 +719,8 @@ static int ssh1_rdpkt(unsigned char **data, int *datalen) memcpy(buf + nowlen, pktin.body + 4, msglen); buf[nowlen + msglen] = '\0'; logevent(buf); + bombout(("Server sent disconnect message:\n\"%s\"", buf+nowlen)); + crReturn(0); } crFinish(0); @@ -768,11 +764,7 @@ static int ssh2_rdpkt(unsigned char **data, int *datalen) pktin.data[st->i] = *(*data)++; (*datalen)--; } -#ifdef FWHACK - if (!memcmp(pktin.data, "Remo", 4)) { /* "Remo"te server has closed ... */ - /* FIXME */ - } -#endif + if (sccipher) sccipher->decrypt(pktin.data, st->cipherblk); @@ -898,6 +890,12 @@ static int ssh2_rdpkt(unsigned char **data, int *datalen) memcpy(buf + nowlen, pktin.data + 14, msglen); buf[nowlen + msglen] = '\0'; logevent(buf); + bombout(("Server sent disconnect message\ntype %d (%s):\n\"%s\"", + reason, + (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) ? + ssh2_disconnect_reasons[reason] : "unknown", + buf+nowlen)); + crReturn(0); } crFinish(0); @@ -1594,6 +1592,9 @@ static void ssh_gotdata(unsigned char *data, int datalen) while (1) { while (datalen > 0) { if (s_rdpkt(&data, &datalen) == 0) { + if (ssh_state == SSH_STATE_CLOSED) { + return; + } ssh_protocol(NULL, 0, 1); if (ssh_state == SSH_STATE_CLOSED) { return; @@ -1686,6 +1687,11 @@ static char *connect_to_host(char *host, int port, char **realhost) /* * Try to find host. */ + { + char buf[200]; + sprintf(buf, "Looking up host \"%.170s\"", host); + logevent(buf); + } addr = sk_namelookup(host, realhost); if ((err = sk_addr_error(addr))) return err; @@ -1697,6 +1703,12 @@ static char *connect_to_host(char *host, int port, char **realhost) /* * Open socket. */ + { + char buf[200], addrbuf[100]; + sk_getaddr(addr, addrbuf, 100); + sprintf(buf, "Connecting to %.100s port %d", addrbuf, port); + logevent(buf); + } s = sk_new(addr, port, 0, 1, &fn_table_ptr); if ((err = sk_socket_error(s))) return err; @@ -1777,6 +1789,7 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) struct MD5Context md5c; static unsigned long supported_ciphers_mask, supported_auths_mask; static int tried_publickey; + static int tis_auth_refused, ccard_auth_refused; static unsigned char session_id[16]; static int cipher_type; static char username[100]; @@ -2025,6 +2038,7 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) crWaitUntil(ispkt); tried_publickey = 0; + tis_auth_refused = ccard_auth_refused = 0; while (pktin.type == SSH1_SMSG_FAILURE) { static char password[100]; @@ -2032,12 +2046,8 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) static int pos; static char c; static int pwpkt_type; - /* - * Show password prompt, having first obtained it via a TIS - * or CryptoCard exchange if we're doing TIS or CryptoCard - * authentication. - */ pwpkt_type = SSH1_CMSG_AUTH_PASSWORD; + if (agent_exists()) { /* * Attempt RSA authentication using Pageant. @@ -2160,9 +2170,9 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) if (*cfg.keyfile && !tried_publickey) pwpkt_type = SSH1_CMSG_AUTH_RSA; - if (pktin.type == SSH1_SMSG_FAILURE && - cfg.try_tis_auth && - (supported_auths_mask & (1 << SSH1_AUTH_TIS))) { + if (cfg.try_tis_auth && + (supported_auths_mask & (1 << SSH1_AUTH_TIS)) && + !tis_auth_refused) { pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE; logevent("Requested TIS authentication"); send_packet(SSH1_CMSG_AUTH_TIS, PKT_END); @@ -2171,6 +2181,8 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) logevent("TIS authentication declined"); if (flags & FLAG_INTERACTIVE) c_write_str("TIS authentication refused.\r\n"); + tis_auth_refused = 1; + continue; } else { int challengelen = ((pktin.body[0] << 24) | (pktin.body[1] << 16) | @@ -2180,12 +2192,17 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) if (challengelen > sizeof(prompt) - 1) challengelen = sizeof(prompt) - 1; /* prevent overrun */ memcpy(prompt, pktin.body + 4, challengelen); - prompt[challengelen] = '\0'; + /* Prompt heuristic comes from OpenSSH */ + strncpy(prompt + challengelen, + memchr(prompt, '\n', challengelen) ? + "": "\r\nResponse: ", + (sizeof prompt) - challengelen); + prompt[(sizeof prompt) - 1] = '\0'; } } - if (pktin.type == SSH1_SMSG_FAILURE && - cfg.try_tis_auth && - (supported_auths_mask & (1 << SSH1_AUTH_CCARD))) { + if (cfg.try_tis_auth && + (supported_auths_mask & (1 << SSH1_AUTH_CCARD)) && + !ccard_auth_refused) { pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE; logevent("Requested CryptoCard authentication"); send_packet(SSH1_CMSG_AUTH_CCARD, PKT_END); @@ -2193,6 +2210,8 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) if (pktin.type != SSH1_SMSG_AUTH_CCARD_CHALLENGE) { logevent("CryptoCard authentication declined"); c_write_str("CryptoCard authentication refused.\r\n"); + ccard_auth_refused = 1; + continue; } else { int challengelen = ((pktin.body[0] << 24) | (pktin.body[1] << 16) | @@ -2202,7 +2221,9 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) if (challengelen > sizeof(prompt) - 1) challengelen = sizeof(prompt) - 1; /* prevent overrun */ memcpy(prompt, pktin.body + 4, challengelen); - strncpy(prompt + challengelen, "\r\nResponse : ", + strncpy(prompt + challengelen, + memchr(prompt, '\n', challengelen) ? + "" : "\r\nResponse: ", sizeof(prompt) - challengelen); prompt[sizeof(prompt) - 1] = '\0'; } @@ -2224,6 +2245,11 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) sfree(comment); } + /* + * Show password prompt, having first obtained it via a TIS + * or CryptoCard exchange if we're doing TIS or CryptoCard + * authentication. + */ if (ssh_get_line) { if (!ssh_get_line(prompt, password, sizeof(password), TRUE)) { /* @@ -2239,7 +2265,9 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) crReturn(1); } } else { - c_write_str(prompt); + /* Prompt may have come from server. We've munged it a bit, so + * we know it to be zero-terminated at least once. */ + c_write_untrusted(prompt, strlen(prompt)); pos = 0; ssh_send_ok = 1; while (pos >= 0) { @@ -2288,7 +2316,7 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt) tried_publickey = 1; i = loadrsakey(cfg.keyfile, &pubkey, password); if (i == 0) { - c_write_str("Couldn't load public key from "); + c_write_str("Couldn't load private key from "); c_write_str(cfg.keyfile); c_write_str(".\r\n"); continue; /* go and try password */ @@ -2709,7 +2737,7 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) int bufsize = from_backend(pktin.type == SSH1_SMSG_STDERR_DATA, pktin.body + 4, len); - if (bufsize > SSH1_BUFFER_LIMIT) { + if (!ssh1_stdout_throttling && bufsize > SSH1_BUFFER_LIMIT) { ssh1_stdout_throttling = 1; ssh1_throttle(+1); } @@ -2955,7 +2983,7 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) bufsize = 0; /* agent channels never back up */ break; } - if (bufsize > SSH1_BUFFER_LIMIT) { + if (!c->v.v1.throttling && bufsize > SSH1_BUFFER_LIMIT) { c->v.v1.throttling = 1; ssh1_throttle(+1); } @@ -2967,6 +2995,15 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) * if no pty is available or in other odd cases. Ignore */ } else if (pktin.type == SSH1_SMSG_EXIT_STATUS) { send_packet(SSH1_CMSG_EXIT_CONFIRMATION, PKT_END); + /* + * In case `helpful' firewalls or proxies tack + * extra human-readable text on the end of the + * session which we might mistake for another + * encrypted packet, we close the session once + * we've sent EXIT_CONFIRMATION. + */ + ssh_state = SSH_STATE_CLOSED; + crReturnV; } else { bombout(("Strange packet received: type %d", pktin.type)); crReturnV; @@ -3806,66 +3843,12 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt) in_commasep_string("publickey", methods, methlen); can_passwd = in_commasep_string("password", methods, methlen); - can_passwd = - in_commasep_string("password", methods, methlen); can_keyb_inter = in_commasep_string("keyboard-interactive", methods, methlen); } method = 0; - if (!method && can_keyb_inter && !tried_keyb_inter) { - method = AUTH_KEYBOARD_INTERACTIVE; - type = AUTH_TYPE_KEYBOARD_INTERACTIVE; - tried_keyb_inter = TRUE; - - ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); - ssh2_pkt_addstring(username); - ssh2_pkt_addstring("ssh-connection"); /* service requested */ - ssh2_pkt_addstring("keyboard-interactive"); /* method */ - ssh2_pkt_addstring(""); /* lang */ - ssh2_pkt_addstring(""); - ssh2_pkt_send(); - - crWaitUntilV(ispkt); - if (pktin.type != SSH2_MSG_USERAUTH_INFO_REQUEST) { - if (pktin.type == SSH2_MSG_USERAUTH_FAILURE) - gotit = TRUE; - logevent("Keyboard-interactive authentication refused"); - type = AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET; - continue; - } - - kbd_inter_running = TRUE; - } - - if (kbd_inter_running) { - method = AUTH_KEYBOARD_INTERACTIVE; - type = AUTH_TYPE_KEYBOARD_INTERACTIVE; - tried_keyb_inter = TRUE; - - /* We've got packet with that "interactive" info - dump banners, and set its prompt as ours */ - { - char *name, *inst, *lang, *prompt; - int name_len, inst_len, lang_len, prompt_len; - ssh2_pkt_getstring(&name, &name_len); - ssh2_pkt_getstring(&inst, &inst_len); - ssh2_pkt_getstring(&lang, &lang_len); - if (name_len > 0) - c_write_untrusted(name, name_len); - if (inst_len > 0) - c_write_untrusted(inst, inst_len); - num_prompts = ssh2_pkt_getuint32(); - - ssh2_pkt_getstring(&prompt, &prompt_len); - strncpy(pwprompt, prompt, sizeof(pwprompt)); - need_pw = TRUE; - - echo = ssh2_pkt_getbool(); - } - } - if (!method && can_pubkey && agent_exists() && !tried_agent) { /* * Attempt public-key authentication using Pageant. @@ -4059,6 +4042,58 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt) } } + if (!method && can_keyb_inter && !tried_keyb_inter) { + method = AUTH_KEYBOARD_INTERACTIVE; + type = AUTH_TYPE_KEYBOARD_INTERACTIVE; + tried_keyb_inter = TRUE; + + ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); + ssh2_pkt_addstring(username); + ssh2_pkt_addstring("ssh-connection"); /* service requested */ + ssh2_pkt_addstring("keyboard-interactive"); /* method */ + ssh2_pkt_addstring(""); /* lang */ + ssh2_pkt_addstring(""); + ssh2_pkt_send(); + + crWaitUntilV(ispkt); + if (pktin.type != SSH2_MSG_USERAUTH_INFO_REQUEST) { + if (pktin.type == SSH2_MSG_USERAUTH_FAILURE) + gotit = TRUE; + logevent("Keyboard-interactive authentication refused"); + type = AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET; + continue; + } + + kbd_inter_running = TRUE; + } + + if (kbd_inter_running) { + method = AUTH_KEYBOARD_INTERACTIVE; + type = AUTH_TYPE_KEYBOARD_INTERACTIVE; + tried_keyb_inter = TRUE; + + /* We've got packet with that "interactive" info + dump banners, and set its prompt as ours */ + { + char *name, *inst, *lang, *prompt; + int name_len, inst_len, lang_len, prompt_len; + ssh2_pkt_getstring(&name, &name_len); + ssh2_pkt_getstring(&inst, &inst_len); + ssh2_pkt_getstring(&lang, &lang_len); + if (name_len > 0) + c_write_untrusted(name, name_len); + if (inst_len > 0) + c_write_untrusted(inst, inst_len); + num_prompts = ssh2_pkt_getuint32(); + + ssh2_pkt_getstring(&prompt, &prompt_len); + strncpy(pwprompt, prompt, sizeof(pwprompt)); + need_pw = TRUE; + + echo = ssh2_pkt_getbool(); + } + } + if (!method && can_passwd) { method = AUTH_PASSWORD; sprintf(pwprompt, "%.90s@%.90s's password: ", username, @@ -5115,7 +5150,7 @@ void *new_sock_channel(Socket s) void ssh_unthrottle(int bufsize) { if (ssh_version == 1) { - if (bufsize < SSH1_BUFFER_LIMIT) { + if (ssh1_stdout_throttling && bufsize < SSH1_BUFFER_LIMIT) { ssh1_stdout_throttling = 0; ssh1_throttle(-1); }