const static struct ssh_signkey *hostkey_algs[] = { &ssh_rsa, &ssh_dss };
const static struct ssh_mac *macs[] = {
- &ssh_hmac_sha1, &ssh_hmac_sha1_96, &ssh_hmac_md5
+ &ssh_hmac_sha256, &ssh_hmac_sha1, &ssh_hmac_sha1_96, &ssh_hmac_md5
};
const static struct ssh_mac *buggymacs[] = {
&ssh_hmac_sha1_buggy, &ssh_hmac_sha1_96_buggy, &ssh_hmac_md5
unsigned char *message;
unsigned char msglen[4];
unsigned lensofar, totallen;
+ int outstanding_requests;
} a;
struct ssh_x11_channel {
Socket s;
static unsigned long ssh_pkt_getuint32(struct Packet *pkt);
static int ssh2_pkt_getbool(struct Packet *pkt);
static void ssh_pkt_getstring(struct Packet *pkt, char **p, int *length);
-static void ssh2_timer(void *ctx, long now);
+static void ssh2_timer(void *ctx, unsigned long now);
static void do_ssh2_transport(Ssh ssh, void *vin, int inlen,
struct Packet *pktin);
static void ssh2_msg_unexpected(Ssh ssh, struct Packet *pktin);
unsigned long incoming_data_size, outgoing_data_size, deferred_data_size;
unsigned long max_data_size;
int kex_in_progress;
- long next_rekey, last_rekey;
+ unsigned long next_rekey, last_rekey;
char *deferred_rekey_reason; /* points to STATIC string; don't free */
/*
Ssh ssh = c->ssh;
void *sentreply = reply;
+ c->u.a.outstanding_requests--;
if (!sentreply) {
/* Fake SSH_AGENT_FAILURE. */
sentreply = "\0\0\0\1\5";
}
if (reply)
sfree(reply);
+ /*
+ * If we've already seen an incoming EOF but haven't sent an
+ * outgoing one, this may be the moment to send it.
+ */
+ if (c->u.a.outstanding_requests == 0 && (c->closes & CLOSES_RCVD_EOF))
+ sshfwd_write_eof(c);
}
/*
{
int i, j, ret;
unsigned char cookie[8], *ptr;
- struct RSAKey servkey, hostkey;
struct MD5Context md5c;
struct do_ssh1_login_state {
int crLine;
int commentlen;
int dlgret;
Filename *keyfile;
+ struct RSAKey servkey, hostkey;
};
crState(do_ssh1_login_state);
}
memcpy(cookie, ptr, 8);
- if (!ssh1_pkt_getrsakey(pktin, &servkey, &s->keystr1) ||
- !ssh1_pkt_getrsakey(pktin, &hostkey, &s->keystr2)) {
+ if (!ssh1_pkt_getrsakey(pktin, &s->servkey, &s->keystr1) ||
+ !ssh1_pkt_getrsakey(pktin, &s->hostkey, &s->keystr2)) {
bombout(("Failed to read SSH-1 public keys from public key packet"));
crStop(0);
}
char logmsg[80];
logevent("Host key fingerprint is:");
strcpy(logmsg, " ");
- hostkey.comment = NULL;
+ s->hostkey.comment = NULL;
rsa_fingerprint(logmsg + strlen(logmsg),
- sizeof(logmsg) - strlen(logmsg), &hostkey);
+ sizeof(logmsg) - strlen(logmsg), &s->hostkey);
logevent(logmsg);
}
ssh->v1_local_protoflags |= SSH1_PROTOFLAG_SCREEN_NUMBER;
MD5Init(&md5c);
- MD5Update(&md5c, s->keystr2, hostkey.bytes);
- MD5Update(&md5c, s->keystr1, servkey.bytes);
+ MD5Update(&md5c, s->keystr2, s->hostkey.bytes);
+ MD5Update(&md5c, s->keystr1, s->servkey.bytes);
MD5Update(&md5c, cookie, 8);
MD5Final(s->session_id, &md5c);
/*
* Verify that the `bits' and `bytes' parameters match.
*/
- if (hostkey.bits > hostkey.bytes * 8 ||
- servkey.bits > servkey.bytes * 8) {
+ if (s->hostkey.bits > s->hostkey.bytes * 8 ||
+ s->servkey.bits > s->servkey.bytes * 8) {
bombout(("SSH-1 public keys were badly formatted"));
crStop(0);
}
- s->len = (hostkey.bytes > servkey.bytes ? hostkey.bytes : servkey.bytes);
+ s->len = (s->hostkey.bytes > s->servkey.bytes ?
+ s->hostkey.bytes : s->servkey.bytes);
s->rsabuf = snewn(s->len, unsigned char);
/*
* First format the key into a string.
*/
- int len = rsastr_len(&hostkey);
+ int len = rsastr_len(&s->hostkey);
char fingerprint[100];
char *keystr = snewn(len, char);
- rsastr_fmt(keystr, &hostkey);
- rsa_fingerprint(fingerprint, sizeof(fingerprint), &hostkey);
+ rsastr_fmt(keystr, &s->hostkey);
+ rsa_fingerprint(fingerprint, sizeof(fingerprint), &s->hostkey);
ssh_set_frozen(ssh, 1);
s->dlgret = verify_ssh_host_key(ssh->frontend,
s->rsabuf[i] ^= s->session_id[i];
}
- if (hostkey.bytes > servkey.bytes) {
- ret = rsaencrypt(s->rsabuf, 32, &servkey);
+ if (s->hostkey.bytes > s->servkey.bytes) {
+ ret = rsaencrypt(s->rsabuf, 32, &s->servkey);
if (ret)
- ret = rsaencrypt(s->rsabuf, servkey.bytes, &hostkey);
+ ret = rsaencrypt(s->rsabuf, s->servkey.bytes, &s->hostkey);
} else {
- ret = rsaencrypt(s->rsabuf, 32, &hostkey);
+ ret = rsaencrypt(s->rsabuf, 32, &s->hostkey);
if (ret)
- ret = rsaencrypt(s->rsabuf, hostkey.bytes, &servkey);
+ ret = rsaencrypt(s->rsabuf, s->hostkey.bytes, &s->servkey);
}
if (!ret) {
bombout(("SSH-1 public key encryptions failed due to bad formatting"));
ssh->crcda_ctx = crcda_make_context();
logevent("Installing CRC compensation attack detector");
- if (servkey.modulus) {
- sfree(servkey.modulus);
- servkey.modulus = NULL;
+ if (s->servkey.modulus) {
+ sfree(s->servkey.modulus);
+ s->servkey.modulus = NULL;
}
- if (servkey.exponent) {
- sfree(servkey.exponent);
- servkey.exponent = NULL;
+ if (s->servkey.exponent) {
+ sfree(s->servkey.exponent);
+ s->servkey.exponent = NULL;
}
- if (hostkey.modulus) {
- sfree(hostkey.modulus);
- hostkey.modulus = NULL;
+ if (s->hostkey.modulus) {
+ sfree(s->hostkey.modulus);
+ s->hostkey.modulus = NULL;
}
- if (hostkey.exponent) {
- sfree(hostkey.exponent);
- hostkey.exponent = NULL;
+ if (s->hostkey.exponent) {
+ sfree(s->hostkey.exponent);
+ s->hostkey.exponent = NULL;
}
crWaitUntil(pktin);
/* XXX: rport_acceptall may not represent
* what was used to open the original connection,
* since it's reconfigurable. */
- ssh2_pkt_addstring(pktout, "0.0.0.0");
+ ssh2_pkt_addstring(pktout, "");
} else {
- ssh2_pkt_addstring(pktout, "127.0.0.1");
+ ssh2_pkt_addstring(pktout, "localhost");
}
ssh2_pkt_adduint32(pktout, epf->sport);
ssh2_pkt_send(ssh, pktout);
if (epf->saddr) {
ssh2_pkt_addstring(pktout, epf->saddr);
} else if (conf_get_int(conf, CONF_rport_acceptall)) {
- ssh2_pkt_addstring(pktout, "0.0.0.0");
+ ssh2_pkt_addstring(pktout, "");
} else {
- ssh2_pkt_addstring(pktout, "127.0.0.1");
+ ssh2_pkt_addstring(pktout, "localhost");
}
ssh2_pkt_adduint32(pktout, epf->sport);
ssh2_pkt_send(ssh, pktout);
c->type = CHAN_AGENT; /* identify channel type */
c->u.a.lensofar = 0;
c->u.a.message = NULL;
+ c->u.a.outstanding_requests = 0;
add234(ssh->channels, c);
send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,
PKT_INT, c->remoteid, PKT_INT, c->localid,
if (c->u.a.lensofar == c->u.a.totallen) {
void *reply;
int replylen;
+ c->u.a.outstanding_requests++;
if (agent_query(c->u.a.message,
c->u.a.totallen,
&reply, &replylen,
if (c->u.a.lensofar == c->u.a.totallen) {
void *reply;
int replylen;
+ c->u.a.outstanding_requests++;
if (agent_query(c->u.a.message,
c->u.a.totallen,
&reply, &replylen,
if (c->type == CHAN_X11) {
x11_send_eof(c->u.x11.s);
} else if (c->type == CHAN_AGENT) {
- /* Manufacture an outgoing EOF in response to the incoming one. */
- sshfwd_write_eof(c);
+ if (c->u.a.outstanding_requests == 0) {
+ /* Manufacture an outgoing EOF in response to the incoming one. */
+ sshfwd_write_eof(c);
+ }
} else if (c->type == CHAN_SOCKDATA) {
pfd_send_eof(c->u.pfd.s);
} else if (c->type == CHAN_MAINSESSION) {
else {
c->type = CHAN_AGENT; /* identify channel type */
c->u.a.lensofar = 0;
+ c->u.a.outstanding_requests = 0;
}
} else {
error = "Unsupported channel type requested";
*/
if (conf_get_int(ssh->conf, CONF_ssh_no_shell)) {
ssh->mainchan = NULL;
- } else if (*conf_get_str(ssh->conf, CONF_ssh_nc_host)) {
- /*
- * Just start a direct-tcpip channel and use it as the main
- * channel.
- */
+ } else {
ssh->mainchan = snew(struct ssh_channel);
ssh->mainchan->ssh = ssh;
ssh2_channel_init(ssh->mainchan);
- logeventf(ssh,
- "Opening direct-tcpip channel to %s:%d in place of session",
- conf_get_str(ssh->conf, CONF_ssh_nc_host),
- conf_get_int(ssh->conf, CONF_ssh_nc_port));
- s->pktout = ssh2_chanopen_init(ssh->mainchan, "direct-tcpip");
- ssh2_pkt_addstring(s->pktout, conf_get_str(ssh->conf, CONF_ssh_nc_host));
- ssh2_pkt_adduint32(s->pktout, conf_get_int(ssh->conf, CONF_ssh_nc_port));
- /*
- * There's nothing meaningful to put in the originator
- * fields, but some servers insist on syntactically correct
- * information.
- */
- ssh2_pkt_addstring(s->pktout, "0.0.0.0");
- ssh2_pkt_adduint32(s->pktout, 0);
- ssh2_pkt_send(ssh, s->pktout);
- crWaitUntilV(pktin);
- if (pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {
- bombout(("Server refused to open a direct-tcpip channel"));
- crStopV;
- /* FIXME: error data comes back in FAILURE packet */
- }
- if (ssh_pkt_getuint32(pktin) != ssh->mainchan->localid) {
- bombout(("Server's channel confirmation cited wrong channel"));
- crStopV;
+ if (*conf_get_str(ssh->conf, CONF_ssh_nc_host)) {
+ /*
+ * Just start a direct-tcpip channel and use it as the main
+ * channel.
+ */
+ ssh_send_port_open(ssh->mainchan,
+ conf_get_str(ssh->conf, CONF_ssh_nc_host),
+ conf_get_int(ssh->conf, CONF_ssh_nc_port),
+ "main channel");
+ ssh->ncmode = TRUE;
+ } else {
+ s->pktout = ssh2_chanopen_init(ssh->mainchan, "session");
+ logevent("Opening session as main channel");
+ ssh2_pkt_send(ssh, s->pktout);
+ ssh->ncmode = FALSE;
}
- ssh->mainchan->remoteid = ssh_pkt_getuint32(pktin);
- ssh->mainchan->halfopen = FALSE;
- ssh->mainchan->type = CHAN_MAINSESSION;
- ssh->mainchan->v.v2.remwindow = ssh_pkt_getuint32(pktin);
- ssh->mainchan->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin);
- add234(ssh->channels, ssh->mainchan);
- update_specials_menu(ssh->frontend);
- logevent("Opened direct-tcpip channel");
- ssh->ncmode = TRUE;
- } else {
- ssh->mainchan = snew(struct ssh_channel);
- ssh->mainchan->ssh = ssh;
- ssh2_channel_init(ssh->mainchan);
- s->pktout = ssh2_chanopen_init(ssh->mainchan, "session");
- ssh2_pkt_send(ssh, s->pktout);
crWaitUntilV(pktin);
if (pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {
- bombout(("Server refused to open a session"));
+ bombout(("Server refused to open channel"));
crStopV;
/* FIXME: error data comes back in FAILURE packet */
}
ssh->mainchan->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin);
add234(ssh->channels, ssh->mainchan);
update_specials_menu(ssh->frontend);
- logevent("Opened channel for session");
- ssh->ncmode = FALSE;
+ logevent("Opened main channel");
}
/*
ssh->packet_dispatch[SSH2_MSG_DEBUG] = ssh2_msg_debug;
}
-static void ssh2_timer(void *ctx, long now)
+static void ssh2_timer(void *ctx, unsigned long now)
{
Ssh ssh = (Ssh)ctx;
return;
if (!ssh->kex_in_progress && conf_get_int(ssh->conf, CONF_ssh_rekey_time) != 0 &&
- now - ssh->next_rekey >= 0) {
+ now == ssh->next_rekey) {
do_ssh2_transport(ssh, "timeout", -1, NULL);
}
}
while (ssh->qhead) {
struct queued_handler *qh = ssh->qhead;
ssh->qhead = qh->next;
- sfree(ssh->qhead);
+ sfree(qh);
}
ssh->qhead = ssh->qtail = NULL;
rekey_time = conf_get_int(conf, CONF_ssh_rekey_time);
if (conf_get_int(ssh->conf, CONF_ssh_rekey_time) != rekey_time &&
rekey_time != 0) {
- long new_next = ssh->last_rekey + rekey_time*60*TICKSPERSEC;
- long now = GETTICKCOUNT();
+ unsigned long new_next = ssh->last_rekey + rekey_time*60*TICKSPERSEC;
+ unsigned long now = GETTICKCOUNT();
- if (new_next - now < 0) {
+ if (now - ssh->last_rekey > rekey_time*60*TICKSPERSEC) {
rekeying = "timeout shortened";
} else {
ssh->next_rekey = schedule_timer(new_next - now, ssh2_timer, ssh);
Ssh ssh = c->ssh;
struct Packet *pktout;
- logeventf(ssh, "Opening forwarded connection to %s:%d", hostname, port);
+ logeventf(ssh, "Opening connection to %s:%d for %s", hostname, port, org);
if (ssh->version == 1) {
send_packet(ssh, SSH1_MSG_PORT_OPEN,