aboutsummaryrefslogtreecommitdiff
path: root/channels.c
diff options
context:
space:
mode:
Diffstat (limited to 'channels.c')
-rw-r--r--channels.c99
1 files changed, 65 insertions, 34 deletions
diff --git a/channels.c b/channels.c
index a55d27817573..1cd5004c47bb 100644
--- a/channels.c
+++ b/channels.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.c,v 1.303 2010/01/30 21:12:08 djm Exp $ */
+/* $OpenBSD: channels.c,v 1.309 2010/08/05 13:08:42 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -114,10 +114,10 @@ typedef struct {
} ForwardPermission;
/* List of all permitted host/port pairs to connect by the user. */
-static ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION];
+static ForwardPermission *permitted_opens = NULL;
/* List of all permitted host/port pairs to connect by the admin. */
-static ForwardPermission permitted_adm_opens[SSH_MAX_FORWARDS_PER_DIRECTION];
+static ForwardPermission *permitted_adm_opens = NULL;
/* Number of permitted host/port pairs in the array permitted by the user. */
static int num_permitted_opens = 0;
@@ -330,6 +330,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
c->ctl_chan = -1;
c->mux_rcb = NULL;
c->mux_ctx = NULL;
+ c->mux_pause = 0;
c->delayed = 1; /* prevent call to channel_post handler */
TAILQ_INIT(&c->status_confirms);
debug("channel %d: new [%s]", found, remote_name);
@@ -703,7 +704,7 @@ channel_register_status_confirm(int id, channel_confirm_cb *cb,
}
void
-channel_register_open_confirm(int id, channel_callback_fn *fn, void *ctx)
+channel_register_open_confirm(int id, channel_open_fn *fn, void *ctx)
{
Channel *c = channel_lookup(id);
@@ -838,8 +839,9 @@ channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset)
if (c->extended_usage == CHAN_EXTENDED_WRITE &&
buffer_len(&c->extended) > 0)
FD_SET(c->efd, writeset);
- else if (!(c->flags & CHAN_EOF_SENT) &&
- c->extended_usage == CHAN_EXTENDED_READ &&
+ else if (c->efd != -1 && !(c->flags & CHAN_EOF_SENT) &&
+ (c->extended_usage == CHAN_EXTENDED_READ ||
+ c->extended_usage == CHAN_EXTENDED_IGNORE) &&
buffer_len(&c->extended) < c->remote_window)
FD_SET(c->efd, readset);
}
@@ -915,7 +917,7 @@ x11_open_helper(Buffer *b)
}
/* Check if authentication data matches our fake data. */
if (data_len != x11_fake_data_len ||
- memcmp(ucp + 12 + ((proto_len + 3) & ~3),
+ timingsafe_bcmp(ucp + 12 + ((proto_len + 3) & ~3),
x11_fake_data, x11_fake_data_len) != 0) {
debug2("X11 auth data does not match fake data.");
return -1;
@@ -991,7 +993,7 @@ channel_pre_x11_open(Channel *c, fd_set *readset, fd_set *writeset)
static void
channel_pre_mux_client(Channel *c, fd_set *readset, fd_set *writeset)
{
- if (c->istate == CHAN_INPUT_OPEN &&
+ if (c->istate == CHAN_INPUT_OPEN && !c->mux_pause &&
buffer_check_alloc(&c->input, CHAN_RBUF))
FD_SET(c->rfd, readset);
if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
@@ -1642,13 +1644,14 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
{
struct termios tio;
u_char *data = NULL, *buf;
- u_int dlen;
+ u_int dlen, olen = 0;
int len;
/* Send buffered output data to the socket. */
if (c->wfd != -1 &&
FD_ISSET(c->wfd, writeset) &&
buffer_len(&c->output) > 0) {
+ olen = buffer_len(&c->output);
if (c->output_filter != NULL) {
if ((buf = c->output_filter(c, &data, &dlen)) == NULL) {
debug2("channel %d: filter stops", c->self);
@@ -1667,7 +1670,6 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
if (c->datagram) {
/* ignore truncated writes, datagrams might get lost */
- c->local_consumed += dlen + 4;
len = write(c->wfd, buf, dlen);
xfree(data);
if (len < 0 && (errno == EINTR || errno == EAGAIN ||
@@ -1680,7 +1682,7 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
chan_write_failed(c);
return -1;
}
- return 1;
+ goto out;
}
#ifdef _AIX
/* XXX: Later AIX versions can't push as much data to tty */
@@ -1722,10 +1724,10 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
}
#endif
buffer_consume(&c->output, len);
- if (compat20 && len > 0) {
- c->local_consumed += len;
- }
}
+ out:
+ if (compat20 && olen > 0)
+ c->local_consumed += olen - buffer_len(&c->output);
return 1;
}
@@ -1755,7 +1757,9 @@ channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset)
buffer_consume(&c->extended, len);
c->local_consumed += len;
}
- } else if (c->extended_usage == CHAN_EXTENDED_READ &&
+ } else if (c->efd != -1 &&
+ (c->extended_usage == CHAN_EXTENDED_READ ||
+ c->extended_usage == CHAN_EXTENDED_IGNORE) &&
(c->detach_close || FD_ISSET(c->efd, readset))) {
len = read(c->efd, buf, sizeof(buf));
debug2("channel %d: read %d from efd %d",
@@ -1768,7 +1772,11 @@ channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset)
c->self, c->efd);
channel_close_fd(&c->efd);
} else {
- buffer_append(&c->extended, buf, len);
+ if (c->extended_usage == CHAN_EXTENDED_IGNORE) {
+ debug3("channel %d: discard efd",
+ c->self);
+ } else
+ buffer_append(&c->extended, buf, len);
}
}
}
@@ -1840,7 +1848,7 @@ channel_post_mux_client(Channel *c, fd_set *readset, fd_set *writeset)
if (!compat20)
fatal("%s: entered with !compat20", __func__);
- if (c->rfd != -1 && FD_ISSET(c->rfd, readset) &&
+ if (c->rfd != -1 && !c->mux_pause && FD_ISSET(c->rfd, readset) &&
(c->istate == CHAN_INPUT_OPEN ||
c->istate == CHAN_INPUT_WAIT_DRAIN)) {
/*
@@ -2164,6 +2172,14 @@ channel_output_poll(void)
data = buffer_get_string(&c->input,
&dlen);
+ if (dlen > c->remote_window ||
+ dlen > c->remote_maxpacket) {
+ debug("channel %d: datagram "
+ "too big for channel",
+ c->self);
+ xfree(data);
+ continue;
+ }
packet_start(SSH2_MSG_CHANNEL_DATA);
packet_put_int(c->remote_id);
packet_put_string(data, dlen);
@@ -2249,7 +2265,7 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
{
int id;
char *data;
- u_int data_len;
+ u_int data_len, win_len;
Channel *c;
/* Get the channel number and verify it. */
@@ -2265,6 +2281,9 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
/* Get the data. */
data = packet_get_string_ptr(&data_len);
+ win_len = data_len;
+ if (c->datagram)
+ win_len += 4; /* string length header */
/*
* Ignore data for protocol > 1.3 if output end is no longer open.
@@ -2275,23 +2294,23 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
*/
if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) {
if (compat20) {
- c->local_window -= data_len;
- c->local_consumed += data_len;
+ c->local_window -= win_len;
+ c->local_consumed += win_len;
}
return;
}
if (compat20) {
- if (data_len > c->local_maxpacket) {
+ if (win_len > c->local_maxpacket) {
logit("channel %d: rcvd big packet %d, maxpack %d",
- c->self, data_len, c->local_maxpacket);
+ c->self, win_len, c->local_maxpacket);
}
- if (data_len > c->local_window) {
+ if (win_len > c->local_window) {
logit("channel %d: rcvd too much data %d, win %d",
- c->self, data_len, c->local_window);
+ c->self, win_len, c->local_window);
return;
}
- c->local_window -= data_len;
+ c->local_window -= win_len;
}
if (c->datagram)
buffer_put_string(&c->output, data, data_len);
@@ -2463,7 +2482,7 @@ channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt)
c->remote_maxpacket = packet_get_int();
if (c->open_confirm) {
debug2("callback start");
- c->open_confirm(c->self, c->open_confirm_ctx);
+ c->open_confirm(c->self, 1, c->open_confirm_ctx);
debug2("callback done");
}
debug2("channel %d: open confirm rwindow %u rmax %u", c->self,
@@ -2514,6 +2533,11 @@ channel_input_open_failure(int type, u_int32_t seq, void *ctxt)
xfree(msg);
if (lang != NULL)
xfree(lang);
+ if (c->open_confirm) {
+ debug2("callback start");
+ c->open_confirm(c->self, 0, c->open_confirm_ctx);
+ debug2("callback done");
+ }
}
packet_check_eom();
/* Schedule the channel for cleanup/deletion. */
@@ -2832,10 +2856,6 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
{
int type, success = 0;
- /* Record locally that connection to this host/port is permitted. */
- if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
- fatal("channel_request_remote_forwarding: too many forwards");
-
/* Send the forward request to the remote side. */
if (compat20) {
const char *address_to_bind;
@@ -2885,6 +2905,9 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
}
}
if (success) {
+ /* Record that connection to this host/port is permitted. */
+ permitted_opens = xrealloc(permitted_opens,
+ num_permitted_opens + 1, sizeof(*permitted_opens));
permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect);
permitted_opens[num_permitted_opens].port_to_connect = port_to_connect;
permitted_opens[num_permitted_opens].listen_port = listen_port;
@@ -2982,10 +3005,10 @@ channel_permit_all_opens(void)
void
channel_add_permitted_opens(char *host, int port)
{
- if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
- fatal("channel_add_permitted_opens: too many forwards");
debug("allow port forwarding to host %s port %d", host, port);
+ permitted_opens = xrealloc(permitted_opens,
+ num_permitted_opens + 1, sizeof(*permitted_opens));
permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host);
permitted_opens[num_permitted_opens].port_to_connect = port;
num_permitted_opens++;
@@ -2996,10 +3019,10 @@ channel_add_permitted_opens(char *host, int port)
int
channel_add_adm_permitted_opens(char *host, int port)
{
- if (num_adm_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
- fatal("channel_add_adm_permitted_opens: too many forwards");
debug("config allows port forwarding to host %s port %d", host, port);
+ permitted_adm_opens = xrealloc(permitted_adm_opens,
+ num_adm_permitted_opens + 1, sizeof(*permitted_adm_opens));
permitted_adm_opens[num_adm_permitted_opens].host_to_connect
= xstrdup(host);
permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port;
@@ -3014,6 +3037,10 @@ channel_clear_permitted_opens(void)
for (i = 0; i < num_permitted_opens; i++)
if (permitted_opens[i].host_to_connect != NULL)
xfree(permitted_opens[i].host_to_connect);
+ if (num_permitted_opens > 0) {
+ xfree(permitted_opens);
+ permitted_opens = NULL;
+ }
num_permitted_opens = 0;
}
@@ -3025,6 +3052,10 @@ channel_clear_adm_permitted_opens(void)
for (i = 0; i < num_adm_permitted_opens; i++)
if (permitted_adm_opens[i].host_to_connect != NULL)
xfree(permitted_adm_opens[i].host_to_connect);
+ if (num_adm_permitted_opens > 0) {
+ xfree(permitted_adm_opens);
+ permitted_adm_opens = NULL;
+ }
num_adm_permitted_opens = 0;
}