diff options
Diffstat (limited to 'channels.c')
-rw-r--r-- | channels.c | 2427 |
1 files changed, 1187 insertions, 1240 deletions
@@ -1,22 +1,22 @@ /* - -channels.c - -Author: Tatu Ylonen <ylo@cs.hut.fi> - -Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland - All rights reserved - -Created: Fri Mar 24 16:35:24 1995 ylo - -This file contains functions for generic socket connection forwarding. -There is also code for initiating connection forwarding for X11 connections, -arbitrary tcp/ip connections, and the authentication agent connection. - -*/ + * + * channels.c + * + * Author: Tatu Ylonen <ylo@cs.hut.fi> + * + * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + * All rights reserved + * + * Created: Fri Mar 24 16:35:24 1995 ylo + * + * This file contains functions for generic socket connection forwarding. + * There is also code for initiating connection forwarding for X11 connections, + * arbitrary tcp/ip connections, and the authentication agent connection. + * + */ #include "includes.h" -RCSID("$Id: channels.c,v 1.6 1999/11/21 02:23:53 damien Exp $"); +RCSID("$Id: channels.c,v 1.7 1999/11/24 13:26:22 damien Exp $"); #include "ssh.h" #include "packet.h" @@ -52,7 +52,7 @@ static int channel_max_fd_value = 0; /* Name and directory of socket for authentication agent forwarding. */ static char *channel_forwarded_auth_socket_name = NULL; -static char *channel_forwarded_auth_socket_dir = NULL; +static char *channel_forwarded_auth_socket_dir = NULL; /* Saved X11 authentication protocol name. */ char *x11_saved_proto = NULL; @@ -70,10 +70,9 @@ unsigned int x11_fake_data_len; The local sides of any remote forwards are stored in this array to prevent a corrupt remote server from accessing arbitrary TCP/IP ports on our local network (which might be behind a firewall). */ -typedef struct -{ - char *host; /* Host name. */ - int port; /* Port number. */ +typedef struct { + char *host; /* Host name. */ + int port; /* Port number. */ } ForwardPermission; /* List of all permitted host/port pairs to connect. */ @@ -90,1056 +89,1015 @@ static int have_hostname_in_open = 0; /* Sets specific protocol options. */ -void channel_set_options(int hostname_in_open) +void +channel_set_options(int hostname_in_open) { - have_hostname_in_open = hostname_in_open; + have_hostname_in_open = hostname_in_open; } /* Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually called by the server, because the user could connect to any port anyway, and the server has no way to know but to trust the client anyway. */ -void channel_permit_all_opens() +void +channel_permit_all_opens() { - all_opens_permitted = 1; + all_opens_permitted = 1; } -/* Allocate a new channel object and set its type and socket. +/* Allocate a new channel object and set its type and socket. This will cause remote_name to be freed. */ -int channel_allocate(int type, int sock, char *remote_name) +int +channel_allocate(int type, int sock, char *remote_name) { - int i, found; - Channel *c; - - /* Update the maximum file descriptor value. */ - if (sock > channel_max_fd_value) - channel_max_fd_value = sock; - - /* Do initial allocation if this is the first call. */ - if (channels_alloc == 0) - { - channels_alloc = 10; - channels = xmalloc(channels_alloc * sizeof(Channel)); - for (i = 0; i < channels_alloc; i++) - channels[i].type = SSH_CHANNEL_FREE; - - /* Kludge: arrange a call to channel_stop_listening if we terminate - with fatal(). */ - fatal_add_cleanup((void (*)(void *))channel_stop_listening, NULL); - } - - /* Try to find a free slot where to put the new channel. */ - for (found = -1, i = 0; i < channels_alloc; i++) - if (channels[i].type == SSH_CHANNEL_FREE) - { - /* Found a free slot. */ - found = i; - break; - } - - if (found == -1) - { - /* There are no free slots. Take last+1 slot and expand the array. */ - found = channels_alloc; - channels_alloc += 10; - debug("channel: expanding %d", channels_alloc); - channels = xrealloc(channels, channels_alloc * sizeof(Channel)); - for (i = found; i < channels_alloc; i++) - channels[i].type = SSH_CHANNEL_FREE; - } - - /* Initialize and return new channel number. */ - c=&channels[found]; - buffer_init(&c->input); - buffer_init(&c->output); - chan_init_iostates(c); - c->self = found; - c->type = type; - c->sock = sock; - c->remote_id = -1; - c->remote_name = remote_name; - debug("channel %d: new [%s]", found, remote_name); - return found; + int i, found; + Channel *c; + + /* Update the maximum file descriptor value. */ + if (sock > channel_max_fd_value) + channel_max_fd_value = sock; + + /* Do initial allocation if this is the first call. */ + if (channels_alloc == 0) { + channels_alloc = 10; + channels = xmalloc(channels_alloc * sizeof(Channel)); + for (i = 0; i < channels_alloc; i++) + channels[i].type = SSH_CHANNEL_FREE; + + /* Kludge: arrange a call to channel_stop_listening if we + terminate with fatal(). */ + fatal_add_cleanup((void (*) (void *)) channel_stop_listening, NULL); + } + /* Try to find a free slot where to put the new channel. */ + for (found = -1, i = 0; i < channels_alloc; i++) + if (channels[i].type == SSH_CHANNEL_FREE) { + /* Found a free slot. */ + found = i; + break; + } + if (found == -1) { + /* There are no free slots. Take last+1 slot and expand + the array. */ + found = channels_alloc; + channels_alloc += 10; + debug("channel: expanding %d", channels_alloc); + channels = xrealloc(channels, channels_alloc * sizeof(Channel)); + for (i = found; i < channels_alloc; i++) + channels[i].type = SSH_CHANNEL_FREE; + } + /* Initialize and return new channel number. */ + c = &channels[found]; + buffer_init(&c->input); + buffer_init(&c->output); + chan_init_iostates(c); + c->self = found; + c->type = type; + c->sock = sock; + c->remote_id = -1; + c->remote_name = remote_name; + debug("channel %d: new [%s]", found, remote_name); + return found; } /* Free the channel and close its socket. */ -void channel_free(int channel) +void +channel_free(int channel) { - if (channel < 0 || channel >= channels_alloc || - channels[channel].type == SSH_CHANNEL_FREE) - packet_disconnect("channel free: bad local channel %d", channel); - - if(compat13) - shutdown(channels[channel].sock, SHUT_RDWR); - close(channels[channel].sock); - buffer_free(&channels[channel].input); - buffer_free(&channels[channel].output); - channels[channel].type = SSH_CHANNEL_FREE; - if (channels[channel].remote_name) - { - xfree(channels[channel].remote_name); - channels[channel].remote_name = NULL; - } + if (channel < 0 || channel >= channels_alloc || + channels[channel].type == SSH_CHANNEL_FREE) + packet_disconnect("channel free: bad local channel %d", channel); + + if (compat13) + shutdown(channels[channel].sock, SHUT_RDWR); + close(channels[channel].sock); + buffer_free(&channels[channel].input); + buffer_free(&channels[channel].output); + channels[channel].type = SSH_CHANNEL_FREE; + if (channels[channel].remote_name) { + xfree(channels[channel].remote_name); + channels[channel].remote_name = NULL; + } } /* This is called just before select() to add any bits relevant to channels in the select bitmasks. */ -void channel_prepare_select(fd_set *readset, fd_set *writeset) +void +channel_prepare_select(fd_set * readset, fd_set * writeset) { - int i; - Channel *ch; - unsigned char *ucp; - unsigned int proto_len, data_len; - - for (i = 0; i < channels_alloc; i++) - { - ch = &channels[i]; - redo: - switch (ch->type) - { - case SSH_CHANNEL_X11_LISTENER: - case SSH_CHANNEL_PORT_LISTENER: - case SSH_CHANNEL_AUTH_SOCKET: - FD_SET(ch->sock, readset); - break; - - case SSH_CHANNEL_OPEN: - if(compat13){ - if (buffer_len(&ch->input) < packet_get_maxsize()) - 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->istate == CHAN_INPUT_OPEN) - if (buffer_len(&ch->input) < packet_get_maxsize()) - FD_SET(ch->sock, readset); - if (ch->ostate == CHAN_OUTPUT_OPEN || ch->ostate == CHAN_OUTPUT_WAIT_DRAIN){ - if (buffer_len(&ch->output) > 0){ - FD_SET(ch->sock, writeset); - }else if(ch->ostate == CHAN_OUTPUT_WAIT_DRAIN) { - chan_obuf_empty(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); - packet_put_int(ch->remote_id); - packet_send(); - ch->type = SSH_CHANNEL_CLOSED; - debug("Closing channel %d after input drain.", i); - break; - } - 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); */ - channel_free(i); - break; - } - FD_SET(ch->sock, writeset); - break; - - case SSH_CHANNEL_X11_OPEN: - /* This is a special state for X11 authentication spoofing. An - opened X11 connection (when authentication spoofing is being - done) remains in this state until the first packet has been - completely read. The authentication data in that packet is - then substituted by the real data if it matches the fake data, - and the channel is put into normal mode. */ - - /* Check if the fixed size part of the packet is in buffer. */ - if (buffer_len(&ch->output) < 12) - break; - - /* Parse the lengths of variable-length fields. */ - ucp = (unsigned char *)buffer_ptr(&ch->output); - if (ucp[0] == 0x42) - { /* Byte order MSB first. */ - proto_len = 256 * ucp[6] + ucp[7]; - data_len = 256 * ucp[8] + ucp[9]; - } - else - if (ucp[0] == 0x6c) - { /* Byte order LSB first. */ - proto_len = ucp[6] + 256 * ucp[7]; - data_len = ucp[8] + 256 * ucp[9]; - } - else - { - debug("Initial X11 packet contains bad byte order byte: 0x%x", - ucp[0]); - ch->type = SSH_CHANNEL_OPEN; - goto reject; - } - - /* Check if the whole packet is in buffer. */ - if (buffer_len(&ch->output) < - 12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3)) - break; - - /* Check if authentication protocol matches. */ - if (proto_len != strlen(x11_saved_proto) || - memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) - { - debug("X11 connection uses different authentication protocol."); - ch->type = SSH_CHANNEL_OPEN; - goto reject; - } - - /* Check if authentication data matches our fake data. */ - if (data_len != x11_fake_data_len || - memcmp(ucp + 12 + ((proto_len + 3) & ~3), - x11_fake_data, x11_fake_data_len) != 0) - { - debug("X11 auth data does not match fake data."); - ch->type = SSH_CHANNEL_OPEN; - goto reject; - } - - /* Check fake data length */ - if (x11_fake_data_len != x11_saved_data_len) - { - error("X11 fake_data_len %d != saved_data_len %d", - x11_fake_data_len, x11_saved_data_len); - ch->type = SSH_CHANNEL_OPEN; - goto reject; - } - - /* Received authentication protocol and data match our fake data. - Substitute the fake data with real data. */ - memcpy(ucp + 12 + ((proto_len + 3) & ~3), - x11_saved_data, x11_saved_data_len); - - /* Start normal processing for the channel. */ - ch->type = SSH_CHANNEL_OPEN; - goto redo; - + int i; + Channel *ch; + unsigned char *ucp; + unsigned int proto_len, data_len; + + for (i = 0; i < channels_alloc; i++) { + ch = &channels[i]; +redo: + switch (ch->type) { + case SSH_CHANNEL_X11_LISTENER: + case SSH_CHANNEL_PORT_LISTENER: + case SSH_CHANNEL_AUTH_SOCKET: + FD_SET(ch->sock, readset); + break; + + case SSH_CHANNEL_OPEN: + if (compat13) { + if (buffer_len(&ch->input) < packet_get_maxsize()) + 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->istate == CHAN_INPUT_OPEN) + if (buffer_len(&ch->input) < packet_get_maxsize()) + FD_SET(ch->sock, readset); + if (ch->ostate == CHAN_OUTPUT_OPEN || + ch->ostate == CHAN_OUTPUT_WAIT_DRAIN) { + if (buffer_len(&ch->output) > 0) { + FD_SET(ch->sock, writeset); + } else if (ch->ostate == CHAN_OUTPUT_WAIT_DRAIN) { + chan_obuf_empty(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); + packet_put_int(ch->remote_id); + packet_send(); + ch->type = SSH_CHANNEL_CLOSED; + debug("Closing channel %d after input drain.", i); + break; + } + break; + + case SSH_CHANNEL_OUTPUT_DRAINING: + if (!compat13) + fatal("cannot happen: OUT_DRAIN"); + if (buffer_len(&ch->output) == 0) { + channel_free(i); + break; + } + FD_SET(ch->sock, writeset); + break; + + case SSH_CHANNEL_X11_OPEN: + /* This is a special state for X11 authentication + spoofing. An opened X11 connection (when + authentication spoofing is being done) remains + in this state until the first packet has been + completely read. The authentication data in + that packet is then substituted by the real + data if it matches the fake data, and the + channel is put into normal mode. */ + + /* Check if the fixed size part of the packet is in buffer. */ + if (buffer_len(&ch->output) < 12) + break; + + /* Parse the lengths of variable-length fields. */ + ucp = (unsigned char *) buffer_ptr(&ch->output); + if (ucp[0] == 0x42) { /* Byte order MSB first. */ + proto_len = 256 * ucp[6] + ucp[7]; + data_len = 256 * ucp[8] + ucp[9]; + } else if (ucp[0] == 0x6c) { /* Byte order LSB first. */ + proto_len = ucp[6] + 256 * ucp[7]; + data_len = ucp[8] + 256 * ucp[9]; + } else { + debug("Initial X11 packet contains bad byte order byte: 0x%x", + ucp[0]); + ch->type = SSH_CHANNEL_OPEN; + goto reject; + } + + /* Check if the whole packet is in buffer. */ + if (buffer_len(&ch->output) < + 12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3)) + break; + + /* Check if authentication protocol matches. */ + if (proto_len != strlen(x11_saved_proto) || + memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) { + debug("X11 connection uses different authentication protocol."); + ch->type = SSH_CHANNEL_OPEN; + goto reject; + } + /* Check if authentication data matches our fake data. */ + if (data_len != x11_fake_data_len || + memcmp(ucp + 12 + ((proto_len + 3) & ~3), + x11_fake_data, x11_fake_data_len) != 0) { + debug("X11 auth data does not match fake data."); + ch->type = SSH_CHANNEL_OPEN; + goto reject; + } + /* Check fake data length */ + if (x11_fake_data_len != x11_saved_data_len) { + error("X11 fake_data_len %d != saved_data_len %d", + x11_fake_data_len, x11_saved_data_len); + ch->type = SSH_CHANNEL_OPEN; + goto reject; + } + /* Received authentication protocol and data match + our fake data. Substitute the fake data with + real data. */ + memcpy(ucp + 12 + ((proto_len + 3) & ~3), + x11_saved_data, x11_saved_data_len); + + /* Start normal processing for the channel. */ + ch->type = SSH_CHANNEL_OPEN; + goto redo; + reject: - /* We have received an X11 connection that has bad authentication - information. */ - log("X11 connection rejected because of wrong authentication.\r\n"); - buffer_clear(&ch->input); - buffer_clear(&ch->output); - 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{ - debug("X11 rejected %d i%d/o%d", ch->self, ch->istate, ch->ostate); - chan_read_failed(ch); - chan_write_failed(ch); - debug("X11 rejected %d i%d/o%d", ch->self, ch->istate, ch->ostate); - } - break; - - case SSH_CHANNEL_FREE: - default: - continue; + /* We have received an X11 connection that has bad + authentication information. */ + log("X11 connection rejected because of wrong authentication.\r\n"); + buffer_clear(&ch->input); + buffer_clear(&ch->output); + 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 { + debug("X11 rejected %d i%d/o%d", ch->self, ch->istate, ch->ostate); + chan_read_failed(ch); + chan_write_failed(ch); + debug("X11 rejected %d i%d/o%d", ch->self, ch->istate, ch->ostate); + } + break; + + case SSH_CHANNEL_FREE: + default: + continue; + } } - } } /* After select, perform any appropriate operations for channels which have events pending. */ -void channel_after_select(fd_set *readset, fd_set *writeset) +void +channel_after_select(fd_set * readset, fd_set * writeset) { - struct sockaddr addr; - int addrlen, newsock, i, newch, len; - Channel *ch; - char buf[16384], *remote_hostname; - - /* Loop over all channels... */ - for (i = 0; i < channels_alloc; i++) - { - ch = &channels[i]; - switch (ch->type) - { - case SSH_CHANNEL_X11_LISTENER: - /* This is our fake X11 server socket. */ - if (FD_ISSET(ch->sock, readset)) - { - debug("X11 connection requested."); - addrlen = sizeof(addr); - newsock = accept(ch->sock, &addr, &addrlen); - if (newsock < 0) - { - error("accept: %.100s", strerror(errno)); - break; - } - remote_hostname = get_remote_hostname(newsock); - snprintf(buf, sizeof buf, "X11 connection from %.200s port %d", - remote_hostname, get_peer_port(newsock)); - xfree(remote_hostname); - newch = channel_allocate(SSH_CHANNEL_OPENING, newsock, - xstrdup(buf)); - packet_start(SSH_SMSG_X11_OPEN); - packet_put_int(newch); - if (have_hostname_in_open) - packet_put_string(buf, strlen(buf)); - packet_send(); - } - break; - - case SSH_CHANNEL_PORT_LISTENER: - /* This socket is listening for connections to a forwarded TCP/IP - port. */ - if (FD_ISSET(ch->sock, readset)) - { - debug("Connection to port %d forwarding to %.100s:%d requested.", - ch->listening_port, ch->path, ch->host_port); - addrlen = sizeof(addr); - newsock = accept(ch->sock, &addr, &addrlen); - if (newsock < 0) - { - error("accept: %.100s", strerror(errno)); - break; - } - remote_hostname = get_remote_hostname(newsock); - snprintf(buf, sizeof buf, "listen port %d:%.100s:%d, connect from %.200s:%d", - ch->listening_port, ch->path, ch->host_port, - remote_hostname, get_peer_port(newsock)); - xfree(remote_hostname); - newch = channel_allocate(SSH_CHANNEL_OPENING, newsock, - xstrdup(buf)); - packet_start(SSH_MSG_PORT_OPEN); - packet_put_int(newch); - packet_put_string(ch->path, strlen(ch->path)); - packet_put_int(ch->host_port); - if (have_hostname_in_open) - packet_put_string(buf, strlen(buf)); - packet_send(); - } - break; - - case SSH_CHANNEL_AUTH_SOCKET: - /* This is the authentication agent socket listening for connections - from clients. */ - if (FD_ISSET(ch->sock, readset)) - { - int nchan; - len = sizeof(addr); - newsock = accept(ch->sock, &addr, &len); - if (newsock < 0) - { - error("accept from auth socket: %.100s", strerror(errno)); - break; + struct sockaddr addr; + int addrlen, newsock, i, newch, len; + Channel *ch; + char buf[16384], *remote_hostname; + + /* Loop over all channels... */ + for (i = 0; i < channels_alloc; i++) { + ch = &channels[i]; + switch (ch->type) { + case SSH_CHANNEL_X11_LISTENER: + /* This is our fake X11 server socket. */ + if (FD_ISSET(ch->sock, readset)) { + debug("X11 connection requested."); + addrlen = sizeof(addr); + newsock = accept(ch->sock, &addr, &addrlen); + if (newsock < 0) { + error("accept: %.100s", strerror(errno)); + break; + } + remote_hostname = get_remote_hostname(newsock); + snprintf(buf, sizeof buf, "X11 connection from %.200s port %d", + remote_hostname, get_peer_port(newsock)); + xfree(remote_hostname); + newch = channel_allocate(SSH_CHANNEL_OPENING, newsock, + xstrdup(buf)); + packet_start(SSH_SMSG_X11_OPEN); + packet_put_int(newch); + if (have_hostname_in_open) + packet_put_string(buf, strlen(buf)); + packet_send(); + } + break; + + case SSH_CHANNEL_PORT_LISTENER: + /* This socket is listening for connections to a + forwarded TCP/IP port. */ + if (FD_ISSET(ch->sock, readset)) { + debug("Connection to port %d forwarding to %.100s:%d requested.", + ch->listening_port, ch->path, ch->host_port); + addrlen = sizeof(addr); + newsock = accept(ch->sock, &addr, &addrlen); + if (newsock < 0) { + error("accept: %.100s", strerror(errno)); + break; + } + remote_hostname = get_remote_hostname(newsock); + snprintf(buf, sizeof buf, "listen port %d:%.100s:%d, connect from %.200s:%d", + ch->listening_port, ch->path, ch->host_port, + remote_hostname, get_peer_port(newsock)); + xfree(remote_hostname); + newch = channel_allocate(SSH_CHANNEL_OPENING, newsock, + xstrdup(buf)); + packet_start(SSH_MSG_PORT_OPEN); + packet_put_int(newch); + packet_put_string(ch->path, strlen(ch->path)); + packet_put_int(ch->host_port); + if (have_hostname_in_open) + packet_put_string(buf, strlen(buf)); + packet_send(); + } + break; + + case SSH_CHANNEL_AUTH_SOCKET: + /* This is the authentication agent socket + listening for connections from clients. */ + if (FD_ISSET(ch->sock, readset)) { + int nchan; + len = sizeof(addr); + newsock = accept(ch->sock, &addr, &len); + if (newsock < 0) { + error("accept from auth socket: %.100s", strerror(errno)); + break; + } + nchan = channel_allocate(SSH_CHANNEL_OPENING, newsock, + xstrdup("accepted auth socket")); + packet_start(SSH_SMSG_AGENT_OPEN); + packet_put_int(nchan); + packet_send(); + } + break; + + case SSH_CHANNEL_OPEN: + /* 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; shutdown socket, if read or write + failes */ + if (FD_ISSET(ch->sock, readset)) { + len = read(ch->sock, buf, sizeof(buf)); + if (len <= 0) { + 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 { + chan_read_failed(ch); + } + break; + } + buffer_append(&ch->input, buf, len); + } + /* Send buffered output data to the socket. */ + if (FD_ISSET(ch->sock, writeset) && buffer_len(&ch->output) > 0) { + len = write(ch->sock, buffer_ptr(&ch->output), + buffer_len(&ch->output)); + if (len <= 0) { + 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 { + chan_write_failed(ch); + } + break; + } + buffer_consume(&ch->output, len); + } + 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) { + len = write(ch->sock, buffer_ptr(&ch->output), + buffer_len(&ch->output)); + if (len <= 0) + buffer_consume(&ch->output, buffer_len(&ch->output)); + else + buffer_consume(&ch->output, len); + } + break; + + case SSH_CHANNEL_X11_OPEN: + case SSH_CHANNEL_FREE: + default: + continue; } - - nchan = channel_allocate(SSH_CHANNEL_OPENING, newsock, - xstrdup("accepted auth socket")); - packet_start(SSH_SMSG_AGENT_OPEN); - packet_put_int(nchan); - packet_send(); - } - break; - - case SSH_CHANNEL_OPEN: - /* 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; - shutdown socket, if read or write failes */ - if (FD_ISSET(ch->sock, readset)) - { - len = read(ch->sock, buf, sizeof(buf)); - if (len <= 0) - { - 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{ - chan_read_failed(ch); - } - break; - } - buffer_append(&ch->input, buf, len); - } - /* Send buffered output data to the socket. */ - if (FD_ISSET(ch->sock, writeset) && buffer_len(&ch->output) > 0) - { - len = write(ch->sock, buffer_ptr(&ch->output), - buffer_len(&ch->output)); - if (len <= 0) - { - 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{ - chan_write_failed(ch); - } - break; - } - buffer_consume(&ch->output, len); - } - 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) - { - len = write(ch->sock, buffer_ptr(&ch->output), - buffer_len(&ch->output)); - if (len <= 0) - buffer_consume(&ch->output, buffer_len(&ch->output)); - else - buffer_consume(&ch->output, len); - } - break; - - case SSH_CHANNEL_X11_OPEN: - case SSH_CHANNEL_FREE: - default: - continue; } - } } /* If there is data to send to the connection, send some of it now. */ -void channel_output_poll() +void +channel_output_poll() { - int len, i; - Channel *ch; - - 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; - - /* Get the amount of buffered data for this channel. */ - len = buffer_len(&ch->input); - if (len > 0) - { - /* Send some data for the other side over the secure connection. */ - if (packet_is_interactive()) - { - if (len > 1024) - len = 512; - } - else - { - if (len > 16384) - len = 16384; /* Keep the packets at reasonable size. */ - } - packet_start(SSH_MSG_CHANNEL_DATA); - packet_put_int(ch->remote_id); - packet_put_string(buffer_ptr(&ch->input), len); - packet_send(); - buffer_consume(&ch->input, len); + int len, i; + Channel *ch; + + 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; + + /* Get the amount of buffered data for this channel. */ + len = buffer_len(&ch->input); + if (len > 0) { + /* Send some data for the other side over the + secure connection. */ + if (packet_is_interactive()) { + if (len > 1024) + len = 512; + } else { + /* Keep the packets at reasonable size. */ + if (len > 16384) + len = 16384; + } + packet_start(SSH_MSG_CHANNEL_DATA); + packet_put_int(ch->remote_id); + packet_put_string(buffer_ptr(&ch->input), len); + packet_send(); + buffer_consume(&ch->input, len); + } else if (ch->istate == CHAN_INPUT_WAIT_DRAIN) { + if (compat13) + fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3"); + /* input-buffer is empty and read-socket shutdown: + tell peer, that we will not send more data: + send IEOF */ + chan_ibuf_empty(ch); + } } - else if(ch->istate == CHAN_INPUT_WAIT_DRAIN) - { - if (compat13) - fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3"); - /* input-buffer is empty and read-socket shutdown: - tell peer, that we will not send more data: send IEOF */ - chan_ibuf_empty(ch); - } - } } /* This is called when a packet of type CHANNEL_DATA has just been received. The message type has already been consumed, but channel number and data is still there. */ -void channel_input_data(int payload_len) +void +channel_input_data(int payload_len) { - int channel; - char *data; - unsigned int data_len; - - /* 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); - - /* 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) - 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); - xfree(data); + int channel; + char *data; + unsigned int data_len; + + /* 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); + + /* 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) + 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); + xfree(data); } /* Returns true if no channel has too much buffered data, and false if one or more channel is overfull. */ -int channel_not_very_much_buffered_data() +int +channel_not_very_much_buffered_data() { - unsigned int i; - Channel *ch; - - 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 (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; + unsigned int i; + Channel *ch; + + 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 (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; + return 1; } /* This is called after receiving CHANNEL_CLOSE/IEOF. */ -void channel_input_close() +void +channel_input_close() { - int channel; - - /* 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 f |