diff options
Diffstat (limited to 'mux.c')
-rw-r--r-- | mux.c | 167 |
1 files changed, 146 insertions, 21 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: mux.c,v 1.24 2011/01/13 21:54:53 djm Exp $ */ | 1 | /* $OpenBSD: mux.c,v 1.29 2011/06/22 22:08:42 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org> | 3 | * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org> |
4 | * | 4 | * |
@@ -87,7 +87,6 @@ | |||
87 | 87 | ||
88 | /* from ssh.c */ | 88 | /* from ssh.c */ |
89 | extern int tty_flag; | 89 | extern int tty_flag; |
90 | extern int force_tty_flag; | ||
91 | extern Options options; | 90 | extern Options options; |
92 | extern int stdin_null_flag; | 91 | extern int stdin_null_flag; |
93 | extern char *host; | 92 | extern char *host; |
@@ -146,6 +145,7 @@ struct mux_master_state { | |||
146 | #define MUX_C_OPEN_FWD 0x10000006 | 145 | #define MUX_C_OPEN_FWD 0x10000006 |
147 | #define MUX_C_CLOSE_FWD 0x10000007 | 146 | #define MUX_C_CLOSE_FWD 0x10000007 |
148 | #define MUX_C_NEW_STDIO_FWD 0x10000008 | 147 | #define MUX_C_NEW_STDIO_FWD 0x10000008 |
148 | #define MUX_C_STOP_LISTENING 0x10000009 | ||
149 | #define MUX_S_OK 0x80000001 | 149 | #define MUX_S_OK 0x80000001 |
150 | #define MUX_S_PERMISSION_DENIED 0x80000002 | 150 | #define MUX_S_PERMISSION_DENIED 0x80000002 |
151 | #define MUX_S_FAILURE 0x80000003 | 151 | #define MUX_S_FAILURE 0x80000003 |
@@ -153,6 +153,7 @@ struct mux_master_state { | |||
153 | #define MUX_S_ALIVE 0x80000005 | 153 | #define MUX_S_ALIVE 0x80000005 |
154 | #define MUX_S_SESSION_OPENED 0x80000006 | 154 | #define MUX_S_SESSION_OPENED 0x80000006 |
155 | #define MUX_S_REMOTE_PORT 0x80000007 | 155 | #define MUX_S_REMOTE_PORT 0x80000007 |
156 | #define MUX_S_TTY_ALLOC_FAIL 0x80000008 | ||
156 | 157 | ||
157 | /* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */ | 158 | /* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */ |
158 | #define MUX_FWD_LOCAL 1 | 159 | #define MUX_FWD_LOCAL 1 |
@@ -168,6 +169,7 @@ static int process_mux_terminate(u_int, Channel *, Buffer *, Buffer *); | |||
168 | static int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *); | 169 | static int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *); |
169 | static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *); | 170 | static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *); |
170 | static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *); | 171 | static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *); |
172 | static int process_mux_stop_listening(u_int, Channel *, Buffer *, Buffer *); | ||
171 | 173 | ||
172 | static const struct { | 174 | static const struct { |
173 | u_int type; | 175 | u_int type; |
@@ -180,6 +182,7 @@ static const struct { | |||
180 | { MUX_C_OPEN_FWD, process_mux_open_fwd }, | 182 | { MUX_C_OPEN_FWD, process_mux_open_fwd }, |
181 | { MUX_C_CLOSE_FWD, process_mux_close_fwd }, | 183 | { MUX_C_CLOSE_FWD, process_mux_close_fwd }, |
182 | { MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd }, | 184 | { MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd }, |
185 | { MUX_C_STOP_LISTENING, process_mux_stop_listening }, | ||
183 | { 0, NULL } | 186 | { 0, NULL } |
184 | }; | 187 | }; |
185 | 188 | ||
@@ -915,6 +918,39 @@ process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | |||
915 | return 0; | 918 | return 0; |
916 | } | 919 | } |
917 | 920 | ||
921 | static int | ||
922 | process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r) | ||
923 | { | ||
924 | debug("%s: channel %d: stop listening", __func__, c->self); | ||
925 | |||
926 | if (options.control_master == SSHCTL_MASTER_ASK || | ||
927 | options.control_master == SSHCTL_MASTER_AUTO_ASK) { | ||
928 | if (!ask_permission("Disable further multiplexing on shared " | ||
929 | "connection to %s? ", host)) { | ||
930 | debug2("%s: stop listen refused by user", __func__); | ||
931 | buffer_put_int(r, MUX_S_PERMISSION_DENIED); | ||
932 | buffer_put_int(r, rid); | ||
933 | buffer_put_cstring(r, "Permission denied"); | ||
934 | return 0; | ||
935 | } | ||
936 | } | ||
937 | |||
938 | if (mux_listener_channel != NULL) { | ||
939 | channel_free(mux_listener_channel); | ||
940 | client_stop_mux(); | ||
941 | xfree(options.control_path); | ||
942 | options.control_path = NULL; | ||
943 | mux_listener_channel = NULL; | ||
944 | muxserver_sock = -1; | ||
945 | } | ||
946 | |||
947 | /* prepare reply */ | ||
948 | buffer_put_int(r, MUX_S_OK); | ||
949 | buffer_put_int(r, rid); | ||
950 | |||
951 | return 0; | ||
952 | } | ||
953 | |||
918 | /* Channel callbacks fired on read/write from mux slave fd */ | 954 | /* Channel callbacks fired on read/write from mux slave fd */ |
919 | static int | 955 | static int |
920 | mux_master_read_cb(Channel *c) | 956 | mux_master_read_cb(Channel *c) |
@@ -1019,6 +1055,27 @@ mux_exit_message(Channel *c, int exitval) | |||
1019 | buffer_free(&m); | 1055 | buffer_free(&m); |
1020 | } | 1056 | } |
1021 | 1057 | ||
1058 | void | ||
1059 | mux_tty_alloc_failed(Channel *c) | ||
1060 | { | ||
1061 | Buffer m; | ||
1062 | Channel *mux_chan; | ||
1063 | |||
1064 | debug3("%s: channel %d: TTY alloc failed", __func__, c->self); | ||
1065 | |||
1066 | if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL) | ||
1067 | fatal("%s: channel %d missing mux channel %d", | ||
1068 | __func__, c->self, c->ctl_chan); | ||
1069 | |||
1070 | /* Append exit message packet to control socket output queue */ | ||
1071 | buffer_init(&m); | ||
1072 | buffer_put_int(&m, MUX_S_TTY_ALLOC_FAIL); | ||
1073 | buffer_put_int(&m, c->self); | ||
1074 | |||
1075 | buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m)); | ||
1076 | buffer_free(&m); | ||
1077 | } | ||
1078 | |||
1022 | /* Prepare a mux master to listen on a Unix domain socket. */ | 1079 | /* Prepare a mux master to listen on a Unix domain socket. */ |
1023 | void | 1080 | void |
1024 | muxserver_listen(void) | 1081 | muxserver_listen(void) |
@@ -1059,21 +1116,25 @@ muxserver_listen(void) | |||
1059 | strlen(options.control_path) + 1; | 1116 | strlen(options.control_path) + 1; |
1060 | 1117 | ||
1061 | if (strlcpy(addr.sun_path, options.control_path, | 1118 | if (strlcpy(addr.sun_path, options.control_path, |
1062 | sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) | 1119 | sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) { |
1063 | fatal("ControlPath too long"); | 1120 | error("ControlPath \"%s\" too long for Unix domain socket", |
1121 | options.control_path); | ||
1122 | goto disable_mux_master; | ||
1123 | } | ||
1064 | 1124 | ||
1065 | if ((muxserver_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) | 1125 | if ((muxserver_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) |
1066 | fatal("%s socket(): %s", __func__, strerror(errno)); | 1126 | fatal("%s socket(): %s", __func__, strerror(errno)); |
1067 | 1127 | ||
1068 | old_umask = umask(0177); | 1128 | old_umask = umask(0177); |
1069 | if (bind(muxserver_sock, (struct sockaddr *)&addr, sun_len) == -1) { | 1129 | if (bind(muxserver_sock, (struct sockaddr *)&addr, sun_len) == -1) { |
1070 | muxserver_sock = -1; | ||
1071 | if (errno == EINVAL || errno == EADDRINUSE) { | 1130 | if (errno == EINVAL || errno == EADDRINUSE) { |
1072 | error("ControlSocket %s already exists, " | 1131 | error("ControlSocket %s already exists, " |
1073 | "disabling multiplexing", options.control_path); | 1132 | "disabling multiplexing", options.control_path); |
1074 | disable_mux_master: | 1133 | disable_mux_master: |
1075 | close(muxserver_sock); | 1134 | if (muxserver_sock != -1) { |
1076 | muxserver_sock = -1; | 1135 | close(muxserver_sock); |
1136 | muxserver_sock = -1; | ||
1137 | } | ||
1077 | xfree(options.control_path); | 1138 | xfree(options.control_path); |
1078 | options.control_path = NULL; | 1139 | options.control_path = NULL; |
1079 | options.control_master = SSHCTL_MASTER_NO; | 1140 | options.control_master = SSHCTL_MASTER_NO; |
@@ -1153,8 +1214,10 @@ mux_session_confirm(int id, int success, void *arg) | |||
1153 | /* Request forwarding with authentication spoofing. */ | 1214 | /* Request forwarding with authentication spoofing. */ |
1154 | debug("Requesting X11 forwarding with authentication " | 1215 | debug("Requesting X11 forwarding with authentication " |
1155 | "spoofing."); | 1216 | "spoofing."); |
1156 | x11_request_forwarding_with_spoofing(id, display, proto, data); | 1217 | x11_request_forwarding_with_spoofing(id, display, proto, |
1157 | /* XXX wait for reply */ | 1218 | data, 1); |
1219 | client_expect_confirm(id, "X11 forwarding", CONFIRM_WARN); | ||
1220 | /* XXX exit_on_forward_failure */ | ||
1158 | } | 1221 | } |
1159 | 1222 | ||
1160 | if (cctx->want_agent_fwd && options.forward_agent) { | 1223 | if (cctx->want_agent_fwd && options.forward_agent) { |
@@ -1573,7 +1636,7 @@ mux_client_request_session(int fd) | |||
1573 | char *e, *term; | 1636 | char *e, *term; |
1574 | u_int i, rid, sid, esid, exitval, type, exitval_seen; | 1637 | u_int i, rid, sid, esid, exitval, type, exitval_seen; |
1575 | extern char **environ; | 1638 | extern char **environ; |
1576 | int devnull; | 1639 | int devnull, rawmode; |
1577 | 1640 | ||
1578 | debug3("%s: entering", __func__); | 1641 | debug3("%s: entering", __func__); |
1579 | 1642 | ||
@@ -1669,8 +1732,9 @@ mux_client_request_session(int fd) | |||
1669 | signal(SIGTERM, control_client_sighandler); | 1732 | signal(SIGTERM, control_client_sighandler); |
1670 | signal(SIGWINCH, control_client_sigrelay); | 1733 | signal(SIGWINCH, control_client_sigrelay); |
1671 | 1734 | ||
1735 | rawmode = tty_flag; | ||
1672 | if (tty_flag) | 1736 | if (tty_flag) |
1673 | enter_raw_mode(force_tty_flag); | 1737 | enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); |
1674 | 1738 | ||
1675 | /* | 1739 | /* |
1676 | * Stick around until the controlee closes the client_fd. | 1740 | * Stick around until the controlee closes the client_fd. |
@@ -1684,22 +1748,35 @@ mux_client_request_session(int fd) | |||
1684 | if (mux_client_read_packet(fd, &m) != 0) | 1748 | if (mux_client_read_packet(fd, &m) != 0) |
1685 | break; | 1749 | break; |
1686 | type = buffer_get_int(&m); | 1750 | type = buffer_get_int(&m); |
1687 | if (type != MUX_S_EXIT_MESSAGE) { | 1751 | switch (type) { |
1752 | case MUX_S_TTY_ALLOC_FAIL: | ||
1753 | if ((esid = buffer_get_int(&m)) != sid) | ||
1754 | fatal("%s: tty alloc fail on unknown session: " | ||
1755 | "my id %u theirs %u", | ||
1756 | __func__, sid, esid); | ||
1757 | leave_raw_mode(options.request_tty == | ||
1758 | REQUEST_TTY_FORCE); | ||
1759 | rawmode = 0; | ||
1760 | continue; | ||
1761 | case MUX_S_EXIT_MESSAGE: | ||
1762 | if ((esid = buffer_get_int(&m)) != sid) | ||
1763 | fatal("%s: exit on unknown session: " | ||
1764 | "my id %u theirs %u", | ||
1765 | __func__, sid, esid); | ||
1766 | if (exitval_seen) | ||
1767 | fatal("%s: exitval sent twice", __func__); | ||
1768 | exitval = buffer_get_int(&m); | ||
1769 | exitval_seen = 1; | ||
1770 | continue; | ||
1771 | default: | ||
1688 | e = buffer_get_string(&m, NULL); | 1772 | e = buffer_get_string(&m, NULL); |
1689 | fatal("%s: master returned error: %s", __func__, e); | 1773 | fatal("%s: master returned error: %s", __func__, e); |
1690 | } | 1774 | } |
1691 | if ((esid = buffer_get_int(&m)) != sid) | ||
1692 | fatal("%s: exit on unknown session: my id %u theirs %u", | ||
1693 | __func__, sid, esid); | ||
1694 | debug("%s: master session id: %u", __func__, sid); | ||
1695 | if (exitval_seen) | ||
1696 | fatal("%s: exitval sent twice", __func__); | ||
1697 | exitval = buffer_get_int(&m); | ||
1698 | exitval_seen = 1; | ||
1699 | } | 1775 | } |
1700 | 1776 | ||
1701 | close(fd); | 1777 | close(fd); |
1702 | leave_raw_mode(force_tty_flag); | 1778 | if (rawmode) |
1779 | leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); | ||
1703 | 1780 | ||
1704 | if (muxclient_terminate) { | 1781 | if (muxclient_terminate) { |
1705 | debug2("Exiting on signal %d", muxclient_terminate); | 1782 | debug2("Exiting on signal %d", muxclient_terminate); |
@@ -1813,6 +1890,50 @@ mux_client_request_stdio_fwd(int fd) | |||
1813 | fatal("%s: master returned unexpected message %u", __func__, type); | 1890 | fatal("%s: master returned unexpected message %u", __func__, type); |
1814 | } | 1891 | } |
1815 | 1892 | ||
1893 | static void | ||
1894 | mux_client_request_stop_listening(int fd) | ||
1895 | { | ||
1896 | Buffer m; | ||
1897 | char *e; | ||
1898 | u_int type, rid; | ||
1899 | |||
1900 | debug3("%s: entering", __func__); | ||
1901 | |||
1902 | buffer_init(&m); | ||
1903 | buffer_put_int(&m, MUX_C_STOP_LISTENING); | ||
1904 | buffer_put_int(&m, muxclient_request_id); | ||
1905 | |||
1906 | if (mux_client_write_packet(fd, &m) != 0) | ||
1907 | fatal("%s: write packet: %s", __func__, strerror(errno)); | ||
1908 | |||
1909 | buffer_clear(&m); | ||
1910 | |||
1911 | /* Read their reply */ | ||
1912 | if (mux_client_read_packet(fd, &m) != 0) | ||
1913 | fatal("%s: read from master failed: %s", | ||
1914 | __func__, strerror(errno)); | ||
1915 | |||
1916 | type = buffer_get_int(&m); | ||
1917 | if ((rid = buffer_get_int(&m)) != muxclient_request_id) | ||
1918 | fatal("%s: out of sequence reply: my id %u theirs %u", | ||
1919 | __func__, muxclient_request_id, rid); | ||
1920 | switch (type) { | ||
1921 | case MUX_S_OK: | ||
1922 | break; | ||
1923 | case MUX_S_PERMISSION_DENIED: | ||
1924 | e = buffer_get_string(&m, NULL); | ||
1925 | fatal("Master refused stop listening request: %s", e); | ||
1926 | case MUX_S_FAILURE: | ||
1927 | e = buffer_get_string(&m, NULL); | ||
1928 | fatal("%s: stop listening request failed: %s", __func__, e); | ||
1929 | default: | ||
1930 | fatal("%s: unexpected response from master 0x%08x", | ||
1931 | __func__, type); | ||
1932 | } | ||
1933 | buffer_free(&m); | ||
1934 | muxclient_request_id++; | ||
1935 | } | ||
1936 | |||
1816 | /* Multiplex client main loop. */ | 1937 | /* Multiplex client main loop. */ |
1817 | void | 1938 | void |
1818 | muxclient(const char *path) | 1939 | muxclient(const char *path) |
@@ -1906,6 +2027,10 @@ muxclient(const char *path) | |||
1906 | case SSHMUX_COMMAND_STDIO_FWD: | 2027 | case SSHMUX_COMMAND_STDIO_FWD: |
1907 | mux_client_request_stdio_fwd(sock); | 2028 | mux_client_request_stdio_fwd(sock); |
1908 | exit(0); | 2029 | exit(0); |
2030 | case SSHMUX_COMMAND_STOP: | ||
2031 | mux_client_request_stop_listening(sock); | ||
2032 | fprintf(stderr, "Stop listening request sent.\r\n"); | ||
2033 | exit(0); | ||
1909 | default: | 2034 | default: |
1910 | fatal("unrecognised muxclient_command %d", muxclient_command); | 2035 | fatal("unrecognised muxclient_command %d", muxclient_command); |
1911 | } | 2036 | } |