summaryrefslogtreecommitdiff
path: root/channels.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2006-05-12 08:53:37 +0000
committerColin Watson <cjwatson@debian.org>2006-05-12 08:53:37 +0000
commit2ee73b36b9a35daeaa4b065046882dc1f5f551b6 (patch)
treef64a4ace625514e94759878c0b94ab0a79805bbd /channels.c
parent3c190ec8e469477ea65fbf4cc83062c65c281434 (diff)
parent3e2e0ac10674d77618c4c7339e18b83ced247492 (diff)
Merge 4.3p2 to the trunk.
Diffstat (limited to 'channels.c')
-rw-r--r--channels.c168
1 files changed, 130 insertions, 38 deletions
diff --git a/channels.c b/channels.c
index 707b57d86..92448da77 100644
--- a/channels.c
+++ b/channels.c
@@ -39,7 +39,7 @@
39 */ 39 */
40 40
41#include "includes.h" 41#include "includes.h"
42RCSID("$OpenBSD: channels.c,v 1.223 2005/07/17 07:17:54 djm Exp $"); 42RCSID("$OpenBSD: channels.c,v 1.232 2006/01/30 12:22:22 reyk Exp $");
43 43
44#include "ssh.h" 44#include "ssh.h"
45#include "ssh1.h" 45#include "ssh1.h"
@@ -58,8 +58,6 @@ RCSID("$OpenBSD: channels.c,v 1.223 2005/07/17 07:17:54 djm Exp $");
58 58
59/* -- channel core */ 59/* -- channel core */
60 60
61#define CHAN_RBUF 16*1024
62
63/* 61/*
64 * Pointer to an array containing all allocated channels. The array is 62 * Pointer to an array containing all allocated channels. The array is
65 * dynamically extended as needed. 63 * dynamically extended as needed.
@@ -142,23 +140,51 @@ static void port_open_helper(Channel *c, char *rtype);
142/* -- channel core */ 140/* -- channel core */
143 141
144Channel * 142Channel *
145channel_lookup(int id) 143channel_by_id(int id)
146{ 144{
147 Channel *c; 145 Channel *c;
148 146
149 if (id < 0 || (u_int)id >= channels_alloc) { 147 if (id < 0 || (u_int)id >= channels_alloc) {
150 logit("channel_lookup: %d: bad id", id); 148 logit("channel_by_id: %d: bad id", id);
151 return NULL; 149 return NULL;
152 } 150 }
153 c = channels[id]; 151 c = channels[id];
154 if (c == NULL) { 152 if (c == NULL) {
155 logit("channel_lookup: %d: bad id: channel free", id); 153 logit("channel_by_id: %d: bad id: channel free", id);
156 return NULL; 154 return NULL;
157 } 155 }
158 return c; 156 return c;
159} 157}
160 158
161/* 159/*
160 * Returns the channel if it is allowed to receive protocol messages.
161 * Private channels, like listening sockets, may not receive messages.
162 */
163Channel *
164channel_lookup(int id)
165{
166 Channel *c;
167
168 if ((c = channel_by_id(id)) == NULL)
169 return (NULL);
170
171 switch(c->type) {
172 case SSH_CHANNEL_X11_OPEN:
173 case SSH_CHANNEL_LARVAL:
174 case SSH_CHANNEL_CONNECTING:
175 case SSH_CHANNEL_DYNAMIC:
176 case SSH_CHANNEL_OPENING:
177 case SSH_CHANNEL_OPEN:
178 case SSH_CHANNEL_INPUT_DRAINING:
179 case SSH_CHANNEL_OUTPUT_DRAINING:
180 return (c);
181 break;
182 }
183 logit("Non-public channel %d, type %d.", id, c->type);
184 return (NULL);
185}
186
187/*
162 * Register filedescriptors for a channel, used when allocating a channel or 188 * Register filedescriptors for a channel, used when allocating a channel or
163 * when the channel consumer/producer is ready, e.g. shell exec'd 189 * when the channel consumer/producer is ready, e.g. shell exec'd
164 */ 190 */
@@ -269,9 +295,11 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
269 c->force_drain = 0; 295 c->force_drain = 0;
270 c->single_connection = 0; 296 c->single_connection = 0;
271 c->detach_user = NULL; 297 c->detach_user = NULL;
298 c->detach_close = 0;
272 c->confirm = NULL; 299 c->confirm = NULL;
273 c->confirm_ctx = NULL; 300 c->confirm_ctx = NULL;
274 c->input_filter = NULL; 301 c->input_filter = NULL;
302 c->output_filter = NULL;
275 debug("channel %d: new [%s]", found, remote_name); 303 debug("channel %d: new [%s]", found, remote_name);
276 return c; 304 return c;
277} 305}
@@ -628,29 +656,32 @@ channel_register_confirm(int id, channel_callback_fn *fn, void *ctx)
628 c->confirm_ctx = ctx; 656 c->confirm_ctx = ctx;
629} 657}
630void 658void
631channel_register_cleanup(int id, channel_callback_fn *fn) 659channel_register_cleanup(int id, channel_callback_fn *fn, int do_close)
632{ 660{
633 Channel *c = channel_lookup(id); 661 Channel *c = channel_by_id(id);
634 662
635 if (c == NULL) { 663 if (c == NULL) {
636 logit("channel_register_cleanup: %d: bad id", id); 664 logit("channel_register_cleanup: %d: bad id", id);
637 return; 665 return;
638 } 666 }
639 c->detach_user = fn; 667 c->detach_user = fn;
668 c->detach_close = do_close;
640} 669}
641void 670void
642channel_cancel_cleanup(int id) 671channel_cancel_cleanup(int id)
643{ 672{
644 Channel *c = channel_lookup(id); 673 Channel *c = channel_by_id(id);
645 674
646 if (c == NULL) { 675 if (c == NULL) {
647 logit("channel_cancel_cleanup: %d: bad id", id); 676 logit("channel_cancel_cleanup: %d: bad id", id);
648 return; 677 return;
649 } 678 }
650 c->detach_user = NULL; 679 c->detach_user = NULL;
680 c->detach_close = 0;
651} 681}
652void 682void
653channel_register_filter(int id, channel_filter_fn *fn) 683channel_register_filter(int id, channel_infilter_fn *ifn,
684 channel_outfilter_fn *ofn)
654{ 685{
655 Channel *c = channel_lookup(id); 686 Channel *c = channel_lookup(id);
656 687
@@ -658,7 +689,8 @@ channel_register_filter(int id, channel_filter_fn *fn)
658 logit("channel_register_filter: %d: bad id", id); 689 logit("channel_register_filter: %d: bad id", id);
659 return; 690 return;
660 } 691 }
661 c->input_filter = fn; 692 c->input_filter = ifn;
693 c->output_filter = ofn;
662} 694}
663 695
664void 696void
@@ -1227,6 +1259,19 @@ port_open_helper(Channel *c, char *rtype)
1227 xfree(remote_ipaddr); 1259 xfree(remote_ipaddr);
1228} 1260}
1229 1261
1262static void
1263channel_set_reuseaddr(int fd)
1264{
1265 int on = 1;
1266
1267 /*
1268 * Set socket options.
1269 * Allow local port reuse in TIME_WAIT.
1270 */
1271 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
1272 error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno));
1273}
1274
1230/* 1275/*
1231 * This socket is listening for connections to a forwarded TCP/IP port. 1276 * This socket is listening for connections to a forwarded TCP/IP port.
1232 */ 1277 */
@@ -1398,6 +1443,8 @@ channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset)
1398 debug2("channel %d: filter stops", c->self); 1443 debug2("channel %d: filter stops", c->self);
1399 chan_read_failed(c); 1444 chan_read_failed(c);
1400 } 1445 }
1446 } else if (c->datagram) {
1447 buffer_put_string(&c->input, buf, len);
1401 } else { 1448 } else {
1402 buffer_append(&c->input, buf, len); 1449 buffer_append(&c->input, buf, len);
1403 } 1450 }
@@ -1408,7 +1455,7 @@ static int
1408channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset) 1455channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset)
1409{ 1456{
1410 struct termios tio; 1457 struct termios tio;
1411 u_char *data; 1458 u_char *data = NULL, *buf;
1412 u_int dlen; 1459 u_int dlen;
1413 int len; 1460 int len;
1414 1461
@@ -1416,14 +1463,45 @@ channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset)
1416 if (c->wfd != -1 && 1463 if (c->wfd != -1 &&
1417 FD_ISSET(c->wfd, writeset) && 1464 FD_ISSET(c->wfd, writeset) &&
1418 buffer_len(&c->output) > 0) { 1465 buffer_len(&c->output) > 0) {
1419 data = buffer_ptr(&c->output); 1466 if (c->output_filter != NULL) {
1420 dlen = buffer_len(&c->output); 1467 if ((buf = c->output_filter(c, &data, &dlen)) == NULL) {
1468 debug2("channel %d: filter stops", c->self);
1469 if (c->type != SSH_CHANNEL_OPEN)
1470 chan_mark_dead(c);
1471 else
1472 chan_write_failed(c);
1473 return -1;
1474 }
1475 } else if (c->datagram) {
1476 buf = data = buffer_get_string(&c->output, &dlen);
1477 } else {
1478 buf = data = buffer_ptr(&c->output);
1479 dlen = buffer_len(&c->output);
1480 }
1481
1482 if (c->datagram) {
1483 /* ignore truncated writes, datagrams might get lost */
1484 c->local_consumed += dlen + 4;
1485 len = write(c->wfd, buf, dlen);
1486 xfree(data);
1487 if (len < 0 && (errno == EINTR || errno == EAGAIN))
1488 return 1;
1489 if (len <= 0) {
1490 if (c->type != SSH_CHANNEL_OPEN)
1491 chan_mark_dead(c);
1492 else
1493 chan_write_failed(c);
1494 return -1;
1495 }
1496 return 1;
1497 }
1421#ifdef _AIX 1498#ifdef _AIX
1422 /* XXX: Later AIX versions can't push as much data to tty */ 1499 /* XXX: Later AIX versions can't push as much data to tty */
1423 if (compat20 && c->wfd_isatty) 1500 if (compat20 && c->wfd_isatty)
1424 dlen = MIN(dlen, 8*1024); 1501 dlen = MIN(dlen, 8*1024);
1425#endif 1502#endif
1426 len = write(c->wfd, data, dlen); 1503
1504 len = write(c->wfd, buf, dlen);
1427 if (len < 0 && (errno == EINTR || errno == EAGAIN)) 1505 if (len < 0 && (errno == EINTR || errno == EAGAIN))
1428 return 1; 1506 return 1;
1429 if (len <= 0) { 1507 if (len <= 0) {
@@ -1440,14 +1518,14 @@ channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset)
1440 } 1518 }
1441 return -1; 1519 return -1;
1442 } 1520 }
1443 if (compat20 && c->isatty && dlen >= 1 && data[0] != '\r') { 1521 if (compat20 && c->isatty && dlen >= 1 && buf[0] != '\r') {
1444 if (tcgetattr(c->wfd, &tio) == 0 && 1522 if (tcgetattr(c->wfd, &tio) == 0 &&
1445 !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) { 1523 !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
1446 /* 1524 /*
1447 * Simulate echo to reduce the impact of 1525 * Simulate echo to reduce the impact of
1448 * traffic analysis. We need to match the 1526 * traffic analysis. We need to match the
1449 * size of a SSH2_MSG_CHANNEL_DATA message 1527 * size of a SSH2_MSG_CHANNEL_DATA message
1450 * (4 byte channel id + data) 1528 * (4 byte channel id + buf)
1451 */ 1529 */
1452 packet_send_ignore(4 + len); 1530 packet_send_ignore(4 + len);
1453 packet_send(); 1531 packet_send();
@@ -1666,7 +1744,7 @@ channel_garbage_collect(Channel *c)
1666 if (c == NULL) 1744 if (c == NULL)
1667 return; 1745 return;
1668 if (c->detach_user != NULL) { 1746 if (c->detach_user != NULL) {
1669 if (!chan_is_dead(c, 0)) 1747 if (!chan_is_dead(c, c->detach_close))
1670 return; 1748 return;
1671 debug2("channel %d: gc: notify user", c->self); 1749 debug2("channel %d: gc: notify user", c->self);
1672 c->detach_user(c->self, NULL); 1750 c->detach_user(c->self, NULL);
@@ -1776,6 +1854,22 @@ channel_output_poll(void)
1776 if ((c->istate == CHAN_INPUT_OPEN || 1854 if ((c->istate == CHAN_INPUT_OPEN ||
1777 c->istate == CHAN_INPUT_WAIT_DRAIN) && 1855 c->istate == CHAN_INPUT_WAIT_DRAIN) &&
1778 (len = buffer_len(&c->input)) > 0) { 1856 (len = buffer_len(&c->input)) > 0) {
1857 if (c->datagram) {
1858 if (len > 0) {
1859 u_char *data;
1860 u_int dlen;
1861
1862 data = buffer_get_string(&c->input,
1863 &dlen);
1864 packet_start(SSH2_MSG_CHANNEL_DATA);
1865 packet_put_int(c->remote_id);
1866 packet_put_string(data, dlen);
1867 packet_send();
1868 c->remote_window -= dlen + 4;
1869 xfree(data);
1870 }
1871 continue;
1872 }
1779 /* 1873 /*
1780 * Send some data for the other side over the secure 1874 * Send some data for the other side over the secure
1781 * connection. 1875 * connection.
@@ -1898,7 +1992,10 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
1898 c->local_window -= data_len; 1992 c->local_window -= data_len;
1899 } 1993 }
1900 packet_check_eom(); 1994 packet_check_eom();
1901 buffer_append(&c->output, data, data_len); 1995 if (c->datagram)
1996 buffer_put_string(&c->output, data, data_len);
1997 else
1998 buffer_append(&c->output, data, data_len);
1902 xfree(data); 1999 xfree(data);
1903} 2000}
1904 2001
@@ -2129,9 +2226,8 @@ channel_input_window_adjust(int type, u_int32_t seq, void *ctxt)
2129 id = packet_get_int(); 2226 id = packet_get_int();
2130 c = channel_lookup(id); 2227 c = channel_lookup(id);
2131 2228
2132 if (c == NULL || c->type != SSH_CHANNEL_OPEN) { 2229 if (c == NULL) {
2133 logit("Received window adjust for " 2230 logit("Received window adjust for non-open channel %d.", id);
2134 "non-open channel %d.", id);
2135 return; 2231 return;
2136 } 2232 }
2137 adjust = packet_get_int(); 2233 adjust = packet_get_int();
@@ -2188,7 +2284,7 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por
2188 const char *host_to_connect, u_short port_to_connect, int gateway_ports) 2284 const char *host_to_connect, u_short port_to_connect, int gateway_ports)
2189{ 2285{
2190 Channel *c; 2286 Channel *c;
2191 int sock, r, success = 0, on = 1, wildcard = 0, is_client; 2287 int sock, r, success = 0, wildcard = 0, is_client;
2192 struct addrinfo hints, *ai, *aitop; 2288 struct addrinfo hints, *ai, *aitop;
2193 const char *host, *addr; 2289 const char *host, *addr;
2194 char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 2290 char ntop[NI_MAXHOST], strport[NI_MAXSERV];
@@ -2275,13 +2371,8 @@ channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_por
2275 verbose("socket: %.100s", strerror(errno)); 2371 verbose("socket: %.100s", strerror(errno));
2276 continue; 2372 continue;
2277 } 2373 }
2278 /* 2374
2279 * Set socket options. 2375 channel_set_reuseaddr(sock);
2280 * Allow local port reuse in TIME_WAIT.
2281 */
2282 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on,
2283 sizeof(on)) == -1)
2284 error("setsockopt SO_REUSEADDR: %s", strerror(errno));
2285 2376
2286 debug("Local forwarding listening on %s port %s.", ntop, strport); 2377 debug("Local forwarding listening on %s port %s.", ntop, strport);
2287 2378
@@ -2453,7 +2544,7 @@ channel_request_rforward_cancel(const char *host, u_short port)
2453 2544
2454 permitted_opens[i].listen_port = 0; 2545 permitted_opens[i].listen_port = 0;
2455 permitted_opens[i].port_to_connect = 0; 2546 permitted_opens[i].port_to_connect = 0;
2456 free(permitted_opens[i].host_to_connect); 2547 xfree(permitted_opens[i].host_to_connect);
2457 permitted_opens[i].host_to_connect = NULL; 2548 permitted_opens[i].host_to_connect = NULL;
2458} 2549}
2459 2550
@@ -2668,6 +2759,9 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost,
2668 char strport[NI_MAXSERV]; 2759 char strport[NI_MAXSERV];
2669 int gaierr, n, num_socks = 0, socks[NUM_SOCKS]; 2760 int gaierr, n, num_socks = 0, socks[NUM_SOCKS];
2670 2761
2762 if (chanids == NULL)
2763 return -1;
2764
2671 for (display_number = x11_display_offset; 2765 for (display_number = x11_display_offset;
2672 display_number < MAX_DISPLAYS; 2766 display_number < MAX_DISPLAYS;
2673 display_number++) { 2767 display_number++) {
@@ -2708,6 +2802,7 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost,
2708 error("setsockopt IPV6_V6ONLY: %.100s", strerror(errno)); 2802 error("setsockopt IPV6_V6ONLY: %.100s", strerror(errno));
2709 } 2803 }
2710#endif 2804#endif
2805 channel_set_reuseaddr(sock);
2711 if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { 2806 if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
2712 debug2("bind port %d: %.100s", port, strerror(errno)); 2807 debug2("bind port %d: %.100s", port, strerror(errno));
2713 close(sock); 2808 close(sock);
@@ -2753,8 +2848,7 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost,
2753 } 2848 }
2754 2849
2755 /* Allocate a channel for each socket. */ 2850 /* Allocate a channel for each socket. */
2756 if (chanids != NULL) 2851 *chanids = xmalloc(sizeof(**chanids) * (num_socks + 1));
2757 *chanids = xmalloc(sizeof(**chanids) * (num_socks + 1));
2758 for (n = 0; n < num_socks; n++) { 2852 for (n = 0; n < num_socks; n++) {
2759 sock = socks[n]; 2853 sock = socks[n];
2760 nc = channel_new("x11 listener", 2854 nc = channel_new("x11 listener",
@@ -2762,11 +2856,9 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost,
2762 CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 2856 CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
2763 0, "X11 inet listener", 1); 2857 0, "X11 inet listener", 1);
2764 nc->single_connection = single_connection; 2858 nc->single_connection = single_connection;
2765 if (*chanids != NULL) 2859 (*chanids)[n] = nc->self;
2766 (*chanids)[n] = nc->self;
2767 } 2860 }
2768 if (*chanids != NULL) 2861 (*chanids)[n] = -1;
2769 (*chanids)[n] = -1;
2770 2862
2771 /* Return the display number for the DISPLAY environment variable. */ 2863 /* Return the display number for the DISPLAY environment variable. */
2772 *display_numberp = display_number; 2864 *display_numberp = display_number;
@@ -2952,7 +3044,7 @@ deny_input_open(int type, u_int32_t seq, void *ctxt)
2952 error("deny_input_open: type %d", type); 3044 error("deny_input_open: type %d", type);
2953 break; 3045 break;
2954 } 3046 }
2955 error("Warning: this is probably a break in attempt by a malicious server."); 3047 error("Warning: this is probably a break-in attempt by a malicious server.");
2956 packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); 3048 packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
2957 packet_put_int(rchan); 3049 packet_put_int(rchan);
2958 packet_send(); 3050 packet_send();