diff options
Diffstat (limited to 'crypto/openssh/channels.c')
-rw-r--r-- | crypto/openssh/channels.c | 99 |
1 files changed, 65 insertions, 34 deletions
diff --git a/crypto/openssh/channels.c b/crypto/openssh/channels.c index a55d278..1cd5004 100644 --- a/crypto/openssh/channels.c +++ b/crypto/openssh/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; } |