struct Packet *pktin);
static void ssh_channel_init(struct ssh_channel *c);
static struct ssh_channel *ssh_channel_msg(Ssh ssh, struct Packet *pktin);
+static void ssh_channel_got_eof(struct ssh_channel *c);
static void ssh2_channel_check_close(struct ssh_channel *c);
+static void ssh_channel_close_local(struct ssh_channel *c, char const *reason);
static void ssh_channel_destroy(struct ssh_channel *c);
static void ssh_channel_unthrottle(struct ssh_channel *c, int bufsize);
static void ssh2_msg_something_unimplemented(Ssh ssh, struct Packet *pktin);
CHAN_X11,
CHAN_AGENT,
CHAN_SOCKDATA,
- CHAN_SOCKDATA_DORMANT, /* one the remote hasn't confirmed */
/*
* CHAN_SHARING indicates a channel which is tracked here on
* behalf of a connection-sharing downstream. We do almost nothing
*/
if (ssh->channels) {
while (NULL != (c = index234(ssh->channels, 0))) {
- switch (c->type) {
- case CHAN_X11:
- x11_close(c->u.x11.xconn);
- break;
- case CHAN_SOCKDATA:
- case CHAN_SOCKDATA_DORMANT:
- pfd_close(c->u.pfd.pf);
- break;
- }
+ ssh_channel_close_local(c, NULL);
del234(ssh->channels, c); /* moving next one to index 0 */
if (ssh->version == 2)
bufchain_clear(&c->v.v2.outbuffer);
void sshfwd_unclean_close(struct ssh_channel *c, const char *err)
{
Ssh ssh = c->ssh;
+ char *reason;
if (ssh->state == SSH_STATE_CLOSED)
return;
- switch (c->type) {
- case CHAN_X11:
- x11_close(c->u.x11.xconn);
- logeventf(ssh, "Forwarded X11 connection terminated due to local "
- "error: %s", err);
- break;
- case CHAN_SOCKDATA:
- case CHAN_SOCKDATA_DORMANT:
- pfd_close(c->u.pfd.pf);
- logeventf(ssh, "Forwarded port closed due to local error: %s", err);
- break;
- }
- c->type = CHAN_ZOMBIE;
+ reason = dupprintf("due to local error: %s", err);
+ ssh_channel_close_local(c, reason);
+ sfree(reason);
c->pending_eof = FALSE; /* this will confuse a zombie channel */
ssh2_channel_check_close(c);
struct ssh_channel *c;
c = ssh_channel_msg(ssh, pktin);
- if (c && c->type == CHAN_SOCKDATA_DORMANT) {
+ if (c && c->type == CHAN_SOCKDATA) {
c->remoteid = ssh_pkt_getuint32(pktin);
c->halfopen = FALSE;
- c->type = CHAN_SOCKDATA;
c->throttling_conn = 0;
pfd_confirm(c->u.pfd.pf);
}
struct ssh_channel *c;
c = ssh_channel_msg(ssh, pktin);
- if (c && c->type == CHAN_SOCKDATA_DORMANT) {
+ if (c && c->type == CHAN_SOCKDATA) {
logevent("Forwarded connection refused by server");
pfd_close(c->u.pfd.pf);
del234(ssh->channels, c);
c = ssh_channel_msg(ssh, pktin);
if (c) {
- if (pktin->type == SSH1_MSG_CHANNEL_CLOSE &&
- !(c->closes & CLOSES_RCVD_EOF)) {
+ if (pktin->type == SSH1_MSG_CHANNEL_CLOSE) {
/*
* Received CHANNEL_CLOSE, which we translate into
* outgoing EOF.
*/
- int send_close = FALSE;
-
- c->closes |= CLOSES_RCVD_EOF;
-
- switch (c->type) {
- case CHAN_X11:
- if (c->u.x11.xconn)
- x11_send_eof(c->u.x11.xconn);
- else
- send_close = TRUE;
- break;
- case CHAN_SOCKDATA:
- if (c->u.pfd.pf)
- pfd_send_eof(c->u.pfd.pf);
- else
- send_close = TRUE;
- break;
- case CHAN_AGENT:
- send_close = TRUE;
- break;
- }
-
- if (send_close && !(c->closes & CLOSES_SENT_EOF)) {
- send_packet(ssh, SSH1_MSG_CHANNEL_CLOSE, PKT_INT, c->remoteid,
- PKT_END);
- c->closes |= CLOSES_SENT_EOF;
- }
+ ssh_channel_got_eof(c);
}
if (pktin->type == SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION &&
s->fingerprint = ssh2_fingerprint(ssh->hostkey, s->hkey);
logevent("Storing additional host key for this host:");
logevent(s->fingerprint);
+ sfree(s->fingerprint);
store_host_key(ssh->savedhost, ssh->savedport,
ssh->hostkey->keytype, s->keystr);
ssh->cross_certifying = FALSE;
{
char *data;
int length;
+ unsigned ext_type = 0; /* 0 means not extended */
struct ssh_channel *c;
c = ssh_channel_msg(ssh, pktin);
if (!c)
return;
- if (pktin->type == SSH2_MSG_CHANNEL_EXTENDED_DATA &&
- ssh_pkt_getuint32(pktin) != SSH2_EXTENDED_DATA_STDERR)
- return; /* extended but not stderr */
+ if (pktin->type == SSH2_MSG_CHANNEL_EXTENDED_DATA)
+ ext_type = ssh_pkt_getuint32(pktin);
ssh_pkt_getstring(pktin, &data, &length);
if (data) {
int bufsize;
c->v.v2.locwindow -= length;
c->v.v2.remlocwin -= length;
- bufsize = ssh_channel_data(c, pktin->type ==
- SSH2_MSG_CHANNEL_EXTENDED_DATA,
+ if (ext_type != 0 && ext_type != SSH2_EXTENDED_DATA_STDERR)
+ length = 0; /* Don't do anything with unknown extended data. */
+ bufsize = ssh_channel_data(c, ext_type == SSH2_EXTENDED_DATA_STDERR,
data, length);
/*
* If it looks like the remote end hit the end of its window,
sfree(buf);
}
-static void ssh_channel_destroy(struct ssh_channel *c)
+/*
+ * Close any local socket and free any local resources associated with
+ * a channel. This converts the channel into a CHAN_ZOMBIE.
+ */
+static void ssh_channel_close_local(struct ssh_channel *c, char const *reason)
{
Ssh ssh = c->ssh;
+ char const *msg = NULL;
switch (c->type) {
case CHAN_MAINSESSION:
update_specials_menu(ssh->frontend);
break;
case CHAN_X11:
- if (c->u.x11.xconn != NULL)
- x11_close(c->u.x11.xconn);
- logevent("Forwarded X11 connection terminated");
+ assert(c->u.x11.xconn != NULL);
+ x11_close(c->u.x11.xconn);
+ msg = "Forwarded X11 connection terminated";
break;
case CHAN_AGENT:
sfree(c->u.a.message);
break;
case CHAN_SOCKDATA:
- if (c->u.pfd.pf != NULL)
- pfd_close(c->u.pfd.pf);
- logevent("Forwarded port closed");
+ assert(c->u.pfd.pf != NULL);
+ pfd_close(c->u.pfd.pf);
+ msg = "Forwarded port closed";
break;
}
+ c->type = CHAN_ZOMBIE;
+ if (msg != NULL) {
+ if (reason != NULL)
+ logeventf(ssh, "%s %s", msg, reason);
+ else
+ logevent(msg);
+ }
+}
+
+static void ssh_channel_destroy(struct ssh_channel *c)
+{
+ Ssh ssh = c->ssh;
+
+ ssh_channel_close_local(c, NULL);
del234(ssh->channels, c);
if (ssh->version == 2) {
}
}
-static void ssh2_channel_got_eof(struct ssh_channel *c)
+static void ssh_channel_got_eof(struct ssh_channel *c)
{
if (c->closes & CLOSES_RCVD_EOF)
return; /* already seen EOF */
c->closes |= CLOSES_RCVD_EOF;
if (c->type == CHAN_X11) {
+ assert(c->u.x11.xconn != NULL);
x11_send_eof(c->u.x11.xconn);
} else if (c->type == CHAN_AGENT) {
if (c->u.a.outstanding_requests == 0) {
sshfwd_write_eof(c);
}
} else if (c->type == CHAN_SOCKDATA) {
+ assert(c->u.pfd.pf != NULL);
pfd_send_eof(c->u.pfd.pf);
} else if (c->type == CHAN_MAINSESSION) {
Ssh ssh = c->ssh;
}
ssh->sent_console_eof = TRUE;
}
-
- ssh2_channel_check_close(c);
}
static void ssh2_msg_channel_eof(Ssh ssh, struct Packet *pktin)
c = ssh_channel_msg(ssh, pktin);
if (!c)
return;
- ssh2_channel_got_eof(c);
+ ssh_channel_got_eof(c);
+ ssh2_channel_check_close(c);
}
static void ssh2_msg_channel_close(Ssh ssh, struct Packet *pktin)
* When we receive CLOSE on a channel, we assume it comes with an
* implied EOF if we haven't seen EOF yet.
*/
- ssh2_channel_got_eof(c);
+ ssh_channel_got_eof(c);
if (!(ssh->remote_bugs & BUG_SENDS_LATE_REQUEST_REPLY)) {
/*
c->v.v2.remwindow = ssh_pkt_getuint32(pktin);
c->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin);
- if (c->type == CHAN_SOCKDATA_DORMANT) {
- c->type = CHAN_SOCKDATA;
- if (c->u.pfd.pf)
- pfd_confirm(c->u.pfd.pf);
+ if (c->type == CHAN_SOCKDATA) {
+ assert(c->u.pfd.pf != NULL);
+ pfd_confirm(c->u.pfd.pf);
} else if (c->type == CHAN_ZOMBIE) {
/*
* This case can occur if a local socket error occurred
return;
assert(c->halfopen); /* ssh_channel_msg will have enforced this */
- if (c->type == CHAN_SOCKDATA_DORMANT) {
+ if (c->type == CHAN_SOCKDATA) {
reason_code = ssh_pkt_getuint32(pktin);
if (reason_code >= lenof(reasons))
reason_code = 0; /* ensure reasons[reason_code] in range */
if (ssh->channels) {
while ((c = delpos234(ssh->channels, 0)) != NULL) {
- switch (c->type) {
- case CHAN_X11:
- if (c->u.x11.xconn != NULL)
- x11_close(c->u.x11.xconn);
- break;
- case CHAN_SOCKDATA:
- case CHAN_SOCKDATA_DORMANT:
- if (c->u.pfd.pf != NULL)
- pfd_close(c->u.pfd.pf);
- break;
- }
+ ssh_channel_close_local(c, NULL);
if (ssh->version == 2) {
struct outstanding_channel_request *ocr, *nocr;
ocr = c->v.v2.chanreq_head;
c->ssh = ssh;
ssh_channel_init(c);
c->halfopen = TRUE;
- c->type = CHAN_SOCKDATA_DORMANT;/* identify channel type */
+ c->type = CHAN_SOCKDATA;/* identify channel type */
c->u.pfd.pf = pf;
return c;
}