summaryrefslogtreecommitdiffstats
path: root/channels.c
diff options
context:
space:
mode:
Diffstat (limited to 'channels.c')
-rw-r--r--channels.c2427
1 files changed, 1187 insertions, 1240 deletions
diff --git a/channels.c b/channels.c
index 3e3b5f36..0a37d1ab 100644
--- a/channels.c
+++ b/channels.c
@@ -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 for