From f8c6db83f64e83e62d301a1e90aefcfe41ce09d9 Mon Sep 17 00:00:00 2001 From: dtucker Date: Sun, 7 Nov 2004 09:06:19 +0000 Subject: [PATCH] - djm@cvs.openbsd.org 2004/11/07 00:01:46 [clientloop.c clientloop.h ssh.1 ssh.c] add basic control of a running multiplex master connection; including the ability to check its status and request it to exit; ok markus@ --- ChangeLog | 4 +++ clientloop.c | 86 +++++++++++++++++++++++++++++++++++++++++++--------- clientloop.h | 10 +++++- ssh.1 | 19 ++++++++++-- ssh.c | 66 +++++++++++++++++++++++++++++++--------- 5 files changed, 152 insertions(+), 33 deletions(-) diff --git a/ChangeLog b/ChangeLog index 101ba2c6..11cf1912 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,10 @@ [sftp.c] command editing and history support via libedit; ok markus@ thanks to hshoexer@ and many testers on tech@ too + - djm@cvs.openbsd.org 2004/11/07 00:01:46 + [clientloop.c clientloop.h ssh.1 ssh.c] + add basic control of a running multiplex master connection; including the + ability to check its status and request it to exit; ok markus@ 20041105 - (dtucker) OpenBSD CVS Sync diff --git a/clientloop.c b/clientloop.c index d77337b8..033a98a5 100644 --- a/clientloop.c +++ b/clientloop.c @@ -59,7 +59,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: clientloop.c,v 1.133 2004/10/29 22:53:56 djm Exp $"); +RCSID("$OpenBSD: clientloop.c,v 1.134 2004/11/07 00:01:46 djm Exp $"); #include "ssh.h" #include "ssh1.h" @@ -561,7 +561,7 @@ client_process_control(fd_set * readset) struct sockaddr_storage addr; struct confirm_ctx *cctx; char *cmd; - u_int len, env_len; + u_int len, env_len, command, flags; uid_t euid; gid_t egid; @@ -591,24 +591,74 @@ client_process_control(fd_set * readset) return; } - allowed = 1; - if (options.control_master == 2) - allowed = ask_permission("Allow shared connection to %s? ", - host); - unset_nonblock(client_fd); + /* Read command */ buffer_init(&m); + if (ssh_msg_recv(client_fd, &m) == -1) { + error("%s: client msg_recv failed", __func__); + close(client_fd); + buffer_free(&m); + return; + } + if ((ver = buffer_get_char(&m)) != 1) { + error("%s: wrong client version %d", __func__, ver); + buffer_free(&m); + close(client_fd); + return; + } + + allowed = 1; + command = buffer_get_int(&m); + flags = buffer_get_int(&m); + + buffer_clear(&m); + switch (command) { + case SSHMUX_COMMAND_OPEN: + if (options.control_master == 2) + allowed = ask_permission("Allow shared connection " + "to %s? ", host); + /* continue below */ + break; + case SSHMUX_COMMAND_TERMINATE: + if (options.control_master == 2) + allowed = ask_permission("Terminate shared connection " + "to %s? ", host); + if (allowed) + quit_pending = 1; + /* FALLTHROUGH */ + case SSHMUX_COMMAND_ALIVE_CHECK: + /* Reply for SSHMUX_COMMAND_TERMINATE and ALIVE_CHECK */ + buffer_clear(&m); + buffer_put_int(&m, allowed); + buffer_put_int(&m, getpid()); + if (ssh_msg_send(client_fd, /* version */1, &m) == -1) { + error("%s: client msg_send failed", __func__); + close(client_fd); + buffer_free(&m); + return; + } + buffer_free(&m); + close(client_fd); + return; + default: + error("Unsupported command %d", command); + buffer_free(&m); + close(client_fd); + return; + } + + /* Reply for SSHMUX_COMMAND_OPEN */ + buffer_clear(&m); buffer_put_int(&m, allowed); buffer_put_int(&m, getpid()); - if (ssh_msg_send(client_fd, /* version */0, &m) == -1) { + if (ssh_msg_send(client_fd, /* version */1, &m) == -1) { error("%s: client msg_send failed", __func__); close(client_fd); buffer_free(&m); return; } - buffer_clear(&m); if (!allowed) { error("Refused control connection"); @@ -617,14 +667,14 @@ client_process_control(fd_set * readset) return; } + buffer_clear(&m); if (ssh_msg_recv(client_fd, &m) == -1) { error("%s: client msg_recv failed", __func__); close(client_fd); buffer_free(&m); return; } - - if ((ver = buffer_get_char(&m)) != 0) { + if ((ver = buffer_get_char(&m)) != 1) { error("%s: wrong client version %d", __func__, ver); buffer_free(&m); close(client_fd); @@ -633,9 +683,8 @@ client_process_control(fd_set * readset) cctx = xmalloc(sizeof(*cctx)); memset(cctx, 0, sizeof(*cctx)); - - cctx->want_tty = buffer_get_int(&m); - cctx->want_subsys = buffer_get_int(&m); + cctx->want_tty = (flags & SSHMUX_FLAG_TTY) != 0; + cctx->want_subsys = (flags & SSHMUX_FLAG_SUBSYS) != 0; cctx->term = buffer_get_string(&m, &len); cmd = buffer_get_string(&m, &len); @@ -667,14 +716,21 @@ client_process_control(fd_set * readset) if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) error("%s: tcgetattr: %s", __func__, strerror(errno)); + /* This roundtrip is just for synchronisation of ttymodes */ buffer_clear(&m); - if (ssh_msg_send(client_fd, /* version */0, &m) == -1) { + if (ssh_msg_send(client_fd, /* version */1, &m) == -1) { error("%s: client msg_send failed", __func__); close(client_fd); close(new_fd[0]); close(new_fd[1]); close(new_fd[2]); buffer_free(&m); + xfree(cctx->term); + if (env_len != 0) { + for (i = 0; i < env_len; i++) + xfree(cctx->env[i]); + xfree(cctx->env); + } return; } buffer_free(&m); diff --git a/clientloop.h b/clientloop.h index 9992d593..b23c111c 100644 --- a/clientloop.h +++ b/clientloop.h @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.h,v 1.11 2004/07/11 17:48:47 deraadt Exp $ */ +/* $OpenBSD: clientloop.h,v 1.12 2004/11/07 00:01:46 djm Exp $ */ /* * Author: Tatu Ylonen @@ -40,3 +40,11 @@ int client_loop(int, int, int); 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 **, dispatch_fn *); + +/* Multiplexing control protocol flags */ +#define SSHMUX_COMMAND_OPEN 1 /* Open new connection */ +#define SSHMUX_COMMAND_ALIVE_CHECK 2 /* Check master is alive */ +#define SSHMUX_COMMAND_TERMINATE 3 /* Ask master to exit */ + +#define SSHMUX_FLAG_TTY (1) /* Request tty on open */ +#define SSHMUX_FLAG_SUBSYS (1<<1) /* Subsystem request on open */ diff --git a/ssh.1 b/ssh.1 index 06cb60ce..ec83319b 100644 --- a/ssh.1 +++ b/ssh.1 @@ -34,7 +34,7 @@ .\" (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.197 2004/10/07 10:10:24 djm Exp $ +.\" $OpenBSD: ssh.1,v 1.198 2004/11/07 00:01:46 djm Exp $ .Dd September 25, 1999 .Dt SSH 1 .Os @@ -62,6 +62,7 @@ .Ek .Op Fl l Ar login_name .Op Fl m Ar mac_spec +.Op Fl O Ar ctl_cmd .Op Fl o Ar option .Bk -words .Op Fl p Ar port @@ -74,7 +75,7 @@ .Sm on .Xc .Oc -.Op Fl S Ar ctl +.Op Fl S Ar ctl_path .Oo Ar user Ns @ Oc Ns Ar hostname .Op Ar command .Sh DESCRIPTION @@ -613,6 +614,18 @@ be specified in order of preference. See the .Cm MACs keyword for more information. +.It Fl O Ar ctl_cmd +Control an active connection multiplexing master process. +When the +.Fl O +option is specified, the +.Ar ctl_cmd +argument is interpreted and passed to the master process. +Valid commands are: +.Dq check +(check that the master process is running) and +.Dq exit +(request the master to exit). .It Fl N Do not execute a remote command. This is useful for just forwarding ports @@ -735,7 +748,7 @@ IPv6 addresses can be specified with an alternative syntax: .Ar hostport . .Xc .Sm on -.It Fl S Ar ctl +.It Fl S Ar ctl_path Specifies the location of a control socket for connection sharing. Refer to the description of .Cm ControlPath diff --git a/ssh.c b/ssh.c index c231c5fa..dfe9b25c 100644 --- a/ssh.c +++ b/ssh.c @@ -40,7 +40,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ssh.c,v 1.228 2004/09/23 13:00:04 djm Exp $"); +RCSID("$OpenBSD: ssh.c,v 1.229 2004/11/07 00:01:46 djm Exp $"); #include #include @@ -144,6 +144,9 @@ pid_t proxy_command_pid = 0; /* fd to control socket */ int control_fd = -1; +/* Multiplexing control command */ +static u_int mux_command = SSHMUX_COMMAND_OPEN; + /* Only used in control client mode */ volatile sig_atomic_t control_client_terminate = 0; u_int control_server_pid = 0; @@ -236,7 +239,7 @@ main(int ac, char **av) again: while ((opt = getopt(ac, av, - "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:MNPR:S:TVXY")) != -1) { + "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:MNO:PR:S:TVXY")) != -1) { switch (opt) { case '1': options.protocol = SSH_PROTO_1; @@ -270,6 +273,14 @@ again: case 'g': options.gateway_ports = 1; break; + case 'O': + if (strcmp(optarg, "check") == 0) + mux_command = SSHMUX_COMMAND_ALIVE_CHECK; + else if (strcmp(optarg, "exit") == 0) + mux_command = SSHMUX_COMMAND_TERMINATE; + else + fatal("Invalid multiplex command."); + break; case 'P': /* deprecated */ options.use_privileged_port = 0; break; @@ -1251,8 +1262,9 @@ control_client(const char *path) struct sockaddr_un addr; int i, r, fd, sock, exitval, num_env, addr_len; Buffer m; - char *cp; + char *term; extern char **environ; + u_int flags; if (stdin_null_flag) { if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1) @@ -1278,26 +1290,52 @@ control_client(const char *path) if (connect(sock, (struct sockaddr*)&addr, addr_len) == -1) fatal("Couldn't connect to %s: %s", path, strerror(errno)); - if ((cp = getenv("TERM")) == NULL) - cp = ""; + if ((term = getenv("TERM")) == NULL) + term = ""; + + flags = 0; + if (tty_flag) + flags |= SSHMUX_FLAG_TTY; + if (subsystem_flag) + flags |= SSHMUX_FLAG_SUBSYS; buffer_init(&m); - /* Get PID of controlee */ + /* Send our command to server */ + buffer_put_int(&m, mux_command); + buffer_put_int(&m, flags); + if (ssh_msg_send(sock, /* version */1, &m) == -1) + fatal("%s: msg_send", __func__); + buffer_clear(&m); + + /* Get authorisation status and PID of controlee */ if (ssh_msg_recv(sock, &m) == -1) fatal("%s: msg_recv", __func__); - if (buffer_get_char(&m) != 0) + if (buffer_get_char(&m) != 1) fatal("%s: wrong version", __func__); - /* Connection allowed? */ if (buffer_get_int(&m) != 1) fatal("Connection to master denied"); control_server_pid = buffer_get_int(&m); buffer_clear(&m); - buffer_put_int(&m, tty_flag); - buffer_put_int(&m, subsystem_flag); - buffer_put_cstring(&m, cp); + switch (mux_command) { + case SSHMUX_COMMAND_ALIVE_CHECK: + fprintf(stderr, "Master running (pid=%d)\r\n", + control_server_pid); + exit(0); + case SSHMUX_COMMAND_TERMINATE: + fprintf(stderr, "Exit request sent.\r\n"); + exit(0); + case SSHMUX_COMMAND_OPEN: + /* continue below */ + break; + default: + fatal("silly mux_command %d", mux_command); + } + + /* SSHMUX_COMMAND_OPEN */ + buffer_put_cstring(&m, term); buffer_append(&command, "\0", 1); buffer_put_cstring(&m, buffer_ptr(&command)); @@ -1319,7 +1357,7 @@ control_client(const char *path) } } - if (ssh_msg_send(sock, /* version */0, &m) == -1) + if (ssh_msg_send(sock, /* version */1, &m) == -1) fatal("%s: msg_send", __func__); mm_send_fd(sock, STDIN_FILENO); @@ -1330,8 +1368,8 @@ control_client(const char *path) buffer_clear(&m); if (ssh_msg_recv(sock, &m) == -1) fatal("%s: msg_recv", __func__); - if (buffer_get_char(&m) != 0) - fatal("%s: master returned error", __func__); + if (buffer_get_char(&m) != 1) + fatal("%s: wrong version", __func__); buffer_free(&m); signal(SIGHUP, control_client_sighandler); -- 2.45.1