- 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@
This commit is contained in:
Darren Tucker 2004-11-07 20:06:19 +11:00
parent 2d963d8721
commit 7ebfc10884
5 changed files with 153 additions and 34 deletions

View File

@ -4,6 +4,10 @@
[sftp.c] [sftp.c]
command editing and history support via libedit; ok markus@ command editing and history support via libedit; ok markus@
thanks to hshoexer@ and many testers on tech@ too 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 20041105
- (dtucker) OpenBSD CVS Sync - (dtucker) OpenBSD CVS Sync
@ -1848,4 +1852,4 @@
- (djm) Trim deprecated options from INSTALL. Mention UsePAM - (djm) Trim deprecated options from INSTALL. Mention UsePAM
- (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu
$Id: ChangeLog,v 1.3579 2004/11/07 09:04:10 dtucker Exp $ $Id: ChangeLog,v 1.3580 2004/11/07 09:06:19 dtucker Exp $

View File

@ -59,7 +59,7 @@
*/ */
#include "includes.h" #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 "ssh.h"
#include "ssh1.h" #include "ssh1.h"
@ -561,7 +561,7 @@ client_process_control(fd_set * readset)
struct sockaddr_storage addr; struct sockaddr_storage addr;
struct confirm_ctx *cctx; struct confirm_ctx *cctx;
char *cmd; char *cmd;
u_int len, env_len; u_int len, env_len, command, flags;
uid_t euid; uid_t euid;
gid_t egid; gid_t egid;
@ -591,24 +591,74 @@ client_process_control(fd_set * readset)
return; return;
} }
allowed = 1;
if (options.control_master == 2)
allowed = ask_permission("Allow shared connection to %s? ",
host);
unset_nonblock(client_fd); unset_nonblock(client_fd);
/* Read command */
buffer_init(&m); 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, allowed);
buffer_put_int(&m, getpid()); 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__); error("%s: client msg_send failed", __func__);
close(client_fd); close(client_fd);
buffer_free(&m); buffer_free(&m);
return; return;
} }
buffer_clear(&m);
if (!allowed) { if (!allowed) {
error("Refused control connection"); error("Refused control connection");
@ -617,14 +667,14 @@ client_process_control(fd_set * readset)
return; return;
} }
buffer_clear(&m);
if (ssh_msg_recv(client_fd, &m) == -1) { if (ssh_msg_recv(client_fd, &m) == -1) {
error("%s: client msg_recv failed", __func__); error("%s: client msg_recv failed", __func__);
close(client_fd); close(client_fd);
buffer_free(&m); buffer_free(&m);
return; return;
} }
if ((ver = buffer_get_char(&m)) != 1) {
if ((ver = buffer_get_char(&m)) != 0) {
error("%s: wrong client version %d", __func__, ver); error("%s: wrong client version %d", __func__, ver);
buffer_free(&m); buffer_free(&m);
close(client_fd); close(client_fd);
@ -633,9 +683,8 @@ client_process_control(fd_set * readset)
cctx = xmalloc(sizeof(*cctx)); cctx = xmalloc(sizeof(*cctx));
memset(cctx, 0, sizeof(*cctx)); memset(cctx, 0, sizeof(*cctx));
cctx->want_tty = (flags & SSHMUX_FLAG_TTY) != 0;
cctx->want_tty = buffer_get_int(&m); cctx->want_subsys = (flags & SSHMUX_FLAG_SUBSYS) != 0;
cctx->want_subsys = buffer_get_int(&m);
cctx->term = buffer_get_string(&m, &len); cctx->term = buffer_get_string(&m, &len);
cmd = 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) if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1)
error("%s: tcgetattr: %s", __func__, strerror(errno)); error("%s: tcgetattr: %s", __func__, strerror(errno));
/* This roundtrip is just for synchronisation of ttymodes */
buffer_clear(&m); 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__); error("%s: client msg_send failed", __func__);
close(client_fd); close(client_fd);
close(new_fd[0]); close(new_fd[0]);
close(new_fd[1]); close(new_fd[1]);
close(new_fd[2]); close(new_fd[2]);
buffer_free(&m); 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; return;
} }
buffer_free(&m); buffer_free(&m);

View File

@ -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> * 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_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 **, dispatch_fn *); 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 */

19
ssh.1
View File

@ -34,7 +34,7 @@
.\" (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.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 .Dd September 25, 1999
.Dt SSH 1 .Dt SSH 1
.Os .Os
@ -62,6 +62,7 @@
.Ek .Ek
.Op Fl l Ar login_name .Op Fl l Ar login_name
.Op Fl m Ar mac_spec .Op Fl m Ar mac_spec
.Op Fl O Ar ctl_cmd
.Op Fl o Ar option .Op Fl o Ar option
.Bk -words .Bk -words
.Op Fl p Ar port .Op Fl p Ar port
@ -74,7 +75,7 @@
.Sm on .Sm on
.Xc .Xc
.Oc .Oc
.Op Fl S Ar ctl .Op Fl S Ar ctl_path
.Oo Ar user Ns @ Oc Ns Ar hostname .Oo Ar user Ns @ Oc Ns Ar hostname
.Op Ar command .Op Ar command
.Sh DESCRIPTION .Sh DESCRIPTION
@ -613,6 +614,18 @@ be specified in order of preference.
See the See the
.Cm MACs .Cm MACs
keyword for more information. 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 .It Fl N
Do not execute a remote command. Do not execute a remote command.
This is useful for just forwarding ports This is useful for just forwarding ports
@ -735,7 +748,7 @@ IPv6 addresses can be specified with an alternative syntax:
.Ar hostport . .Ar hostport .
.Xc .Xc
.Sm on .Sm on
.It Fl S Ar ctl .It Fl S Ar ctl_path
Specifies the location of a control socket for connection sharing. Specifies the location of a control socket for connection sharing.
Refer to the description of Refer to the description of
.Cm ControlPath .Cm ControlPath

66
ssh.c
View File

@ -40,7 +40,7 @@
*/ */
#include "includes.h" #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/evp.h>
#include <openssl/err.h> #include <openssl/err.h>
@ -144,6 +144,9 @@ pid_t proxy_command_pid = 0;
/* fd to control socket */ /* fd to control socket */
int control_fd = -1; int control_fd = -1;
/* Multiplexing control command */
static u_int mux_command = SSHMUX_COMMAND_OPEN;
/* Only used in control client mode */ /* Only used in control client mode */
volatile sig_atomic_t control_client_terminate = 0; volatile sig_atomic_t control_client_terminate = 0;
u_int control_server_pid = 0; u_int control_server_pid = 0;
@ -236,7 +239,7 @@ main(int ac, char **av)
again: again:
while ((opt = getopt(ac, av, 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) { switch (opt) {
case '1': case '1':
options.protocol = SSH_PROTO_1; options.protocol = SSH_PROTO_1;
@ -270,6 +273,14 @@ again:
case 'g': case 'g':
options.gateway_ports = 1; options.gateway_ports = 1;
break; 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 */ case 'P': /* deprecated */
options.use_privileged_port = 0; options.use_privileged_port = 0;
break; break;
@ -1251,8 +1262,9 @@ control_client(const char *path)
struct sockaddr_un addr; struct sockaddr_un addr;
int i, r, fd, sock, exitval, num_env, addr_len; int i, r, fd, sock, exitval, num_env, addr_len;
Buffer m; Buffer m;
char *cp; char *term;
extern char **environ; extern char **environ;
u_int flags;
if (stdin_null_flag) { if (stdin_null_flag) {
if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1) 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) if (connect(sock, (struct sockaddr*)&addr, addr_len) == -1)
fatal("Couldn't connect to %s: %s", path, strerror(errno)); fatal("Couldn't connect to %s: %s", path, strerror(errno));
if ((cp = getenv("TERM")) == NULL) if ((term = getenv("TERM")) == NULL)
cp = ""; term = "";
flags = 0;
if (tty_flag)
flags |= SSHMUX_FLAG_TTY;
if (subsystem_flag)
flags |= SSHMUX_FLAG_SUBSYS;
buffer_init(&m); 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) if (ssh_msg_recv(sock, &m) == -1)
fatal("%s: msg_recv", __func__); fatal("%s: msg_recv", __func__);
if (buffer_get_char(&m) != 0) if (buffer_get_char(&m) != 1)
fatal("%s: wrong version", __func__); fatal("%s: wrong version", __func__);
/* Connection allowed? */
if (buffer_get_int(&m) != 1) if (buffer_get_int(&m) != 1)
fatal("Connection to master denied"); fatal("Connection to master denied");
control_server_pid = buffer_get_int(&m); control_server_pid = buffer_get_int(&m);
buffer_clear(&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_append(&command, "\0", 1);
buffer_put_cstring(&m, buffer_ptr(&command)); 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__); fatal("%s: msg_send", __func__);
mm_send_fd(sock, STDIN_FILENO); mm_send_fd(sock, STDIN_FILENO);
@ -1330,8 +1368,8 @@ control_client(const char *path)
buffer_clear(&m); buffer_clear(&m);
if (ssh_msg_recv(sock, &m) == -1) if (ssh_msg_recv(sock, &m) == -1)
fatal("%s: msg_recv", __func__); fatal("%s: msg_recv", __func__);
if (buffer_get_char(&m) != 0) if (buffer_get_char(&m) != 1)
fatal("%s: master returned error", __func__); fatal("%s: wrong version", __func__);
buffer_free(&m); buffer_free(&m);
signal(SIGHUP, control_client_sighandler); signal(SIGHUP, control_client_sighandler);