summaryrefslogtreecommitdiff
path: root/channels.c
diff options
context:
space:
mode:
Diffstat (limited to 'channels.c')
-rw-r--r--channels.c214
1 files changed, 164 insertions, 50 deletions
diff --git a/channels.c b/channels.c
index e8589d8c4..81261679a 100644
--- a/channels.c
+++ b/channels.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: channels.c,v 1.301 2010/01/11 01:39:46 dtucker Exp $ */ 1/* $OpenBSD: channels.c,v 1.302 2010/01/26 01:28:35 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
@@ -239,7 +239,6 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd,
239 c->rfd = rfd; 239 c->rfd = rfd;
240 c->wfd = wfd; 240 c->wfd = wfd;
241 c->sock = (rfd == wfd) ? rfd : -1; 241 c->sock = (rfd == wfd) ? rfd : -1;
242 c->ctl_fd = -1; /* XXX: set elsewhere */
243 c->efd = efd; 242 c->efd = efd;
244 c->extended_usage = extusage; 243 c->extended_usage = extusage;
245 244
@@ -328,6 +327,9 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
328 c->output_filter = NULL; 327 c->output_filter = NULL;
329 c->filter_ctx = NULL; 328 c->filter_ctx = NULL;
330 c->filter_cleanup = NULL; 329 c->filter_cleanup = NULL;
330 c->ctl_chan = -1;
331 c->mux_rcb = NULL;
332 c->mux_ctx = NULL;
331 c->delayed = 1; /* prevent call to channel_post handler */ 333 c->delayed = 1; /* prevent call to channel_post handler */
332 TAILQ_INIT(&c->status_confirms); 334 TAILQ_INIT(&c->status_confirms);
333 debug("channel %d: new [%s]", found, remote_name); 335 debug("channel %d: new [%s]", found, remote_name);
@@ -370,11 +372,10 @@ channel_close_fd(int *fdp)
370static void 372static void
371channel_close_fds(Channel *c) 373channel_close_fds(Channel *c)
372{ 374{
373 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",
374 c->self, c->rfd, c->wfd, c->efd, c->ctl_fd); 376 c->self, c->rfd, c->wfd, c->efd);
375 377
376 channel_close_fd(&c->sock); 378 channel_close_fd(&c->sock);
377 channel_close_fd(&c->ctl_fd);
378 channel_close_fd(&c->rfd); 379 channel_close_fd(&c->rfd);
379 channel_close_fd(&c->wfd); 380 channel_close_fd(&c->wfd);
380 channel_close_fd(&c->efd); 381 channel_close_fd(&c->efd);
@@ -400,8 +401,6 @@ channel_free(Channel *c)
400 401
401 if (c->sock != -1) 402 if (c->sock != -1)
402 shutdown(c->sock, SHUT_RDWR); 403 shutdown(c->sock, SHUT_RDWR);
403 if (c->ctl_fd != -1)
404 shutdown(c->ctl_fd, SHUT_RDWR);
405 channel_close_fds(c); 404 channel_close_fds(c);
406 buffer_free(&c->input); 405 buffer_free(&c->input);
407 buffer_free(&c->output); 406 buffer_free(&c->output);
@@ -523,6 +522,7 @@ channel_still_open(void)
523 case SSH_CHANNEL_X11_LISTENER: 522 case SSH_CHANNEL_X11_LISTENER:
524 case SSH_CHANNEL_PORT_LISTENER: 523 case SSH_CHANNEL_PORT_LISTENER:
525 case SSH_CHANNEL_RPORT_LISTENER: 524 case SSH_CHANNEL_RPORT_LISTENER:
525 case SSH_CHANNEL_MUX_LISTENER:
526 case SSH_CHANNEL_CLOSED: 526 case SSH_CHANNEL_CLOSED:
527 case SSH_CHANNEL_AUTH_SOCKET: 527 case SSH_CHANNEL_AUTH_SOCKET:
528 case SSH_CHANNEL_DYNAMIC: 528 case SSH_CHANNEL_DYNAMIC:
@@ -536,6 +536,7 @@ channel_still_open(void)
536 case SSH_CHANNEL_OPENING: 536 case SSH_CHANNEL_OPENING:
537 case SSH_CHANNEL_OPEN: 537 case SSH_CHANNEL_OPEN:
538 case SSH_CHANNEL_X11_OPEN: 538 case SSH_CHANNEL_X11_OPEN:
539 case SSH_CHANNEL_MUX_CLIENT:
539 return 1; 540 return 1;
540 case SSH_CHANNEL_INPUT_DRAINING: 541 case SSH_CHANNEL_INPUT_DRAINING:
541 case SSH_CHANNEL_OUTPUT_DRAINING: 542 case SSH_CHANNEL_OUTPUT_DRAINING:
@@ -567,6 +568,8 @@ channel_find_open(void)
567 case SSH_CHANNEL_X11_LISTENER: 568 case SSH_CHANNEL_X11_LISTENER:
568 case SSH_CHANNEL_PORT_LISTENER: 569 case SSH_CHANNEL_PORT_LISTENER:
569 case SSH_CHANNEL_RPORT_LISTENER: 570 case SSH_CHANNEL_RPORT_LISTENER:
571 case SSH_CHANNEL_MUX_LISTENER:
572 case SSH_CHANNEL_MUX_CLIENT:
570 case SSH_CHANNEL_OPENING: 573 case SSH_CHANNEL_OPENING:
571 case SSH_CHANNEL_CONNECTING: 574 case SSH_CHANNEL_CONNECTING:
572 case SSH_CHANNEL_ZOMBIE: 575 case SSH_CHANNEL_ZOMBIE:
@@ -617,6 +620,8 @@ channel_open_message(void)
617 case SSH_CHANNEL_CLOSED: 620 case SSH_CHANNEL_CLOSED:
618 case SSH_CHANNEL_AUTH_SOCKET: 621 case SSH_CHANNEL_AUTH_SOCKET:
619 case SSH_CHANNEL_ZOMBIE: 622 case SSH_CHANNEL_ZOMBIE:
623 case SSH_CHANNEL_MUX_CLIENT:
624 case SSH_CHANNEL_MUX_LISTENER:
620 continue; 625 continue;
621 case SSH_CHANNEL_LARVAL: 626 case SSH_CHANNEL_LARVAL:
622 case SSH_CHANNEL_OPENING: 627 case SSH_CHANNEL_OPENING:
@@ -627,12 +632,12 @@ channel_open_message(void)
627 case SSH_CHANNEL_INPUT_DRAINING: 632 case SSH_CHANNEL_INPUT_DRAINING:
628 case SSH_CHANNEL_OUTPUT_DRAINING: 633 case SSH_CHANNEL_OUTPUT_DRAINING:
629 snprintf(buf, sizeof buf, 634 snprintf(buf, sizeof buf,
630 " #%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",
631 c->self, c->remote_name, 636 c->self, c->remote_name,
632 c->type, c->remote_id, 637 c->type, c->remote_id,
633 c->istate, buffer_len(&c->input), 638 c->istate, buffer_len(&c->input),
634 c->ostate, buffer_len(&c->output), 639 c->ostate, buffer_len(&c->output),
635 c->rfd, c->wfd, c->ctl_fd); 640 c->rfd, c->wfd, c->ctl_chan);
636 buffer_append(&buffer, buf, strlen(buf)); 641 buffer_append(&buffer, buf, strlen(buf));
637 continue; 642 continue;
638 default: 643 default:
@@ -839,9 +844,6 @@ channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset)
839 FD_SET(c->efd, readset); 844 FD_SET(c->efd, readset);
840 } 845 }
841 /* XXX: What about efd? races? */ 846 /* XXX: What about efd? races? */
842 if (compat20 && c->ctl_fd != -1 &&
843 c->istate == CHAN_INPUT_OPEN && c->ostate == CHAN_OUTPUT_OPEN)
844 FD_SET(c->ctl_fd, readset);
845} 847}
846 848
847/* ARGSUSED */ 849/* ARGSUSED */
@@ -986,6 +988,28 @@ channel_pre_x11_open(Channel *c, fd_set *readset, fd_set *writeset)
986 } 988 }
987} 989}
988 990
991static void
992channel_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
989/* try to decode a socks4 header */ 1013/* try to decode a socks4 header */
990/* ARGSUSED */ 1014/* ARGSUSED */
991static int 1015static int
@@ -1218,19 +1242,14 @@ channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset)
1218} 1242}
1219 1243
1220Channel * 1244Channel *
1221channel_connect_stdio_fwd(const char *host_to_connect, u_short port_to_connect) 1245channel_connect_stdio_fwd(const char *host_to_connect, u_short port_to_connect,
1246 int in, int out)
1222{ 1247{
1223 Channel *c; 1248 Channel *c;
1224 int in, out;
1225 1249
1226 debug("channel_connect_stdio_fwd %s:%d", host_to_connect, 1250 debug("channel_connect_stdio_fwd %s:%d", host_to_connect,
1227 port_to_connect); 1251 port_to_connect);
1228 1252
1229 in = dup(STDIN_FILENO);
1230 out = dup(STDOUT_FILENO);
1231 if (in < 0 || out < 0)
1232 fatal("channel_connect_stdio_fwd: dup() in/out failed");
1233
1234 c = channel_new("stdio-forward", SSH_CHANNEL_OPENING, in, out, 1253 c = channel_new("stdio-forward", SSH_CHANNEL_OPENING, in, out,
1235 -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 1254 -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
1236 0, "stdio-forward", /*nonblock*/0); 1255 0, "stdio-forward", /*nonblock*/0);
@@ -1749,36 +1768,6 @@ channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset)
1749 return 1; 1768 return 1;
1750} 1769}
1751 1770
1752/* ARGSUSED */
1753static int
1754channel_handle_ctl(Channel *c, fd_set *readset, fd_set *writeset)
1755{
1756 char buf[16];
1757 int len;
1758
1759 /* Monitor control fd to detect if the slave client exits */
1760 if (c->ctl_fd != -1 && FD_ISSET(c->ctl_fd, readset)) {
1761 len = read(c->ctl_fd, buf, sizeof(buf));
1762 if (len < 0 &&
1763 (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
1764 return 1;
1765 if (len <= 0) {
1766 debug2("channel %d: ctl read<=0", c->self);
1767 if (c->type != SSH_CHANNEL_OPEN) {
1768 debug2("channel %d: not open", c->self);
1769 chan_mark_dead(c);
1770 return -1;
1771 } else {
1772 chan_read_failed(c);
1773 chan_write_failed(c);
1774 }
1775 return -1;
1776 } else
1777 fatal("%s: unexpected data on ctl fd", __func__);
1778 }
1779 return 1;
1780}
1781
1782static int 1771static int
1783channel_check_window(Channel *c) 1772channel_check_window(Channel *c)
1784{ 1773{
@@ -1809,10 +1798,131 @@ channel_post_open(Channel *c, fd_set *readset, fd_set *writeset)
1809 if (!compat20) 1798 if (!compat20)
1810 return; 1799 return;
1811 channel_handle_efd(c, readset, writeset); 1800 channel_handle_efd(c, readset, writeset);
1812 channel_handle_ctl(c, readset, writeset);
1813 channel_check_window(c); 1801 channel_check_window(c);
1814} 1802}
1815 1803
1804static u_int
1805read_mux(Channel *c, u_int need)
1806{
1807 char buf[CHAN_RBUF];
1808 int len;
1809 u_int rlen;
1810
1811 if (buffer_len(&c->input) < need) {
1812 rlen = need - buffer_len(&c->input);
1813 len = read(c->rfd, buf, MIN(rlen, CHAN_RBUF));
1814 if (len <= 0) {
1815 if (errno != EINTR && errno != EAGAIN) {
1816 debug2("channel %d: ctl read<=0 rfd %d len %d",
1817 c->self, c->rfd, len);
1818 chan_read_failed(c);
1819 return 0;
1820 }
1821 } else
1822 buffer_append(&c->input, buf, len);
1823 }
1824 return buffer_len(&c->input);
1825}
1826
1827static void
1828channel_post_mux_client(Channel *c, fd_set *readset, fd_set *writeset)
1829{
1830 u_int need;
1831 ssize_t len;
1832
1833 if (!compat20)
1834 fatal("%s: entered with !compat20", __func__);
1835
1836 if (c->rfd != -1 && FD_ISSET(c->rfd, readset) &&
1837 (c->istate == CHAN_INPUT_OPEN ||
1838 c->istate == CHAN_INPUT_WAIT_DRAIN)) {
1839 /*
1840 * Don't not read past the precise end of packets to
1841 * avoid disrupting fd passing.
1842 */
1843 if (read_mux(c, 4) < 4) /* read header */
1844 return;
1845 need = get_u32(buffer_ptr(&c->input));
1846#define CHANNEL_MUX_MAX_PACKET (256 * 1024)
1847 if (need > CHANNEL_MUX_MAX_PACKET) {
1848 debug2("channel %d: packet too big %u > %u",
1849 c->self, CHANNEL_MUX_MAX_PACKET, need);
1850 chan_rcvd_oclose(c);
1851 return;
1852 }
1853 if (read_mux(c, need + 4) < need + 4) /* read body */
1854 return;
1855 if (c->mux_rcb(c) != 0) {
1856 debug("channel %d: mux_rcb failed", c->self);
1857 chan_mark_dead(c);
1858 return;
1859 }
1860 }
1861
1862 if (c->wfd != -1 && FD_ISSET(c->wfd, writeset) &&
1863 buffer_len(&c->output) > 0) {
1864 len = write(c->wfd, buffer_ptr(&c->output),
1865 buffer_len(&c->output));
1866 if (len < 0 && (errno == EINTR || errno == EAGAIN))
1867 return;
1868 if (len <= 0) {
1869 chan_mark_dead(c);
1870 return;
1871 }
1872 buffer_consume(&c->output, len);
1873 }
1874}
1875
1876static void
1877channel_post_mux_listener(Channel *c, fd_set *readset, fd_set *writeset)
1878{
1879 Channel *nc;
1880 struct sockaddr_storage addr;
1881 socklen_t addrlen;
1882 int newsock;
1883 uid_t euid;
1884 gid_t egid;
1885
1886 if (!FD_ISSET(c->sock, readset))
1887 return;
1888
1889 debug("multiplexing control connection");
1890
1891 /*
1892 * Accept connection on control socket
1893 */
1894 memset(&addr, 0, sizeof(addr));
1895 addrlen = sizeof(addr);
1896 if ((newsock = accept(c->sock, (struct sockaddr*)&addr,
1897 &addrlen)) == -1) {
1898 error("%s accept: %s", __func__, strerror(errno));
1899 return;
1900 }
1901
1902 if (getpeereid(newsock, &euid, &egid) < 0) {
1903 error("%s getpeereid failed: %s", __func__,
1904 strerror(errno));
1905 close(newsock);
1906 return;
1907 }
1908 if ((euid != 0) && (getuid() != euid)) {
1909 error("multiplex uid mismatch: peer euid %u != uid %u",
1910 (u_int)euid, (u_int)getuid());
1911 close(newsock);
1912 return;
1913 }
1914 nc = channel_new("multiplex client", SSH_CHANNEL_MUX_CLIENT,
1915 newsock, newsock, -1, c->local_window_max,
1916 c->local_maxpacket, 0, "mux-control", 1);
1917 nc->mux_rcb = c->mux_rcb;
1918 debug3("%s: new mux channel %d fd %d", __func__,
1919 nc->self, nc->sock);
1920 /* establish state */
1921 nc->mux_rcb(nc);
1922 /* mux state transitions must not elicit protocol messages */
1923 nc->flags |= CHAN_LOCAL;
1924}
1925
1816/* ARGSUSED */ 1926/* ARGSUSED */
1817static void 1927static void
1818channel_post_output_drain_13(Channel *c, fd_set *readset, fd_set *writeset) 1928channel_post_output_drain_13(Channel *c, fd_set *readset, fd_set *writeset)
@@ -1841,6 +1951,8 @@ channel_handler_init_20(void)
1841 channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; 1951 channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener;
1842 channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; 1952 channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting;
1843 channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; 1953 channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic;
1954 channel_pre[SSH_CHANNEL_MUX_LISTENER] = &channel_pre_listener;
1955 channel_pre[SSH_CHANNEL_MUX_CLIENT] = &channel_pre_mux_client;
1844 1956
1845 channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; 1957 channel_post[SSH_CHANNEL_OPEN] = &channel_post_open;
1846 channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; 1958 channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener;
@@ -1849,6 +1961,8 @@ channel_handler_init_20(void)
1849 channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; 1961 channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener;
1850 channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; 1962 channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting;
1851 channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; 1963 channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open;
1964 channel_post[SSH_CHANNEL_MUX_LISTENER] = &channel_post_mux_listener;
1965 channel_post[SSH_CHANNEL_MUX_CLIENT] = &channel_post_mux_client;
1852} 1966}
1853 1967
1854static void 1968static void