diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2000-01-10 10:12:53 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2000-01-10 10:12:53 +0000 |
commit | 81d4e173fb94de00dee8adcdb06e0e3c364c1ca5 (patch) | |
tree | 46619917cabb98073eb08125bbfe59ac1e60e4fe /usr.bin/ssh/channels.c | |
parent | b01fae556319b04966bedf0ce1ae8a4cf21d35b5 (diff) |
discard data for channel if state != CHAN_OUTPUT_OPEN, fixes lockup
Diffstat (limited to 'usr.bin/ssh/channels.c')
-rw-r--r-- | usr.bin/ssh/channels.c | 63 |
1 files changed, 35 insertions, 28 deletions
diff --git a/usr.bin/ssh/channels.c b/usr.bin/ssh/channels.c index 9d6c4a70246..3f32ea9a5cd 100644 --- a/usr.bin/ssh/channels.c +++ b/usr.bin/ssh/channels.c @@ -16,7 +16,7 @@ */ #include "includes.h" -RCSID("$Id: channels.c,v 1.36 2000/01/04 07:52:03 markus Exp $"); +RCSID("$Id: channels.c,v 1.37 2000/01/10 10:12:52 markus Exp $"); #include "ssh.h" #include "packet.h" @@ -533,10 +533,19 @@ channel_output_poll() for (i = 0; i < channels_alloc; i++) { ch = &channels[i]; + /* We are only interested in channels that can have buffered incoming data. */ - if (ch->type != SSH_CHANNEL_OPEN && - ch->type != SSH_CHANNEL_INPUT_DRAINING) - continue; + if (compat13) { + if (ch->type != SSH_CHANNEL_OPEN && + ch->type != SSH_CHANNEL_INPUT_DRAINING) + continue; + } else { + if (ch->type != SSH_CHANNEL_OPEN) + continue; + if (ch->istate != CHAN_INPUT_OPEN && + ch->istate != CHAN_INPUT_WAIT_DRAIN) + continue; + } /* Get the amount of buffered data for this channel. */ len = buffer_len(&ch->input); @@ -576,25 +585,33 @@ channel_output_poll() void channel_input_data(int payload_len) { - int channel; + int id; char *data; unsigned int data_len; + Channel *ch; /* Get the channel number and verify it. */ - channel = packet_get_int(); - if (channel < 0 || channel >= channels_alloc || - channels[channel].type == SSH_CHANNEL_FREE) - packet_disconnect("Received data for nonexistent channel %d.", channel); + id = packet_get_int(); + if (id < 0 || id >= channels_alloc) + packet_disconnect("Received data for nonexistent channel %d.", id); + ch = &channels[id]; + + if (ch->type == SSH_CHANNEL_FREE) + packet_disconnect("Received data for free channel %d.", ch->self); /* Ignore any data for non-open channels (might happen on close) */ - if (channels[channel].type != SSH_CHANNEL_OPEN && - channels[channel].type != SSH_CHANNEL_X11_OPEN) + if (ch->type != SSH_CHANNEL_OPEN && + ch->type != SSH_CHANNEL_X11_OPEN) + return; + + /* same for protocol 1.5 if output end is no longer open */ + if (!compat13 && ch->ostate != CHAN_OUTPUT_OPEN) return; /* Get the data. */ data = packet_get_string(&data_len); packet_integrity_check(payload_len, 4 + 4 + data_len, SSH_MSG_CHANNEL_DATA); - buffer_append(&channels[channel].output, data, data_len); + buffer_append(&ch->output, data, data_len); xfree(data); } @@ -611,23 +628,11 @@ channel_not_very_much_buffered_data() for (i = 0; i < channels_alloc; i++) { ch = &channels[i]; - switch (ch->type) { - case SSH_CHANNEL_X11_LISTENER: - case SSH_CHANNEL_PORT_LISTENER: - case SSH_CHANNEL_AUTH_SOCKET: - continue; - case SSH_CHANNEL_OPEN: + if (ch->type == SSH_CHANNEL_OPEN) { if (buffer_len(&ch->input) > packet_get_maxsize()) return 0; if (buffer_len(&ch->output) > packet_get_maxsize()) return 0; - continue; - case SSH_CHANNEL_INPUT_DRAINING: - case SSH_CHANNEL_OUTPUT_DRAINING: - case SSH_CHANNEL_X11_OPEN: - case SSH_CHANNEL_FREE: - default: - continue; } } return 1; @@ -854,9 +859,11 @@ channel_open_message() case SSH_CHANNEL_X11_OPEN: case SSH_CHANNEL_INPUT_DRAINING: case SSH_CHANNEL_OUTPUT_DRAINING: - snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d o%d)\r\n", - c->self, c->remote_name, - c->type, c->remote_id, c->istate, c->ostate); + snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d/%d o%d/%d)\r\n", + c->self, c->remote_name, + c->type, c->remote_id, + c->istate, buffer_len(&c->input), + c->ostate, buffer_len(&c->output)); buffer_append(&buffer, buf, strlen(buf)); continue; default: |