summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--PROTOCOL.mux19
-rw-r--r--clientloop.c34
-rw-r--r--clientloop.h4
-rw-r--r--mux.c86
-rw-r--r--ssh.16
-rw-r--r--ssh.c4
7 files changed, 140 insertions, 18 deletions
diff --git a/ChangeLog b/ChangeLog
index f7602a1b2..ddee8e5dd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
5920110221 6420110221
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
150The contents of "reserved" are currently ignored. 150The contents of "reserved" are currently ignored.
151 151
152A server may reply with a MUX_S_SESSION_OPEED, a MUX_S_PERMISSION_DENIED 152A server may reply with a MUX_S_SESSION_OPENED, a MUX_S_PERMISSION_DENIED
153or a MUX_S_FAILURE. 153or a MUX_S_FAILURE.
154 154
1558. Status messages 1558. Requesting shutdown of mux listener
156
157A client may request the master to stop accepting new multiplexing requests
158and remove its listener socket.
159
160 uint32 MUX_C_STOP_LISTENING
161 uint32 request id
162
163A server may reply with a MUX_S_OK, a MUX_S_PERMISSION_DENIED or a
164MUX_S_FAILURE.
165
1669. Status messages
156 167
157The MUX_S_OK message is empty: 168The 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
193XXX TODO 205XXX TODO
194XXX extended status (e.g. report open channels / forwards) 206XXX extended status (e.g. report open channels / forwards)
195XXX graceful close (delete listening socket, but keep existing sessions active)
196XXX lock (maybe) 207XXX lock (maybe)
197XXX watch in/out traffic (pre/post crypto) 208XXX watch in/out traffic (pre/post crypto)
198XXX inject packet (what about replies) 209XXX inject packet (what about replies)
@@ -200,4 +211,4 @@ XXX server->client error/warning notifications
200XXX port0 rfwd (need custom response message) 211XXX port0 rfwd (need custom response message)
201XXX send signals via mux 212XXX 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
265set_control_persist_exit_time(void) 265set_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
2128void
2129client_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 */
2126void 2142void
2127cleanup_exit(int i) 2143cleanup_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 *);
45void client_session2_setup(int, int, int, const char *, struct termios *, 45void client_session2_setup(int, int, int, const char *, struct termios *,
46 int, Buffer *, char **); 46 int, Buffer *, char **);
47int client_request_tun_fwd(int, int, int); 47int client_request_tun_fwd(int, int, int);
48void client_stop_mux(void);
48 49
49/* Escape filter for protocol 2 sessions */ 50/* Escape filter for protocol 2 sessions */
50void *client_new_escape_filter_ctx(int); 51void *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
68void muxserver_listen(void); 70void muxserver_listen(void);
69void muxclient(const char *); 71void muxclient(const char *);
diff --git a/mux.c b/mux.c
index e370462db..09468359f 100644
--- a/mux.c
+++ b/mux.c
@@ -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 *);
168static int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *); 169static int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *);
169static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *); 170static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *);
170static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *); 171static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *);
172static int process_mux_stop_listening(u_int, Channel *, Buffer *, Buffer *);
171 173
172static const struct { 174static 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
921static int
922process_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 */
919static int 955static int
920mux_master_read_cb(Channel *c) 956mux_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
1852static void
1853mux_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. */
1817void 1897void
1818muxclient(const char *path) 1898muxclient(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 }
diff --git a/ssh.1 b/ssh.1
index e3a42b5ad..1b0bcb781 100644
--- a/ssh.1
+++ b/ssh.1
@@ -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
399Can be used to give options in the format used in the configuration file. 401Can be used to give options in the format used in the configuration file.
400This is useful for specifying options for which there is no separate 402This is useful for specifying options for which there is no separate
diff --git a/ssh.c b/ssh.c
index b543c6117..4fd131c20 100644
--- a/ssh.c
+++ b/ssh.c
@@ -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;