summaryrefslogtreecommitdiff
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 a55d27817..1cd5004c4 100644
--- a/channels.c
+++ b/channels.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: channels.c,v 1.303 2010/01/30 21:12:08 djm Exp $ */ 1/* $OpenBSD: channels.c,v 1.309 2010/08/05 13:08:42 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -114,10 +114,10 @@ typedef struct {
114} ForwardPermission; 114} ForwardPermission;
115 115
116/* List of all permitted host/port pairs to connect by the user. */ 116/* List of all permitted host/port pairs to connect by the user. */
117static ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION]; 117static ForwardPermission *permitted_opens = NULL;
118 118
119/* List of all permitted host/port pairs to connect by the admin. */ 119/* List of all permitted host/port pairs to connect by the admin. */
120static ForwardPermission permitted_adm_opens[SSH_MAX_FORWARDS_PER_DIRECTION]; 120static ForwardPermission *permitted_adm_opens = NULL;
121 121
122/* Number of permitted host/port pairs in the array permitted by the user. */ 122/* Number of permitted host/port pairs in the array permitted by the user. */
123static int num_permitted_opens = 0; 123static int num_permitted_opens = 0;
@@ -330,6 +330,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
330 c->ctl_chan = -1; 330 c->ctl_chan = -1;
331 c->mux_rcb = NULL; 331 c->mux_rcb = NULL;
332 c->mux_ctx = NULL; 332 c->mux_ctx = NULL;
333 c->mux_pause = 0;
333 c->delayed = 1; /* prevent call to channel_post handler */ 334 c->delayed = 1; /* prevent call to channel_post handler */
334 TAILQ_INIT(&c->status_confirms); 335 TAILQ_INIT(&c->status_confirms);
335 debug("channel %d: new [%s]", found, remote_name); 336 debug("channel %d: new [%s]", found, remote_name);
@@ -703,7 +704,7 @@ channel_register_status_confirm(int id, channel_confirm_cb *cb,
703} 704}
704 705
705void 706void
706channel_register_open_confirm(int id, channel_callback_fn *fn, void *ctx) 707channel_register_open_confirm(int id, channel_open_fn *fn, void *ctx)
707{ 708{
708 Channel *c = channel_lookup(id); 709 Channel *c = channel_lookup(id);
709 710
@@ -838,8 +839,9 @@ channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset)
838 if (c->extended_usage == CHAN_EXTENDED_WRITE && 839 if (c->extended_usage == CHAN_EXTENDED_WRITE &&
839 buffer_len(&c->extended) > 0) 840 buffer_len(&c->extended) > 0)
840 FD_SET(c->efd, writeset); 841 FD_SET(c->efd, writeset);
841 else if (!(c->flags & CHAN_EOF_SENT) && 842 else if (c->efd != -1 && !(c->flags & CHAN_EOF_SENT) &&
842 c->extended_usage == CHAN_EXTENDED_READ && 843 (c->extended_usage == CHAN_EXTENDED_READ ||
844 c->extended_usage == CHAN_EXTENDED_IGNORE) &&
843 buffer_len(&c->extended) < c->remote_window) 845 buffer_len(&c->extended) < c->remote_window)
844 FD_SET(c->efd, readset); 846 FD_SET(c->efd, readset);
845 } 847 }
@@ -915,7 +917,7 @@ x11_open_helper(Buffer *b)
915 } 917 }
916 /* Check if authentication data matches our fake data. */ 918 /* Check if authentication data matches our fake data. */
917 if (data_len != x11_fake_data_len || 919 if (data_len != x11_fake_data_len ||
918 memcmp(ucp + 12 + ((proto_len + 3) & ~3), 920 timingsafe_bcmp(ucp + 12 + ((proto_len + 3) & ~3),
919 x11_fake_data, x11_fake_data_len) != 0) { 921 x11_fake_data, x11_fake_data_len) != 0) {
920 debug2("X11 auth data does not match fake data."); 922 debug2("X11 auth data does not match fake data.");
921 return -1; 923 return -1;
@@ -991,7 +993,7 @@ channel_pre_x11_open(Channel *c, fd_set *readset, fd_set *writeset)
991static void 993static void
992channel_pre_mux_client(Channel *c, fd_set *readset, fd_set *writeset) 994channel_pre_mux_client(Channel *c, fd_set *readset, fd_set *writeset)
993{ 995{
994 if (c->istate == CHAN_INPUT_OPEN && 996 if (c->istate == CHAN_INPUT_OPEN && !c->mux_pause &&
995 buffer_check_alloc(&c->input, CHAN_RBUF)) 997 buffer_check_alloc(&c->input, CHAN_RBUF))
996 FD_SET(c->rfd, readset); 998 FD_SET(c->rfd, readset);
997 if (c->istate == CHAN_INPUT_WAIT_DRAIN) { 999 if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
@@ -1642,13 +1644,14 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
1642{ 1644{
1643 struct termios tio; 1645 struct termios tio;
1644 u_char *data = NULL, *buf; 1646 u_char *data = NULL, *buf;
1645 u_int dlen; 1647 u_int dlen, olen = 0;
1646 int len; 1648 int len;
1647 1649
1648 /* Send buffered output data to the socket. */ 1650 /* Send buffered output data to the socket. */
1649 if (c->wfd != -1 && 1651 if (c->wfd != -1 &&
1650 FD_ISSET(c->wfd, writeset) && 1652 FD_ISSET(c->wfd, writeset) &&
1651 buffer_len(&c->output) > 0) { 1653 buffer_len(&c->output) > 0) {
1654 olen = buffer_len(&c->output);
1652 if (c->output_filter != NULL) { 1655 if (c->output_filter != NULL) {
1653 if ((buf = c->output_filter(c, &data, &dlen)) == NULL) { 1656 if ((buf = c->output_filter(c, &data, &dlen)) == NULL) {
1654 debug2("channel %d: filter stops", c->self); 1657 debug2("channel %d: filter stops", c->self);
@@ -1667,7 +1670,6 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
1667 1670
1668 if (c->datagram) { 1671 if (c->datagram) {
1669 /* ignore truncated writes, datagrams might get lost */ 1672 /* ignore truncated writes, datagrams might get lost */
1670 c->local_consumed += dlen + 4;
1671 len = write(c->wfd, buf, dlen); 1673 len = write(c->wfd, buf, dlen);
1672 xfree(data); 1674 xfree(data);
1673 if (len < 0 && (errno == EINTR || errno == EAGAIN || 1675 if (len < 0 && (errno == EINTR || errno == EAGAIN ||
@@ -1680,7 +1682,7 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
1680 chan_write_failed(c); 1682 chan_write_failed(c);
1681 return -1; 1683 return -1;
1682 } 1684 }
1683 return 1; 1685 goto out;
1684 } 1686 }
1685#ifdef _AIX 1687#ifdef _AIX
1686 /* XXX: Later AIX versions can't push as much data to tty */ 1688 /* 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)
1722 } 1724 }
1723#endif 1725#endif
1724 buffer_consume(&c->output, len); 1726 buffer_consume(&c->output, len);
1725 if (compat20 && len > 0) {
1726 c->local_consumed += len;
1727 }
1728 } 1727 }
1728 out:
1729 if (compat20 && olen > 0)
1730 c->local_consumed += olen - buffer_len(&c->output);
1729 return 1; 1731 return 1;
1730} 1732}
1731 1733
@@ -1755,7 +1757,9 @@ channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset)
1755 buffer_consume(&c->extended, len); 1757 buffer_consume(&c->extended, len);
1756 c->local_consumed += len; 1758 c->local_consumed += len;
1757 } 1759 }
1758 } else if (c->extended_usage == CHAN_EXTENDED_READ && 1760 } else if (c->efd != -1 &&
1761 (c->extended_usage == CHAN_EXTENDED_READ ||
1762 c->extended_usage == CHAN_EXTENDED_IGNORE) &&
1759 (c->detach_close || FD_ISSET(c->efd, readset))) { 1763 (c->detach_close || FD_ISSET(c->efd, readset))) {
1760 len = read(c->efd, buf, sizeof(buf)); 1764 len = read(c->efd, buf, sizeof(buf));
1761 debug2("channel %d: read %d from efd %d", 1765 debug2("channel %d: read %d from efd %d",
@@ -1768,7 +1772,11 @@ channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset)
1768 c->self, c->efd); 1772 c->self, c->efd);
1769 channel_close_fd(&c->efd); 1773 channel_close_fd(&c->efd);
1770 } else { 1774 } else {
1771 buffer_append(&c->extended, buf, len); 1775 if (c->extended_usage == CHAN_EXTENDED_IGNORE) {
1776 debug3("channel %d: discard efd",
1777 c->self);
1778 } else
1779 buffer_append(&c->extended, buf, len);
1772 } 1780 }
1773 } 1781 }
1774 } 1782 }
@@ -1840,7 +1848,7 @@ channel_post_mux_client(Channel *c, fd_set *readset, fd_set *writeset)
1840 if (!compat20) 1848 if (!compat20)
1841 fatal("%s: entered with !compat20", __func__); 1849 fatal("%s: entered with !compat20", __func__);
1842 1850
1843 if (c->rfd != -1 && FD_ISSET(c->rfd, readset) && 1851 if (c->rfd != -1 && !c->mux_pause && FD_ISSET(c->rfd, readset) &&
1844 (c->istate == CHAN_INPUT_OPEN || 1852 (c->istate == CHAN_INPUT_OPEN ||
1845 c->istate == CHAN_INPUT_WAIT_DRAIN)) { 1853 c->istate == CHAN_INPUT_WAIT_DRAIN)) {
1846 /* 1854 /*
@@ -2164,6 +2172,14 @@ channel_output_poll(void)
2164 2172
2165 data = buffer_get_string(&c->input, 2173 data = buffer_get_string(&c->input,
2166 &dlen); 2174 &dlen);
2175 if (dlen > c->remote_window ||
2176 dlen > c->remote_maxpacket) {
2177 debug("channel %d: datagram "
2178 "too big for channel",
2179 c->self);
2180 xfree(data);
2181 continue;
2182 }
2167 packet_start(SSH2_MSG_CHANNEL_DATA); 2183 packet_start(SSH2_MSG_CHANNEL_DATA);
2168 packet_put_int(c->remote_id); 2184 packet_put_int(c->remote_id);
2169 packet_put_string(data, dlen); 2185 packet_put_string(data, dlen);
@@ -2249,7 +2265,7 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
2249{ 2265{
2250 int id; 2266 int id;
2251 char *data; 2267 char *data;
2252 u_int data_len; 2268 u_int data_len, win_len;
2253 Channel *c; 2269 Channel *c;
2254 2270
2255 /* Get the channel number and verify it. */ 2271 /* Get the channel number and verify it. */
@@ -2265,6 +2281,9 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
2265 2281
2266 /* Get the data. */ 2282 /* Get the data. */
2267 data = packet_get_string_ptr(&data_len); 2283 data = packet_get_string_ptr(&data_len);
2284 win_len = data_len;
2285 if (c->datagram)
2286 win_len += 4; /* string length header */
2268 2287
2269 /* 2288 /*
2270 * Ignore data for protocol > 1.3 if output end is no longer open. 2289 * 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)
2275 */ 2294 */
2276 if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) { 2295 if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) {
2277 if (compat20) { 2296 if (compat20) {
2278 c->local_window -= data_len; 2297 c->local_window -= win_len;
2279 c->local_consumed += data_len; 2298 c->local_consumed += win_len;
2280 } 2299 }
2281 return; 2300 return;
2282 } 2301 }
2283 2302
2284 if (compat20) { 2303 if (compat20) {
2285 if (data_len > c->local_maxpacket) { 2304 if (win_len > c->local_maxpacket) {
2286 logit("channel %d: rcvd big packet %d, maxpack %d", 2305 logit("channel %d: rcvd big packet %d, maxpack %d",
2287 c->self, data_len, c->local_maxpacket); 2306 c->self, win_len, c->local_maxpacket);
2288 } 2307 }
2289 if (data_len > c->local_window) { 2308 if (win_len > c->local_window) {
2290 logit("channel %d: rcvd too much data %d, win %d", 2309 logit("channel %d: rcvd too much data %d, win %d",
2291 c->self, data_len, c->local_window); 2310 c->self, win_len, c->local_window);
2292 return; 2311 return;
2293 } 2312 }
2294 c->local_window -= data_len; 2313 c->local_window -= win_len;
2295 } 2314 }
2296 if (c->datagram) 2315 if (c->datagram)
2297 buffer_put_string(&c->output, data, data_len); 2316 buffer_put_string(&c->output, data, data_len);
@@ -2463,7 +2482,7 @@ channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt)
2463 c->remote_maxpacket = packet_get_int(); 2482 c->remote_maxpacket = packet_get_int();
2464 if (c->open_confirm) { 2483 if (c->open_confirm) {
2465 debug2("callback start"); 2484 debug2("callback start");
2466 c->open_confirm(c->self, c->open_confirm_ctx); 2485 c->open_confirm(c->self, 1, c->open_confirm_ctx);
2467 debug2("callback done"); 2486 debug2("callback done");
2468 } 2487 }
2469 debug2("channel %d: open confirm rwindow %u rmax %u", c->self, 2488 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)
2514 xfree(msg); 2533 xfree(msg);
2515 if (lang != NULL) 2534 if (lang != NULL)
2516 xfree(lang); 2535 xfree(lang);
2536 if (c->open_confirm) {
2537 debug2("callback start");
2538 c->open_confirm(c->self, 0, c->open_confirm_ctx);
2539 debug2("callback done");
2540 }
2517 } 2541 }
2518 packet_check_eom(); 2542 packet_check_eom();
2519 /* Schedule the channel for cleanup/deletion. */ 2543 /* Schedule the channel for cleanup/deletion. */
@@ -2832,10 +2856,6 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
2832{ 2856{
2833 int type, success = 0; 2857 int type, success = 0;
2834 2858
2835 /* Record locally that connection to this host/port is permitted. */
2836 if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
2837 fatal("channel_request_remote_forwarding: too many forwards");
2838
2839 /* Send the forward request to the remote side. */ 2859 /* Send the forward request to the remote side. */
2840 if (compat20) { 2860 if (compat20) {
2841 const char *address_to_bind; 2861 const char *address_to_bind;
@@ -2885,6 +2905,9 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
2885 } 2905 }
2886 } 2906 }
2887 if (success) { 2907 if (success) {
2908 /* Record that connection to this host/port is permitted. */
2909 permitted_opens = xrealloc(permitted_opens,
2910 num_permitted_opens + 1, sizeof(*permitted_opens));
2888 permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect); 2911 permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect);
2889 permitted_opens[num_permitted_opens].port_to_connect = port_to_connect; 2912 permitted_opens[num_permitted_opens].port_to_connect = port_to_connect;
2890 permitted_opens[num_permitted_opens].listen_port = listen_port; 2913 permitted_opens[num_permitted_opens].listen_port = listen_port;
@@ -2982,10 +3005,10 @@ channel_permit_all_opens(void)
2982void 3005void
2983channel_add_permitted_opens(char *host, int port) 3006channel_add_permitted_opens(char *host, int port)
2984{ 3007{
2985 if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
2986 fatal("channel_add_permitted_opens: too many forwards");
2987 debug("allow port forwarding to host %s port %d", host, port); 3008 debug("allow port forwarding to host %s port %d", host, port);
2988 3009
3010 permitted_opens = xrealloc(permitted_opens,
3011 num_permitted_opens + 1, sizeof(*permitted_opens));
2989 permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host); 3012 permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host);
2990 permitted_opens[num_permitted_opens].port_to_connect = port; 3013 permitted_opens[num_permitted_opens].port_to_connect = port;
2991 num_permitted_opens++; 3014 num_permitted_opens++;
@@ -2996,10 +3019,10 @@ channel_add_permitted_opens(char *host, int port)
2996int 3019int
2997channel_add_adm_permitted_opens(char *host, int port) 3020channel_add_adm_permitted_opens(char *host, int port)
2998{ 3021{
2999 if (num_adm_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
3000 fatal("channel_add_adm_permitted_opens: too many forwards");
3001 debug("config allows port forwarding to host %s port %d", host, port); 3022 debug("config allows port forwarding to host %s port %d", host, port);
3002 3023
3024 permitted_adm_opens = xrealloc(permitted_adm_opens,
3025 num_adm_permitted_opens + 1, sizeof(*permitted_adm_opens));
3003 permitted_adm_opens[num_adm_permitted_opens].host_to_connect 3026 permitted_adm_opens[num_adm_permitted_opens].host_to_connect
3004 = xstrdup(host); 3027 = xstrdup(host);
3005 permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port; 3028 permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port;
@@ -3014,6 +3037,10 @@ channel_clear_permitted_opens(void)
3014 for (i = 0; i < num_permitted_opens; i++) 3037 for (i = 0; i < num_permitted_opens; i++)
3015 if (permitted_opens[i].host_to_connect != NULL) 3038 if (permitted_opens[i].host_to_connect != NULL)
3016 xfree(permitted_opens[i].host_to_connect); 3039 xfree(permitted_opens[i].host_to_connect);
3040 if (num_permitted_opens > 0) {
3041 xfree(permitted_opens);
3042 permitted_opens = NULL;
3043 }
3017 num_permitted_opens = 0; 3044 num_permitted_opens = 0;
3018} 3045}
3019 3046
@@ -3025,6 +3052,10 @@ channel_clear_adm_permitted_opens(void)
3025 for (i = 0; i < num_adm_permitted_opens; i++) 3052 for (i = 0; i < num_adm_permitted_opens; i++)
3026 if (permitted_adm_opens[i].host_to_connect != NULL) 3053 if (permitted_adm_opens[i].host_to_connect != NULL)
3027 xfree(permitted_adm_opens[i].host_to_connect); 3054 xfree(permitted_adm_opens[i].host_to_connect);
3055 if (num_adm_permitted_opens > 0) {
3056 xfree(permitted_adm_opens);
3057 permitted_adm_opens = NULL;
3058 }
3028 num_adm_permitted_opens = 0; 3059 num_adm_permitted_opens = 0;
3029} 3060}
3030 3061