summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@cvs.openbsd.org>2004-11-07 00:01:47 +0000
committerDamien Miller <djm@cvs.openbsd.org>2004-11-07 00:01:47 +0000
commitbb00c160285f0b7509c204c59fcf29be69136017 (patch)
tree014f9fc02dcac1735ba03b564fead21285c6c5be
parent9ea78d6935d5710a08ab020a1b12ccc4cfd24d66 (diff)
add basic control of a running multiplex master connection; including the
ability to check its status and request it to exit; ok markus@
-rw-r--r--usr.bin/ssh/clientloop.c86
-rw-r--r--usr.bin/ssh/clientloop.h10
-rw-r--r--usr.bin/ssh/ssh.119
-rw-r--r--usr.bin/ssh/ssh.c66
4 files changed, 148 insertions, 33 deletions
diff --git a/usr.bin/ssh/clientloop.c b/usr.bin/ssh/clientloop.c
index d77337b826b..033a98a5b97 100644
--- a/usr.bin/ssh/clientloop.c
+++ b/usr.bin/ssh/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/usr.bin/ssh/clientloop.h b/usr.bin/ssh/clientloop.h
index 9992d5938b0..b23c111cbd6 100644
--- a/usr.bin/ssh/clientloop.h
+++ b/usr.bin/ssh/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 <ylo@cs.hut.fi>
@@ -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/usr.bin/ssh/ssh.1 b/usr.bin/ssh/ssh.1
index 06cb60cec19..ec83319b828 100644
--- a/usr.bin/ssh/ssh.1
+++ b/usr.bin/ssh/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/usr.bin/ssh/ssh.c b/usr.bin/ssh/ssh.c
index 49eacaa42da..f9000985cf4 100644
--- a/usr.bin/ssh/ssh.c
+++ b/usr.bin/ssh/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 <openssl/evp.h>
#include <openssl/err.h>
@@ -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;
@@ -231,7 +234,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;
@@ -265,6 +268,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;
@@ -1239,8 +1250,9 @@ control_client(const char *path)
struct sockaddr_un addr;
int i, r, fd, sock, exitval, num_env;
Buffer m;
- char *cp;
+ char *term;
extern char **environ;
+ u_int flags;
if (stdin_null_flag) {
if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1)
@@ -1266,26 +1278,52 @@ control_client(const char *path)
if (connect(sock, (struct sockaddr*)&addr, addr.sun_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));
@@ -1307,7 +1345,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);
@@ -1318,8 +1356,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);