- djm@cvs.openbsd.org 2011/04/17 22:42:42

[PROTOCOL.mux clientloop.c clientloop.h mux.c ssh.1 ssh.c]
     allow graceful shutdown of multiplexing: request that a mux server
     removes its listener socket and refuse future multiplexing requests;
     ok markus@
This commit is contained in:
Damien Miller 2011-05-05 14:16:22 +10:00
parent ad21032e65
commit 6c3eec7ab2
7 changed files with 140 additions and 18 deletions

View File

@ -55,6 +55,11 @@
- djm@cvs.openbsd.org 2011/04/13 04:09:37 - djm@cvs.openbsd.org 2011/04/13 04:09:37
[ssh-keygen.1] [ssh-keygen.1]
mention valid -b sizes for ECDSA keys; bz#1862 mention valid -b sizes for ECDSA keys; bz#1862
- djm@cvs.openbsd.org 2011/04/17 22:42:42
[PROTOCOL.mux clientloop.c clientloop.h mux.c ssh.1 ssh.c]
allow graceful shutdown of multiplexing: request that a mux server
removes its listener socket and refuse future multiplexing requests;
ok markus@
20110221 20110221
- (dtucker) [contrib/cygwin/ssh-host-config] From Corinna: revamp of the - (dtucker) [contrib/cygwin/ssh-host-config] From Corinna: revamp of the

View File

@ -149,10 +149,21 @@ The client then sends its standard input and output file descriptors
The contents of "reserved" are currently ignored. The contents of "reserved" are currently ignored.
A server may reply with a MUX_S_SESSION_OPEED, a MUX_S_PERMISSION_DENIED A server may reply with a MUX_S_SESSION_OPENED, a MUX_S_PERMISSION_DENIED
or a MUX_S_FAILURE. or a MUX_S_FAILURE.
8. Status messages 8. Requesting shutdown of mux listener
A client may request the master to stop accepting new multiplexing requests
and remove its listener socket.
uint32 MUX_C_STOP_LISTENING
uint32 request id
A server may reply with a MUX_S_OK, a MUX_S_PERMISSION_DENIED or a
MUX_S_FAILURE.
9. Status messages
The MUX_S_OK message is empty: The MUX_S_OK message is empty:
@ -178,6 +189,7 @@ The MUX_S_PERMISSION_DENIED and MUX_S_FAILURE include a reason:
#define MUX_C_OPEN_FWD 0x10000006 #define MUX_C_OPEN_FWD 0x10000006
#define MUX_C_CLOSE_FWD 0x10000007 #define MUX_C_CLOSE_FWD 0x10000007
#define MUX_C_NEW_STDIO_FWD 0x10000008 #define MUX_C_NEW_STDIO_FWD 0x10000008
#define MUX_C_STOP_LISTENING 0x10000009
#define MUX_S_OK 0x80000001 #define MUX_S_OK 0x80000001
#define MUX_S_PERMISSION_DENIED 0x80000002 #define MUX_S_PERMISSION_DENIED 0x80000002
#define MUX_S_FAILURE 0x80000003 #define MUX_S_FAILURE 0x80000003
@ -192,7 +204,6 @@ The MUX_S_PERMISSION_DENIED and MUX_S_FAILURE include a reason:
XXX TODO XXX TODO
XXX extended status (e.g. report open channels / forwards) XXX extended status (e.g. report open channels / forwards)
XXX graceful close (delete listening socket, but keep existing sessions active)
XXX lock (maybe) XXX lock (maybe)
XXX watch in/out traffic (pre/post crypto) XXX watch in/out traffic (pre/post crypto)
XXX inject packet (what about replies) XXX inject packet (what about replies)
@ -200,4 +211,4 @@ XXX server->client error/warning notifications
XXX port0 rfwd (need custom response message) XXX port0 rfwd (need custom response message)
XXX send signals via mux XXX send signals via mux
$OpenBSD: PROTOCOL.mux,v 1.4 2011/01/31 21:42:15 djm Exp $ $OpenBSD: PROTOCOL.mux,v 1.5 2011/04/17 22:42:41 djm Exp $

View File

@ -1,4 +1,4 @@
/* $OpenBSD: clientloop.c,v 1.231 2011/01/16 12:05:59 djm Exp $ */ /* $OpenBSD: clientloop.c,v 1.232 2011/04/17 22:42:41 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -265,10 +265,10 @@ static void
set_control_persist_exit_time(void) set_control_persist_exit_time(void)
{ {
if (muxserver_sock == -1 || !options.control_persist if (muxserver_sock == -1 || !options.control_persist
|| options.control_persist_timeout == 0) || options.control_persist_timeout == 0) {
/* not using a ControlPersist timeout */ /* not using a ControlPersist timeout */
control_persist_exit_time = 0; control_persist_exit_time = 0;
else if (channel_still_open()) { } else if (channel_still_open()) {
/* some client connections are still open */ /* some client connections are still open */
if (control_persist_exit_time > 0) if (control_persist_exit_time > 0)
debug2("%s: cancel scheduled exit", __func__); debug2("%s: cancel scheduled exit", __func__);
@ -1419,14 +1419,17 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
if (compat20) { if (compat20) {
session_ident = ssh2_chan_id; session_ident = ssh2_chan_id;
if (escape_char_arg != SSH_ESCAPECHAR_NONE) if (session_ident != -1) {
if (escape_char_arg != SSH_ESCAPECHAR_NONE) {
channel_register_filter(session_ident, channel_register_filter(session_ident,
client_simple_escape_filter, NULL, client_simple_escape_filter, NULL,
client_filter_cleanup, client_filter_cleanup,
client_new_escape_filter_ctx(escape_char_arg)); client_new_escape_filter_ctx(
if (session_ident != -1) escape_char_arg));
}
channel_register_cleanup(session_ident, channel_register_cleanup(session_ident,
client_channel_closed, 0); client_channel_closed, 0);
}
} else { } else {
/* Check if we should immediately send eof on stdin. */ /* Check if we should immediately send eof on stdin. */
client_check_initial_eof_on_stdin(); client_check_initial_eof_on_stdin();
@ -2122,6 +2125,19 @@ client_init_dispatch(void)
client_init_dispatch_15(); client_init_dispatch_15();
} }
void
client_stop_mux(void)
{
if (options.control_path != NULL && muxserver_sock != -1)
unlink(options.control_path);
/*
* If we are in persist mode, signal that we should close when all
* active channels are closed.
*/
if (options.control_persist)
session_closed = 1;
}
/* client specific fatal cleanup */ /* client specific fatal cleanup */
void void
cleanup_exit(int i) cleanup_exit(int i)

View File

@ -1,4 +1,4 @@
/* $OpenBSD: clientloop.h,v 1.25 2010/06/25 23:15:36 djm Exp $ */ /* $OpenBSD: clientloop.h,v 1.26 2011/04/17 22:42:41 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -45,6 +45,7 @@ void client_global_request_reply_fwd(int, u_int32_t, void *);
void client_session2_setup(int, int, int, const char *, struct termios *, void client_session2_setup(int, int, int, const char *, struct termios *,
int, Buffer *, char **); int, Buffer *, char **);
int client_request_tun_fwd(int, int, int); int client_request_tun_fwd(int, int, int);
void client_stop_mux(void);
/* Escape filter for protocol 2 sessions */ /* Escape filter for protocol 2 sessions */
void *client_new_escape_filter_ctx(int); void *client_new_escape_filter_ctx(int);
@ -64,6 +65,7 @@ void client_register_global_confirm(global_confirm_cb *, void *);
#define SSHMUX_COMMAND_TERMINATE 3 /* Ask master to exit */ #define SSHMUX_COMMAND_TERMINATE 3 /* Ask master to exit */
#define SSHMUX_COMMAND_STDIO_FWD 4 /* Open stdio fwd (ssh -W) */ #define SSHMUX_COMMAND_STDIO_FWD 4 /* Open stdio fwd (ssh -W) */
#define SSHMUX_COMMAND_FORWARD 5 /* Forward only, no command */ #define SSHMUX_COMMAND_FORWARD 5 /* Forward only, no command */
#define SSHMUX_COMMAND_STOP 6 /* Disable mux but not conn */
void muxserver_listen(void); void muxserver_listen(void);
void muxclient(const char *); void muxclient(const char *);

86
mux.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: mux.c,v 1.24 2011/01/13 21:54:53 djm Exp $ */ /* $OpenBSD: mux.c,v 1.25 2011/04/17 22:42:41 djm Exp $ */
/* /*
* Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org> * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
* *
@ -146,6 +146,7 @@ struct mux_master_state {
#define MUX_C_OPEN_FWD 0x10000006 #define MUX_C_OPEN_FWD 0x10000006
#define MUX_C_CLOSE_FWD 0x10000007 #define MUX_C_CLOSE_FWD 0x10000007
#define MUX_C_NEW_STDIO_FWD 0x10000008 #define MUX_C_NEW_STDIO_FWD 0x10000008
#define MUX_C_STOP_LISTENING 0x10000009
#define MUX_S_OK 0x80000001 #define MUX_S_OK 0x80000001
#define MUX_S_PERMISSION_DENIED 0x80000002 #define MUX_S_PERMISSION_DENIED 0x80000002
#define MUX_S_FAILURE 0x80000003 #define MUX_S_FAILURE 0x80000003
@ -168,6 +169,7 @@ static int process_mux_terminate(u_int, Channel *, Buffer *, Buffer *);
static int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *); static int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *);
static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *); static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *);
static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *); static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *);
static int process_mux_stop_listening(u_int, Channel *, Buffer *, Buffer *);
static const struct { static const struct {
u_int type; u_int type;
@ -180,6 +182,7 @@ static const struct {
{ MUX_C_OPEN_FWD, process_mux_open_fwd }, { MUX_C_OPEN_FWD, process_mux_open_fwd },
{ MUX_C_CLOSE_FWD, process_mux_close_fwd }, { MUX_C_CLOSE_FWD, process_mux_close_fwd },
{ MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd }, { MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd },
{ MUX_C_STOP_LISTENING, process_mux_stop_listening },
{ 0, NULL } { 0, NULL }
}; };
@ -915,6 +918,39 @@ process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
return 0; return 0;
} }
static int
process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r)
{
debug("%s: channel %d: stop listening", __func__, c->self);
if (options.control_master == SSHCTL_MASTER_ASK ||
options.control_master == SSHCTL_MASTER_AUTO_ASK) {
if (!ask_permission("Disable further multiplexing on shared "
"connection to %s? ", host)) {
debug2("%s: stop listen refused by user", __func__);
buffer_put_int(r, MUX_S_PERMISSION_DENIED);
buffer_put_int(r, rid);
buffer_put_cstring(r, "Permission denied");
return 0;
}
}
if (mux_listener_channel != NULL) {
channel_free(mux_listener_channel);
client_stop_mux();
xfree(options.control_path);
options.control_path = NULL;
mux_listener_channel = NULL;
muxserver_sock = -1;
}
/* prepare reply */
buffer_put_int(r, MUX_S_OK);
buffer_put_int(r, rid);
return 0;
}
/* Channel callbacks fired on read/write from mux slave fd */ /* Channel callbacks fired on read/write from mux slave fd */
static int static int
mux_master_read_cb(Channel *c) mux_master_read_cb(Channel *c)
@ -1813,6 +1849,50 @@ mux_client_request_stdio_fwd(int fd)
fatal("%s: master returned unexpected message %u", __func__, type); fatal("%s: master returned unexpected message %u", __func__, type);
} }
static void
mux_client_request_stop_listening(int fd)
{
Buffer m;
char *e;
u_int type, rid;
debug3("%s: entering", __func__);
buffer_init(&m);
buffer_put_int(&m, MUX_C_STOP_LISTENING);
buffer_put_int(&m, muxclient_request_id);
if (mux_client_write_packet(fd, &m) != 0)
fatal("%s: write packet: %s", __func__, strerror(errno));
buffer_clear(&m);
/* Read their reply */
if (mux_client_read_packet(fd, &m) != 0)
fatal("%s: read from master failed: %s",
__func__, strerror(errno));
type = buffer_get_int(&m);
if ((rid = buffer_get_int(&m)) != muxclient_request_id)
fatal("%s: out of sequence reply: my id %u theirs %u",
__func__, muxclient_request_id, rid);
switch (type) {
case MUX_S_OK:
break;
case MUX_S_PERMISSION_DENIED:
e = buffer_get_string(&m, NULL);
fatal("Master refused stop listening request: %s", e);
case MUX_S_FAILURE:
e = buffer_get_string(&m, NULL);
fatal("%s: stop listening request failed: %s", __func__, e);
default:
fatal("%s: unexpected response from master 0x%08x",
__func__, type);
}
buffer_free(&m);
muxclient_request_id++;
}
/* Multiplex client main loop. */ /* Multiplex client main loop. */
void void
muxclient(const char *path) muxclient(const char *path)
@ -1906,6 +1986,10 @@ muxclient(const char *path)
case SSHMUX_COMMAND_STDIO_FWD: case SSHMUX_COMMAND_STDIO_FWD:
mux_client_request_stdio_fwd(sock); mux_client_request_stdio_fwd(sock);
exit(0); exit(0);
case SSHMUX_COMMAND_STOP:
mux_client_request_stop_listening(sock);
fprintf(stderr, "Stop listening request sent.\r\n");
exit(0);
default: default:
fatal("unrecognised muxclient_command %d", muxclient_command); fatal("unrecognised muxclient_command %d", muxclient_command);
} }

6
ssh.1
View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.\" $OpenBSD: ssh.1,v 1.316 2010/11/18 15:01:00 jmc Exp $ .\" $OpenBSD: ssh.1,v 1.317 2011/04/17 22:42:41 djm Exp $
.Dd $Mdocdate: November 18 2010 $ .Dd $Mdocdate: April 17 2011 $
.Dt SSH 1 .Dt SSH 1
.Os .Os
.Sh NAME .Sh NAME
@ -395,6 +395,8 @@ Valid commands are:
(request forwardings without command execution) and (request forwardings without command execution) and
.Dq exit .Dq exit
(request the master to exit). (request the master to exit).
.Dq stop
(request the master to stop accepting further multiplexing requests).
.It Fl o Ar option .It Fl o Ar option
Can be used to give options in the format used in the configuration file. Can be used to give options in the format used in the configuration file.
This is useful for specifying options for which there is no separate This is useful for specifying options for which there is no separate

4
ssh.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh.c,v 1.356 2011/01/06 22:23:53 djm Exp $ */ /* $OpenBSD: ssh.c,v 1.357 2011/04/17 22:42:42 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -345,6 +345,8 @@ main(int ac, char **av)
muxclient_command = SSHMUX_COMMAND_FORWARD; muxclient_command = SSHMUX_COMMAND_FORWARD;
else if (strcmp(optarg, "exit") == 0) else if (strcmp(optarg, "exit") == 0)
muxclient_command = SSHMUX_COMMAND_TERMINATE; muxclient_command = SSHMUX_COMMAND_TERMINATE;
else if (strcmp(optarg, "stop") == 0)
muxclient_command = SSHMUX_COMMAND_STOP;
else else
fatal("Invalid multiplex command."); fatal("Invalid multiplex command.");
break; break;