mirror of
git://anongit.mindrot.org/openssh.git
synced 2025-01-12 12:49:29 +00:00
- 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:
parent
ad21032e65
commit
6c3eec7ab2
@ -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
|
||||
|
19
PROTOCOL.mux
19
PROTOCOL.mux
@ -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 $
|
||||
|
34
clientloop.c
34
clientloop.c
@ -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>
|
||||
* 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)
|
||||
|
@ -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>
|
||||
@ -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 *);
|
||||
|
86
mux.c
86
mux.c
@ -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>
|
||||
*
|
||||
@ -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);
|
||||
}
|
||||
|
6
ssh.1
6
ssh.1
@ -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
|
||||
|
4
ssh.c
4
ssh.c
@ -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>
|
||||
* 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;
|
||||
|
Loading…
Reference in New Issue
Block a user