diff options
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | PROTOCOL.mux | 19 | ||||
-rw-r--r-- | clientloop.c | 34 | ||||
-rw-r--r-- | clientloop.h | 4 | ||||
-rw-r--r-- | mux.c | 86 | ||||
-rw-r--r-- | ssh.1 | 6 | ||||
-rw-r--r-- | ssh.c | 4 |
7 files changed, 140 insertions, 18 deletions
@@ -55,6 +55,11 @@ | |||
55 | - djm@cvs.openbsd.org 2011/04/13 04:09:37 | 55 | - djm@cvs.openbsd.org 2011/04/13 04:09:37 |
56 | [ssh-keygen.1] | 56 | [ssh-keygen.1] |
57 | mention valid -b sizes for ECDSA keys; bz#1862 | 57 | mention valid -b sizes for ECDSA keys; bz#1862 |
58 | - djm@cvs.openbsd.org 2011/04/17 22:42:42 | ||
59 | [PROTOCOL.mux clientloop.c clientloop.h mux.c ssh.1 ssh.c] | ||
60 | allow graceful shutdown of multiplexing: request that a mux server | ||
61 | removes its listener socket and refuse future multiplexing requests; | ||
62 | ok markus@ | ||
58 | 63 | ||
59 | 20110221 | 64 | 20110221 |
60 | - (dtucker) [contrib/cygwin/ssh-host-config] From Corinna: revamp of the | 65 | - (dtucker) [contrib/cygwin/ssh-host-config] From Corinna: revamp of the |
diff --git a/PROTOCOL.mux b/PROTOCOL.mux index 2a5817bd7..05bb14690 100644 --- a/PROTOCOL.mux +++ b/PROTOCOL.mux | |||
@@ -149,10 +149,21 @@ The client then sends its standard input and output file descriptors | |||
149 | 149 | ||
150 | The contents of "reserved" are currently ignored. | 150 | The contents of "reserved" are currently ignored. |
151 | 151 | ||
152 | A server may reply with a MUX_S_SESSION_OPEED, a MUX_S_PERMISSION_DENIED | 152 | A server may reply with a MUX_S_SESSION_OPENED, a MUX_S_PERMISSION_DENIED |
153 | or a MUX_S_FAILURE. | 153 | or a MUX_S_FAILURE. |
154 | 154 | ||
155 | 8. Status messages | 155 | 8. Requesting shutdown of mux listener |
156 | |||
157 | A client may request the master to stop accepting new multiplexing requests | ||
158 | and remove its listener socket. | ||
159 | |||
160 | uint32 MUX_C_STOP_LISTENING | ||
161 | uint32 request id | ||
162 | |||
163 | A server may reply with a MUX_S_OK, a MUX_S_PERMISSION_DENIED or a | ||
164 | MUX_S_FAILURE. | ||
165 | |||
166 | 9. Status messages | ||
156 | 167 | ||
157 | The MUX_S_OK message is empty: | 168 | The MUX_S_OK message is empty: |
158 | 169 | ||
@@ -178,6 +189,7 @@ The MUX_S_PERMISSION_DENIED and MUX_S_FAILURE include a reason: | |||
178 | #define MUX_C_OPEN_FWD 0x10000006 | 189 | #define MUX_C_OPEN_FWD 0x10000006 |
179 | #define MUX_C_CLOSE_FWD 0x10000007 | 190 | #define MUX_C_CLOSE_FWD 0x10000007 |
180 | #define MUX_C_NEW_STDIO_FWD 0x10000008 | 191 | #define MUX_C_NEW_STDIO_FWD 0x10000008 |
192 | #define MUX_C_STOP_LISTENING 0x10000009 | ||
181 | #define MUX_S_OK 0x80000001 | 193 | #define MUX_S_OK 0x80000001 |
182 | #define MUX_S_PERMISSION_DENIED 0x80000002 | 194 | #define MUX_S_PERMISSION_DENIED 0x80000002 |
183 | #define MUX_S_FAILURE 0x80000003 | 195 | #define MUX_S_FAILURE 0x80000003 |
@@ -192,7 +204,6 @@ The MUX_S_PERMISSION_DENIED and MUX_S_FAILURE include a reason: | |||
192 | 204 | ||
193 | XXX TODO | 205 | XXX TODO |
194 | XXX extended status (e.g. report open channels / forwards) | 206 | XXX extended status (e.g. report open channels / forwards) |
195 | XXX graceful close (delete listening socket, but keep existing sessions active) | ||
196 | XXX lock (maybe) | 207 | XXX lock (maybe) |
197 | XXX watch in/out traffic (pre/post crypto) | 208 | XXX watch in/out traffic (pre/post crypto) |
198 | XXX inject packet (what about replies) | 209 | XXX inject packet (what about replies) |
@@ -200,4 +211,4 @@ XXX server->client error/warning notifications | |||
200 | XXX port0 rfwd (need custom response message) | 211 | XXX port0 rfwd (need custom response message) |
201 | XXX send signals via mux | 212 | XXX send signals via mux |
202 | 213 | ||
203 | $OpenBSD: PROTOCOL.mux,v 1.4 2011/01/31 21:42:15 djm Exp $ | 214 | $OpenBSD: PROTOCOL.mux,v 1.5 2011/04/17 22:42:41 djm Exp $ |
diff --git a/clientloop.c b/clientloop.c index f6c1444a3..502dd982c 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.c,v 1.231 2011/01/16 12:05:59 djm Exp $ */ | 1 | /* $OpenBSD: clientloop.c,v 1.232 2011/04/17 22:42:41 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 |
@@ -265,10 +265,10 @@ static void | |||
265 | set_control_persist_exit_time(void) | 265 | set_control_persist_exit_time(void) |
266 | { | 266 | { |
267 | if (muxserver_sock == -1 || !options.control_persist | 267 | if (muxserver_sock == -1 || !options.control_persist |
268 | || options.control_persist_timeout == 0) | 268 | || options.control_persist_timeout == 0) { |
269 | /* not using a ControlPersist timeout */ | 269 | /* not using a ControlPersist timeout */ |
270 | control_persist_exit_time = 0; | 270 | control_persist_exit_time = 0; |
271 | else if (channel_still_open()) { | 271 | } else if (channel_still_open()) { |
272 | /* some client connections are still open */ | 272 | /* some client connections are still open */ |
273 | if (control_persist_exit_time > 0) | 273 | if (control_persist_exit_time > 0) |
274 | debug2("%s: cancel scheduled exit", __func__); | 274 | debug2("%s: cancel scheduled exit", __func__); |
@@ -1419,14 +1419,17 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1419 | 1419 | ||
1420 | if (compat20) { | 1420 | if (compat20) { |
1421 | session_ident = ssh2_chan_id; | 1421 | session_ident = ssh2_chan_id; |
1422 | if (escape_char_arg != SSH_ESCAPECHAR_NONE) | 1422 | if (session_ident != -1) { |
1423 | channel_register_filter(session_ident, | 1423 | if (escape_char_arg != SSH_ESCAPECHAR_NONE) { |
1424 | client_simple_escape_filter, NULL, | 1424 | channel_register_filter(session_ident, |
1425 | client_filter_cleanup, | 1425 | client_simple_escape_filter, NULL, |
1426 | client_new_escape_filter_ctx(escape_char_arg)); | 1426 | client_filter_cleanup, |
1427 | if (session_ident != -1) | 1427 | client_new_escape_filter_ctx( |
1428 | escape_char_arg)); | ||
1429 | } | ||
1428 | channel_register_cleanup(session_ident, | 1430 | channel_register_cleanup(session_ident, |
1429 | client_channel_closed, 0); | 1431 | client_channel_closed, 0); |
1432 | } | ||
1430 | } else { | 1433 | } else { |
1431 | /* Check if we should immediately send eof on stdin. */ | 1434 | /* Check if we should immediately send eof on stdin. */ |
1432 | client_check_initial_eof_on_stdin(); | 1435 | client_check_initial_eof_on_stdin(); |
@@ -2122,6 +2125,19 @@ client_init_dispatch(void) | |||
2122 | client_init_dispatch_15(); | 2125 | client_init_dispatch_15(); |
2123 | } | 2126 | } |
2124 | 2127 | ||
2128 | void | ||
2129 | client_stop_mux(void) | ||
2130 | { | ||
2131 | if (options.control_path != NULL && muxserver_sock != -1) | ||
2132 | unlink(options.control_path); | ||
2133 | /* | ||
2134 | * If we are in persist mode, signal that we should close when all | ||
2135 | * active channels are closed. | ||
2136 | */ | ||
2137 | if (options.control_persist) | ||
2138 | session_closed = 1; | ||
2139 | } | ||
2140 | |||
2125 | /* client specific fatal cleanup */ | 2141 | /* client specific fatal cleanup */ |
2126 | void | 2142 | void |
2127 | cleanup_exit(int i) | 2143 | cleanup_exit(int i) |
diff --git a/clientloop.h b/clientloop.h index 52115db6e..37d072906 100644 --- a/clientloop.h +++ b/clientloop.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.h,v 1.25 2010/06/25 23:15:36 djm Exp $ */ | 1 | /* $OpenBSD: clientloop.h,v 1.26 2011/04/17 22:42:41 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -45,6 +45,7 @@ void client_global_request_reply_fwd(int, u_int32_t, void *); | |||
45 | void client_session2_setup(int, int, int, const char *, struct termios *, | 45 | void client_session2_setup(int, int, int, const char *, struct termios *, |
46 | int, Buffer *, char **); | 46 | int, Buffer *, char **); |
47 | int client_request_tun_fwd(int, int, int); | 47 | int client_request_tun_fwd(int, int, int); |
48 | void client_stop_mux(void); | ||
48 | 49 | ||
49 | /* Escape filter for protocol 2 sessions */ | 50 | /* Escape filter for protocol 2 sessions */ |
50 | void *client_new_escape_filter_ctx(int); | 51 | void *client_new_escape_filter_ctx(int); |
@@ -64,6 +65,7 @@ void client_register_global_confirm(global_confirm_cb *, void *); | |||
64 | #define SSHMUX_COMMAND_TERMINATE 3 /* Ask master to exit */ | 65 | #define SSHMUX_COMMAND_TERMINATE 3 /* Ask master to exit */ |
65 | #define SSHMUX_COMMAND_STDIO_FWD 4 /* Open stdio fwd (ssh -W) */ | 66 | #define SSHMUX_COMMAND_STDIO_FWD 4 /* Open stdio fwd (ssh -W) */ |
66 | #define SSHMUX_COMMAND_FORWARD 5 /* Forward only, no command */ | 67 | #define SSHMUX_COMMAND_FORWARD 5 /* Forward only, no command */ |
68 | #define SSHMUX_COMMAND_STOP 6 /* Disable mux but not conn */ | ||
67 | 69 | ||
68 | void muxserver_listen(void); | 70 | void muxserver_listen(void); |
69 | void muxclient(const char *); | 71 | void muxclient(const char *); |
@@ -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.25 2011/04/17 22:42:41 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 | * |
@@ -146,6 +146,7 @@ struct mux_master_state { | |||
146 | #define MUX_C_OPEN_FWD 0x10000006 | 146 | #define MUX_C_OPEN_FWD 0x10000006 |
147 | #define MUX_C_CLOSE_FWD 0x10000007 | 147 | #define MUX_C_CLOSE_FWD 0x10000007 |
148 | #define MUX_C_NEW_STDIO_FWD 0x10000008 | 148 | #define MUX_C_NEW_STDIO_FWD 0x10000008 |
149 | #define MUX_C_STOP_LISTENING 0x10000009 | ||
149 | #define MUX_S_OK 0x80000001 | 150 | #define MUX_S_OK 0x80000001 |
150 | #define MUX_S_PERMISSION_DENIED 0x80000002 | 151 | #define MUX_S_PERMISSION_DENIED 0x80000002 |
151 | #define MUX_S_FAILURE 0x80000003 | 152 | #define MUX_S_FAILURE 0x80000003 |
@@ -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) |
@@ -1813,6 +1849,50 @@ mux_client_request_stdio_fwd(int fd) | |||
1813 | fatal("%s: master returned unexpected message %u", __func__, type); | 1849 | fatal("%s: master returned unexpected message %u", __func__, type); |
1814 | } | 1850 | } |
1815 | 1851 | ||
1852 | static void | ||
1853 | mux_client_request_stop_listening(int fd) | ||
1854 | { | ||
1855 | Buffer m; | ||
1856 | char *e; | ||
1857 | u_int type, rid; | ||
1858 | |||
1859 | debug3("%s: entering", __func__); | ||
1860 | |||
1861 | buffer_init(&m); | ||
1862 | buffer_put_int(&m, MUX_C_STOP_LISTENING); | ||
1863 | buffer_put_int(&m, muxclient_request_id); | ||
1864 | |||
1865 | if (mux_client_write_packet(fd, &m) != 0) | ||
1866 | fatal("%s: write packet: %s", __func__, strerror(errno)); | ||
1867 | |||
1868 | buffer_clear(&m); | ||
1869 | |||
1870 | /* Read their reply */ | ||
1871 | if (mux_client_read_packet(fd, &m) != 0) | ||
1872 | fatal("%s: read from master failed: %s", | ||
1873 | __func__, strerror(errno)); | ||
1874 | |||
1875 | type = buffer_get_int(&m); | ||
1876 | if ((rid = buffer_get_int(&m)) != muxclient_request_id) | ||
1877 | fatal("%s: out of sequence reply: my id %u theirs %u", | ||
1878 | __func__, muxclient_request_id, rid); | ||
1879 | switch (type) { | ||
1880 | case MUX_S_OK: | ||
1881 | break; | ||
1882 | case MUX_S_PERMISSION_DENIED: | ||
1883 | e = buffer_get_string(&m, NULL); | ||
1884 | fatal("Master refused stop listening request: %s", e); | ||
1885 | case MUX_S_FAILURE: | ||
1886 | e = buffer_get_string(&m, NULL); | ||
1887 | fatal("%s: stop listening request failed: %s", __func__, e); | ||
1888 | default: | ||
1889 | fatal("%s: unexpected response from master 0x%08x", | ||
1890 | __func__, type); | ||
1891 | } | ||
1892 | buffer_free(&m); | ||
1893 | muxclient_request_id++; | ||
1894 | } | ||
1895 | |||
1816 | /* Multiplex client main loop. */ | 1896 | /* Multiplex client main loop. */ |
1817 | void | 1897 | void |
1818 | muxclient(const char *path) | 1898 | muxclient(const char *path) |
@@ -1906,6 +1986,10 @@ muxclient(const char *path) | |||
1906 | case SSHMUX_COMMAND_STDIO_FWD: | 1986 | case SSHMUX_COMMAND_STDIO_FWD: |
1907 | mux_client_request_stdio_fwd(sock); | 1987 | mux_client_request_stdio_fwd(sock); |
1908 | exit(0); | 1988 | exit(0); |
1989 | case SSHMUX_COMMAND_STOP: | ||
1990 | mux_client_request_stop_listening(sock); | ||
1991 | fprintf(stderr, "Stop listening request sent.\r\n"); | ||
1992 | exit(0); | ||
1909 | default: | 1993 | default: |
1910 | fatal("unrecognised muxclient_command %d", muxclient_command); | 1994 | fatal("unrecognised muxclient_command %d", muxclient_command); |
1911 | } | 1995 | } |
@@ -33,8 +33,8 @@ | |||
33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
35 | .\" | 35 | .\" |
36 | .\" $OpenBSD: ssh.1,v 1.316 2010/11/18 15:01:00 jmc Exp $ | 36 | .\" $OpenBSD: ssh.1,v 1.317 2011/04/17 22:42:41 djm Exp $ |
37 | .Dd $Mdocdate: November 18 2010 $ | 37 | .Dd $Mdocdate: April 17 2011 $ |
38 | .Dt SSH 1 | 38 | .Dt SSH 1 |
39 | .Os | 39 | .Os |
40 | .Sh NAME | 40 | .Sh NAME |
@@ -395,6 +395,8 @@ Valid commands are: | |||
395 | (request forwardings without command execution) and | 395 | (request forwardings without command execution) and |
396 | .Dq exit | 396 | .Dq exit |
397 | (request the master to exit). | 397 | (request the master to exit). |
398 | .Dq stop | ||
399 | (request the master to stop accepting further multiplexing requests). | ||
398 | .It Fl o Ar option | 400 | .It Fl o Ar option |
399 | Can be used to give options in the format used in the configuration file. | 401 | Can be used to give options in the format used in the configuration file. |
400 | This is useful for specifying options for which there is no separate | 402 | This is useful for specifying options for which there is no separate |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh.c,v 1.356 2011/01/06 22:23:53 djm Exp $ */ | 1 | /* $OpenBSD: ssh.c,v 1.357 2011/04/17 22:42: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 |
@@ -345,6 +345,8 @@ main(int ac, char **av) | |||
345 | muxclient_command = SSHMUX_COMMAND_FORWARD; | 345 | muxclient_command = SSHMUX_COMMAND_FORWARD; |
346 | else if (strcmp(optarg, "exit") == 0) | 346 | else if (strcmp(optarg, "exit") == 0) |
347 | muxclient_command = SSHMUX_COMMAND_TERMINATE; | 347 | muxclient_command = SSHMUX_COMMAND_TERMINATE; |
348 | else if (strcmp(optarg, "stop") == 0) | ||
349 | muxclient_command = SSHMUX_COMMAND_STOP; | ||
348 | else | 350 | else |
349 | fatal("Invalid multiplex command."); | 351 | fatal("Invalid multiplex command."); |
350 | break; | 352 | break; |