diff options
Diffstat (limited to 'channels.c')
-rw-r--r-- | channels.c | 99 |
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. */ |
117 | static ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION]; | 117 | static 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. */ |
120 | static ForwardPermission permitted_adm_opens[SSH_MAX_FORWARDS_PER_DIRECTION]; | 120 | static 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. */ |
123 | static int num_permitted_opens = 0; | 123 | static 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 | ||
705 | void | 706 | void |
706 | channel_register_open_confirm(int id, channel_callback_fn *fn, void *ctx) | 707 | channel_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) | |||
991 | static void | 993 | static void |
992 | channel_pre_mux_client(Channel *c, fd_set *readset, fd_set *writeset) | 994 | channel_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) | |||
2982 | void | 3005 | void |
2983 | channel_add_permitted_opens(char *host, int port) | 3006 | channel_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) | |||
2996 | int | 3019 | int |
2997 | channel_add_adm_permitted_opens(char *host, int port) | 3020 | channel_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 | ||