summaryrefslogtreecommitdiff
path: root/usr.bin/ssh/channels.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/ssh/channels.c')
-rw-r--r--usr.bin/ssh/channels.c166
1 files changed, 109 insertions, 57 deletions
diff --git a/usr.bin/ssh/channels.c b/usr.bin/ssh/channels.c
index a0eb88f6c91..6637011ebdf 100644
--- a/usr.bin/ssh/channels.c
+++ b/usr.bin/ssh/channels.c
@@ -16,7 +16,7 @@ arbitrary tcp/ip connections, and the authentication agent connection.
*/
#include "includes.h"
-RCSID("$Id: channels.c,v 1.13 1999/10/14 18:17:42 markus Exp $");
+RCSID("$Id: channels.c,v 1.14 1999/10/16 20:47:13 markus Exp $");
#include "ssh.h"
#include "packet.h"
@@ -26,42 +26,16 @@ RCSID("$Id: channels.c,v 1.13 1999/10/14 18:17:42 markus Exp $");
#include "uidswap.h"
#include "servconf.h"
+#include "channels.h"
+#include "nchan.h"
+#include "compat.h"
+
/* Maximum number of fake X11 displays to try. */
#define MAX_DISPLAYS 1000
-/* Definitions for channel types. */
-#define SSH_CHANNEL_FREE 0 /* This channel is free (unused). */
-#define SSH_CHANNEL_X11_LISTENER 1 /* Listening for inet X11 conn. */
-#define SSH_CHANNEL_PORT_LISTENER 2 /* Listening on a port. */
-#define SSH_CHANNEL_OPENING 3 /* waiting for confirmation */
-#define SSH_CHANNEL_OPEN 4 /* normal open two-way channel */
-#define SSH_CHANNEL_CLOSED 5 /* waiting for close confirmation */
-/* SSH_CHANNEL_AUTH_FD 6 authentication fd */
-#define SSH_CHANNEL_AUTH_SOCKET 7 /* authentication socket */
-/* SSH_CHANNEL_AUTH_SOCKET_FD 8 connection to auth socket */
-#define SSH_CHANNEL_X11_OPEN 9 /* reading first X11 packet */
-#define SSH_CHANNEL_INPUT_DRAINING 10 /* sending remaining data to conn */
-#define SSH_CHANNEL_OUTPUT_DRAINING 11 /* sending remaining data to app */
-
/* Max len of agent socket */
#define MAX_SOCKET_NAME 100
-/* Data structure for channel data. This is iniailized in channel_allocate
- and cleared in channel_free. */
-
-typedef struct
-{
- int type;
- int sock;
- int remote_id;
- Buffer input;
- Buffer output;
- char path[200]; /* path for unix domain sockets, or host name for forwards */
- int host_port; /* port to connect for forwards */
- int listening_port; /* port being listened for forwards */
- char *remote_name;
-} Channel;
-
/* Pointer to an array containing all allocated channels. The array is
dynamically extended as needed. */
static Channel *channels = NULL;
@@ -160,8 +134,10 @@ int channel_allocate(int type, int sock, char *remote_name)
/* Found a free slot. Initialize the fields and return its number. */
buffer_init(&channels[i].input);
buffer_init(&channels[i].output);
+ channels[i].self = i;
channels[i].type = type;
channels[i].sock = sock;
+ channels[i].flags = 0;
channels[i].remote_id = -1;
channels[i].remote_name = remote_name;
return i;
@@ -178,8 +154,10 @@ int channel_allocate(int type, int sock, char *remote_name)
available. Initialize and return its number. */
buffer_init(&channels[old_channels].input);
buffer_init(&channels[old_channels].output);
+ channels[old_channels].self = old_channels;
channels[old_channels].type = type;
channels[old_channels].sock = sock;
+ channels[old_channels].flags = 0;
channels[old_channels].remote_id = -1;
channels[old_channels].remote_name = remote_name;
return old_channels;
@@ -191,7 +169,8 @@ void channel_free(int channel)
{
assert(channel >= 0 && channel < channels_alloc &&
channels[channel].type != SSH_CHANNEL_FREE);
- shutdown(channels[channel].sock, SHUT_RDWR);
+ if(compat13)
+ shutdown(channels[channel].sock, SHUT_RDWR);
close(channels[channel].sock);
buffer_free(&channels[channel].input);
buffer_free(&channels[channel].output);
@@ -226,13 +205,32 @@ void channel_prepare_select(fd_set *readset, fd_set *writeset)
break;
case SSH_CHANNEL_OPEN:
- if (buffer_len(&ch->input) < 32768)
- FD_SET(ch->sock, readset);
- if (buffer_len(&ch->output) > 0)
- FD_SET(ch->sock, writeset);
- break;
+ if(compat13){
+ if (buffer_len(&ch->input) < 32768)
+ FD_SET(ch->sock, readset);
+ if (buffer_len(&ch->output) > 0)
+ FD_SET(ch->sock, writeset);
+ break;
+ }
+ /* test whether sockets are 'alive' for read/write */
+ if (!(ch->flags & CHAN_SHUT_RD))
+ if (buffer_len(&ch->input) < 32768)
+ FD_SET(ch->sock, readset);
+ if (!(ch->flags & CHAN_SHUT_WR)){
+ if (buffer_len(&ch->output) > 0){
+ FD_SET(ch->sock, writeset);
+ }else if(ch->flags & CHAN_IEOF_RCVD){
+ /* if output-buffer empty AND IEOF received,
+ we won't get more data for writing */
+ chan_shutdown_write(ch);
+ chan_send_oclose(ch);
+ }
+ }
+ break;
case SSH_CHANNEL_INPUT_DRAINING:
+ if (!compat13)
+ fatal("cannot happen: IN_DRAIN");
if (buffer_len(&ch->input) == 0)
{
packet_start(SSH_MSG_CHANNEL_CLOSE);
@@ -245,6 +243,8 @@ void channel_prepare_select(fd_set *readset, fd_set *writeset)
break;
case SSH_CHANNEL_OUTPUT_DRAINING:
+ if (!compat13)
+ fatal("cannot happen: OUT_DRAIN");
if (buffer_len(&ch->output) == 0)
{
/* debug("Freeing channel %d after output drain.", i); */
@@ -327,12 +327,19 @@ void channel_prepare_select(fd_set *readset, fd_set *writeset)
log("X11 connection rejected because of wrong authentication.\r\n");
buffer_clear(&ch->input);
buffer_clear(&ch->output);
- close(ch->sock);
- ch->sock = -1;
- ch->type = SSH_CHANNEL_CLOSED;
- packet_start(SSH_MSG_CHANNEL_CLOSE);
- packet_put_int(ch->remote_id);
- packet_send();
+ if (compat13) {
+ close(ch->sock);
+ ch->sock = -1;
+ ch->type = SSH_CHANNEL_CLOSED;
+ packet_start(SSH_MSG_CHANNEL_CLOSE);
+ packet_put_int(ch->remote_id);
+ packet_send();
+ }else{
+ chan_shutdown_read(ch); /* shutdown, since close() does not update ch->flags */
+ chan_send_ieof(ch); /* no need to wait for output-buffer */
+ chan_shutdown_write(ch);
+ chan_send_oclose(ch);
+ }
break;
case SSH_CHANNEL_FREE:
@@ -441,15 +448,24 @@ void channel_after_select(fd_set *readset, fd_set *writeset)
/* This is an open two-way communication channel. It is not of
interest to us at this point what kind of data is being
transmitted. */
- /* Read available incoming data and append it to buffer. */
+
+ /* Read available incoming data and append it to buffer;
+ shutdown socket, if read or write failes */
if (FD_ISSET(ch->sock, readset))
{
len = read(ch->sock, buf, sizeof(buf));
if (len <= 0)
{
- buffer_consume(&ch->output, buffer_len(&ch->output));
- ch->type = SSH_CHANNEL_INPUT_DRAINING;
- debug("Channel %d status set to input draining.", i);
+ if (compat13) {
+ buffer_consume(&ch->output, buffer_len(&ch->output));
+ ch->type = SSH_CHANNEL_INPUT_DRAINING;
+ debug("Channel %d status set to input draining.", i);
+ }else{
+ buffer_consume(&ch->output, buffer_len(&ch->output));
+ chan_shutdown_read(ch);
+ /* we have to wait until the input-buffer has been
+ sent to our peer before we can send IEOF */
+ }
break;
}
buffer_append(&ch->input, buf, len);
@@ -461,16 +477,25 @@ void channel_after_select(fd_set *readset, fd_set *writeset)
buffer_len(&ch->output));
if (len <= 0)
{
- buffer_consume(&ch->output, buffer_len(&ch->output));
- debug("Channel %d status set to input draining.", i);
- ch->type = SSH_CHANNEL_INPUT_DRAINING;
+ if (compat13) {
+ buffer_consume(&ch->output, buffer_len(&ch->output));
+ debug("Channel %d status set to input draining.", i);
+ ch->type = SSH_CHANNEL_INPUT_DRAINING;
+ }else{
+ buffer_consume(&ch->output, buffer_len(&ch->output));
+ chan_shutdown_write(ch);
+ chan_send_oclose(ch);
+ }
break;
}
buffer_consume(&ch->output, len);
}
+ chan_del_if_dead(ch);
break;
case SSH_CHANNEL_OUTPUT_DRAINING:
+ if (!compat13)
+ fatal("cannot happen: OUT_DRAIN");
/* Send buffered output data to the socket. */
if (FD_ISSET(ch->sock, writeset) && buffer_len(&ch->output) > 0)
{
@@ -528,6 +553,14 @@ void channel_output_poll()
packet_send();
buffer_consume(&ch->input, len);
}
+ else if(ch->flags & CHAN_SHUT_RD)
+ {
+ if (compat13)
+ fatal("cannot happen: CHAN_SHUT_RD set for proto 1.3");
+ /* input-buffer is empty and read-socket shutdown:
+ tell peer, that we will not send more data: send IEOF */
+ chan_send_ieof(ch);
+ }
}
}
@@ -570,7 +603,7 @@ int channel_not_very_much_buffered_data()
for (i = 0; i < channels_alloc; i++)
{
ch = &channels[i];
- switch (channels[i].type)
+ switch (ch->type)
{
case SSH_CHANNEL_X11_LISTENER:
case SSH_CHANNEL_PORT_LISTENER:
@@ -593,7 +626,7 @@ int channel_not_very_much_buffered_data()
return 1;
}
-/* This is called after receiving CHANNEL_CLOSE. */
+/* This is called after receiving CHANNEL_CLOSE/IEOF. */
void channel_input_close()
{
@@ -605,6 +638,12 @@ void channel_input_close()
channels[channel].type == SSH_CHANNEL_FREE)
packet_disconnect("Received data for nonexistent channel %d.", channel);
+ if(!compat13){
+ /* proto version 1.5 overloads CLOSE with IEOF */
+ chan_rcvd_ieof(&channels[channel]);
+ return;
+ }
+
/* Send a confirmation that we have closed the channel and no more data is
coming for it. */
packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION);
@@ -628,7 +667,7 @@ void channel_input_close()
}
}
-/* This is called after receiving CHANNEL_CLOSE_CONFIRMATION. */
+/* This is called after receiving CHANNEL_CLOSE_CONFIRMATION/OCLOSE. */
void channel_input_close_confirmation()
{
@@ -639,6 +678,13 @@ void channel_input_close_confirmation()
if (channel < 0 || channel >= channels_alloc)
packet_disconnect("Received close confirmation for out-of-range channel %d.",
channel);
+
+ if(!compat13){
+ /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */
+ chan_rcvd_oclose(&channels[channel]);
+ return;
+ }
+
if (channels[channel].type != SSH_CHANNEL_CLOSED)
packet_disconnect("Received close confirmation for non-closed channel %d (type %d).",
channel, channels[channel].type);
@@ -748,8 +794,11 @@ int channel_still_open()
case SSH_CHANNEL_OPENING:
case SSH_CHANNEL_OPEN:
case SSH_CHANNEL_X11_OPEN:
+ return 1;
case SSH_CHANNEL_INPUT_DRAINING:
case SSH_CHANNEL_OUTPUT_DRAINING:
+ if (!compat13)
+ fatal("cannot happen: OUT_DRAIN");
return 1;
default:
fatal("channel_still_open: bad channel type %d", channels[i].type);
@@ -771,8 +820,9 @@ char *channel_open_message()
buffer_init(&buffer);
sprintf(buf, "The following connections are open:\r\n");
buffer_append(&buffer, buf, strlen(buf));
- for (i = 0; i < channels_alloc; i++)
- switch (channels[i].type)
+ for (i = 0; i < channels_alloc; i++){
+ Channel *c=&channels[i];
+ switch (c->type)
{
case SSH_CHANNEL_FREE:
case SSH_CHANNEL_X11_LISTENER:
@@ -785,13 +835,15 @@ char *channel_open_message()
case SSH_CHANNEL_X11_OPEN:
case SSH_CHANNEL_INPUT_DRAINING:
case SSH_CHANNEL_OUTPUT_DRAINING:
- sprintf(buf, " %.300s\r\n", channels[i].remote_name);
+ snprintf(buf, sizeof buf, " #%d/%d %.300s\r\n",
+ c->self,c->type,c->remote_name);
buffer_append(&buffer, buf, strlen(buf));
continue;
default:
- fatal("channel_still_open: bad channel type %d", channels[i].type);
+ fatal("channel_still_open: bad channel type %d", c->type);
/*NOTREACHED*/
}
+ }
buffer_append(&buffer, "\0", 1);
cp = xstrdup(buffer_ptr(&buffer));
buffer_free(&buffer);