Commit 6c3eec7a authored by Damien Miller's avatar Damien Miller

- 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@
parent ad21032e
......@@ -55,6 +55,11 @@
- djm@cvs.openbsd.org 2011/04/13 04:09:37
[ssh-keygen.1]
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
- (dtucker) [contrib/cygwin/ssh-host-config] From Corinna: revamp of the
......
......@@ -149,10 +149,21 @@ The client then sends its standard input and output file descriptors
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.
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:
......@@ -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_CLOSE_FWD 0x10000007
#define MUX_C_NEW_STDIO_FWD 0x10000008
#define MUX_C_STOP_LISTENING 0x10000009
#define MUX_S_OK 0x80000001
#define MUX_S_PERMISSION_DENIED 0x80000002
#define MUX_S_FAILURE 0x80000003
......@@ -192,7 +204,6 @@ The MUX_S_PERMISSION_DENIED and MUX_S_FAILURE include a reason:
XXX TODO
XXX extended status (e.g. report open channels / forwards)
XXX graceful close (delete listening socket, but keep existing sessions active)
XXX lock (maybe)
XXX watch in/out traffic (pre/post crypto)
XXX inject packet (what about replies)
......@@ -200,4 +211,4 @@ XXX server->client error/warning notifications
XXX port0 rfwd (need custom response message)
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 $
/* $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>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
......@@ -265,10 +265,10 @@ static void
set_control_persist_exit_time(void)
{
if (muxserver_sock == -1 || !options.control_persist
|| options.control_persist_timeout == 0)
|| options.control_persist_timeout == 0) {
/* not using a ControlPersist timeout */
control_persist_exit_time = 0;
else if (channel_still_open()) {
} else if (channel_still_open()) {
/* some client connections are still open */
if (control_persist_exit_time > 0)
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) {
session_ident = ssh2_chan_id;
if (escape_char_arg != SSH_ESCAPECHAR_NONE)
channel_register_filter(session_ident,
client_simple_escape_filter, NULL,
client_filter_cleanup,
client_new_escape_filter_ctx(escape_char_arg));
if (session_ident != -1)
if (session_ident != -1) {
if (escape_char_arg != SSH_ESCAPECHAR_NONE) {
channel_register_filter(session_ident,
client_simple_escape_filter, NULL,
client_filter_cleanup,
client_new_escape_filter_ctx(
escape_char_arg));
}
channel_register_cleanup(session_ident,
client_channel_closed, 0);
}
} else {
/* Check if we should immediately send eof on stdin. */
client_check_initial_eof_on_stdin();
......@@ -2122,6 +2125,19 @@ client_init_dispatch(void)
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 */
void
cleanup_exit(int i)
......
/* $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>
......@@ -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 *,
int, Buffer *, char **);
int client_request_tun_fwd(int, int, int);
void client_stop_mux(void);
/* Escape filter for protocol 2 sessions */
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_STDIO_FWD 4 /* Open stdio fwd (ssh -W) */
#define SSHMUX_COMMAND_FORWARD 5 /* Forward only, no command */
#define SSHMUX_COMMAND_STOP 6 /* Disable mux but not conn */
void muxserver_listen(void);
void muxclient(const char *);
......
/* $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>
*
......@@ -146,6 +146,7 @@ struct mux_master_state {
#define MUX_C_OPEN_FWD 0x10000006
#define MUX_C_CLOSE_FWD 0x10000007
#define MUX_C_NEW_STDIO_FWD 0x10000008
#define MUX_C_STOP_LISTENING 0x10000009
#define MUX_S_OK 0x80000001
#define MUX_S_PERMISSION_DENIED 0x80000002
#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_close_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 {
u_int type;
......@@ -180,6 +182,7 @@ static const struct {
{ MUX_C_OPEN_FWD, process_mux_open_fwd },
{ MUX_C_CLOSE_FWD, process_mux_close_fwd },
{ MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd },
{ MUX_C_STOP_LISTENING, process_mux_stop_listening },
{ 0, NULL }
};
......@@ -915,6 +918,39 @@ process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
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 */
static int
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);
}
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. */
void
muxclient(const char *path)
......@@ -1906,6 +1986,10 @@ muxclient(const char *path)
case SSHMUX_COMMAND_STDIO_FWD:
mux_client_request_stdio_fwd(sock);
exit(0);
case SSHMUX_COMMAND_STOP:
mux_client_request_stop_listening(sock);
fprintf(stderr, "Stop listening request sent.\r\n");
exit(0);
default:
fatal("unrecognised muxclient_command %d", muxclient_command);
}
......
......@@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" 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 $
.Dd $Mdocdate: November 18 2010 $
.\" $OpenBSD: ssh.1,v 1.317 2011/04/17 22:42:41 djm Exp $
.Dd $Mdocdate: April 17 2011 $
.Dt SSH 1
.Os
.Sh NAME
......@@ -395,6 +395,8 @@ Valid commands are:
(request forwardings without command execution) and
.Dq exit
(request the master to exit).
.Dq stop
(request the master to stop accepting further multiplexing requests).
.It Fl o Ar option
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
......
/* $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>
* 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;
else if (strcmp(optarg, "exit") == 0)
muxclient_command = SSHMUX_COMMAND_TERMINATE;
else if (strcmp(optarg, "stop") == 0)
muxclient_command = SSHMUX_COMMAND_STOP;
else
fatal("Invalid multiplex command.");
break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment