diff options
Diffstat (limited to 'channels.c')
-rw-r--r-- | channels.c | 279 |
1 files changed, 214 insertions, 65 deletions
diff --git a/channels.c b/channels.c index 94065a443..a55d27817 100644 --- a/channels.c +++ b/channels.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: channels.c,v 1.296 2009/05/25 06:48:00 andreas Exp $ */ | 1 | /* $OpenBSD: channels.c,v 1.303 2010/01/30 21:12:08 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 |
@@ -53,6 +53,7 @@ | |||
53 | #include <arpa/inet.h> | 53 | #include <arpa/inet.h> |
54 | 54 | ||
55 | #include <errno.h> | 55 | #include <errno.h> |
56 | #include <fcntl.h> | ||
56 | #include <netdb.h> | 57 | #include <netdb.h> |
57 | #include <stdio.h> | 58 | #include <stdio.h> |
58 | #include <stdlib.h> | 59 | #include <stdlib.h> |
@@ -228,12 +229,16 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd, | |||
228 | channel_max_fd = MAX(channel_max_fd, wfd); | 229 | channel_max_fd = MAX(channel_max_fd, wfd); |
229 | channel_max_fd = MAX(channel_max_fd, efd); | 230 | channel_max_fd = MAX(channel_max_fd, efd); |
230 | 231 | ||
231 | /* XXX set close-on-exec -markus */ | 232 | if (rfd != -1) |
233 | fcntl(rfd, F_SETFD, FD_CLOEXEC); | ||
234 | if (wfd != -1 && wfd != rfd) | ||
235 | fcntl(wfd, F_SETFD, FD_CLOEXEC); | ||
236 | if (efd != -1 && efd != rfd && efd != wfd) | ||
237 | fcntl(efd, F_SETFD, FD_CLOEXEC); | ||
232 | 238 | ||
233 | c->rfd = rfd; | 239 | c->rfd = rfd; |
234 | c->wfd = wfd; | 240 | c->wfd = wfd; |
235 | c->sock = (rfd == wfd) ? rfd : -1; | 241 | c->sock = (rfd == wfd) ? rfd : -1; |
236 | c->ctl_fd = -1; /* XXX: set elsewhere */ | ||
237 | c->efd = efd; | 242 | c->efd = efd; |
238 | c->extended_usage = extusage; | 243 | c->extended_usage = extusage; |
239 | 244 | ||
@@ -322,6 +327,10 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, | |||
322 | c->output_filter = NULL; | 327 | c->output_filter = NULL; |
323 | c->filter_ctx = NULL; | 328 | c->filter_ctx = NULL; |
324 | c->filter_cleanup = NULL; | 329 | c->filter_cleanup = NULL; |
330 | c->ctl_chan = -1; | ||
331 | c->mux_rcb = NULL; | ||
332 | c->mux_ctx = NULL; | ||
333 | c->delayed = 1; /* prevent call to channel_post handler */ | ||
325 | TAILQ_INIT(&c->status_confirms); | 334 | TAILQ_INIT(&c->status_confirms); |
326 | debug("channel %d: new [%s]", found, remote_name); | 335 | debug("channel %d: new [%s]", found, remote_name); |
327 | return c; | 336 | return c; |
@@ -363,11 +372,10 @@ channel_close_fd(int *fdp) | |||
363 | static void | 372 | static void |
364 | channel_close_fds(Channel *c) | 373 | channel_close_fds(Channel *c) |
365 | { | 374 | { |
366 | debug3("channel %d: close_fds r %d w %d e %d c %d", | 375 | debug3("channel %d: close_fds r %d w %d e %d", |
367 | c->self, c->rfd, c->wfd, c->efd, c->ctl_fd); | 376 | c->self, c->rfd, c->wfd, c->efd); |
368 | 377 | ||
369 | channel_close_fd(&c->sock); | 378 | channel_close_fd(&c->sock); |
370 | channel_close_fd(&c->ctl_fd); | ||
371 | channel_close_fd(&c->rfd); | 379 | channel_close_fd(&c->rfd); |
372 | channel_close_fd(&c->wfd); | 380 | channel_close_fd(&c->wfd); |
373 | channel_close_fd(&c->efd); | 381 | channel_close_fd(&c->efd); |
@@ -393,8 +401,6 @@ channel_free(Channel *c) | |||
393 | 401 | ||
394 | if (c->sock != -1) | 402 | if (c->sock != -1) |
395 | shutdown(c->sock, SHUT_RDWR); | 403 | shutdown(c->sock, SHUT_RDWR); |
396 | if (c->ctl_fd != -1) | ||
397 | shutdown(c->ctl_fd, SHUT_RDWR); | ||
398 | channel_close_fds(c); | 404 | channel_close_fds(c); |
399 | buffer_free(&c->input); | 405 | buffer_free(&c->input); |
400 | buffer_free(&c->output); | 406 | buffer_free(&c->output); |
@@ -516,6 +522,7 @@ channel_still_open(void) | |||
516 | case SSH_CHANNEL_X11_LISTENER: | 522 | case SSH_CHANNEL_X11_LISTENER: |
517 | case SSH_CHANNEL_PORT_LISTENER: | 523 | case SSH_CHANNEL_PORT_LISTENER: |
518 | case SSH_CHANNEL_RPORT_LISTENER: | 524 | case SSH_CHANNEL_RPORT_LISTENER: |
525 | case SSH_CHANNEL_MUX_LISTENER: | ||
519 | case SSH_CHANNEL_CLOSED: | 526 | case SSH_CHANNEL_CLOSED: |
520 | case SSH_CHANNEL_AUTH_SOCKET: | 527 | case SSH_CHANNEL_AUTH_SOCKET: |
521 | case SSH_CHANNEL_DYNAMIC: | 528 | case SSH_CHANNEL_DYNAMIC: |
@@ -529,6 +536,7 @@ channel_still_open(void) | |||
529 | case SSH_CHANNEL_OPENING: | 536 | case SSH_CHANNEL_OPENING: |
530 | case SSH_CHANNEL_OPEN: | 537 | case SSH_CHANNEL_OPEN: |
531 | case SSH_CHANNEL_X11_OPEN: | 538 | case SSH_CHANNEL_X11_OPEN: |
539 | case SSH_CHANNEL_MUX_CLIENT: | ||
532 | return 1; | 540 | return 1; |
533 | case SSH_CHANNEL_INPUT_DRAINING: | 541 | case SSH_CHANNEL_INPUT_DRAINING: |
534 | case SSH_CHANNEL_OUTPUT_DRAINING: | 542 | case SSH_CHANNEL_OUTPUT_DRAINING: |
@@ -560,6 +568,8 @@ channel_find_open(void) | |||
560 | case SSH_CHANNEL_X11_LISTENER: | 568 | case SSH_CHANNEL_X11_LISTENER: |
561 | case SSH_CHANNEL_PORT_LISTENER: | 569 | case SSH_CHANNEL_PORT_LISTENER: |
562 | case SSH_CHANNEL_RPORT_LISTENER: | 570 | case SSH_CHANNEL_RPORT_LISTENER: |
571 | case SSH_CHANNEL_MUX_LISTENER: | ||
572 | case SSH_CHANNEL_MUX_CLIENT: | ||
563 | case SSH_CHANNEL_OPENING: | 573 | case SSH_CHANNEL_OPENING: |
564 | case SSH_CHANNEL_CONNECTING: | 574 | case SSH_CHANNEL_CONNECTING: |
565 | case SSH_CHANNEL_ZOMBIE: | 575 | case SSH_CHANNEL_ZOMBIE: |
@@ -610,6 +620,8 @@ channel_open_message(void) | |||
610 | case SSH_CHANNEL_CLOSED: | 620 | case SSH_CHANNEL_CLOSED: |
611 | case SSH_CHANNEL_AUTH_SOCKET: | 621 | case SSH_CHANNEL_AUTH_SOCKET: |
612 | case SSH_CHANNEL_ZOMBIE: | 622 | case SSH_CHANNEL_ZOMBIE: |
623 | case SSH_CHANNEL_MUX_CLIENT: | ||
624 | case SSH_CHANNEL_MUX_LISTENER: | ||
613 | continue; | 625 | continue; |
614 | case SSH_CHANNEL_LARVAL: | 626 | case SSH_CHANNEL_LARVAL: |
615 | case SSH_CHANNEL_OPENING: | 627 | case SSH_CHANNEL_OPENING: |
@@ -620,12 +632,12 @@ channel_open_message(void) | |||
620 | case SSH_CHANNEL_INPUT_DRAINING: | 632 | case SSH_CHANNEL_INPUT_DRAINING: |
621 | case SSH_CHANNEL_OUTPUT_DRAINING: | 633 | case SSH_CHANNEL_OUTPUT_DRAINING: |
622 | snprintf(buf, sizeof buf, | 634 | snprintf(buf, sizeof buf, |
623 | " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d cfd %d)\r\n", | 635 | " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d cc %d)\r\n", |
624 | c->self, c->remote_name, | 636 | c->self, c->remote_name, |
625 | c->type, c->remote_id, | 637 | c->type, c->remote_id, |
626 | c->istate, buffer_len(&c->input), | 638 | c->istate, buffer_len(&c->input), |
627 | c->ostate, buffer_len(&c->output), | 639 | c->ostate, buffer_len(&c->output), |
628 | c->rfd, c->wfd, c->ctl_fd); | 640 | c->rfd, c->wfd, c->ctl_chan); |
629 | buffer_append(&buffer, buf, strlen(buf)); | 641 | buffer_append(&buffer, buf, strlen(buf)); |
630 | continue; | 642 | continue; |
631 | default: | 643 | default: |
@@ -832,9 +844,6 @@ channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset) | |||
832 | FD_SET(c->efd, readset); | 844 | FD_SET(c->efd, readset); |
833 | } | 845 | } |
834 | /* XXX: What about efd? races? */ | 846 | /* XXX: What about efd? races? */ |
835 | if (compat20 && c->ctl_fd != -1 && | ||
836 | c->istate == CHAN_INPUT_OPEN && c->ostate == CHAN_OUTPUT_OPEN) | ||
837 | FD_SET(c->ctl_fd, readset); | ||
838 | } | 847 | } |
839 | 848 | ||
840 | /* ARGSUSED */ | 849 | /* ARGSUSED */ |
@@ -979,6 +988,28 @@ channel_pre_x11_open(Channel *c, fd_set *readset, fd_set *writeset) | |||
979 | } | 988 | } |
980 | } | 989 | } |
981 | 990 | ||
991 | static void | ||
992 | channel_pre_mux_client(Channel *c, fd_set *readset, fd_set *writeset) | ||
993 | { | ||
994 | if (c->istate == CHAN_INPUT_OPEN && | ||
995 | buffer_check_alloc(&c->input, CHAN_RBUF)) | ||
996 | FD_SET(c->rfd, readset); | ||
997 | if (c->istate == CHAN_INPUT_WAIT_DRAIN) { | ||
998 | /* clear buffer immediately (discard any partial packet) */ | ||
999 | buffer_clear(&c->input); | ||
1000 | chan_ibuf_empty(c); | ||
1001 | /* Start output drain. XXX just kill chan? */ | ||
1002 | chan_rcvd_oclose(c); | ||
1003 | } | ||
1004 | if (c->ostate == CHAN_OUTPUT_OPEN || | ||
1005 | c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { | ||
1006 | if (buffer_len(&c->output) > 0) | ||
1007 | FD_SET(c->wfd, writeset); | ||
1008 | else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) | ||
1009 | chan_obuf_empty(c); | ||
1010 | } | ||
1011 | } | ||
1012 | |||
982 | /* try to decode a socks4 header */ | 1013 | /* try to decode a socks4 header */ |
983 | /* ARGSUSED */ | 1014 | /* ARGSUSED */ |
984 | static int | 1015 | static int |
@@ -1210,6 +1241,30 @@ channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset) | |||
1210 | return 1; | 1241 | return 1; |
1211 | } | 1242 | } |
1212 | 1243 | ||
1244 | Channel * | ||
1245 | channel_connect_stdio_fwd(const char *host_to_connect, u_short port_to_connect, | ||
1246 | int in, int out) | ||
1247 | { | ||
1248 | Channel *c; | ||
1249 | |||
1250 | debug("channel_connect_stdio_fwd %s:%d", host_to_connect, | ||
1251 | port_to_connect); | ||
1252 | |||
1253 | c = channel_new("stdio-forward", SSH_CHANNEL_OPENING, in, out, | ||
1254 | -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, | ||
1255 | 0, "stdio-forward", /*nonblock*/0); | ||
1256 | |||
1257 | c->path = xstrdup(host_to_connect); | ||
1258 | c->host_port = port_to_connect; | ||
1259 | c->listening_port = 0; | ||
1260 | c->force_drain = 1; | ||
1261 | |||
1262 | channel_register_fds(c, in, out, -1, 0, 1, 0); | ||
1263 | port_open_helper(c, "direct-tcpip"); | ||
1264 | |||
1265 | return c; | ||
1266 | } | ||
1267 | |||
1213 | /* dynamic port forwarding */ | 1268 | /* dynamic port forwarding */ |
1214 | static void | 1269 | static void |
1215 | channel_pre_dynamic(Channel *c, fd_set *readset, fd_set *writeset) | 1270 | channel_pre_dynamic(Channel *c, fd_set *readset, fd_set *writeset) |
@@ -1219,7 +1274,6 @@ channel_pre_dynamic(Channel *c, fd_set *readset, fd_set *writeset) | |||
1219 | int ret; | 1274 | int ret; |
1220 | 1275 | ||
1221 | have = buffer_len(&c->input); | 1276 | have = buffer_len(&c->input); |
1222 | c->delayed = 0; | ||
1223 | debug2("channel %d: pre_dynamic: have %d", c->self, have); | 1277 | debug2("channel %d: pre_dynamic: have %d", c->self, have); |
1224 | /* buffer_dump(&c->input); */ | 1278 | /* buffer_dump(&c->input); */ |
1225 | /* check if the fixed size part of the packet is in buffer. */ | 1279 | /* check if the fixed size part of the packet is in buffer. */ |
@@ -1322,6 +1376,13 @@ port_open_helper(Channel *c, char *rtype) | |||
1322 | char *remote_ipaddr = get_peer_ipaddr(c->sock); | 1376 | char *remote_ipaddr = get_peer_ipaddr(c->sock); |
1323 | int remote_port = get_peer_port(c->sock); | 1377 | int remote_port = get_peer_port(c->sock); |
1324 | 1378 | ||
1379 | if (remote_port == -1) { | ||
1380 | /* Fake addr/port to appease peers that validate it (Tectia) */ | ||
1381 | xfree(remote_ipaddr); | ||
1382 | remote_ipaddr = xstrdup("127.0.0.1"); | ||
1383 | remote_port = 65535; | ||
1384 | } | ||
1385 | |||
1325 | direct = (strcmp(rtype, "direct-tcpip") == 0); | 1386 | direct = (strcmp(rtype, "direct-tcpip") == 0); |
1326 | 1387 | ||
1327 | snprintf(buf, sizeof buf, | 1388 | snprintf(buf, sizeof buf, |
@@ -1423,16 +1484,8 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset) | |||
1423 | if (c->path != NULL) | 1484 | if (c->path != NULL) |
1424 | nc->path = xstrdup(c->path); | 1485 | nc->path = xstrdup(c->path); |
1425 | 1486 | ||
1426 | if (nextstate == SSH_CHANNEL_DYNAMIC) { | 1487 | if (nextstate != SSH_CHANNEL_DYNAMIC) |
1427 | /* | ||
1428 | * do not call the channel_post handler until | ||
1429 | * this flag has been reset by a pre-handler. | ||
1430 | * otherwise the FD_ISSET calls might overflow | ||
1431 | */ | ||
1432 | nc->delayed = 1; | ||
1433 | } else { | ||
1434 | port_open_helper(nc, rtype); | 1488 | port_open_helper(nc, rtype); |
1435 | } | ||
1436 | } | 1489 | } |
1437 | } | 1490 | } |
1438 | 1491 | ||
@@ -1722,36 +1775,6 @@ channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset) | |||
1722 | return 1; | 1775 | return 1; |
1723 | } | 1776 | } |
1724 | 1777 | ||
1725 | /* ARGSUSED */ | ||
1726 | static int | ||
1727 | channel_handle_ctl(Channel *c, fd_set *readset, fd_set *writeset) | ||
1728 | { | ||
1729 | char buf[16]; | ||
1730 | int len; | ||
1731 | |||
1732 | /* Monitor control fd to detect if the slave client exits */ | ||
1733 | if (c->ctl_fd != -1 && FD_ISSET(c->ctl_fd, readset)) { | ||
1734 | len = read(c->ctl_fd, buf, sizeof(buf)); | ||
1735 | if (len < 0 && | ||
1736 | (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) | ||
1737 | return 1; | ||
1738 | if (len <= 0) { | ||
1739 | debug2("channel %d: ctl read<=0", c->self); | ||
1740 | if (c->type != SSH_CHANNEL_OPEN) { | ||
1741 | debug2("channel %d: not open", c->self); | ||
1742 | chan_mark_dead(c); | ||
1743 | return -1; | ||
1744 | } else { | ||
1745 | chan_read_failed(c); | ||
1746 | chan_write_failed(c); | ||
1747 | } | ||
1748 | return -1; | ||
1749 | } else | ||
1750 | fatal("%s: unexpected data on ctl fd", __func__); | ||
1751 | } | ||
1752 | return 1; | ||
1753 | } | ||
1754 | |||
1755 | static int | 1778 | static int |
1756 | channel_check_window(Channel *c) | 1779 | channel_check_window(Channel *c) |
1757 | { | 1780 | { |
@@ -1777,17 +1800,136 @@ channel_check_window(Channel *c) | |||
1777 | static void | 1800 | static void |
1778 | channel_post_open(Channel *c, fd_set *readset, fd_set *writeset) | 1801 | channel_post_open(Channel *c, fd_set *readset, fd_set *writeset) |
1779 | { | 1802 | { |
1780 | if (c->delayed) | ||
1781 | return; | ||
1782 | channel_handle_rfd(c, readset, writeset); | 1803 | channel_handle_rfd(c, readset, writeset); |
1783 | channel_handle_wfd(c, readset, writeset); | 1804 | channel_handle_wfd(c, readset, writeset); |
1784 | if (!compat20) | 1805 | if (!compat20) |
1785 | return; | 1806 | return; |
1786 | channel_handle_efd(c, readset, writeset); | 1807 | channel_handle_efd(c, readset, writeset); |
1787 | channel_handle_ctl(c, readset, writeset); | ||
1788 | channel_check_window(c); | 1808 | channel_check_window(c); |
1789 | } | 1809 | } |
1790 | 1810 | ||
1811 | static u_int | ||
1812 | read_mux(Channel *c, u_int need) | ||
1813 | { | ||
1814 | char buf[CHAN_RBUF]; | ||
1815 | int len; | ||
1816 | u_int rlen; | ||
1817 | |||
1818 | if (buffer_len(&c->input) < need) { | ||
1819 | rlen = need - buffer_len(&c->input); | ||
1820 | len = read(c->rfd, buf, MIN(rlen, CHAN_RBUF)); | ||
1821 | if (len <= 0) { | ||
1822 | if (errno != EINTR && errno != EAGAIN) { | ||
1823 | debug2("channel %d: ctl read<=0 rfd %d len %d", | ||
1824 | c->self, c->rfd, len); | ||
1825 | chan_read_failed(c); | ||
1826 | return 0; | ||
1827 | } | ||
1828 | } else | ||
1829 | buffer_append(&c->input, buf, len); | ||
1830 | } | ||
1831 | return buffer_len(&c->input); | ||
1832 | } | ||
1833 | |||
1834 | static void | ||
1835 | channel_post_mux_client(Channel *c, fd_set *readset, fd_set *writeset) | ||
1836 | { | ||
1837 | u_int need; | ||
1838 | ssize_t len; | ||
1839 | |||
1840 | if (!compat20) | ||
1841 | fatal("%s: entered with !compat20", __func__); | ||
1842 | |||
1843 | if (c->rfd != -1 && FD_ISSET(c->rfd, readset) && | ||
1844 | (c->istate == CHAN_INPUT_OPEN || | ||
1845 | c->istate == CHAN_INPUT_WAIT_DRAIN)) { | ||
1846 | /* | ||
1847 | * Don't not read past the precise end of packets to | ||
1848 | * avoid disrupting fd passing. | ||
1849 | */ | ||
1850 | if (read_mux(c, 4) < 4) /* read header */ | ||
1851 | return; | ||
1852 | need = get_u32(buffer_ptr(&c->input)); | ||
1853 | #define CHANNEL_MUX_MAX_PACKET (256 * 1024) | ||
1854 | if (need > CHANNEL_MUX_MAX_PACKET) { | ||
1855 | debug2("channel %d: packet too big %u > %u", | ||
1856 | c->self, CHANNEL_MUX_MAX_PACKET, need); | ||
1857 | chan_rcvd_oclose(c); | ||
1858 | return; | ||
1859 | } | ||
1860 | if (read_mux(c, need + 4) < need + 4) /* read body */ | ||
1861 | return; | ||
1862 | if (c->mux_rcb(c) != 0) { | ||
1863 | debug("channel %d: mux_rcb failed", c->self); | ||
1864 | chan_mark_dead(c); | ||
1865 | return; | ||
1866 | } | ||
1867 | } | ||
1868 | |||
1869 | if (c->wfd != -1 && FD_ISSET(c->wfd, writeset) && | ||
1870 | buffer_len(&c->output) > 0) { | ||
1871 | len = write(c->wfd, buffer_ptr(&c->output), | ||
1872 | buffer_len(&c->output)); | ||
1873 | if (len < 0 && (errno == EINTR || errno == EAGAIN)) | ||
1874 | return; | ||
1875 | if (len <= 0) { | ||
1876 | chan_mark_dead(c); | ||
1877 | return; | ||
1878 | } | ||
1879 | buffer_consume(&c->output, len); | ||
1880 | } | ||
1881 | } | ||
1882 | |||
1883 | static void | ||
1884 | channel_post_mux_listener(Channel *c, fd_set *readset, fd_set *writeset) | ||
1885 | { | ||
1886 | Channel *nc; | ||
1887 | struct sockaddr_storage addr; | ||
1888 | socklen_t addrlen; | ||
1889 | int newsock; | ||
1890 | uid_t euid; | ||
1891 | gid_t egid; | ||
1892 | |||
1893 | if (!FD_ISSET(c->sock, readset)) | ||
1894 | return; | ||
1895 | |||
1896 | debug("multiplexing control connection"); | ||
1897 | |||
1898 | /* | ||
1899 | * Accept connection on control socket | ||
1900 | */ | ||
1901 | memset(&addr, 0, sizeof(addr)); | ||
1902 | addrlen = sizeof(addr); | ||
1903 | if ((newsock = accept(c->sock, (struct sockaddr*)&addr, | ||
1904 | &addrlen)) == -1) { | ||
1905 | error("%s accept: %s", __func__, strerror(errno)); | ||
1906 | return; | ||
1907 | } | ||
1908 | |||
1909 | if (getpeereid(newsock, &euid, &egid) < 0) { | ||
1910 | error("%s getpeereid failed: %s", __func__, | ||
1911 | strerror(errno)); | ||
1912 | close(newsock); | ||
1913 | return; | ||
1914 | } | ||
1915 | if ((euid != 0) && (getuid() != euid)) { | ||
1916 | error("multiplex uid mismatch: peer euid %u != uid %u", | ||
1917 | (u_int)euid, (u_int)getuid()); | ||
1918 | close(newsock); | ||
1919 | return; | ||
1920 | } | ||
1921 | nc = channel_new("multiplex client", SSH_CHANNEL_MUX_CLIENT, | ||
1922 | newsock, newsock, -1, c->local_window_max, | ||
1923 | c->local_maxpacket, 0, "mux-control", 1); | ||
1924 | nc->mux_rcb = c->mux_rcb; | ||
1925 | debug3("%s: new mux channel %d fd %d", __func__, | ||
1926 | nc->self, nc->sock); | ||
1927 | /* establish state */ | ||
1928 | nc->mux_rcb(nc); | ||
1929 | /* mux state transitions must not elicit protocol messages */ | ||
1930 | nc->flags |= CHAN_LOCAL; | ||
1931 | } | ||
1932 | |||
1791 | /* ARGSUSED */ | 1933 | /* ARGSUSED */ |
1792 | static void | 1934 | static void |
1793 | channel_post_output_drain_13(Channel *c, fd_set *readset, fd_set *writeset) | 1935 | channel_post_output_drain_13(Channel *c, fd_set *readset, fd_set *writeset) |
@@ -1816,6 +1958,8 @@ channel_handler_init_20(void) | |||
1816 | channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; | 1958 | channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; |
1817 | channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; | 1959 | channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; |
1818 | channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; | 1960 | channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; |
1961 | channel_pre[SSH_CHANNEL_MUX_LISTENER] = &channel_pre_listener; | ||
1962 | channel_pre[SSH_CHANNEL_MUX_CLIENT] = &channel_pre_mux_client; | ||
1819 | 1963 | ||
1820 | channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; | 1964 | channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; |
1821 | channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; | 1965 | channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; |
@@ -1824,6 +1968,8 @@ channel_handler_init_20(void) | |||
1824 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; | 1968 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; |
1825 | channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; | 1969 | channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; |
1826 | channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; | 1970 | channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; |
1971 | channel_post[SSH_CHANNEL_MUX_LISTENER] = &channel_post_mux_listener; | ||
1972 | channel_post[SSH_CHANNEL_MUX_CLIENT] = &channel_post_mux_client; | ||
1827 | } | 1973 | } |
1828 | 1974 | ||
1829 | static void | 1975 | static void |
@@ -1910,17 +2056,23 @@ static void | |||
1910 | channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset) | 2056 | channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset) |
1911 | { | 2057 | { |
1912 | static int did_init = 0; | 2058 | static int did_init = 0; |
1913 | u_int i; | 2059 | u_int i, oalloc; |
1914 | Channel *c; | 2060 | Channel *c; |
1915 | 2061 | ||
1916 | if (!did_init) { | 2062 | if (!did_init) { |
1917 | channel_handler_init(); | 2063 | channel_handler_init(); |
1918 | did_init = 1; | 2064 | did_init = 1; |
1919 | } | 2065 | } |
1920 | for (i = 0; i < channels_alloc; i++) { | 2066 | for (i = 0, oalloc = channels_alloc; i < oalloc; i++) { |
1921 | c = channels[i]; | 2067 | c = channels[i]; |
1922 | if (c == NULL) | 2068 | if (c == NULL) |
1923 | continue; | 2069 | continue; |
2070 | if (c->delayed) { | ||
2071 | if (ftab == channel_pre) | ||
2072 | c->delayed = 0; | ||
2073 | else | ||
2074 | continue; | ||
2075 | } | ||
1924 | if (ftab[c->type] != NULL) | 2076 | if (ftab[c->type] != NULL) |
1925 | (*ftab[c->type])(c, readset, writeset); | 2077 | (*ftab[c->type])(c, readset, writeset); |
1926 | channel_garbage_collect(c); | 2078 | channel_garbage_collect(c); |
@@ -2577,6 +2729,8 @@ channel_setup_fwd_listener(int type, const char *listen_addr, | |||
2577 | } | 2729 | } |
2578 | 2730 | ||
2579 | channel_set_reuseaddr(sock); | 2731 | channel_set_reuseaddr(sock); |
2732 | if (ai->ai_family == AF_INET6) | ||
2733 | sock_set_v6only(sock); | ||
2580 | 2734 | ||
2581 | debug("Local forwarding listening on %s port %s.", | 2735 | debug("Local forwarding listening on %s port %s.", |
2582 | ntop, strport); | 2736 | ntop, strport); |
@@ -3112,13 +3266,8 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost, | |||
3112 | continue; | 3266 | continue; |
3113 | } | 3267 | } |
3114 | } | 3268 | } |
3115 | #ifdef IPV6_V6ONLY | 3269 | if (ai->ai_family == AF_INET6) |
3116 | if (ai->ai_family == AF_INET6) { | 3270 | sock_set_v6only(sock); |
3117 | int on = 1; | ||
3118 | if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) | ||
3119 | error("setsockopt IPV6_V6ONLY: %.100s", strerror(errno)); | ||
3120 | } | ||
3121 | #endif | ||
3122 | if (x11_use_localhost) | 3271 | if (x11_use_localhost) |
3123 | channel_set_reuseaddr(sock); | 3272 | channel_set_reuseaddr(sock); |
3124 | if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { | 3273 | if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { |