- djm@cvs.openbsd.org 2008/06/12 03:40:52
[clientloop.h mux.c channels.c clientloop.c channels.h] Enable ~ escapes for multiplex slave sessions; give each channel its own escape state and hook the escape filters up to muxed channels. bz #1331 Mux slaves do not currently support the ~^Z and ~& escapes. NB. this change cranks the mux protocol version, so a new ssh mux client will not be able to connect to a running old ssh mux master. ok dtucker@
This commit is contained in:
parent
267e28bb75
commit
2fb66caca2
12
ChangeLog
12
ChangeLog
|
@ -68,6 +68,16 @@
|
||||||
[key.c]
|
[key.c]
|
||||||
use an odd number of rows and columns and a separate start marker, looks
|
use an odd number of rows and columns and a separate start marker, looks
|
||||||
better; ok grunk@
|
better; ok grunk@
|
||||||
|
- djm@cvs.openbsd.org 2008/06/12 03:40:52
|
||||||
|
[clientloop.h mux.c channels.c clientloop.c channels.h]
|
||||||
|
Enable ~ escapes for multiplex slave sessions; give each channel
|
||||||
|
its own escape state and hook the escape filters up to muxed
|
||||||
|
channels. bz #1331
|
||||||
|
Mux slaves do not currently support the ~^Z and ~& escapes.
|
||||||
|
NB. this change cranks the mux protocol version, so a new ssh
|
||||||
|
mux client will not be able to connect to a running old ssh
|
||||||
|
mux master.
|
||||||
|
ok dtucker@
|
||||||
|
|
||||||
20080611
|
20080611
|
||||||
- (djm) [channels.c configure.ac]
|
- (djm) [channels.c configure.ac]
|
||||||
|
@ -4230,4 +4240,4 @@
|
||||||
OpenServer 6 and add osr5bigcrypt support so when someone migrates
|
OpenServer 6 and add osr5bigcrypt support so when someone migrates
|
||||||
passwords between UnixWare and OpenServer they will still work. OK dtucker@
|
passwords between UnixWare and OpenServer they will still work. OK dtucker@
|
||||||
|
|
||||||
$Id: ChangeLog,v 1.4976 2008/06/12 18:48:11 dtucker Exp $
|
$Id: ChangeLog,v 1.4977 2008/06/12 18:49:33 dtucker Exp $
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: channels.c,v 1.278 2008/06/10 04:50:25 dtucker Exp $ */
|
/* $OpenBSD: channels.c,v 1.279 2008/06/12 03:40:52 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
|
@ -731,7 +731,7 @@ channel_cancel_cleanup(int id)
|
||||||
|
|
||||||
void
|
void
|
||||||
channel_register_filter(int id, channel_infilter_fn *ifn,
|
channel_register_filter(int id, channel_infilter_fn *ifn,
|
||||||
channel_outfilter_fn *ofn)
|
channel_outfilter_fn *ofn, void *ctx)
|
||||||
{
|
{
|
||||||
Channel *c = channel_lookup(id);
|
Channel *c = channel_lookup(id);
|
||||||
|
|
||||||
|
@ -741,6 +741,7 @@ channel_register_filter(int id, channel_infilter_fn *ifn,
|
||||||
}
|
}
|
||||||
c->input_filter = ifn;
|
c->input_filter = ifn;
|
||||||
c->output_filter = ofn;
|
c->output_filter = ofn;
|
||||||
|
c->filter_ctx = ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: channels.h,v 1.93 2008/06/10 04:50:25 dtucker Exp $ */
|
/* $OpenBSD: channels.h,v 1.94 2008/06/12 03:40:52 djm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
|
@ -131,6 +131,7 @@ struct Channel {
|
||||||
/* filter */
|
/* filter */
|
||||||
channel_infilter_fn *input_filter;
|
channel_infilter_fn *input_filter;
|
||||||
channel_outfilter_fn *output_filter;
|
channel_outfilter_fn *output_filter;
|
||||||
|
void *filter_ctx;
|
||||||
|
|
||||||
/* keep boundaries */
|
/* keep boundaries */
|
||||||
int datagram;
|
int datagram;
|
||||||
|
@ -195,7 +196,7 @@ void channel_request_start(int, char *, int);
|
||||||
void channel_register_cleanup(int, channel_callback_fn *, int);
|
void channel_register_cleanup(int, channel_callback_fn *, int);
|
||||||
void channel_register_open_confirm(int, channel_callback_fn *, void *);
|
void channel_register_open_confirm(int, channel_callback_fn *, void *);
|
||||||
void channel_register_filter(int, channel_infilter_fn *,
|
void channel_register_filter(int, channel_infilter_fn *,
|
||||||
channel_outfilter_fn *);
|
channel_outfilter_fn *, void *);
|
||||||
void channel_register_status_confirm(int, channel_confirm_cb *,
|
void channel_register_status_confirm(int, channel_confirm_cb *,
|
||||||
channel_confirm_abandon_cb *, void *);
|
channel_confirm_abandon_cb *, void *);
|
||||||
void channel_cancel_cleanup(int);
|
void channel_cancel_cleanup(int);
|
||||||
|
|
154
clientloop.c
154
clientloop.c
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: clientloop.c,v 1.194 2008/05/19 20:53:52 djm Exp $ */
|
/* $OpenBSD: clientloop.c,v 1.195 2008/06/12 03:40:52 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
|
@ -144,8 +144,8 @@ static int in_non_blocking_mode = 0;
|
||||||
|
|
||||||
/* Common data for the client loop code. */
|
/* Common data for the client loop code. */
|
||||||
static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */
|
static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */
|
||||||
static int escape_char; /* Escape character. */
|
static int escape_char1; /* Escape character. (proto1 only) */
|
||||||
static int escape_pending; /* Last character was the escape character */
|
static int escape_pending1; /* Last character was an escape (proto1 only) */
|
||||||
static int last_was_cr; /* Last character was a newline. */
|
static int last_was_cr; /* Last character was a newline. */
|
||||||
static int exit_status; /* Used to store the exit status of the command. */
|
static int exit_status; /* Used to store the exit status of the command. */
|
||||||
static int stdin_eof; /* EOF has been encountered on standard error. */
|
static int stdin_eof; /* EOF has been encountered on standard error. */
|
||||||
|
@ -162,6 +162,13 @@ static int session_closed = 0; /* In SSH2: login session closed. */
|
||||||
static void client_init_dispatch(void);
|
static void client_init_dispatch(void);
|
||||||
int session_ident = -1;
|
int session_ident = -1;
|
||||||
|
|
||||||
|
/* Track escape per proto2 channel */
|
||||||
|
struct escape_filter_ctx {
|
||||||
|
int escape_pending;
|
||||||
|
int escape_char;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Context for channel confirmation replies */
|
||||||
struct channel_reply_ctx {
|
struct channel_reply_ctx {
|
||||||
const char *request_type;
|
const char *request_type;
|
||||||
int id, do_close;
|
int id, do_close;
|
||||||
|
@ -385,8 +392,8 @@ client_check_initial_eof_on_stdin(void)
|
||||||
* and also process it as an escape character if
|
* and also process it as an escape character if
|
||||||
* appropriate.
|
* appropriate.
|
||||||
*/
|
*/
|
||||||
if ((u_char) buf[0] == escape_char)
|
if ((u_char) buf[0] == escape_char1)
|
||||||
escape_pending = 1;
|
escape_pending1 = 1;
|
||||||
else
|
else
|
||||||
buffer_append(&stdin_buffer, buf, 1);
|
buffer_append(&stdin_buffer, buf, 1);
|
||||||
}
|
}
|
||||||
|
@ -813,9 +820,12 @@ out:
|
||||||
xfree(fwd.connect_host);
|
xfree(fwd.connect_host);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* process the characters one by one */
|
/*
|
||||||
|
* Process the characters one by one, call with c==NULL for proto1 case.
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
|
process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
|
||||||
|
char *buf, int len)
|
||||||
{
|
{
|
||||||
char string[1024];
|
char string[1024];
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
@ -823,7 +833,20 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
|
||||||
u_int i;
|
u_int i;
|
||||||
u_char ch;
|
u_char ch;
|
||||||
char *s;
|
char *s;
|
||||||
|
int *escape_pendingp, escape_char;
|
||||||
|
struct escape_filter_ctx *efc;
|
||||||
|
|
||||||
|
if (c == NULL) {
|
||||||
|
escape_pendingp = &escape_pending1;
|
||||||
|
escape_char = escape_char1;
|
||||||
|
} else {
|
||||||
|
if (c->filter_ctx == NULL)
|
||||||
|
return 0;
|
||||||
|
efc = (struct escape_filter_ctx *)c->filter_ctx;
|
||||||
|
escape_pendingp = &efc->escape_pending;
|
||||||
|
escape_char = efc->escape_char;
|
||||||
|
}
|
||||||
|
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
|
@ -831,25 +854,43 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
|
||||||
/* Get one character at a time. */
|
/* Get one character at a time. */
|
||||||
ch = buf[i];
|
ch = buf[i];
|
||||||
|
|
||||||
if (escape_pending) {
|
if (*escape_pendingp) {
|
||||||
/* We have previously seen an escape character. */
|
/* We have previously seen an escape character. */
|
||||||
/* Clear the flag now. */
|
/* Clear the flag now. */
|
||||||
escape_pending = 0;
|
*escape_pendingp = 0;
|
||||||
|
|
||||||
/* Process the escaped character. */
|
/* Process the escaped character. */
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case '.':
|
case '.':
|
||||||
/* Terminate the connection. */
|
/* Terminate the connection. */
|
||||||
snprintf(string, sizeof string, "%c.\r\n", escape_char);
|
snprintf(string, sizeof string, "%c.\r\n",
|
||||||
|
escape_char);
|
||||||
buffer_append(berr, string, strlen(string));
|
buffer_append(berr, string, strlen(string));
|
||||||
|
|
||||||
quit_pending = 1;
|
if (c && c->ctl_fd != -1) {
|
||||||
|
chan_read_failed(c);
|
||||||
|
chan_write_failed(c);
|
||||||
|
return 0;
|
||||||
|
} else
|
||||||
|
quit_pending = 1;
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
case 'Z' - 64:
|
case 'Z' - 64:
|
||||||
|
/* XXX support this for mux clients */
|
||||||
|
if (c && c->ctl_fd != -1) {
|
||||||
|
noescape:
|
||||||
|
snprintf(string, sizeof string,
|
||||||
|
"%c%c escape not available to "
|
||||||
|
"multiplexed sessions\r\n",
|
||||||
|
escape_char, ch);
|
||||||
|
buffer_append(berr, string,
|
||||||
|
strlen(string));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
/* Suspend the program. */
|
/* Suspend the program. */
|
||||||
/* Print a message to that effect to the user. */
|
/* Print a message to that effect to the user. */
|
||||||
snprintf(string, sizeof string, "%c^Z [suspend ssh]\r\n", escape_char);
|
snprintf(string, sizeof string,
|
||||||
|
"%c^Z [suspend ssh]\r\n", escape_char);
|
||||||
buffer_append(berr, string, strlen(string));
|
buffer_append(berr, string, strlen(string));
|
||||||
|
|
||||||
/* Restore terminal modes and suspend. */
|
/* Restore terminal modes and suspend. */
|
||||||
|
@ -881,6 +922,8 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case '&':
|
case '&':
|
||||||
|
if (c && c->ctl_fd != -1)
|
||||||
|
goto noescape;
|
||||||
/*
|
/*
|
||||||
* Detach the program (continue to serve connections,
|
* Detach the program (continue to serve connections,
|
||||||
* but put in background and no more new connections).
|
* but put in background and no more new connections).
|
||||||
|
@ -929,27 +972,50 @@ process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
snprintf(string, sizeof string,
|
if (c && c->ctl_fd != -1) {
|
||||||
|
snprintf(string, sizeof string,
|
||||||
"%c?\r\n\
|
"%c?\r\n\
|
||||||
Supported escape sequences:\r\n\
|
Supported escape sequences:\r\n\
|
||||||
%c. - terminate connection\r\n\
|
%c. - terminate session\r\n\
|
||||||
%cB - send a BREAK to the remote system\r\n\
|
%cB - send a BREAK to the remote system\r\n\
|
||||||
%cC - open a command line\r\n\
|
%cC - open a command line\r\n\
|
||||||
%cR - Request rekey (SSH protocol 2 only)\r\n\
|
%cR - Request rekey (SSH protocol 2 only)\r\n\
|
||||||
%c^Z - suspend ssh\r\n\
|
%c# - list forwarded connections\r\n\
|
||||||
%c# - list forwarded connections\r\n\
|
%c? - this message\r\n\
|
||||||
%c& - background ssh (when waiting for connections to terminate)\r\n\
|
%c%c - send the escape character by typing it twice\r\n\
|
||||||
%c? - this message\r\n\
|
|
||||||
%c%c - send the escape character by typing it twice\r\n\
|
|
||||||
(Note that escapes are only recognized immediately after newline.)\r\n",
|
(Note that escapes are only recognized immediately after newline.)\r\n",
|
||||||
escape_char, escape_char, escape_char, escape_char,
|
escape_char, escape_char,
|
||||||
escape_char, escape_char, escape_char, escape_char,
|
escape_char, escape_char,
|
||||||
escape_char, escape_char, escape_char);
|
escape_char, escape_char,
|
||||||
|
escape_char, escape_char,
|
||||||
|
escape_char);
|
||||||
|
} else {
|
||||||
|
snprintf(string, sizeof string,
|
||||||
|
"%c?\r\n\
|
||||||
|
Supported escape sequences:\r\n\
|
||||||
|
%c. - terminate connection (and any multiplexed sessions)\r\n\
|
||||||
|
%cB - send a BREAK to the remote system\r\n\
|
||||||
|
%cC - open a command line\r\n\
|
||||||
|
%cR - Request rekey (SSH protocol 2 only)\r\n\
|
||||||
|
%c^Z - suspend ssh\r\n\
|
||||||
|
%c# - list forwarded connections\r\n\
|
||||||
|
%c& - background ssh (when waiting for connections to terminate)\r\n\
|
||||||
|
%c? - this message\r\n\
|
||||||
|
%c%c - send the escape character by typing it twice\r\n\
|
||||||
|
(Note that escapes are only recognized immediately after newline.)\r\n",
|
||||||
|
escape_char, escape_char,
|
||||||
|
escape_char, escape_char,
|
||||||
|
escape_char, escape_char,
|
||||||
|
escape_char, escape_char,
|
||||||
|
escape_char, escape_char,
|
||||||
|
escape_char);
|
||||||
|
}
|
||||||
buffer_append(berr, string, strlen(string));
|
buffer_append(berr, string, strlen(string));
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case '#':
|
case '#':
|
||||||
snprintf(string, sizeof string, "%c#\r\n", escape_char);
|
snprintf(string, sizeof string, "%c#\r\n",
|
||||||
|
escape_char);
|
||||||
buffer_append(berr, string, strlen(string));
|
buffer_append(berr, string, strlen(string));
|
||||||
s = channel_open_message();
|
s = channel_open_message();
|
||||||
buffer_append(berr, s, strlen(s));
|
buffer_append(berr, s, strlen(s));
|
||||||
|
@ -975,7 +1041,7 @@ Supported escape sequences:\r\n\
|
||||||
*/
|
*/
|
||||||
if (last_was_cr && ch == escape_char) {
|
if (last_was_cr && ch == escape_char) {
|
||||||
/* It is. Set the flag and continue to next character. */
|
/* It is. Set the flag and continue to next character. */
|
||||||
escape_pending = 1;
|
*escape_pendingp = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1026,7 +1092,7 @@ client_process_input(fd_set *readset)
|
||||||
packet_start(SSH_CMSG_EOF);
|
packet_start(SSH_CMSG_EOF);
|
||||||
packet_send();
|
packet_send();
|
||||||
}
|
}
|
||||||
} else if (escape_char == SSH_ESCAPECHAR_NONE) {
|
} else if (escape_char1 == SSH_ESCAPECHAR_NONE) {
|
||||||
/*
|
/*
|
||||||
* Normal successful read, and no escape character.
|
* Normal successful read, and no escape character.
|
||||||
* Just append the data to buffer.
|
* Just append the data to buffer.
|
||||||
|
@ -1037,8 +1103,8 @@ client_process_input(fd_set *readset)
|
||||||
* Normal, successful read. But we have an escape character
|
* Normal, successful read. But we have an escape character
|
||||||
* and have to process the characters one by one.
|
* and have to process the characters one by one.
|
||||||
*/
|
*/
|
||||||
if (process_escapes(&stdin_buffer, &stdout_buffer,
|
if (process_escapes(NULL, &stdin_buffer,
|
||||||
&stderr_buffer, buf, len) == -1)
|
&stdout_buffer, &stderr_buffer, buf, len) == -1)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1113,13 +1179,26 @@ client_process_buffered_input_packets(void)
|
||||||
|
|
||||||
/* scan buf[] for '~' before sending data to the peer */
|
/* scan buf[] for '~' before sending data to the peer */
|
||||||
|
|
||||||
static int
|
/* Helper: allocate a new escape_filter_ctx and fill in its escape char */
|
||||||
simple_escape_filter(Channel *c, char *buf, int len)
|
void *
|
||||||
|
client_new_escape_filter_ctx(int escape_char)
|
||||||
|
{
|
||||||
|
struct escape_filter_ctx *ret;
|
||||||
|
|
||||||
|
ret = xmalloc(sizeof(*ret));
|
||||||
|
ret->escape_pending = 0;
|
||||||
|
ret->escape_char = escape_char;
|
||||||
|
return (void *)ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
client_simple_escape_filter(Channel *c, char *buf, int len)
|
||||||
{
|
{
|
||||||
if (c->extended_usage != CHAN_EXTENDED_WRITE)
|
if (c->extended_usage != CHAN_EXTENDED_WRITE)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return process_escapes(&c->input, &c->output, &c->extended, buf, len);
|
return process_escapes(c, &c->input, &c->output, &c->extended,
|
||||||
|
buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1151,7 +1230,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
|
||||||
start_time = get_current_time();
|
start_time = get_current_time();
|
||||||
|
|
||||||
/* Initialize variables. */
|
/* Initialize variables. */
|
||||||
escape_pending = 0;
|
escape_pending1 = 0;
|
||||||
last_was_cr = 1;
|
last_was_cr = 1;
|
||||||
exit_status = -1;
|
exit_status = -1;
|
||||||
stdin_eof = 0;
|
stdin_eof = 0;
|
||||||
|
@ -1178,7 +1257,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
|
||||||
stdout_bytes = 0;
|
stdout_bytes = 0;
|
||||||
stderr_bytes = 0;
|
stderr_bytes = 0;
|
||||||
quit_pending = 0;
|
quit_pending = 0;
|
||||||
escape_char = escape_char_arg;
|
escape_char1 = escape_char_arg;
|
||||||
|
|
||||||
/* Initialize buffers. */
|
/* Initialize buffers. */
|
||||||
buffer_init(&stdin_buffer);
|
buffer_init(&stdin_buffer);
|
||||||
|
@ -1206,9 +1285,10 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
|
||||||
|
|
||||||
if (compat20) {
|
if (compat20) {
|
||||||
session_ident = ssh2_chan_id;
|
session_ident = ssh2_chan_id;
|
||||||
if (escape_char != SSH_ESCAPECHAR_NONE)
|
if (escape_char_arg != SSH_ESCAPECHAR_NONE)
|
||||||
channel_register_filter(session_ident,
|
channel_register_filter(session_ident,
|
||||||
simple_escape_filter, NULL);
|
client_simple_escape_filter, NULL,
|
||||||
|
client_new_escape_filter_ctx(escape_char_arg));
|
||||||
if (session_ident != -1)
|
if (session_ident != -1)
|
||||||
channel_register_cleanup(session_ident,
|
channel_register_cleanup(session_ident,
|
||||||
client_channel_closed, 0);
|
client_channel_closed, 0);
|
||||||
|
|
22
clientloop.h
22
clientloop.h
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: clientloop.h,v 1.19 2008/05/09 14:18:44 djm Exp $ */
|
/* $OpenBSD: clientloop.h,v 1.20 2008/06/12 03:40:52 djm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
|
@ -46,8 +46,12 @@ void client_session2_setup(int, int, int, const char *, struct termios *,
|
||||||
int, Buffer *, char **);
|
int, Buffer *, char **);
|
||||||
int client_request_tun_fwd(int, int, int);
|
int client_request_tun_fwd(int, int, int);
|
||||||
|
|
||||||
|
/* Escape filter for protocol 2 sessions */
|
||||||
|
void *client_new_escape_filter_ctx(int);
|
||||||
|
int client_simple_escape_filter(Channel *, char *, int);
|
||||||
|
|
||||||
/* Multiplexing protocol version */
|
/* Multiplexing protocol version */
|
||||||
#define SSHMUX_VER 1
|
#define SSHMUX_VER 2
|
||||||
|
|
||||||
/* Multiplexing control protocol flags */
|
/* Multiplexing control protocol flags */
|
||||||
#define SSHMUX_COMMAND_OPEN 1 /* Open new connection */
|
#define SSHMUX_COMMAND_OPEN 1 /* Open new connection */
|
||||||
|
@ -59,20 +63,6 @@ int client_request_tun_fwd(int, int, int);
|
||||||
#define SSHMUX_FLAG_X11_FWD (1<<2) /* Request X11 forwarding */
|
#define SSHMUX_FLAG_X11_FWD (1<<2) /* Request X11 forwarding */
|
||||||
#define SSHMUX_FLAG_AGENT_FWD (1<<3) /* Request agent forwarding */
|
#define SSHMUX_FLAG_AGENT_FWD (1<<3) /* Request agent forwarding */
|
||||||
|
|
||||||
/* Multiplexing routines */
|
|
||||||
|
|
||||||
struct mux_session_confirm_ctx {
|
|
||||||
int want_tty;
|
|
||||||
int want_subsys;
|
|
||||||
int want_x_fwd;
|
|
||||||
int want_agent_fwd;
|
|
||||||
Buffer cmd;
|
|
||||||
char *term;
|
|
||||||
struct termios tio;
|
|
||||||
char **env;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* mux.c */
|
|
||||||
void muxserver_listen(void);
|
void muxserver_listen(void);
|
||||||
int muxserver_accept_control(void);
|
int muxserver_accept_control(void);
|
||||||
void muxclient(const char *);
|
void muxclient(const char *);
|
||||||
|
|
93
mux.c
93
mux.c
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: mux.c,v 1.1 2008/05/09 14:18:44 djm Exp $ */
|
/* $OpenBSD: mux.c,v 1.2 2008/06/12 03:40:52 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
|
* Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
|
||||||
*
|
*
|
||||||
|
@ -19,6 +19,20 @@
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO:
|
||||||
|
* 1. partial reads in muxserver_accept_control (maybe make channels
|
||||||
|
* from accepted connections)
|
||||||
|
* 2. Better signalling from master to slave, especially passing of
|
||||||
|
* error messages
|
||||||
|
* 3. Better fall-back from mux slave error to new connection.
|
||||||
|
* 3. Add/delete forwardings via slave
|
||||||
|
* 4. ExitOnForwardingFailure (after #3 obviously)
|
||||||
|
* 5. Maybe extension mechanisms for multi-X11/multi-agent forwarding
|
||||||
|
* 6. Document the mux mini-protocol somewhere.
|
||||||
|
* 6. Support ~^Z in mux slaves.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
@ -71,6 +85,18 @@ extern char *host;
|
||||||
int subsystem_flag;
|
int subsystem_flag;
|
||||||
extern Buffer command;
|
extern Buffer command;
|
||||||
|
|
||||||
|
/* Context for session open confirmation callback */
|
||||||
|
struct mux_session_confirm_ctx {
|
||||||
|
int want_tty;
|
||||||
|
int want_subsys;
|
||||||
|
int want_x_fwd;
|
||||||
|
int want_agent_fwd;
|
||||||
|
Buffer cmd;
|
||||||
|
char *term;
|
||||||
|
struct termios tio;
|
||||||
|
char **env;
|
||||||
|
};
|
||||||
|
|
||||||
/* fd to control socket */
|
/* fd to control socket */
|
||||||
int muxserver_sock = -1;
|
int muxserver_sock = -1;
|
||||||
|
|
||||||
|
@ -131,7 +157,7 @@ muxserver_listen(void)
|
||||||
|
|
||||||
/* Callback on open confirmation in mux master for a mux client session. */
|
/* Callback on open confirmation in mux master for a mux client session. */
|
||||||
static void
|
static void
|
||||||
client_extra_session2_setup(int id, void *arg)
|
mux_session_confirm(int id, void *arg)
|
||||||
{
|
{
|
||||||
struct mux_session_confirm_ctx *cctx = arg;
|
struct mux_session_confirm_ctx *cctx = arg;
|
||||||
const char *display;
|
const char *display;
|
||||||
|
@ -190,7 +216,7 @@ muxserver_accept_control(void)
|
||||||
struct sockaddr_storage addr;
|
struct sockaddr_storage addr;
|
||||||
struct mux_session_confirm_ctx *cctx;
|
struct mux_session_confirm_ctx *cctx;
|
||||||
char *cmd;
|
char *cmd;
|
||||||
u_int i, j, len, env_len, mux_command, flags;
|
u_int i, j, len, env_len, mux_command, flags, escape_char;
|
||||||
uid_t euid;
|
uid_t euid;
|
||||||
gid_t egid;
|
gid_t egid;
|
||||||
int start_close = 0;
|
int start_close = 0;
|
||||||
|
@ -317,6 +343,7 @@ muxserver_accept_control(void)
|
||||||
cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0;
|
cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0;
|
||||||
cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0;
|
cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0;
|
||||||
cctx->term = buffer_get_string(&m, &len);
|
cctx->term = buffer_get_string(&m, &len);
|
||||||
|
escape_char = buffer_get_int(&m);
|
||||||
|
|
||||||
cmd = buffer_get_string(&m, &len);
|
cmd = buffer_get_string(&m, &len);
|
||||||
buffer_init(&cctx->cmd);
|
buffer_init(&cctx->cmd);
|
||||||
|
@ -402,14 +429,17 @@ muxserver_accept_control(void)
|
||||||
new_fd[0], new_fd[1], new_fd[2], window, packetmax,
|
new_fd[0], new_fd[1], new_fd[2], window, packetmax,
|
||||||
CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
|
CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
|
||||||
|
|
||||||
/* XXX */
|
|
||||||
c->ctl_fd = client_fd;
|
c->ctl_fd = client_fd;
|
||||||
|
if (cctx->want_tty && escape_char != 0xffffffff) {
|
||||||
|
channel_register_filter(c->self,
|
||||||
|
client_simple_escape_filter, NULL,
|
||||||
|
client_new_escape_filter_ctx((int)escape_char));
|
||||||
|
}
|
||||||
|
|
||||||
debug3("%s: channel_new: %d", __func__, c->self);
|
debug3("%s: channel_new: %d", __func__, c->self);
|
||||||
|
|
||||||
channel_send_open(c->self);
|
channel_send_open(c->self);
|
||||||
channel_register_open_confirm(c->self,
|
channel_register_open_confirm(c->self, mux_session_confirm, cctx);
|
||||||
client_extra_session2_setup, cctx);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,33 +591,34 @@ muxclient(const char *path)
|
||||||
fprintf(stderr, "Exit request sent.\r\n");
|
fprintf(stderr, "Exit request sent.\r\n");
|
||||||
exit(0);
|
exit(0);
|
||||||
case SSHMUX_COMMAND_OPEN:
|
case SSHMUX_COMMAND_OPEN:
|
||||||
/* continue below */
|
buffer_put_cstring(&m, term ? term : "");
|
||||||
|
if (options.escape_char == SSH_ESCAPECHAR_NONE)
|
||||||
|
buffer_put_int(&m, 0xffffffff);
|
||||||
|
else
|
||||||
|
buffer_put_int(&m, options.escape_char);
|
||||||
|
buffer_append(&command, "\0", 1);
|
||||||
|
buffer_put_cstring(&m, buffer_ptr(&command));
|
||||||
|
|
||||||
|
if (options.num_send_env == 0 || environ == NULL) {
|
||||||
|
buffer_put_int(&m, 0);
|
||||||
|
} else {
|
||||||
|
/* Pass environment */
|
||||||
|
num_env = 0;
|
||||||
|
for (i = 0; environ[i] != NULL; i++) {
|
||||||
|
if (env_permitted(environ[i]))
|
||||||
|
num_env++; /* Count */
|
||||||
|
}
|
||||||
|
buffer_put_int(&m, num_env);
|
||||||
|
for (i = 0; environ[i] != NULL && num_env >= 0; i++) {
|
||||||
|
if (env_permitted(environ[i])) {
|
||||||
|
num_env--;
|
||||||
|
buffer_put_cstring(&m, environ[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fatal("silly muxclient_command %d", muxclient_command);
|
fatal("unrecognised muxclient_command %d", muxclient_command);
|
||||||
}
|
|
||||||
|
|
||||||
/* SSHMUX_COMMAND_OPEN */
|
|
||||||
buffer_put_cstring(&m, term ? term : "");
|
|
||||||
buffer_append(&command, "\0", 1);
|
|
||||||
buffer_put_cstring(&m, buffer_ptr(&command));
|
|
||||||
|
|
||||||
if (options.num_send_env == 0 || environ == NULL) {
|
|
||||||
buffer_put_int(&m, 0);
|
|
||||||
} else {
|
|
||||||
/* Pass environment */
|
|
||||||
num_env = 0;
|
|
||||||
for (i = 0; environ[i] != NULL; i++)
|
|
||||||
if (env_permitted(environ[i]))
|
|
||||||
num_env++; /* Count */
|
|
||||||
|
|
||||||
buffer_put_int(&m, num_env);
|
|
||||||
|
|
||||||
for (i = 0; environ[i] != NULL && num_env >= 0; i++)
|
|
||||||
if (env_permitted(environ[i])) {
|
|
||||||
num_env--;
|
|
||||||
buffer_put_cstring(&m, environ[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1)
|
if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1)
|
||||||
|
|
Loading…
Reference in New Issue