X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/d9add7bc6646db3641d4e2b189be62ac8f63185e..b453763560ea30f029f9ebc8297605288800c6da:/ssh.c diff --git a/ssh.c b/ssh.c index 808327d0..137e4607 100644 --- a/ssh.c +++ b/ssh.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "putty.h" #include "tree234.h" @@ -1052,7 +1053,7 @@ static void c_write_stderr(int trusted, const char *buf, int len) { int i; for (i = 0; i < len; i++) - if (buf[i] != '\r' && (trusted || buf[i] & 0x60)) + if (buf[i] != '\r' && (trusted || buf[i] == '\n' || (buf[i] & 0x60))) fputc(buf[i], stderr); } @@ -1489,6 +1490,7 @@ static struct Packet *construct_packet(Ssh ssh, int pkttype, va_list ap) while ((argtype = va_arg(ap, int)) != PKT_END) { unsigned char *argp, argchar; + char *sargp; unsigned long argint; int arglen; switch (argtype) { @@ -1507,8 +1509,8 @@ static struct Packet *construct_packet(Ssh ssh, int pkttype, va_list ap) ssh_pkt_adddata(pkt, argp, arglen); break; case PKT_STR: - argp = va_arg(ap, unsigned char *); - ssh_pkt_addstring(pkt, argp); + sargp = va_arg(ap, char *); + ssh_pkt_addstring(pkt, sargp); break; case PKT_BIGNUM: bn = va_arg(ap, Bignum); @@ -1654,7 +1656,7 @@ static void ssh_pkt_addstring(struct Packet *pkt, char *data) static void ssh1_pkt_addmp(struct Packet *pkt, Bignum b) { int len = ssh1_bignum_length(b); - unsigned char *data = snewn(len, char); + unsigned char *data = snewn(len, unsigned char); (void) ssh1_write_bignum(data, b); ssh_pkt_adddata(pkt, data, len); sfree(data); @@ -1904,7 +1906,6 @@ static void ssh2_pkt_send(Ssh ssh, struct Packet *pkt) ssh2_pkt_send_noqueue(ssh, pkt); } -#if 0 /* disused */ /* * Either queue or defer a packet, depending on whether queueing is * set. @@ -1916,7 +1917,6 @@ static void ssh2_pkt_defer(Ssh ssh, struct Packet *pkt) else ssh2_pkt_defer_noqueue(ssh, pkt, FALSE); } -#endif /* * Send the whole deferred data block constructed by @@ -1950,6 +1950,74 @@ static void ssh_pkt_defersend(Ssh ssh) } /* + * Send a packet whose length needs to be disguised (typically + * passwords or keyboard-interactive responses). + */ +static void ssh2_pkt_send_with_padding(Ssh ssh, struct Packet *pkt, + int padsize) +{ +#if 0 + if (0) { + /* + * The simplest way to do this is to adjust the + * variable-length padding field in the outgoing packet. + * + * Currently compiled out, because some Cisco SSH servers + * don't like excessively padded packets (bah, why's it + * always Cisco?) + */ + pkt->forcepad = padsize; + ssh2_pkt_send(ssh, pkt); + } else +#endif + { + /* + * If we can't do that, however, an alternative approach is + * to use the pkt_defer mechanism to bundle the packet + * tightly together with an SSH_MSG_IGNORE such that their + * combined length is a constant. So first we construct the + * final form of this packet and defer its sending. + */ + ssh2_pkt_defer(ssh, pkt); + + /* + * Now construct an SSH_MSG_IGNORE which includes a string + * that's an exact multiple of the cipher block size. (If + * the cipher is NULL so that the block size is + * unavailable, we don't do this trick at all, because we + * gain nothing by it.) + */ + if (ssh->cscipher) { + int stringlen, i; + + stringlen = (256 - ssh->deferred_len); + stringlen += ssh->cscipher->blksize - 1; + stringlen -= (stringlen % ssh->cscipher->blksize); + if (ssh->cscomp) { + /* + * Temporarily disable actual compression, so we + * can guarantee to get this string exactly the + * length we want it. The compression-disabling + * routine should return an integer indicating how + * many bytes we should adjust our string length + * by. + */ + stringlen -= + ssh->cscomp->disable_compression(ssh->cs_comp_ctx); + } + pkt = ssh2_pkt_init(SSH2_MSG_IGNORE); + ssh2_pkt_addstring_start(pkt); + for (i = 0; i < stringlen; i++) { + char c = (char) random_byte(); + ssh2_pkt_addstring_data(pkt, &c, 1); + } + ssh2_pkt_defer(ssh, pkt); + } + ssh_pkt_defersend(ssh); + } +} + +/* * Send all queued SSH-2 packets. We send them by means of * ssh2_pkt_defer_noqueue(), in case they included a pair of * packets that needed to be lumped together. @@ -2166,6 +2234,13 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) ssh->remote_bugs = 0; + /* + * General notes on server version strings: + * - Not all servers reporting "Cisco-1.25" have all the bugs listed + * here -- in particular, we've heard of one that's perfectly happy + * with SSH1_MSG_IGNOREs -- but this string never seems to change, + * so we can't distinguish them. + */ if (ssh->cfg.sshbug_ignore1 == FORCE_ON || (ssh->cfg.sshbug_ignore1 == AUTO && (!strcmp(imp, "1.2.18") || !strcmp(imp, "1.2.19") || @@ -2627,6 +2702,9 @@ static int ssh_closing(Plug plug, const char *error_msg, int error_code, error_msg = "Server closed network connection"; } + if (ssh->close_expected && ssh->clean_exit && ssh->exitcode < 0) + ssh->exitcode = 0; + if (need_notify) notify_remote_exit(ssh->frontend); @@ -3486,6 +3564,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, /* and try again */ } else { assert(0 && "unexpected return from loadrsakey()"); + got_passphrase = FALSE; /* placate optimisers */ } } @@ -3703,19 +3782,19 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, * magnitude of the password length, but it will * introduce a bit of extra uncertainty. * - * A few servers (the old 1.2.18 through 1.2.22) - * can't deal with SSH1_MSG_IGNORE. For these - * servers, we need an alternative defence. We make - * use of the fact that the password is interpreted - * as a C string: so we can append a NUL, then some - * random data. + * A few servers can't deal with SSH1_MSG_IGNORE, at + * least in this context. For these servers, we need + * an alternative defence. We make use of the fact + * that the password is interpreted as a C string: + * so we can append a NUL, then some random data. * - * One server (a Cisco one) can deal with neither - * SSH1_MSG_IGNORE _nor_ a padded password string. - * For this server we are left with no defences + * A few servers can deal with neither SSH1_MSG_IGNORE + * here _nor_ a padded password string. + * For these servers we are left with no defences * against password length sniffing. */ - if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE)) { + if (!(ssh->remote_bugs & BUG_CHOKES_ON_SSH1_IGNORE) && + !(ssh->remote_bugs & BUG_NEEDS_SSH1_PLAIN_PASSWORD)) { /* * The server can deal with SSH1_MSG_IGNORE, so * we can use the primary defence. @@ -3784,10 +3863,8 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, PKTT_OTHER, PKT_END); } else { /* - * The server has _both_ - * BUG_CHOKES_ON_SSH1_IGNORE and - * BUG_NEEDS_SSH1_PLAIN_PASSWORD. There is - * therefore nothing we can do. + * The server is believed unable to cope with + * any of our password camouflage methods. */ int len; len = strlen(s->cur_prompt->prompts[0]->result); @@ -4569,7 +4646,7 @@ static void ssh1_msg_channel_data(Ssh ssh, struct Packet *pktin) /* Data for an agent message. Buffer it. */ while (len > 0) { if (c->u.a.lensofar < 4) { - unsigned int l = min(4 - c->u.a.lensofar, len); + unsigned int l = min(4 - c->u.a.lensofar, (unsigned)len); memcpy(c->u.a.msglen + c->u.a.lensofar, p, l); p += l; @@ -4586,7 +4663,7 @@ static void ssh1_msg_channel_data(Ssh ssh, struct Packet *pktin) if (c->u.a.lensofar >= 4 && len > 0) { unsigned int l = min(c->u.a.totallen - c->u.a.lensofar, - len); + (unsigned)len); memcpy(c->u.a.message + c->u.a.lensofar, p, l); p += l; @@ -6006,7 +6083,8 @@ static void ssh2_msg_channel_data(Ssh ssh, struct Packet *pktin) case CHAN_AGENT: while (length > 0) { if (c->u.a.lensofar < 4) { - unsigned int l = min(4 - c->u.a.lensofar, length); + unsigned int l = min(4 - c->u.a.lensofar, + (unsigned)length); memcpy(c->u.a.msglen + c->u.a.lensofar, data, l); data += l; @@ -6023,7 +6101,7 @@ static void ssh2_msg_channel_data(Ssh ssh, struct Packet *pktin) if (c->u.a.lensofar >= 4 && length > 0) { unsigned int l = min(c->u.a.totallen - c->u.a.lensofar, - length); + (unsigned)length); memcpy(c->u.a.message + c->u.a.lensofar, data, l); data += l; @@ -6292,11 +6370,13 @@ static void ssh2_msg_channel_request(Ssh ssh, struct Packet *pktin) is_plausible = FALSE; } } + ssh->exitcode = 128; /* means `unknown signal' */ if (is_plausible) { if (is_int) { /* Old non-standard OpenSSH. */ int signum = ssh_pkt_getuint32(pktin); fmt_sig = dupprintf(" %d", signum); + ssh->exitcode = 128 + signum; } else { /* As per the drafts. */ char *sig; @@ -6308,6 +6388,82 @@ static void ssh2_msg_channel_request(Ssh ssh, struct Packet *pktin) fmt_sig = dupprintf(" \"%.*s\"", siglen, sig); } + + /* + * Really hideous method of translating the + * signal description back into a locally + * meaningful number. + */ + + if (0) + ; +#ifdef SIGABRT + else if (siglen == lenof("ABRT")-1 && + !memcmp(sig, "ABRT", siglen)) + ssh->exitcode = 128 + SIGABRT; +#endif +#ifdef SIGALRM + else if (siglen == lenof("ALRM")-1 && + !memcmp(sig, "ALRM", siglen)) + ssh->exitcode = 128 + SIGALRM; +#endif +#ifdef SIGFPE + else if (siglen == lenof("FPE")-1 && + !memcmp(sig, "FPE", siglen)) + ssh->exitcode = 128 + SIGFPE; +#endif +#ifdef SIGHUP + else if (siglen == lenof("HUP")-1 && + !memcmp(sig, "HUP", siglen)) + ssh->exitcode = 128 + SIGHUP; +#endif +#ifdef SIGILL + else if (siglen == lenof("ILL")-1 && + !memcmp(sig, "ILL", siglen)) + ssh->exitcode = 128 + SIGILL; +#endif +#ifdef SIGINT + else if (siglen == lenof("INT")-1 && + !memcmp(sig, "INT", siglen)) + ssh->exitcode = 128 + SIGINT; +#endif +#ifdef SIGKILL + else if (siglen == lenof("KILL")-1 && + !memcmp(sig, "KILL", siglen)) + ssh->exitcode = 128 + SIGKILL; +#endif +#ifdef SIGPIPE + else if (siglen == lenof("PIPE")-1 && + !memcmp(sig, "PIPE", siglen)) + ssh->exitcode = 128 + SIGPIPE; +#endif +#ifdef SIGQUIT + else if (siglen == lenof("QUIT")-1 && + !memcmp(sig, "QUIT", siglen)) + ssh->exitcode = 128 + SIGQUIT; +#endif +#ifdef SIGSEGV + else if (siglen == lenof("SEGV")-1 && + !memcmp(sig, "SEGV", siglen)) + ssh->exitcode = 128 + SIGSEGV; +#endif +#ifdef SIGTERM + else if (siglen == lenof("TERM")-1 && + !memcmp(sig, "TERM", siglen)) + ssh->exitcode = 128 + SIGTERM; +#endif +#ifdef SIGUSR1 + else if (siglen == lenof("USR1")-1 && + !memcmp(sig, "USR1", siglen)) + ssh->exitcode = 128 + SIGUSR1; +#endif +#ifdef SIGUSR2 + else if (siglen == lenof("USR2")-1 && + !memcmp(sig, "USR2", siglen)) + ssh->exitcode = 128 + SIGUSR2; +#endif + else + ssh->exitcode = 128; } core = ssh2_pkt_getbool(pktin); ssh_pkt_getstring(pktin, &msg, &msglen); @@ -7368,7 +7524,6 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, * Send the responses to the server. */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE); - s->pktout->forcepad = 256; ssh2_pkt_adduint32(s->pktout, s->num_prompts); for (i=0; i < s->num_prompts; i++) { dont_log_password(ssh, s->pktout, PKTLOG_BLANK); @@ -7376,7 +7531,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, s->cur_prompt->prompts[i]->result); end_log_omission(ssh, s->pktout); } - ssh2_pkt_send(ssh, s->pktout); + ssh2_pkt_send_with_padding(ssh, s->pktout, 256); /* * Get the next packet in case it's another @@ -7446,7 +7601,6 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, * people who find out how long their password is! */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); - s->pktout->forcepad = 256; ssh2_pkt_addstring(s->pktout, s->username); ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */ @@ -7455,7 +7609,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, dont_log_password(ssh, s->pktout, PKTLOG_BLANK); ssh2_pkt_addstring(s->pktout, s->password); end_log_omission(ssh, s->pktout); - ssh2_pkt_send(ssh, s->pktout); + ssh2_pkt_send_with_padding(ssh, s->pktout, 256); logevent("Sent password"); s->type = AUTH_TYPE_PASSWORD; @@ -7576,7 +7730,6 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, * (see above for padding rationale) */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); - s->pktout->forcepad = 256; ssh2_pkt_addstring(s->pktout, s->username); ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */ @@ -7588,7 +7741,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, s->cur_prompt->prompts[1]->result); free_prompts(s->cur_prompt); end_log_omission(ssh, s->pktout); - ssh2_pkt_send(ssh, s->pktout); + ssh2_pkt_send_with_padding(ssh, s->pktout, 256); logevent("Sent new password"); /*