X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/514702987c9252fcb0ab98882a6603b3bd0505ce..b3ebaa287b8a57f3d35675889adc86f6384eb458:/ssh.c diff --git a/ssh.c b/ssh.c index 115e902f..a2e74c0e 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -15,26 +14,6 @@ #define TRUE 1 #endif -#define logevent(s) { logevent(s); \ - if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) \ - { fprintf(stderr, "%s\n", s); fflush(stderr); } } - -/* logevent, only printf-formatted. */ -void logeventf(char *fmt, ...) -{ - va_list ap; - char stuff[200]; - - va_start(ap, fmt); - vsprintf(stuff, fmt, ap); - va_end(ap); - logevent(stuff); -} - -#define bombout(msg) ( ssh->state = SSH_STATE_CLOSED, \ - (ssh->s ? sk_close(ssh->s), ssh->s = NULL : 0), \ - logeventf msg, connection_fatal msg ) - #define SSH1_MSG_DISCONNECT 1 /* 0x1 */ #define SSH1_SMSG_PUBLIC_KEY 2 /* 0x2 */ #define SSH1_CMSG_SESSION_KEY 3 /* 0x3 */ @@ -187,7 +166,7 @@ static const char *const ssh2_disconnect_reasons[] = { #define translate(x) if (type == x) return #x #define translatec(x,ctx) if (type == x && (pkt_ctx & ctx)) return #x -char *ssh1_pkt_type(int type) +static char *ssh1_pkt_type(int type) { translate(SSH1_MSG_DISCONNECT); translate(SSH1_SMSG_PUBLIC_KEY); @@ -232,7 +211,7 @@ char *ssh1_pkt_type(int type) translate(SSH1_CMSG_AUTH_CCARD_RESPONSE); return "unknown"; } -char *ssh2_pkt_type(int pkt_ctx, int type) +static char *ssh2_pkt_type(int pkt_ctx, int type) { translate(SSH2_MSG_DISCONNECT); translate(SSH2_MSG_IGNORE); @@ -312,21 +291,6 @@ enum { PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM }; typedef struct ssh_tag *Ssh; -extern char *x11_init(Socket *, char *, void *); -extern void x11_close(Socket); -extern int x11_send(Socket, char *, int); -extern void x11_invent_auth(char *, int, char *, int); -extern void x11_unthrottle(Socket s); -extern void x11_override_throttle(Socket s, int enable); - -extern char *pfd_newconnect(Socket * s, char *hostname, int port, void *c); -extern char *pfd_addforward(char *desthost, int destport, int port); -extern void pfd_close(Socket s); -extern int pfd_send(Socket s, char *data, int len); -extern void pfd_confirm(Socket s); -extern void pfd_unthrottle(Socket s); -extern void pfd_override_throttle(Socket s, int enable); - static void ssh2_pkt_init(Ssh, int pkt_type); static void ssh2_pkt_addbool(Ssh, unsigned char value); static void ssh2_pkt_adduint32(Ssh, unsigned long value); @@ -334,7 +298,7 @@ static void ssh2_pkt_addstring_start(Ssh); static void ssh2_pkt_addstring_str(Ssh, char *data); static void ssh2_pkt_addstring_data(Ssh, char *data, int len); static void ssh2_pkt_addstring(Ssh, char *data); -static char *ssh2_mpint_fmt(Bignum b, int *len); +static unsigned char *ssh2_mpint_fmt(Bignum b, int *len); static void ssh2_pkt_addmp(Ssh, Bignum b); static int ssh2_pkt_construct(Ssh); static void ssh2_pkt_send(Ssh); @@ -371,19 +335,28 @@ const static struct ssh_kex *kex_algs[] = { const static struct ssh_signkey *hostkey_algs[] = { &ssh_rsa, &ssh_dss }; -static void nullmac_key(unsigned char *key) +static void *nullmac_make_context(void) +{ + return NULL; +} +static void nullmac_free_context(void *handle) { } -static void nullmac_generate(unsigned char *blk, int len, +static void nullmac_key(void *handle, unsigned char *key) +{ +} +static void nullmac_generate(void *handle, unsigned char *blk, int len, unsigned long seq) { } -static int nullmac_verify(unsigned char *blk, int len, unsigned long seq) +static int nullmac_verify(void *handle, unsigned char *blk, int len, + unsigned long seq) { return 1; } const static struct ssh_mac ssh_mac_none = { - nullmac_key, nullmac_key, nullmac_generate, nullmac_verify, "none", 0 + nullmac_make_context, nullmac_free_context, nullmac_key, + nullmac_generate, nullmac_verify, "none", 0 }; const static struct ssh_mac *macs[] = { &ssh_sha1, &ssh_md5, &ssh_mac_none @@ -392,23 +365,27 @@ const static struct ssh_mac *buggymacs[] = { &ssh_sha1_buggy, &ssh_md5, &ssh_mac_none }; -static void ssh_comp_none_init(void) +static void *ssh_comp_none_init(void) { + return NULL; } -static int ssh_comp_none_block(unsigned char *block, int len, +static void ssh_comp_none_cleanup(void *handle) +{ +} +static int ssh_comp_none_block(void *handle, unsigned char *block, int len, unsigned char **outblock, int *outlen) { return 0; } -static int ssh_comp_none_disable(void) +static int ssh_comp_none_disable(void *handle) { return 0; } const static struct ssh_compress ssh_comp_none = { "none", - ssh_comp_none_init, ssh_comp_none_block, - ssh_comp_none_init, ssh_comp_none_block, - ssh_comp_none_disable + ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block, + ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block, + ssh_comp_none_disable, NULL }; extern const struct ssh_compress ssh_zlib; const static struct ssh_compress *compressions[] = { @@ -542,6 +519,9 @@ struct ssh_tag { Socket s; + void *ldisc; + void *logctx; + unsigned char session_key[32]; int v1_compressing; int v1_remote_protoflags; @@ -550,12 +530,18 @@ struct ssh_tag { int X11_fwd_enabled; int remote_bugs; const struct ssh_cipher *cipher; + void *v1_cipher_ctx; + void *crcda_ctx; const struct ssh2_cipher *cscipher, *sccipher; + void *cs_cipher_ctx, *sc_cipher_ctx; const struct ssh_mac *csmac, *scmac; + void *cs_mac_ctx, *sc_mac_ctx; const struct ssh_compress *cscomp, *sccomp; + void *cs_comp_ctx, *sc_comp_ctx; const struct ssh_kex *kex; const struct ssh_signkey *hostkey; unsigned char v2_session_id[20]; + void *kex_ctx; char *savedhost; int savedport; @@ -606,6 +592,8 @@ struct ssh_tag { char *portfwd_strptr; int pkt_ctx; + void *x11auth; + int version; int v1_throttle_count; int overall_bufsize; @@ -634,6 +622,25 @@ struct ssh_tag { int (*s_rdpkt) (Ssh ssh, unsigned char **data, int *datalen); }; +#define logevent(s) logevent(ssh->frontend, s) + +/* logevent, only printf-formatted. */ +static void logeventf(Ssh ssh, char *fmt, ...) +{ + va_list ap; + char *buf; + + va_start(ap, fmt); + buf = dupvprintf(fmt, ap); + va_end(ap); + logevent(buf); + sfree(buf); +} + +#define bombout(msg) ( ssh->state = SSH_STATE_CLOSED, \ + (ssh->s ? sk_close(ssh->s), ssh->s = NULL : 0), \ + logeventf msg, connection_fatal msg ) + static int ssh_channelcmp(void *av, void *bv) { struct ssh_channel *a = (struct ssh_channel *) av; @@ -797,18 +804,19 @@ static int ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen) st->to_read -= st->chunk; } - if (ssh->cipher && detect_attack(ssh->pktin.data, st->biglen, NULL)) { - bombout(("Network attack (CRC compensation) detected!")); + if (ssh->cipher && detect_attack(ssh->crcda_ctx, ssh->pktin.data, + st->biglen, NULL)) { + bombout((ssh,"Network attack (CRC compensation) detected!")); crReturn(0); } if (ssh->cipher) - ssh->cipher->decrypt(ssh->pktin.data, st->biglen); + ssh->cipher->decrypt(ssh->v1_cipher_ctx, ssh->pktin.data, st->biglen); st->realcrc = crc32(ssh->pktin.data, st->biglen - 4); st->gotcrc = GET_32BIT(ssh->pktin.data + st->biglen - 4); if (st->gotcrc != st->realcrc) { - bombout(("Incorrect CRC received on packet")); + bombout((ssh,"Incorrect CRC received on packet")); crReturn(0); } @@ -817,7 +825,8 @@ static int ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen) if (ssh->v1_compressing) { unsigned char *decompblk; int decomplen; - zlib_decompress_block(ssh->pktin.body - 1, ssh->pktin.length + 1, + zlib_decompress_block(ssh->sc_comp_ctx, + ssh->pktin.body - 1, ssh->pktin.length + 1, &decompblk, &decomplen); if (ssh->pktin.maxlen < st->pad + decomplen) { @@ -834,8 +843,11 @@ static int ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen) ssh->pktin.type = ssh->pktin.body[-1]; - log_packet(PKT_INCOMING, ssh->pktin.type, ssh1_pkt_type(ssh->pktin.type), - ssh->pktin.body, ssh->pktin.length); + if (ssh->logctx) + log_packet(ssh->logctx, + PKT_INCOMING, ssh->pktin.type, + ssh1_pkt_type(ssh->pktin.type), + ssh->pktin.body, ssh->pktin.length); if (ssh->pktin.type == SSH1_SMSG_STDOUT_DATA || ssh->pktin.type == SSH1_SMSG_STDERR_DATA || @@ -844,7 +856,7 @@ static int ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen) ssh->pktin.type == SSH1_SMSG_AUTH_CCARD_CHALLENGE) { long stringlen = GET_32BIT(ssh->pktin.body); if (stringlen + 4 != ssh->pktin.length) { - bombout(("Received data packet with bogus string length")); + bombout((ssh,"Received data packet with bogus string length")); crReturn(0); } } @@ -877,7 +889,7 @@ static int ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen) memcpy(buf + nowlen, ssh->pktin.body + 4, msglen); buf[nowlen + msglen] = '\0'; /* logevent(buf); (this is now done within the bombout macro) */ - bombout(("Server sent disconnect message:\n\"%s\"", buf+nowlen)); + bombout((ssh,"Server sent disconnect message:\n\"%s\"", buf+nowlen)); crReturn(0); } @@ -917,7 +929,8 @@ static int ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen) } if (ssh->sccipher) - ssh->sccipher->decrypt(ssh->pktin.data, st->cipherblk); + ssh->sccipher->decrypt(ssh->sc_cipher_ctx, + ssh->pktin.data, st->cipherblk); /* * Now get the length and padding figures. @@ -930,7 +943,7 @@ static int ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen) * do us any more damage. */ if (st->len < 0 || st->pad < 0 || st->len + st->pad < 0) { - bombout(("Incoming packet was garbled on decryption")); + bombout((ssh,"Incoming packet was garbled on decryption")); crReturn(0); } @@ -968,16 +981,17 @@ static int ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen) } /* Decrypt everything _except_ the MAC. */ if (ssh->sccipher) - ssh->sccipher->decrypt(ssh->pktin.data + st->cipherblk, + ssh->sccipher->decrypt(ssh->sc_cipher_ctx, + ssh->pktin.data + st->cipherblk, st->packetlen - st->cipherblk); /* * Check the MAC. */ if (ssh->scmac - && !ssh->scmac->verify(ssh->pktin.data, st->len + 4, + && !ssh->scmac->verify(ssh->sc_mac_ctx, ssh->pktin.data, st->len + 4, st->incoming_sequence)) { - bombout(("Incorrect MAC received on packet")); + bombout((ssh,"Incorrect MAC received on packet")); crReturn(0); } st->incoming_sequence++; /* whether or not we MACed */ @@ -989,7 +1003,8 @@ static int ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen) unsigned char *newpayload; int newlen; if (ssh->sccomp && - ssh->sccomp->decompress(ssh->pktin.data + 5, ssh->pktin.length - 5, + ssh->sccomp->decompress(ssh->sc_comp_ctx, + ssh->pktin.data + 5, ssh->pktin.length - 5, &newpayload, &newlen)) { if (ssh->pktin.maxlen < newlen + 5) { ssh->pktin.maxlen = newlen + 5; @@ -1005,9 +1020,10 @@ static int ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen) ssh->pktin.savedpos = 6; ssh->pktin.type = ssh->pktin.data[5]; - log_packet(PKT_INCOMING, ssh->pktin.type, - ssh2_pkt_type(ssh->pkt_ctx, ssh->pktin.type), - ssh->pktin.data+6, ssh->pktin.length-6); + if (ssh->logctx) + log_packet(ssh->logctx, PKT_INCOMING, ssh->pktin.type, + ssh2_pkt_type(ssh->pkt_ctx, ssh->pktin.type), + ssh->pktin.data+6, ssh->pktin.length-6); switch (ssh->pktin.type) { /* @@ -1016,30 +1032,29 @@ static int ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen) case SSH2_MSG_DISCONNECT: { /* log reason code in disconnect message */ - char buf[256]; + char *buf; + int nowlen; int reason = GET_32BIT(ssh->pktin.data + 6); unsigned msglen = GET_32BIT(ssh->pktin.data + 10); - unsigned nowlen; + if (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) { - sprintf(buf, "Received disconnect message (%s)", - ssh2_disconnect_reasons[reason]); + buf = dupprintf("Received disconnect message (%s)", + ssh2_disconnect_reasons[reason]); } else { - sprintf(buf, "Received disconnect message (unknown type %d)", - reason); + buf = dupprintf("Received disconnect message (unknown" + " type %d)", reason); } logevent(buf); - strcpy(buf, "Disconnection message text: "); - nowlen = strlen(buf); - if (msglen > sizeof(buf) - nowlen - 1) - msglen = sizeof(buf) - nowlen - 1; - memcpy(buf + nowlen, ssh->pktin.data + 14, msglen); - buf[nowlen + msglen] = '\0'; + sfree(buf); + buf = dupprintf("Disconnection message text: %n%.*s", + &nowlen, msglen, ssh->pktin.data + 14); logevent(buf); - bombout(("Server sent disconnect message\ntype %d (%s):\n\"%s\"", + bombout((ssh,"Server sent disconnect message\ntype %d (%s):\n\"%s\"", reason, (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) ? ssh2_disconnect_reasons[reason] : "unknown", buf+nowlen)); + sfree(buf); crReturn(0); } break; @@ -1148,13 +1163,16 @@ static int s_wrpkt_prepare(Ssh ssh) ssh->pktout.body[-1] = ssh->pktout.type; - log_packet(PKT_OUTGOING, ssh->pktout.type, ssh1_pkt_type(ssh->pktout.type), - ssh->pktout.body, ssh->pktout.length); + if (ssh->logctx) + log_packet(ssh->logctx, PKT_OUTGOING, ssh->pktout.type, + ssh1_pkt_type(ssh->pktout.type), + ssh->pktout.body, ssh->pktout.length); if (ssh->v1_compressing) { unsigned char *compblk; int complen; - zlib_compress_block(ssh->pktout.body - 1, ssh->pktout.length + 1, + zlib_compress_block(ssh->cs_comp_ctx, + ssh->pktout.body - 1, ssh->pktout.length + 1, &compblk, &complen); ssh1_pktout_size(ssh, complen - 1); memcpy(ssh->pktout.body - 1, compblk, complen); @@ -1172,7 +1190,7 @@ static int s_wrpkt_prepare(Ssh ssh) PUT_32BIT(ssh->pktout.data, len); if (ssh->cipher) - ssh->cipher->encrypt(ssh->pktout.data + 4, biglen); + ssh->cipher->encrypt(ssh->v1_cipher_ctx, ssh->pktout.data + 4, biglen); return biglen + 4; } @@ -1181,7 +1199,7 @@ static void s_wrpkt(Ssh ssh) { int len, backlog; len = s_wrpkt_prepare(ssh); - backlog = sk_write(ssh->s, ssh->pktout.data, len); + backlog = sk_write(ssh->s, (char *)ssh->pktout.data, len); if (backlog > SSH_MAX_BACKLOG) ssh_throttle_all(ssh, 1, backlog); } @@ -1217,7 +1235,7 @@ static void construct_packet(Ssh ssh, int pkttype, va_list ap1, va_list ap2) pktlen += 4; break; case PKT_CHAR: - (void) va_arg(ap1, char); + (void) va_arg(ap1, int); pktlen++; break; case PKT_DATA: @@ -1227,7 +1245,7 @@ static void construct_packet(Ssh ssh, int pkttype, va_list ap1, va_list ap2) break; case PKT_STR: argp = va_arg(ap1, unsigned char *); - arglen = strlen(argp); + arglen = strlen((char *)argp); pktlen += 4 + arglen; break; case PKT_BIGNUM: @@ -1250,7 +1268,7 @@ static void construct_packet(Ssh ssh, int pkttype, va_list ap1, va_list ap2) p += 4; break; case PKT_CHAR: - argchar = va_arg(ap2, unsigned char); + argchar = (unsigned char) va_arg(ap2, int); *p = argchar; p++; break; @@ -1262,7 +1280,7 @@ static void construct_packet(Ssh ssh, int pkttype, va_list ap1, va_list ap2) break; case PKT_STR: argp = va_arg(ap2, unsigned char *); - arglen = strlen(argp); + arglen = strlen((char *)argp); PUT_32BIT(p, arglen); memcpy(p + 4, argp, arglen); p += 4 + arglen; @@ -1393,7 +1411,7 @@ static void ssh2_pkt_addstring(Ssh ssh, char *data) ssh2_pkt_addstring_start(ssh); ssh2_pkt_addstring_str(ssh, data); } -static char *ssh2_mpint_fmt(Bignum b, int *len) +static unsigned char *ssh2_mpint_fmt(Bignum b, int *len) { unsigned char *p; int i, n = (bignum_bitcount(b) + 7) / 8; @@ -1416,7 +1434,7 @@ static void ssh2_pkt_addmp(Ssh ssh, Bignum b) int len; p = ssh2_mpint_fmt(b, &len); ssh2_pkt_addstring_start(ssh); - ssh2_pkt_addstring_data(ssh, p, len); + ssh2_pkt_addstring_data(ssh, (char *)p, len); sfree(p); } @@ -1429,9 +1447,10 @@ static int ssh2_pkt_construct(Ssh ssh) { int cipherblk, maclen, padding, i; - log_packet(PKT_OUTGOING, ssh->pktout.data[5], - ssh2_pkt_type(ssh->pkt_ctx, ssh->pktout.data[5]), - ssh->pktout.data + 6, ssh->pktout.length - 6); + if (ssh->logctx) + log_packet(ssh->logctx, PKT_OUTGOING, ssh->pktout.data[5], + ssh2_pkt_type(ssh->pkt_ctx, ssh->pktout.data[5]), + ssh->pktout.data + 6, ssh->pktout.length - 6); /* * Compress packet payload. @@ -1440,7 +1459,8 @@ static int ssh2_pkt_construct(Ssh ssh) unsigned char *newpayload; int newlen; if (ssh->cscomp && - ssh->cscomp->compress(ssh->pktout.data + 5, ssh->pktout.length - 5, + ssh->cscomp->compress(ssh->cs_comp_ctx, ssh->pktout.data + 5, + ssh->pktout.length - 5, &newpayload, &newlen)) { ssh->pktout.length = 5; ssh2_pkt_adddata(ssh, newpayload, newlen); @@ -1464,12 +1484,14 @@ static int ssh2_pkt_construct(Ssh ssh) ssh->pktout.data[ssh->pktout.length + i] = random_byte(); PUT_32BIT(ssh->pktout.data, ssh->pktout.length + padding - 4); if (ssh->csmac) - ssh->csmac->generate(ssh->pktout.data, ssh->pktout.length + padding, + ssh->csmac->generate(ssh->cs_mac_ctx, ssh->pktout.data, + ssh->pktout.length + padding, ssh->v2_outgoing_sequence); ssh->v2_outgoing_sequence++; /* whether or not we MACed */ if (ssh->cscipher) - ssh->cscipher->encrypt(ssh->pktout.data, ssh->pktout.length + padding); + ssh->cscipher->encrypt(ssh->cs_cipher_ctx, + ssh->pktout.data, ssh->pktout.length + padding); /* Ready-to-send packet starts at ssh->pktout.data. We return length. */ return ssh->pktout.length + padding + maclen; @@ -1483,7 +1505,7 @@ static void ssh2_pkt_send(Ssh ssh) int len; int backlog; len = ssh2_pkt_construct(ssh); - backlog = sk_write(ssh->s, ssh->pktout.data, len); + backlog = sk_write(ssh->s, (char *)ssh->pktout.data, len); if (backlog > SSH_MAX_BACKLOG) ssh_throttle_all(ssh, 1, backlog); } @@ -1518,7 +1540,8 @@ static void ssh2_pkt_defer(Ssh ssh) static void ssh_pkt_defersend(Ssh ssh) { int backlog; - backlog = sk_write(ssh->s, ssh->deferred_send_data, ssh->deferred_len); + backlog = sk_write(ssh->s, (char *)ssh->deferred_send_data, + ssh->deferred_len); ssh->deferred_len = ssh->deferred_size = 0; sfree(ssh->deferred_send_data); ssh->deferred_send_data = NULL; @@ -1572,15 +1595,19 @@ static int ssh2_pkt_getbool(Ssh ssh) } static void ssh2_pkt_getstring(Ssh ssh, char **p, int *length) { + int len; *p = NULL; *length = 0; if (ssh->pktin.length - ssh->pktin.savedpos < 4) return; - *length = GET_32BIT(ssh->pktin.data + ssh->pktin.savedpos); + len = GET_32BIT(ssh->pktin.data + ssh->pktin.savedpos); + if (len < 0) + return; + *length = len; ssh->pktin.savedpos += 4; if (ssh->pktin.length - ssh->pktin.savedpos < *length) return; - *p = ssh->pktin.data + ssh->pktin.savedpos; + *p = (char *)(ssh->pktin.data + ssh->pktin.savedpos); ssh->pktin.savedpos += *length; } static Bignum ssh2_pkt_getmp(Ssh ssh) @@ -1593,10 +1620,10 @@ static Bignum ssh2_pkt_getmp(Ssh ssh) if (!p) return NULL; if (p[0] & 0x80) { - bombout(("internal error: Can't handle negative mpints")); + bombout((ssh,"internal error: Can't handle negative mpints")); return NULL; } - b = bignum_from_bytes(p, length); + b = bignum_from_bytes((unsigned char *)p, length); return b; } @@ -1646,18 +1673,18 @@ static void ssh2_add_sigblob(Ssh ssh, void *pkblob_v, int pkblob_len, if (len != siglen) { unsigned char newlen[4]; ssh2_pkt_addstring_start(ssh); - ssh2_pkt_addstring_data(ssh, sigblob, pos); + ssh2_pkt_addstring_data(ssh, (char *)sigblob, pos); /* dmemdump(sigblob, pos); */ pos += 4; /* point to start of actual sig */ PUT_32BIT(newlen, len); - ssh2_pkt_addstring_data(ssh, newlen, 4); + ssh2_pkt_addstring_data(ssh, (char *)newlen, 4); /* dmemdump(newlen, 4); */ newlen[0] = 0; while (len-- > siglen) { - ssh2_pkt_addstring_data(ssh, newlen, 1); + ssh2_pkt_addstring_data(ssh, (char *)newlen, 1); /* dmemdump(newlen, 1); */ } - ssh2_pkt_addstring_data(ssh, sigblob+pos, siglen); + ssh2_pkt_addstring_data(ssh, (char *)(sigblob+pos), siglen); /* dmemdump(sigblob+pos, siglen); */ return; } @@ -1666,7 +1693,7 @@ static void ssh2_add_sigblob(Ssh ssh, void *pkblob_v, int pkblob_len, } ssh2_pkt_addstring_start(ssh); - ssh2_pkt_addstring_data(ssh, sigblob, sigblob_len); + ssh2_pkt_addstring_data(ssh, (char *)sigblob, sigblob_len); } /* @@ -1724,9 +1751,9 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) if (cfg.sshbug_hmac2 == BUG_ON || (cfg.sshbug_hmac2 == BUG_AUTO && - (!strncmp(imp, "2.1.0", 5) || !strncmp(imp, "2.0.", 4) || - !strncmp(imp, "2.2.0", 5) || !strncmp(imp, "2.3.0", 5) || - !strncmp(imp, "2.1 ", 4)))) { + (wc_match("2.1.0*", imp) || wc_match("2.0.*", imp) || + wc_match("2.2.0*", imp) || wc_match("2.3.0*", imp) || + wc_match("2.1 *", imp)))) { /* * These versions have the HMAC bug. */ @@ -1736,7 +1763,7 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) if (cfg.sshbug_derivekey2 == BUG_ON || (cfg.sshbug_derivekey2 == BUG_AUTO && - (!strncmp(imp, "2.0.", 4)))) { + (wc_match("2.0.0*", imp) || wc_match("2.0.1[01]*", imp) ))) { /* * These versions have the key-derivation bug (failing to * include the literal shared secret in the hashes that @@ -1748,8 +1775,8 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) if (cfg.sshbug_rsapad2 == BUG_ON || (cfg.sshbug_rsapad2 == BUG_AUTO && - ((!strncmp(imp, "OpenSSH_2.", 10) && imp[10]>='5' && imp[10]<='9') || - (!strncmp(imp, "OpenSSH_3.", 10) && imp[10]>='0' && imp[10]<='2')))){ + (wc_match("OpenSSH_2.[5-9]*", imp) || + wc_match("OpenSSH_3.[0-2]*", imp)))) { /* * These versions have the SSH2 RSA padding bug. */ @@ -1759,7 +1786,7 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) if (cfg.sshbug_dhgex2 == BUG_ON) { /* - * These versions have the SSH2 DH GEX bug. + * User specified the SSH2 DH GEX bug. */ ssh->remote_bugs |= BUG_SSH2_DH_GEX; logevent("We believe remote version has SSH2 DH group exchange bug"); @@ -1817,7 +1844,7 @@ static int do_ssh_init(Ssh ssh, unsigned char c) s->i = -1; } else if (s->i < sizeof(s->version) - 1) s->version[s->i++] = c; - } else if (c == '\n') + } else if (c == '\012') break; } @@ -1845,11 +1872,11 @@ static int do_ssh_init(Ssh ssh, unsigned char c) s->proto2 = ssh_versioncmp(s->version, "1.99") >= 0; if (cfg.sshprot == 0 && !s->proto1) { - bombout(("SSH protocol version 1 required by user but not provided by server")); + bombout((ssh,"SSH protocol version 1 required by user but not provided by server")); crReturn(0); } if (cfg.sshprot == 3 && !s->proto2) { - bombout(("SSH protocol version 2 required by user but not provided by server")); + bombout((ssh,"SSH protocol version 2 required by user but not provided by server")); crReturn(0); } @@ -1867,7 +1894,7 @@ static int do_ssh_init(Ssh ssh, unsigned char c) sha_string(&ssh->exhashbase, s->vstring, strcspn(s->vstring, "\r\n")); sprintf(vlog, "We claim version: %s", verstring); logevent(vlog); - strcat(verstring, "\n"); + strcat(verstring, "\012"); logevent("Using SSH protocol version 2"); sk_write(ssh->s, verstring, strlen(verstring)); ssh->protocol = ssh2_protocol; @@ -1883,7 +1910,7 @@ static int do_ssh_init(Ssh ssh, unsigned char c) sshver); sprintf(vlog, "We claim version: %s", verstring); logevent(vlog); - strcat(verstring, "\n"); + strcat(verstring, "\012"); logevent("Using SSH protocol version 1"); sk_write(ssh->s, verstring, strlen(verstring)); @@ -1956,7 +1983,7 @@ static int ssh_closing(Plug plug, char *error_msg, int error_code, if (error_msg) { /* A socket error has occurred. */ logevent(error_msg); - connection_fatal(error_msg); + connection_fatal(ssh->frontend, error_msg); } else { /* Otherwise, the remote side closed the connection normally. */ } @@ -1966,7 +1993,7 @@ static int ssh_closing(Plug plug, char *error_msg, int error_code, static int ssh_receive(Plug plug, int urgent, char *data, int len) { Ssh ssh = (Ssh) plug; - ssh_gotdata(ssh, data, len); + ssh_gotdata(ssh, (unsigned char *)data, len); if (ssh->state == SSH_STATE_CLOSED) { if (ssh->s) { sk_close(ssh->s); @@ -2019,27 +2046,22 @@ static char *connect_to_host(Ssh ssh, char *host, int port, /* * 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))) + logeventf(ssh, "Looking up host \"%s\"", host); + addr = name_lookup(host, port, realhost); + if ((err = sk_addr_error(addr)) != NULL) return err; /* * Open socket. */ { - char buf[200], addrbuf[100]; + char addrbuf[100]; sk_getaddr(addr, addrbuf, 100); - sprintf(buf, "Connecting to %.100s port %d", addrbuf, port); - logevent(buf); + logeventf(ssh, "Connecting to %s port %d", addrbuf, port); } ssh->fn = &fn_table; ssh->s = new_connection(addr, *realhost, port, 0, 1, nodelay, (Plug) ssh); - if ((err = sk_socket_error(ssh->s))) { + if ((err = sk_socket_error(ssh->s)) != NULL) { ssh->s = NULL; return err; } @@ -2103,7 +2125,7 @@ static void ssh_throttle_all(Ssh ssh, int enable, int bufsize) */ /* Set up a username or password input loop on a given buffer. */ -void setup_userpass_input(Ssh ssh, char *buffer, int buflen, int echo) +static void setup_userpass_input(Ssh ssh, char *buffer, int buflen, int echo) { ssh->userpass_input_buffer = buffer; ssh->userpass_input_buflen = buflen; @@ -2117,7 +2139,7 @@ void setup_userpass_input(Ssh ssh, char *buffer, int buflen, int echo) * buffer), <0 for failure (user hit ^C/^D, bomb out and exit), 0 * for inconclusive (keep waiting for more input please). */ -int process_userpass_input(Ssh ssh, unsigned char *in, int inlen) +static int process_userpass_input(Ssh ssh, unsigned char *in, int inlen) { char c; @@ -2205,7 +2227,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) crWaitUntil(ispkt); if (ssh->pktin.type != SSH1_SMSG_PUBLIC_KEY) { - bombout(("Public key packet not received")); + bombout((ssh,"Public key packet not received")); crReturn(0); } @@ -2266,7 +2288,8 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) fatalbox("Out of memory"); rsastr_fmt(keystr, &hostkey); rsa_fingerprint(fingerprint, sizeof(fingerprint), &hostkey); - verify_ssh_host_key(ssh->savedhost, ssh->savedport, "rsa", keystr, + verify_ssh_host_key(ssh->frontend, + ssh->savedhost, ssh->savedport, "rsa", keystr, fingerprint); sfree(keystr); } @@ -2314,17 +2337,17 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) } if (!cipher_chosen) { if ((s->supported_ciphers_mask & (1 << SSH_CIPHER_3DES)) == 0) - bombout(("Server violates SSH 1 protocol by not " + bombout((ssh,"Server violates SSH 1 protocol by not " "supporting 3DES encryption")); else /* shouldn't happen */ - bombout(("No supported ciphers found")); + bombout((ssh,"No supported ciphers found")); crReturn(0); } /* Warn about chosen cipher if necessary. */ if (warn) - askcipher(cipher_string, 0); + askcipher(ssh->frontend, cipher_string, 0); } switch (s->cipher_type) { @@ -2353,12 +2376,17 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh->cipher = (s->cipher_type == SSH_CIPHER_BLOWFISH ? &ssh_blowfish_ssh1 : s->cipher_type == SSH_CIPHER_DES ? &ssh_des : &ssh_3des); - ssh->cipher->sesskey(ssh->session_key); + ssh->v1_cipher_ctx = ssh->cipher->make_context(); + ssh->cipher->sesskey(ssh->v1_cipher_ctx, ssh->session_key); + logeventf(ssh, "Initialised %s encryption", ssh->cipher->text_name); + + ssh->crcda_ctx = crcda_make_context(); + logevent("Installing CRC compensation attack detector"); crWaitUntil(ispkt); if (ssh->pktin.type != SSH1_SMSG_SUCCESS) { - bombout(("Encryption not successfully enabled")); + bombout((ssh,"Encryption not successfully enabled")); crReturn(0); } @@ -2472,7 +2500,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) s->p += ssh1_read_bignum(s->p, &s->key.modulus); s->commentlen = GET_32BIT(s->p); s->p += 4; - s->commentp = s->p; + s->commentp = (char *)s->p; s->p += s->commentlen; send_packet(ssh, SSH1_CMSG_AUTH_RSA, PKT_BIGNUM, s->key.modulus, PKT_END); @@ -2614,8 +2642,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) char msgbuf[256]; if (flags & FLAG_VERBOSE) c_write_str(ssh, "Trying public key authentication.\r\n"); - sprintf(msgbuf, "Trying public key \"%.200s\"", cfg.keyfile); - logevent(msgbuf); + logeventf(ssh, "Trying public key \"%s\"", cfg.keyfile); type = key_type(cfg.keyfile); if (type != SSH_KEYTYPE_SSH1) { sprintf(msgbuf, "Key is of wrong type (%s)", @@ -2652,7 +2679,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) PKT_STR, "No more passwords available to try", PKT_END); logevent("Unable to authenticate"); - connection_fatal("Unable to authenticate"); + connection_fatal(ssh->frontend, "Unable to authenticate"); ssh->state = SSH_STATE_CLOSED; crReturn(1); } @@ -2708,7 +2735,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) continue; /* go and try password */ } if (ssh->pktin.type != SSH1_SMSG_AUTH_RSA_CHALLENGE) { - bombout(("Bizarre response to offer of public key")); + bombout((ssh,"Bizarre response to offer of public key")); crReturn(0); } @@ -2744,7 +2771,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) " our public key.\r\n"); continue; /* go and try password */ } else if (ssh->pktin.type != SSH1_SMSG_SUCCESS) { - bombout(("Bizarre response to RSA authentication response")); + bombout((ssh,"Bizarre response to RSA authentication response")); crReturn(0); } @@ -2877,7 +2904,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) c_write_str(ssh, "Access denied\r\n"); logevent("Authentication refused"); } else if (ssh->pktin.type != SSH1_SMSG_SUCCESS) { - bombout(("Strange packet received, type %d", ssh->pktin.type)); + bombout((ssh,"Strange packet received, type %d", ssh->pktin.type)); crReturn(0); } } @@ -2977,7 +3004,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) } while (!ispkt); if (ssh->pktin.type != SSH1_SMSG_SUCCESS && ssh->pktin.type != SSH1_SMSG_FAILURE) { - bombout(("Protocol confusion")); + bombout((ssh,"Protocol confusion")); crReturnV; } else if (ssh->pktin.type == SSH1_SMSG_FAILURE) { logevent("Agent forwarding refused"); @@ -2990,11 +3017,14 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (cfg.x11_forward) { char proto[20], data[64]; logevent("Requesting X11 forwarding"); - x11_invent_auth(proto, sizeof(proto), data, sizeof(data)); + ssh->x11auth = x11_invent_auth(proto, sizeof(proto), + data, sizeof(data), cfg.x11_auth); + x11_get_real_auth(ssh->x11auth, cfg.x11_display); if (ssh->v1_local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) { send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING, PKT_STR, proto, PKT_STR, data, - PKT_INT, 0, PKT_END); + PKT_INT, x11_get_screen_number(cfg.x11_display), + PKT_END); } else { send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING, PKT_STR, proto, PKT_STR, data, PKT_END); @@ -3004,7 +3034,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) } while (!ispkt); if (ssh->pktin.type != SSH1_SMSG_SUCCESS && ssh->pktin.type != SSH1_SMSG_FAILURE) { - bombout(("Protocol confusion")); + bombout((ssh,"Protocol confusion")); crReturnV; } else if (ssh->pktin.type == SSH1_SMSG_FAILURE) { logevent("X11 forwarding refused"); @@ -3018,91 +3048,104 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) char type; int n; int sport,dport,sserv,dserv; - char sports[256], dports[256], host[256]; - char buf[1024]; - struct servent *se; + char sports[256], dports[256], saddr[256], host[256]; ssh->rportfwds = newtree234(ssh_rportcmp_ssh1); /* Add port forwardings. */ ssh->portfwd_strptr = cfg.portfwd; while (*ssh->portfwd_strptr) { type = *ssh->portfwd_strptr++; + saddr[0] = '\0'; n = 0; - while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != '\t') - sports[n++] = *ssh->portfwd_strptr++; + while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != '\t') { + if (*ssh->portfwd_strptr == ':') { + /* + * We've seen a colon in the middle of the + * source port number. This means that + * everything we've seen until now is the + * source _address_, so we'll move it into + * saddr and start sports from the beginning + * again. + */ + ssh->portfwd_strptr++; + sports[n] = '\0'; + strcpy(saddr, sports); + n = 0; + } + if (n < 255) sports[n++] = *ssh->portfwd_strptr++; + } sports[n] = 0; if (*ssh->portfwd_strptr == '\t') ssh->portfwd_strptr++; n = 0; - while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != ':') - host[n++] = *ssh->portfwd_strptr++; + while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != ':') { + if (n < 255) host[n++] = *ssh->portfwd_strptr++; + } host[n] = 0; if (*ssh->portfwd_strptr == ':') ssh->portfwd_strptr++; n = 0; - while (*ssh->portfwd_strptr) - dports[n++] = *ssh->portfwd_strptr++; + while (*ssh->portfwd_strptr) { + if (n < 255) dports[n++] = *ssh->portfwd_strptr++; + } dports[n] = 0; ssh->portfwd_strptr++; dport = atoi(dports); dserv = 0; if (dport == 0) { dserv = 1; - se = getservbyname(dports, NULL); - if (se != NULL) { - dport = ntohs(se->s_port); - } else { - sprintf(buf, - "Service lookup failed for destination port \"%s\"", - dports); - logevent(buf); + dport = net_service_lookup(dports); + if (!dport) { + logeventf(ssh, "Service lookup failed for" + " destination port \"%s\"", dports); } } sport = atoi(sports); sserv = 0; if (sport == 0) { sserv = 1; - se = getservbyname(sports, NULL); - if (se != NULL) { - sport = ntohs(se->s_port); - } else { - sprintf(buf, - "Service lookup failed for source port \"%s\"", - sports); - logevent(buf); + sport = net_service_lookup(sports); + if (!sport) { + logeventf(ssh, "Service lookup failed for source" + " port \"%s\"", sports); } } if (sport && dport) { if (type == 'L') { - pfd_addforward(host, dport, sport); - sprintf(buf, "Local port %.*s%.*s%d%.*s forwarding to" - " %s:%.*s%.*s%d%.*s", - sserv ? strlen(sports) : 0, sports, - sserv, "(", sport, sserv, ")", - host, - dserv ? strlen(dports) : 0, dports, - dserv, "(", dport, dserv, ")"); - logevent(buf); + pfd_addforward(host, dport, *saddr ? saddr : NULL, + sport, ssh); + logeventf(ssh, "Local port %.*s%.*s%.*s%.*s%d%.*s" + " forwarding to %s:%.*s%.*s%d%.*s", + (int)(*saddr?strlen(saddr):0), *saddr?saddr:NULL, + (int)(*saddr?1:0), ":", + (int)(sserv ? strlen(sports) : 0), sports, + sserv, "(", sport, sserv, ")", + host, + (int)(dserv ? strlen(dports) : 0), dports, + dserv, "(", dport, dserv, ")"); } else { struct ssh_rportfwd *pf; pf = smalloc(sizeof(*pf)); strcpy(pf->dhost, host); pf->dport = dport; + if (saddr) { + logeventf(ssh, + "SSH1 cannot handle source address spec \"%s:%d\"; ignoring", + saddr, sport); + } if (add234(ssh->rportfwds, pf) != pf) { - sprintf(buf, - "Duplicate remote port forwarding to %s:%d", - host, dport); - logevent(buf); + logeventf(ssh, + "Duplicate remote port forwarding to %s:%d", + host, dport); sfree(pf); } else { - sprintf(buf, "Requesting remote port %.*s%.*s%d%.*s" - " forward to %s:%.*s%.*s%d%.*s", - sserv ? strlen(sports) : 0, sports, - sserv, "(", sport, sserv, ")", - host, - dserv ? strlen(dports) : 0, dports, - dserv, "(", dport, dserv, ")"); - logevent(buf); + logeventf(ssh, "Requesting remote port %.*s%.*s%d%.*s" + " forward to %s:%.*s%.*s%d%.*s", + (int)(sserv ? strlen(sports) : 0), sports, + sserv, "(", sport, sserv, ")", + host, + (int)(dserv ? strlen(dports) : 0), dports, + dserv, "(", dport, dserv, ")"); send_packet(ssh, SSH1_CMSG_PORT_FORWARD_REQUEST, PKT_INT, sport, PKT_STR, host, @@ -3113,7 +3156,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) } while (!ispkt); if (ssh->pktin.type != SSH1_SMSG_SUCCESS && ssh->pktin.type != SSH1_SMSG_FAILURE) { - bombout(("Protocol confusion")); + bombout((ssh,"Protocol confusion")); crReturnV; } else if (ssh->pktin.type == SSH1_SMSG_FAILURE) { c_write_str(ssh, "Server refused port" @@ -3138,7 +3181,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) } while (!ispkt); if (ssh->pktin.type != SSH1_SMSG_SUCCESS && ssh->pktin.type != SSH1_SMSG_FAILURE) { - bombout(("Protocol confusion")); + bombout((ssh,"Protocol confusion")); crReturnV; } else if (ssh->pktin.type == SSH1_SMSG_FAILURE) { c_write_str(ssh, "Server refused to allocate pty\r\n"); @@ -3156,15 +3199,17 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) } while (!ispkt); if (ssh->pktin.type != SSH1_SMSG_SUCCESS && ssh->pktin.type != SSH1_SMSG_FAILURE) { - bombout(("Protocol confusion")); + bombout((ssh,"Protocol confusion")); crReturnV; } else if (ssh->pktin.type == SSH1_SMSG_FAILURE) { c_write_str(ssh, "Server refused to compress\r\n"); } logevent("Started compression"); ssh->v1_compressing = TRUE; - zlib_compress_init(); - zlib_decompress_init(); + ssh->cs_comp_ctx = zlib_compress_init(); + logevent("Initialised zlib (RFC1950) compression"); + ssh->sc_comp_ctx = zlib_decompress_init(); + logevent("Initialised zlib (RFC1950) decompression"); } /* @@ -3194,7 +3239,8 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (ssh->eof_needed) ssh_special(ssh, TS_EOF); - ldisc_send(NULL, 0, 0); /* cause ldisc to notice changes */ + if (ssh->ldisc) + ldisc_send(ssh->ldisc, NULL, 0, 0);/* cause ldisc to notice changes */ ssh->send_ok = 1; ssh->channels = newtree234(ssh_channelcmp); while (1) { @@ -3206,7 +3252,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) int bufsize = from_backend(ssh->frontend, ssh->pktin.type == SSH1_SMSG_STDERR_DATA, - ssh->pktin.body + 4, len); + (char *)(ssh->pktin.body) + 4, len); if (!ssh->v1_stdout_throttling && bufsize > SSH1_BUFFER_LIMIT) { ssh->v1_stdout_throttling = 1; ssh1_throttle(ssh, +1); @@ -3230,7 +3276,8 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) c = smalloc(sizeof(struct ssh_channel)); c->ssh = ssh; - if (x11_init(&c->u.x11.s, cfg.x11_display, c) != NULL) { + if (x11_init(&c->u.x11.s, cfg.x11_display, c, + ssh->x11auth, NULL, -1) != NULL) { logevent("opening X11 forward connection failed"); sfree(c); send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE, @@ -3286,7 +3333,8 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) c->ssh = ssh; hostsize = GET_32BIT(ssh->pktin.body+4); - for(h = host, p = ssh->pktin.body+8; hostsize != 0; hostsize--) { + for (h = host, p = (char *)(ssh->pktin.body+8); + hostsize != 0; hostsize--) { if (h+1 < host+sizeof(host)) *h++ = *p; p++; @@ -3356,7 +3404,6 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) } else if (ssh->pktin.type == SSH1_MSG_CHANNEL_OPEN_FAILURE) { unsigned int remoteid = GET_32BIT(ssh->pktin.body); - unsigned int localid = GET_32BIT(ssh->pktin.body+4); struct ssh_channel *c; c = find234(ssh->channels, &remoteid, ssh_channelfind); @@ -3403,7 +3450,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) sfree(c); } } else { - bombout(("Received CHANNEL_CLOSE%s for %s channel %d\n", + bombout((ssh,"Received CHANNEL_CLOSE%s for %s channel %d\n", ssh->pktin.type == SSH1_MSG_CHANNEL_CLOSE ? "" : "_CONFIRMATION", c ? "half-open" : "nonexistent", i)); @@ -3419,10 +3466,10 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) int bufsize; switch (c->type) { case CHAN_X11: - bufsize = x11_send(c->u.x11.s, p, len); + bufsize = x11_send(c->u.x11.s, (char *)p, len); break; case CHAN_SOCKDATA: - bufsize = pfd_send(c->u.pfd.s, p, len); + bufsize = pfd_send(c->u.pfd.s, (char *)p, len); break; case CHAN_AGENT: /* Data for an agent message. Buffer it. */ @@ -3505,7 +3552,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh->state = SSH_STATE_CLOSED; crReturnV; } else { - bombout(("Strange packet received: type %d", ssh->pktin.type)); + bombout((ssh,"Strange packet received: type %d", ssh->pktin.type)); crReturnV; } } else { @@ -3527,7 +3574,10 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) */ static int in_commasep_string(char *needle, char *haystack, int haylen) { - int needlen = strlen(needle); + int needlen; + if (!needle || !haystack) /* protect against null pointers */ + return 0; + needlen = strlen(needle); while (1) { /* * Is it at the start of the string? @@ -3553,8 +3603,9 @@ static int in_commasep_string(char *needle, char *haystack, int haylen) /* * SSH2 key creation method. */ -static void ssh2_mkkey(Ssh ssh, Bignum K, char *H, char *sessid, char chr, - char *keyspace) +static void ssh2_mkkey(Ssh ssh, Bignum K, unsigned char *H, + unsigned char *sessid, char chr, + unsigned char *keyspace) { SHA_State s; /* First 20 bytes. */ @@ -3762,7 +3813,8 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (!ispkt) crWaitUntil(ispkt); - sha_string(&ssh->exhash, ssh->pktin.data + 5, ssh->pktin.length - 5); + if (ssh->pktin.length > 5) + sha_string(&ssh->exhash, ssh->pktin.data + 5, ssh->pktin.length - 5); /* * Now examine the other side's KEXINIT to see what we're up @@ -3773,7 +3825,7 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) int i, j, len; if (ssh->pktin.type != SSH2_MSG_KEXINIT) { - bombout(("expected key exchange packet from server")); + bombout((ssh,"expected key exchange packet from server")); crReturn(0); } ssh->kex = NULL; @@ -3818,12 +3870,13 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) } if (s->cscipher_tobe) { if (s->warn) - askcipher(s->cscipher_tobe->name, 1); + askcipher(ssh->frontend, s->cscipher_tobe->name, 1); break; } } if (!s->cscipher_tobe) { - bombout(("Couldn't agree a client-to-server cipher (available: %s)", str)); + bombout((ssh,"Couldn't agree a client-to-server cipher (available: %s)", + str ? str : "(null)")); crReturn(0); } @@ -3843,12 +3896,13 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) } if (s->sccipher_tobe) { if (s->warn) - askcipher(s->sccipher_tobe->name, 2); + askcipher(ssh->frontend, s->sccipher_tobe->name, 2); break; } } if (!s->sccipher_tobe) { - bombout(("Couldn't agree a server-to-client cipher (available: %s)", str)); + bombout((ssh,"Couldn't agree a server-to-client cipher (available: %s)", + str ? str : "(null)")); crReturn(0); } @@ -3921,17 +3975,17 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) crWaitUntil(ispkt); if (ssh->pktin.type != SSH2_MSG_KEX_DH_GEX_GROUP) { - bombout(("expected key exchange group packet from server")); + bombout((ssh,"expected key exchange group packet from server")); crReturn(0); } s->p = ssh2_pkt_getmp(ssh); s->g = ssh2_pkt_getmp(ssh); - dh_setup_group(s->p, s->g); + ssh->kex_ctx = dh_setup_group(s->p, s->g); s->kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT; s->kex_reply_value = SSH2_MSG_KEX_DH_GEX_REPLY; } else { ssh->pkt_ctx |= SSH2_PKTCTX_DHGROUP1; - dh_setup_group1(); + ssh->kex_ctx = dh_setup_group1(); s->kex_init_value = SSH2_MSG_KEXDH_INIT; s->kex_reply_value = SSH2_MSG_KEXDH_REPLY; } @@ -3940,21 +3994,21 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) /* * Now generate and send e for Diffie-Hellman. */ - s->e = dh_create_e(s->nbits * 2); + s->e = dh_create_e(ssh->kex_ctx, s->nbits * 2); ssh2_pkt_init(ssh, s->kex_init_value); ssh2_pkt_addmp(ssh, s->e); ssh2_pkt_send(ssh); crWaitUntil(ispkt); if (ssh->pktin.type != s->kex_reply_value) { - bombout(("expected key exchange reply packet from server")); + bombout((ssh,"expected key exchange reply packet from server")); crReturn(0); } ssh2_pkt_getstring(ssh, &s->hostkeydata, &s->hostkeylen); s->f = ssh2_pkt_getmp(ssh); ssh2_pkt_getstring(ssh, &s->sigdata, &s->siglen); - s->K = dh_find_K(s->f); + s->K = dh_find_K(ssh->kex_ctx, s->f); sha_string(&ssh->exhash, s->hostkeydata, s->hostkeylen); if (ssh->kex == &ssh_diffiehellman_gex) { @@ -3967,7 +4021,7 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) sha_mpint(&ssh->exhash, s->K); SHA_Final(&ssh->exhash, s->exchange_hash); - dh_cleanup(); + dh_cleanup(ssh->kex_ctx); #if 0 debug(("Exchange hash is:\n")); @@ -3977,8 +4031,8 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) s->hkey = ssh->hostkey->newkey(s->hostkeydata, s->hostkeylen); if (!s->hkey || !ssh->hostkey->verifysig(s->hkey, s->sigdata, s->siglen, - s->exchange_hash, 20)) { - bombout(("Server's host key did not match the signature supplied")); + (char *)s->exchange_hash, 20)) { + bombout((ssh,"Server's host key did not match the signature supplied")); crReturn(0); } @@ -3988,7 +4042,8 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) */ s->keystr = ssh->hostkey->fmtkey(s->hkey); s->fingerprint = ssh->hostkey->fingerprint(s->hkey); - verify_ssh_host_key(ssh->savedhost, ssh->savedport, ssh->hostkey->keytype, + verify_ssh_host_key(ssh->frontend, + ssh->savedhost, ssh->savedport, ssh->hostkey->keytype, s->keystr, s->fingerprint); if (s->first_kex) { /* don't bother logging this in rekeys */ logevent("Host key fingerprint is:"); @@ -4009,21 +4064,43 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) */ crWaitUntil(ispkt); if (ssh->pktin.type != SSH2_MSG_NEWKEYS) { - bombout(("expected new-keys packet from server")); + bombout((ssh,"expected new-keys packet from server")); crReturn(0); } /* * Create and initialise session keys. */ + if (ssh->cs_cipher_ctx) + ssh->cscipher->free_context(ssh->cs_cipher_ctx); ssh->cscipher = s->cscipher_tobe; + ssh->cs_cipher_ctx = ssh->cscipher->make_context(); + + if (ssh->sc_cipher_ctx) + ssh->sccipher->free_context(ssh->sc_cipher_ctx); ssh->sccipher = s->sccipher_tobe; + ssh->sc_cipher_ctx = ssh->sccipher->make_context(); + + if (ssh->cs_mac_ctx) + ssh->csmac->free_context(ssh->cs_mac_ctx); ssh->csmac = s->csmac_tobe; + ssh->cs_mac_ctx = ssh->csmac->make_context(); + + if (ssh->sc_mac_ctx) + ssh->scmac->free_context(ssh->sc_mac_ctx); ssh->scmac = s->scmac_tobe; + ssh->sc_mac_ctx = ssh->scmac->make_context(); + + if (ssh->cs_comp_ctx) + ssh->cscomp->compress_cleanup(ssh->cs_comp_ctx); ssh->cscomp = s->cscomp_tobe; + ssh->cs_comp_ctx = ssh->cscomp->compress_init(); + + if (ssh->sc_comp_ctx) + ssh->sccomp->decompress_cleanup(ssh->sc_comp_ctx); ssh->sccomp = s->sccomp_tobe; - ssh->cscomp->compress_init(); - ssh->sccomp->decompress_init(); + ssh->sc_comp_ctx = ssh->sccomp->decompress_init(); + /* * Set IVs after keys. Here we use the exchange hash from the * _first_ key exchange. @@ -4034,18 +4111,28 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) memcpy(ssh->v2_session_id, s->exchange_hash, sizeof(s->exchange_hash)); ssh2_mkkey(ssh,s->K,s->exchange_hash,ssh->v2_session_id,'C',keyspace); - ssh->cscipher->setcskey(keyspace); + ssh->cscipher->setkey(ssh->cs_cipher_ctx, keyspace); ssh2_mkkey(ssh,s->K,s->exchange_hash,ssh->v2_session_id,'D',keyspace); - ssh->sccipher->setsckey(keyspace); + ssh->sccipher->setkey(ssh->sc_cipher_ctx, keyspace); ssh2_mkkey(ssh,s->K,s->exchange_hash,ssh->v2_session_id,'A',keyspace); - ssh->cscipher->setcsiv(keyspace); + ssh->cscipher->setiv(ssh->cs_cipher_ctx, keyspace); ssh2_mkkey(ssh,s->K,s->exchange_hash,ssh->v2_session_id,'B',keyspace); - ssh->sccipher->setsciv(keyspace); + ssh->sccipher->setiv(ssh->sc_cipher_ctx, keyspace); ssh2_mkkey(ssh,s->K,s->exchange_hash,ssh->v2_session_id,'E',keyspace); - ssh->csmac->setcskey(keyspace); + ssh->csmac->setkey(ssh->cs_mac_ctx, keyspace); ssh2_mkkey(ssh,s->K,s->exchange_hash,ssh->v2_session_id,'F',keyspace); - ssh->scmac->setsckey(keyspace); + ssh->scmac->setkey(ssh->sc_mac_ctx, keyspace); } + logeventf(ssh, "Initialised %.200s client->server encryption", + ssh->cscipher->text_name); + logeventf(ssh, "Initialised %.200s server->client encryption", + ssh->sccipher->text_name); + if (ssh->cscomp->text_name) + logeventf(ssh, "Initialised %s compression", + ssh->cscomp->text_name); + if (ssh->sccomp->text_name) + logeventf(ssh, "Initialised %s decompression", + ssh->sccomp->text_name); /* * If this is the first key exchange phase, we must pass the @@ -4192,7 +4279,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh2_pkt_send(ssh); crWaitUntilV(ispkt); if (ssh->pktin.type != SSH2_MSG_SERVICE_ACCEPT) { - bombout(("Server refused user authentication protocol")); + bombout((ssh,"Server refused user authentication protocol")); crReturnV; } @@ -4255,16 +4342,17 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) } while (ret == 0); if (ret < 0) cleanup_exit(0); + c_write_str(ssh, "\r\n"); } - c_write_str(ssh, "\r\n"); s->username[strcspn(s->username, "\n\r")] = '\0'; } else { - char stuff[200]; + char *stuff; strncpy(s->username, cfg.username, sizeof(s->username)); s->username[sizeof(s->username)-1] = '\0'; if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) { - sprintf(stuff, "Using username \"%s\".\r\n", s->username); + stuff = dupprintf("Using username \"%s\".\r\n", s->username); c_write_str(ssh, stuff); + sfree(stuff); } } s->got_username = TRUE; @@ -4292,19 +4380,21 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) /* Load the pub half of cfg.keyfile so we notice if it's in Pageant */ if (*cfg.keyfile) { int keytype; - logeventf("Reading private key file \"%.150s\"", cfg.keyfile); + logeventf(ssh, "Reading private key file \"%.150s\"", cfg.keyfile); keytype = key_type(cfg.keyfile); if (keytype == SSH_KEYTYPE_SSH2) { s->publickey_blob = ssh2_userkey_loadpub(cfg.keyfile, NULL, &s->publickey_bloblen); } else { - char msgbuf[256]; - logeventf("Unable to use this key file (%s)", - key_type_to_str(keytype)); - sprintf(msgbuf, "Unable to use key file \"%.150s\" (%s)\r\n", - cfg.keyfile, key_type_to_str(keytype)); + char *msgbuf; + logeventf(ssh, "Unable to use this key file (%s)", + key_type_to_str(keytype)); + msgbuf = dupprintf("Unable to use key file \"%.150s\"" + " (%s)\r\n", cfg.keyfile, + key_type_to_str(keytype)); c_write_str(ssh, msgbuf); + sfree(msgbuf); s->publickey_blob = NULL; } } else @@ -4352,7 +4442,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (!s->gotit) s->curr_prompt = 0; } else if (ssh->pktin.type != SSH2_MSG_USERAUTH_FAILURE) { - bombout(("Strange packet received during authentication: type %d", + bombout((ssh,"Strange packet received during authentication: type %d", ssh->pktin.type)); crReturnV; } @@ -4479,13 +4569,13 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) logevent("This key matches configured key file"); s->tried_pubkey_config = 1; } - s->pkblob = s->p; + s->pkblob = (char *)s->p; s->p += s->pklen; s->alglen = GET_32BIT(s->pkblob); s->alg = s->pkblob + 4; s->commentlen = GET_32BIT(s->p); s->p += 4; - s->commentp = s->p; + s->commentp = (char *)s->p; s->p += s->commentlen; ssh2_pkt_init(ssh, SSH2_MSG_USERAUTH_REQUEST); ssh2_pkt_addstring(ssh, s->username); @@ -4591,8 +4681,10 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) * First, offer the public blob to see if the server is * willing to accept it. */ - pub_blob = ssh2_userkey_loadpub(cfg.keyfile, &algorithm, - &pub_blob_len); + pub_blob = + (unsigned char *)ssh2_userkey_loadpub(cfg.keyfile, + &algorithm, + &pub_blob_len); if (pub_blob) { ssh2_pkt_init(ssh, SSH2_MSG_USERAUTH_REQUEST); ssh2_pkt_addstring(ssh, s->username); @@ -4601,7 +4693,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh2_pkt_addbool(ssh, FALSE); /* no signature included */ ssh2_pkt_addstring(ssh, algorithm); ssh2_pkt_addstring_start(ssh); - ssh2_pkt_addstring_data(ssh, pub_blob, pub_blob_len); + ssh2_pkt_addstring_data(ssh, (char *)pub_blob, + pub_blob_len); ssh2_pkt_send(ssh); logevent("Offered public key"); /* FIXME */ @@ -4741,7 +4834,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh2_pkt_addstring(ssh, "en"); /* language tag */ ssh2_pkt_send(ssh); logevent("Unable to authenticate"); - connection_fatal("Unable to authenticate"); + connection_fatal(ssh->frontend, + "Unable to authenticate"); ssh->state = SSH_STATE_CLOSED; crReturnV; } @@ -4801,7 +4895,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh2_pkt_addstring(ssh, key->alg->name); pkblob = key->alg->public_blob(key->data, &pkblob_len); ssh2_pkt_addstring_start(ssh); - ssh2_pkt_addstring_data(ssh, pkblob, pkblob_len); + ssh2_pkt_addstring_data(ssh, (char *)pkblob, pkblob_len); /* * The data to be signed is: @@ -4817,7 +4911,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) memcpy(sigdata + 4, ssh->v2_session_id, 20); memcpy(sigdata + 24, ssh->pktout.data + 5, ssh->pktout.length - 5); - sigblob = key->alg->sign(key->data, sigdata, + sigblob = key->alg->sign(key->data, (char *)sigdata, sigdata_len, &sigblob_len); ssh2_add_sigblob(ssh, pkblob, pkblob_len, sigblob, sigblob_len); @@ -4849,6 +4943,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh2_pkt_addstring(ssh, "password"); ssh2_pkt_addbool(ssh, FALSE); ssh2_pkt_addstring(ssh, s->password); + memset(s->password, 0, sizeof(s->password)); ssh2_pkt_defer(ssh); /* * We'll include a string that's an exact multiple of the @@ -4872,7 +4967,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) * bytes we should adjust our string length * by. */ - stringlen -= ssh->cscomp->disable_compression(); + stringlen -= + ssh->cscomp->disable_compression(ssh->cs_comp_ctx); } ssh2_pkt_init(ssh, SSH2_MSG_IGNORE); ssh2_pkt_addstring_start(ssh); @@ -4948,12 +5044,12 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh2_pkt_send(ssh); crWaitUntilV(ispkt); if (ssh->pktin.type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) { - bombout(("Server refused to open a session")); + bombout((ssh,"Server refused to open a session")); crReturnV; /* FIXME: error data comes back in FAILURE packet */ } if (ssh2_pkt_getuint32(ssh) != ssh->mainchan->localid) { - bombout(("Server's channel confirmation cited wrong channel")); + bombout((ssh,"Server's channel confirmation cited wrong channel")); crReturnV; } ssh->mainchan->remoteid = ssh2_pkt_getuint32(ssh); @@ -4971,7 +5067,9 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (cfg.x11_forward) { char proto[20], data[64]; logevent("Requesting X11 forwarding"); - x11_invent_auth(proto, sizeof(proto), data, sizeof(data)); + ssh->x11auth = x11_invent_auth(proto, sizeof(proto), + data, sizeof(data), cfg.x11_auth); + x11_get_real_auth(ssh->x11auth, cfg.x11_display); ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(ssh, ssh->mainchan->remoteid); ssh2_pkt_addstring(ssh, "x11-req"); @@ -4979,7 +5077,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh2_pkt_addbool(ssh, 0); /* many connections */ ssh2_pkt_addstring(ssh, proto); ssh2_pkt_addstring(ssh, data); - ssh2_pkt_adduint32(ssh, 0); /* screen number */ + ssh2_pkt_adduint32(ssh, x11_get_screen_number(cfg.x11_display)); ssh2_pkt_send(ssh); do { @@ -4996,7 +5094,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (ssh->pktin.type != SSH2_MSG_CHANNEL_SUCCESS) { if (ssh->pktin.type != SSH2_MSG_CHANNEL_FAILURE) { - bombout(("Unexpected response to X11 forwarding request:" + bombout((ssh,"Unexpected response to X11 forwarding request:" " packet type %d", ssh->pktin.type)); crReturnV; } @@ -5014,71 +5112,81 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) char type; int n; int sport,dport,sserv,dserv; - char sports[256], dports[256], host[256]; - char buf[1024]; - struct servent *se; + char sports[256], dports[256], saddr[256], host[256]; ssh->rportfwds = newtree234(ssh_rportcmp_ssh2); /* Add port forwardings. */ ssh->portfwd_strptr = cfg.portfwd; while (*ssh->portfwd_strptr) { type = *ssh->portfwd_strptr++; + saddr[0] = '\0'; n = 0; - while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != '\t') - sports[n++] = *ssh->portfwd_strptr++; + while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != '\t') { + if (*ssh->portfwd_strptr == ':') { + /* + * We've seen a colon in the middle of the + * source port number. This means that + * everything we've seen until now is the + * source _address_, so we'll move it into + * saddr and start sports from the beginning + * again. + */ + ssh->portfwd_strptr++; + sports[n] = '\0'; + strcpy(saddr, sports); + n = 0; + } + if (n < 255) sports[n++] = *ssh->portfwd_strptr++; + } sports[n] = 0; if (*ssh->portfwd_strptr == '\t') ssh->portfwd_strptr++; n = 0; - while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != ':') - host[n++] = *ssh->portfwd_strptr++; + while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != ':') { + if (n < 255) host[n++] = *ssh->portfwd_strptr++; + } host[n] = 0; if (*ssh->portfwd_strptr == ':') ssh->portfwd_strptr++; n = 0; - while (*ssh->portfwd_strptr) - dports[n++] = *ssh->portfwd_strptr++; + while (*ssh->portfwd_strptr) { + if (n < 255) dports[n++] = *ssh->portfwd_strptr++; + } dports[n] = 0; ssh->portfwd_strptr++; dport = atoi(dports); dserv = 0; if (dport == 0) { dserv = 1; - se = getservbyname(dports, NULL); - if (se != NULL) { - dport = ntohs(se->s_port); - } else { - sprintf(buf, - "Service lookup failed for destination port \"%s\"", - dports); - logevent(buf); + dport = net_service_lookup(dports); + if (!dport) { + logeventf(ssh, "Service lookup failed for destination" + " port \"%s\"", dports); } } sport = atoi(sports); sserv = 0; if (sport == 0) { sserv = 1; - se = getservbyname(sports, NULL); - if (se != NULL) { - sport = ntohs(se->s_port); - } else { - sprintf(buf, - "Service lookup failed for source port \"%s\"", - sports); - logevent(buf); + sport = net_service_lookup(sports); + if (!sport) { + logeventf(ssh, "Service lookup failed for source" + " port \"%s\"", sports); } } if (sport && dport) { if (type == 'L') { - pfd_addforward(host, dport, sport); - sprintf(buf, "Local port %.*s%.*s%d%.*s forwarding to" - " %s:%.*s%.*s%d%.*s", - sserv ? strlen(sports) : 0, sports, - sserv, "(", sport, sserv, ")", - host, - dserv ? strlen(dports) : 0, dports, - dserv, "(", dport, dserv, ")"); - logevent(buf); + pfd_addforward(host, dport, *saddr ? saddr : NULL, + sport, ssh); + logeventf(ssh, "Local port %.*s%.*s%.*s%.*s%d%.*s" + " forwarding to %s:%.*s%.*s%d%.*s", + (int)(*saddr?strlen(saddr):0), *saddr?saddr:NULL, + (int)(*saddr?1:0), ":", + (int)(sserv ? strlen(sports) : 0), sports, + sserv, "(", sport, sserv, ")", + host, + (int)(dserv ? strlen(dports) : 0), dports, + dserv, "(", dport, dserv, ")"); } else { struct ssh_rportfwd *pf; pf = smalloc(sizeof(*pf)); @@ -5086,23 +5194,26 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) pf->dport = dport; pf->sport = sport; if (add234(ssh->rportfwds, pf) != pf) { - sprintf(buf, - "Duplicate remote port forwarding to %s:%d", - host, dport); - logevent(buf); + logeventf(ssh, "Duplicate remote port forwarding" + " to %s:%d", host, dport); sfree(pf); } else { - sprintf(buf, "Requesting remote port %.*s%.*s%d%.*s" - " forward to %s:%.*s%.*s%d%.*s", - sserv ? strlen(sports) : 0, sports, - sserv, "(", sport, sserv, ")", - host, - dserv ? strlen(dports) : 0, dports, - dserv, "(", dport, dserv, ")"); - logevent(buf); + logeventf(ssh, "Requesting remote port " + "%.*s%.*s%.*s%.*s%d%.*s" + " forward to %s:%.*s%.*s%d%.*s", + (int)(*saddr?strlen(saddr):0), + *saddr?saddr:NULL, + (int)(*saddr?1:0), ":", + (int)(sserv ? strlen(sports) : 0), sports, + sserv, "(", sport, sserv, ")", + host, + (int)(dserv ? strlen(dports) : 0), dports, + dserv, "(", dport, dserv, ")"); ssh2_pkt_init(ssh, SSH2_MSG_GLOBAL_REQUEST); ssh2_pkt_addstring(ssh, "tcpip-forward"); ssh2_pkt_addbool(ssh, 1);/* want reply */ + if (*saddr) + ssh2_pkt_addstring(ssh, saddr); if (cfg.rport_acceptall) ssh2_pkt_addstring(ssh, "0.0.0.0"); else @@ -5124,7 +5235,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (ssh->pktin.type != SSH2_MSG_REQUEST_SUCCESS) { if (ssh->pktin.type != SSH2_MSG_REQUEST_FAILURE) { - bombout(("Unexpected response to port " + bombout((ssh,"Unexpected response to port " "forwarding request: packet type %d", ssh->pktin.type)); crReturnV; @@ -5164,7 +5275,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (ssh->pktin.type != SSH2_MSG_CHANNEL_SUCCESS) { if (ssh->pktin.type != SSH2_MSG_CHANNEL_FAILURE) { - bombout(("Unexpected response to agent forwarding request:" + bombout((ssh,"Unexpected response to agent forwarding request:" " packet type %d", ssh->pktin.type)); crReturnV; } @@ -5207,7 +5318,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (ssh->pktin.type != SSH2_MSG_CHANNEL_SUCCESS) { if (ssh->pktin.type != SSH2_MSG_CHANNEL_FAILURE) { - bombout(("Unexpected response to pty request:" + bombout((ssh,"Unexpected response to pty request:" " packet type %d", ssh->pktin.type)); crReturnV; } @@ -5265,7 +5376,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) } while (ssh->pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST); if (ssh->pktin.type != SSH2_MSG_CHANNEL_SUCCESS) { if (ssh->pktin.type != SSH2_MSG_CHANNEL_FAILURE) { - bombout(("Unexpected response to shell/command request:" + bombout((ssh,"Unexpected response to shell/command request:" " packet type %d", ssh->pktin.type)); crReturnV; } @@ -5280,7 +5391,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh->fallback_cmd = TRUE; continue; } - bombout(("Server refused to start a shell/command")); + bombout((ssh,"Server refused to start a shell/command")); crReturnV; } else { logevent("Started a shell/command"); @@ -5297,7 +5408,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) /* * Transfer data! */ - ldisc_send(NULL, 0, 0); /* cause ldisc to notice changes */ + if (ssh->ldisc) + ldisc_send(ssh->ldisc, NULL, 0, 0);/* cause ldisc to notice changes */ ssh->send_ok = 1; while (1) { crReturnV; @@ -5416,7 +5528,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) c = find234(ssh->channels, &i, ssh_channelfind); if (!c || ((int)c->remoteid) == -1) { - bombout(("Received CHANNEL_CLOSE for %s channel %d\n", + bombout((ssh,"Received CHANNEL_CLOSE for %s channel %d\n", c ? "half-open" : "nonexistent", i)); } /* Do pre-close processing on the channel. */ @@ -5477,8 +5589,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) unsigned i = ssh2_pkt_getuint32(ssh); struct ssh_channel *c; c = find234(ssh->channels, &i, ssh_channelfind); - if (!c) - continue; /* nonexistent channel */ + if (!c || c->closes) + continue; /* nonexistent or closing channel */ c->v.v2.remwindow += ssh2_pkt_getuint32(ssh); s->try_send = TRUE; } else if (ssh->pktin.type == SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) { @@ -5602,6 +5714,9 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) } else if (ssh->pktin.type == SSH2_MSG_CHANNEL_OPEN) { char *type; int typelen; + char *peeraddr; + int peeraddrlen; + int port; char *error = NULL; struct ssh_channel *c; unsigned remid, winsize, pktsize; @@ -5612,16 +5727,24 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) remid = ssh2_pkt_getuint32(ssh); winsize = ssh2_pkt_getuint32(ssh); pktsize = ssh2_pkt_getuint32(ssh); + ssh2_pkt_getstring(ssh, &peeraddr, &peeraddrlen); + port = ssh2_pkt_getuint32(ssh); if (typelen == 3 && !memcmp(type, "x11", 3)) { + char *addrstr = smalloc(peeraddrlen+1); + memcpy(addrstr, peeraddr, peeraddrlen); + peeraddr[peeraddrlen] = '\0'; + if (!ssh->X11_fwd_enabled) error = "X11 forwarding is not enabled"; - else if (x11_init(&c->u.x11.s, cfg.x11_display, c) != - NULL) { + else if (x11_init(&c->u.x11.s, cfg.x11_display, c, + ssh->x11auth, addrstr, port) != NULL) { error = "Unable to open an X11 connection"; } else { c->type = CHAN_X11; } + + sfree(addrstr); } else if (typelen == 15 && !memcmp(type, "forwarded-tcpip", 15)) { struct ssh_rportfwd pf, *realpf; @@ -5635,13 +5758,10 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) } else { char *e = pfd_newconnect(&c->u.pfd.s, realpf->dhost, realpf->dport, c); - char buf[1024]; - sprintf(buf, "Received remote port open request for %s:%d", - realpf->dhost, realpf->dport); - logevent(buf); + logeventf(ssh, "Received remote port open request" + " for %s:%d", realpf->dhost, realpf->dport); if (e != NULL) { - sprintf(buf, "Port open failed: %s", e); - logevent(buf); + logeventf(ssh, "Port open failed: %s", e); error = "Port open failed"; } else { logevent("Forwarded port opened successfully"); @@ -5685,14 +5805,14 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh2_pkt_send(ssh); } } else { - bombout(("Strange packet received: type %d", ssh->pktin.type)); + bombout((ssh,"Strange packet received: type %d", ssh->pktin.type)); crReturnV; } } else { /* * We have spare data. Add it to the channel buffer. */ - ssh2_add_channel_data(ssh->mainchan, in, inlen); + ssh2_add_channel_data(ssh->mainchan, (char *)in, inlen); s->try_send = TRUE; } if (s->try_send) { @@ -5702,7 +5822,10 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) * Try to send data on all channels if we can. */ for (i = 0; NULL != (c = index234(ssh->channels, i)); i++) { - int bufsize = ssh2_try_send(c); + int bufsize; + if (c->closes) + continue; /* don't send on closing channels */ + bufsize = ssh2_try_send(c); if (bufsize == 0) { switch (c->type) { case CHAN_MAINSESSION: @@ -5752,18 +5875,28 @@ static char *ssh_init(void *frontend_handle, void **backend_handle, ssh = smalloc(sizeof(*ssh)); ssh->s = NULL; ssh->cipher = NULL; + ssh->v1_cipher_ctx = NULL; + ssh->crcda_ctx = NULL; ssh->cscipher = NULL; + ssh->cs_cipher_ctx = NULL; ssh->sccipher = NULL; + ssh->sc_cipher_ctx = NULL; ssh->csmac = NULL; + ssh->cs_mac_ctx = NULL; ssh->scmac = NULL; + ssh->sc_mac_ctx = NULL; ssh->cscomp = NULL; + ssh->cs_comp_ctx = NULL; ssh->sccomp = NULL; + ssh->sc_comp_ctx = NULL; ssh->kex = NULL; ssh->hostkey = NULL; ssh->exitcode = -1; ssh->state = SSH_STATE_PREPACKET; ssh->size_needed = FALSE; ssh->eof_needed = FALSE; + ssh->ldisc = NULL; + ssh->logctx = NULL; { static const struct Packet empty = { 0, 0, NULL, NULL, 0 }; ssh->pktin = ssh->pktout = empty; @@ -5773,6 +5906,8 @@ static char *ssh_init(void *frontend_handle, void **backend_handle, ssh->deferred_size = 0; ssh->fallback_cmd = 0; ssh->pkt_ctx = 0; + ssh->x11auth = NULL; + ssh->v1_compressing = FALSE; ssh->v2_outgoing_sequence = 0; ssh->ssh1_rdpkt_crstate = 0; ssh->ssh2_rdpkt_crstate = 0; @@ -5786,6 +5921,9 @@ static char *ssh_init(void *frontend_handle, void **backend_handle, ssh->do_ssh1_login_state = NULL; ssh->do_ssh2_transport_state = NULL; ssh->do_ssh2_authconn_state = NULL; + ssh->mainchan = NULL; + ssh->throttled_all = 0; + ssh->v1_stdout_throttling = 0; *backend_handle = ssh; @@ -5805,6 +5943,8 @@ static char *ssh_init(void *frontend_handle, void **backend_handle, ssh->overall_bufsize = 0; ssh->fallback_cmd = 0; + ssh->protocol = NULL; + p = connect_to_host(ssh, host, port, realhost, nodelay); if (p != NULL) return p; @@ -5822,7 +5962,7 @@ static int ssh_send(void *handle, char *buf, int len) if (ssh == NULL || ssh->s == NULL || ssh->protocol == NULL) return 0; - ssh->protocol(ssh, buf, len, 0); + ssh->protocol(ssh, (unsigned char *)buf, len, 0); return ssh_sendbuffer(ssh); } @@ -5879,8 +6019,6 @@ static void ssh_size(void *handle, int width, int height) break; case SSH_STATE_SESSION: if (!cfg.nopty) { - if (!term) - return; if (ssh->version == 1) { send_packet(ssh, SSH1_CMSG_WINDOW_SIZE, PKT_INT, ssh->term_height, @@ -5968,7 +6106,7 @@ void *new_sock_channel(void *handle, Socket s) * This is called when stdout/stderr (the entity to which * from_backend sends data) manages to clear some backlog. */ -void ssh_unthrottle(void *handle, int bufsize) +static void ssh_unthrottle(void *handle, int bufsize) { Ssh ssh = (Ssh) handle; if (ssh->version == 1) { @@ -5982,15 +6120,12 @@ void ssh_unthrottle(void *handle, int bufsize) } } -void ssh_send_port_open(void *handle, void *channel, char *hostname, - int port, char *org) +void ssh_send_port_open(void *channel, char *hostname, int port, char *org) { - Ssh ssh = (Ssh) handle; struct ssh_channel *c = (struct ssh_channel *)channel; - char buf[1024]; + Ssh ssh = c->ssh; - sprintf(buf, "Opening forwarded connection to %.512s:%d", hostname, port); - logevent(buf); + logeventf(ssh, "Opening forwarded connection to %s:%d", hostname, port); if (ssh->version == 1) { send_packet(ssh, SSH1_MSG_PORT_OPEN, @@ -6043,6 +6178,18 @@ static int ssh_ldisc(void *handle, int option) return FALSE; } +static void ssh_provide_ldisc(void *handle, void *ldisc) +{ + Ssh ssh = (Ssh) handle; + ssh->ldisc = ldisc; +} + +static void ssh_provide_logctx(void *handle, void *logctx) +{ + Ssh ssh = (Ssh) handle; + ssh->logctx = logctx; +} + static int ssh_return_exitcode(void *handle) { Ssh ssh = (Ssh) handle; @@ -6070,6 +6217,8 @@ Backend ssh_backend = { ssh_return_exitcode, ssh_sendok, ssh_ldisc, + ssh_provide_ldisc, + ssh_provide_logctx, ssh_unthrottle, 22 };