#define BUG_CHOKES_ON_RSA 8
#define BUG_SSH2_RSA_PADDING 16
#define BUG_SSH2_DERIVEKEY 32
+#define BUG_SSH2_DH_GEX 64
static int ssh_pkt_ctx = 0;
struct ssh_channel {
unsigned remoteid, localid;
int type;
+ /*
+ * In SSH1, this value contains four bits:
+ *
+ * 1 We have sent SSH1_MSG_CHANNEL_CLOSE.
+ * 2 We have sent SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION.
+ * 4 We have received SSH1_MSG_CHANNEL_CLOSE.
+ * 8 We have received SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION.
+ *
+ * A channel is completely finished with when all four bits are set.
+ */
int closes;
union {
struct ssh1_data_channel {
ssh_remote_bugs |= BUG_SSH2_RSA_PADDING;
logevent("We believe remote version has SSH2 RSA padding bug");
}
+
+ if (cfg.sshbug_dhgex2 == BUG_ON) {
+ /*
+ * These versions have the SSH2 DH GEX bug.
+ */
+ ssh_remote_bugs |= BUG_SSH2_DH_GEX;
+ logevent("We believe remote version has SSH2 DH group exchange bug");
+ }
}
static int do_ssh_init(unsigned char c)
ssh2_pkt_send();
}
}
- c->closes = 1;
+ c->closes = 1; /* sent MSG_CLOSE */
if (c->type == CHAN_X11) {
c->u.x11.s = NULL;
logevent("Forwarded X11 connection terminated");
unsigned i = GET_32BIT(pktin.body);
struct ssh_channel *c;
c = find234(ssh_channels, &i, ssh_channelfind);
- if (c) {
+ if (c && ((int)c->remoteid) != -1) {
int closetype;
closetype =
(pktin.type == SSH1_MSG_CHANNEL_CLOSE ? 1 : 2);
- if (!(c->closes & closetype))
- send_packet(pktin.type, PKT_INT, c->remoteid,
- PKT_END);
+
if ((c->closes == 0) && (c->type == CHAN_X11)) {
logevent("Forwarded X11 connection terminated");
assert(c->u.x11.s != NULL);
pfd_close(c->u.pfd.s);
c->u.pfd.s = NULL;
}
- c->closes |= closetype;
- if (c->closes == 3) {
+
+ c->closes |= (closetype << 2); /* seen this message */
+ if (!(c->closes & closetype)) {
+ send_packet(pktin.type, PKT_INT, c->remoteid,
+ PKT_END);
+ c->closes |= closetype; /* sent it too */
+ }
+
+ if (c->closes == 15) {
del234(ssh_channels, c);
sfree(c);
}
+ } else {
+ bombout(("Received CHANNEL_CLOSE%s for %s channel %d\n",
+ pktin.type == SSH1_MSG_CHANNEL_CLOSE ? "" :
+ "_CONFIRMATION", c ? "half-open" : "nonexistent",
+ i));
}
} else if (pktin.type == SSH1_MSG_CHANNEL_DATA) {
/* Data sent down one of our channels. */
/*
* Be prepared to work around the buggy MAC problem.
*/
- if (cfg.buggymac || (ssh_remote_bugs & BUG_SSH2_HMAC))
+ if (ssh_remote_bugs & BUG_SSH2_HMAC)
maclist = buggymacs, nmacs = lenof(buggymacs);
else
maclist = macs, nmacs = lenof(macs);
/* List key exchange algorithms. */
ssh2_pkt_addstring_start();
for (i = 0; i < lenof(kex_algs); i++) {
+ if (kex_algs[i] == &ssh_diffiehellman_gex &&
+ (ssh_remote_bugs & BUG_SSH2_DH_GEX))
+ continue;
ssh2_pkt_addstring_str(kex_algs[i]->name);
if (i < lenof(kex_algs) - 1)
ssh2_pkt_addstring_str(",");
pktin.savedpos += 16; /* skip garbage cookie */
ssh2_pkt_getstring(&str, &len); /* key exchange algorithms */
for (i = 0; i < lenof(kex_algs); i++) {
+ if (kex_algs[i] == &ssh_diffiehellman_gex &&
+ (ssh_remote_bugs & BUG_SSH2_DH_GEX))
+ continue;
if (in_commasep_string(kex_algs[i]->name, str, len)) {
kex = kex_algs[i];
break;
struct ssh_channel *c;
c = find234(ssh_channels, &i, ssh_channelfind);
- if (!c)
- continue; /* nonexistent channel */
+ if (!c || ((int)c->remoteid) == -1) {
+ bombout(("Received CHANNEL_CLOSE for %s channel %d\n",
+ c ? "half-open" : "nonexistent", i));
+ }
/* Do pre-close processing on the channel. */
switch (c->type) {
case CHAN_MAINSESSION: