1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 09:27:59 +00:00

Server prep: parse a lot of new channel requests.

ssh2connection.c now knows how to unmarshal the message formats for
all the channel requests we'll need to handle when we're the server
and a client sends them. Each one is translated into a call to a new
method in the Channel vtable, which is implemented by a trivial
'always fail' routine in every channel type we know about so far.
This commit is contained in:
Simon Tatham 2018-10-20 21:48:49 +01:00
parent 445030b3ea
commit 9fe719f47d
13 changed files with 345 additions and 0 deletions

View File

@ -159,6 +159,16 @@ static const struct ChannelVtable agentf_channelvt = {
chan_no_exit_status,
chan_no_exit_signal,
chan_no_exit_signal_numeric,
chan_no_run_shell,
chan_no_run_command,
chan_no_run_subsystem,
chan_no_enable_x11_forwarding,
chan_no_enable_agent_forwarding,
chan_no_allocate_pty,
chan_no_set_env,
chan_no_send_break,
chan_no_send_signal,
chan_no_change_window_size,
chan_no_request_response,
};

View File

@ -37,6 +37,16 @@ static const struct ChannelVtable mainchan_channelvt = {
mainchan_rcvd_exit_status,
mainchan_rcvd_exit_signal,
mainchan_rcvd_exit_signal_numeric,
chan_no_run_shell,
chan_no_run_command,
chan_no_run_subsystem,
chan_no_enable_x11_forwarding,
chan_no_enable_agent_forwarding,
chan_no_allocate_pty,
chan_no_set_env,
chan_no_send_break,
chan_no_send_signal,
chan_no_change_window_size,
mainchan_request_response,
};

View File

@ -454,6 +454,16 @@ static const struct ChannelVtable PortForwarding_channelvt = {
chan_no_exit_status,
chan_no_exit_signal,
chan_no_exit_signal_numeric,
chan_no_run_shell,
chan_no_run_command,
chan_no_run_subsystem,
chan_no_enable_x11_forwarding,
chan_no_enable_agent_forwarding,
chan_no_allocate_pty,
chan_no_set_env,
chan_no_send_break,
chan_no_send_signal,
chan_no_change_window_size,
chan_no_request_response,
};

2
ssh.h
View File

@ -1435,6 +1435,8 @@ struct ssh_ttymodes {
};
struct ssh_ttymodes get_ttymodes_from_conf(Seat *seat, Conf *conf);
struct ssh_ttymodes read_ttymodes_from_packet(
BinarySource *bs, int ssh_version);
void write_ttymodes_to_packet(BinarySink *bs, int ssh_version,
struct ssh_ttymodes modes);

View File

@ -429,6 +429,9 @@ static const struct SshChannelVtable ssh1mainchan_vtable = {
NULL /* get_conf */,
NULL /* window_override_removed is only used by SSH-2 sharing */,
NULL /* x11_sharing_handover, likewise */,
NULL /* send_exit_status */,
NULL /* send_exit_signal */,
NULL /* send_exit_signal_numeric */,
ssh1mainchan_request_x11_forwarding,
ssh1mainchan_request_agent_forwarding,
ssh1mainchan_request_pty,

View File

@ -105,6 +105,9 @@ static const struct SshChannelVtable ssh1channel_vtable = {
ssh1channel_get_conf,
ssh1channel_window_override_removed,
NULL /* x11_sharing_handover is only used by SSH-2 connection sharing */,
NULL /* send_exit_status */,
NULL /* send_exit_signal */,
NULL /* send_exit_signal_numeric */,
NULL /* request_x11_forwarding */,
NULL /* request_agent_forwarding */,
NULL /* request_pty */,

View File

@ -343,6 +343,23 @@ int ssh2channel_start_subsystem(
return TRUE;
}
void ssh2channel_send_exit_status(SshChannel *sc, int status)
{
assert(FALSE && "Should never be called in the client");
}
void ssh2channel_send_exit_signal(
SshChannel *sc, ptrlen signame, int core_dumped, ptrlen msg)
{
assert(FALSE && "Should never be called in the client");
}
void ssh2channel_send_exit_signal_numeric(
SshChannel *sc, int signum, int core_dumped, ptrlen msg)
{
assert(FALSE && "Should never be called in the client");
}
void ssh2channel_request_x11_forwarding(
SshChannel *sc, int want_reply, const char *authproto,
const char *authdata, int screen_number, int oneshot)

View File

@ -137,6 +137,9 @@ static const struct SshChannelVtable ssh2channel_vtable = {
ssh2channel_get_conf,
ssh2channel_window_override_removed,
ssh2channel_x11_sharing_handover,
ssh2channel_send_exit_status,
ssh2channel_send_exit_signal,
ssh2channel_send_exit_signal_numeric,
ssh2channel_request_x11_forwarding,
ssh2channel_request_agent_forwarding,
ssh2channel_request_pty,
@ -655,6 +658,66 @@ static int ssh2_connection_filter_queue(struct ssh2_connection_state *s)
reply_success = FALSE;
break;
}
} else if (ptrlen_eq_string(type, "shell")) {
reply_success = chan_run_shell(c->chan);
} else if (ptrlen_eq_string(type, "exec")) {
ptrlen command = get_string(pktin);
reply_success = chan_run_command(c->chan, command);
} else if (ptrlen_eq_string(type, "subsystem")) {
ptrlen subsys = get_string(pktin);
reply_success = chan_run_subsystem(c->chan, subsys);
} else if (ptrlen_eq_string(type, "x11-req")) {
int oneshot = get_bool(pktin);
ptrlen authproto = get_string(pktin);
ptrlen authdata = get_string(pktin);
unsigned screen_number = get_uint32(pktin);
reply_success = chan_enable_x11_forwarding(
c->chan, oneshot, authproto, authdata, screen_number);
} else if (ptrlen_eq_string(type,
"auth-agent-req@openssh.com")) {
reply_success = chan_enable_agent_forwarding(c->chan);
} else if (ptrlen_eq_string(type, "pty-req")) {
ptrlen termtype = get_string(pktin);
unsigned width = get_uint32(pktin);
unsigned height = get_uint32(pktin);
unsigned pixwidth = get_uint32(pktin);
unsigned pixheight = get_uint32(pktin);
ptrlen encoded_modes = get_string(pktin);
BinarySource bs_modes[1];
struct ssh_ttymodes modes;
BinarySource_BARE_INIT(
bs_modes, encoded_modes.ptr, encoded_modes.len);
modes = read_ttymodes_from_packet(bs_modes, 2);
if (get_err(bs_modes) || get_avail(bs_modes) > 0) {
ppl_logevent(("Unable to decode terminal mode "
"string"));
reply_success = FALSE;
} else {
reply_success = chan_allocate_pty(
c->chan, termtype, width, height,
pixwidth, pixheight, modes);
}
} else if (ptrlen_eq_string(type, "env")) {
ptrlen var = get_string(pktin);
ptrlen value = get_string(pktin);
reply_success = chan_set_env(c->chan, var, value);
} else if (ptrlen_eq_string(type, "break")) {
unsigned length = get_uint32(pktin);
reply_success = chan_send_break(c->chan, length);
} else if (ptrlen_eq_string(type, "signal")) {
ptrlen signame = get_string(pktin);
reply_success = chan_send_signal(c->chan, signame);
} else if (ptrlen_eq_string(type, "window-change")) {
unsigned width = get_uint32(pktin);
unsigned height = get_uint32(pktin);
unsigned pixwidth = get_uint32(pktin);
unsigned pixheight = get_uint32(pktin);
reply_success = chan_change_window_size(
c->chan, width, height, pixwidth, pixheight);
}
if (want_reply) {
int type = (reply_success ? SSH2_MSG_CHANNEL_SUCCESS :

View File

@ -166,6 +166,11 @@ void ssh2_rportfwd_remove(
SshChannel *ssh2_session_open(ConnectionLayer *cl, Channel *chan);
void ssh2channel_send_exit_status(SshChannel *c, int status);
void ssh2channel_send_exit_signal(
SshChannel *c, ptrlen signame, int core_dumped, ptrlen msg);
void ssh2channel_send_exit_signal_numeric(
SshChannel *c, int signum, int core_dumped, ptrlen msg);
void ssh2channel_request_x11_forwarding(
SshChannel *c, int want_reply, const char *authproto,
const char *authdata, int screen_number, int oneshot);

View File

@ -34,6 +34,22 @@ struct ChannelVtable {
Channel *chan, ptrlen signame, int core_dumped, ptrlen msg);
int (*rcvd_exit_signal_numeric)(
Channel *chan, int signum, int core_dumped, ptrlen msg);
int (*run_shell)(Channel *chan);
int (*run_command)(Channel *chan, ptrlen command);
int (*run_subsystem)(Channel *chan, ptrlen subsys);
int (*enable_x11_forwarding)(
Channel *chan, int oneshot, ptrlen authproto, ptrlen authdata,
unsigned screen_number);
int (*enable_agent_forwarding)(Channel *chan);
int (*allocate_pty)(
Channel *chan, ptrlen termtype, unsigned width, unsigned height,
unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes);
int (*set_env)(Channel *chan, ptrlen var, ptrlen value);
int (*send_break)(Channel *chan, unsigned length);
int (*send_signal)(Channel *chan, ptrlen signame);
int (*change_window_size)(
Channel *chan, unsigned width, unsigned height,
unsigned pixwidth, unsigned pixheight);
/* A method for signalling success/failure responses to channel
* requests initiated from the SshChannel vtable with want_reply
@ -61,6 +77,26 @@ struct Channel {
((ch)->vt->rcvd_exit_signal(ch, sig, core, msg))
#define chan_rcvd_exit_signal_numeric(ch, sig, core, msg) \
((ch)->vt->rcvd_exit_signal_numeric(ch, sig, core, msg))
#define chan_run_shell(ch) \
((ch)->vt->run_shell(ch))
#define chan_run_command(ch, cmd) \
((ch)->vt->run_command(ch, cmd))
#define chan_run_subsystem(ch, subsys) \
((ch)->vt->run_subsystem(ch, subsys))
#define chan_enable_x11_forwarding(ch, oneshot, ap, ad, scr) \
((ch)->vt->enable_x11_forwarding(ch, oneshot, ap, ad, scr))
#define chan_enable_agent_forwarding(ch) \
((ch)->vt->enable_agent_forwarding(ch))
#define chan_allocate_pty(ch, termtype, w, h, pw, ph, modes) \
((ch)->vt->allocate_pty(ch, termtype, w, h, pw, ph, modes))
#define chan_set_env(ch, var, value) \
((ch)->vt->set_env(ch, var, value))
#define chan_send_break(ch, length) \
((ch)->vt->send_break(ch, length))
#define chan_send_signal(ch, signame) \
((ch)->vt->send_signal(ch, signame))
#define chan_change_window_size(ch, w, h, pw, ph) \
((ch)->vt->change_window_size(ch, w, h, pw, ph))
#define chan_request_response(ch, success) \
((ch)->vt->request_response(ch, success))
@ -81,6 +117,22 @@ int chan_default_want_close(Channel *, int, int);
int chan_no_exit_status(Channel *, int);
int chan_no_exit_signal(Channel *, ptrlen, int, ptrlen);
int chan_no_exit_signal_numeric(Channel *, int, int, ptrlen);
int chan_no_run_shell(Channel *chan);
int chan_no_run_command(Channel *chan, ptrlen command);
int chan_no_run_subsystem(Channel *chan, ptrlen subsys);
int chan_no_enable_x11_forwarding(
Channel *chan, int oneshot, ptrlen authproto, ptrlen authdata,
unsigned screen_number);
int chan_no_enable_agent_forwarding(Channel *chan);
int chan_no_allocate_pty(
Channel *chan, ptrlen termtype, unsigned width, unsigned height,
unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes);
int chan_no_set_env(Channel *chan, ptrlen var, ptrlen value);
int chan_no_send_break(Channel *chan, unsigned length);
int chan_no_send_signal(Channel *chan, ptrlen signame);
int chan_no_change_window_size(
Channel *chan, unsigned width, unsigned height,
unsigned pixwidth, unsigned pixheight);
/* default implementation that never expects to receive a response */
void chan_no_request_response(Channel *, int);
@ -131,6 +183,11 @@ struct SshChannelVtable {
* wouldn't do anything usefully different with the reply in any
* case.)
*/
void (*send_exit_status)(SshChannel *c, int status);
void (*send_exit_signal)(
SshChannel *c, ptrlen signame, int core_dumped, ptrlen msg);
void (*send_exit_signal_numeric)(
SshChannel *c, int signum, int core_dumped, ptrlen msg);
void (*request_x11_forwarding)(
SshChannel *c, int want_reply, const char *authproto,
const char *authdata, int screen_number, int oneshot);
@ -170,6 +227,12 @@ struct SshChannel {
#define sshfwd_window_override_removed(c) ((c)->vt->window_override_removed(c))
#define sshfwd_x11_sharing_handover(c, cs, ch, pa, pp, e, pmaj, pmin, d, l) \
((c)->vt->x11_sharing_handover(c, cs, ch, pa, pp, e, pmaj, pmin, d, l))
#define sshfwd_send_exit_status(c, status) \
((c)->vt->send_exit_status(c, status))
#define sshfwd_send_exit_signal(c, sig, core, msg) \
((c)->vt->send_exit_signal(c, sig, core, msg))
#define sshfwd_send_exit_signal_numeric(c, sig, core, msg) \
((c)->vt->send_exit_signal_numeric(c, sig, core, msg))
#define sshfwd_request_x11_forwarding(c, wr, ap, ad, scr, oneshot) \
((c)->vt->request_x11_forwarding(c, wr, ap, ad, scr, oneshot))
#define sshfwd_request_agent_forwarding(c, wr) \

View File

@ -280,6 +280,16 @@ static const struct ChannelVtable zombiechan_channelvt = {
chan_no_exit_status,
chan_no_exit_signal,
chan_no_exit_signal_numeric,
chan_no_run_shell,
chan_no_run_command,
chan_no_run_subsystem,
chan_no_enable_x11_forwarding,
chan_no_enable_agent_forwarding,
chan_no_allocate_pty,
chan_no_set_env,
chan_no_send_break,
chan_no_send_signal,
chan_no_change_window_size,
chan_no_request_response,
};
@ -366,6 +376,62 @@ int chan_no_exit_signal_numeric(
return FALSE;
}
int chan_no_run_shell(Channel *chan)
{
return FALSE;
}
int chan_no_run_command(Channel *chan, ptrlen command)
{
return FALSE;
}
int chan_no_run_subsystem(Channel *chan, ptrlen subsys)
{
return FALSE;
}
int chan_no_enable_x11_forwarding(
Channel *chan, int oneshot, ptrlen authproto, ptrlen authdata,
unsigned screen_number)
{
return FALSE;
}
int chan_no_enable_agent_forwarding(Channel *chan)
{
return FALSE;
}
int chan_no_allocate_pty(
Channel *chan, ptrlen termtype, unsigned width, unsigned height,
unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes)
{
return FALSE;
}
int chan_no_set_env(Channel *chan, ptrlen var, ptrlen value)
{
return FALSE;
}
int chan_no_send_break(Channel *chan, unsigned length)
{
return FALSE;
}
int chan_no_send_signal(Channel *chan, ptrlen signame)
{
return FALSE;
}
int chan_no_change_window_size(
Channel *chan, unsigned width, unsigned height,
unsigned pixwidth, unsigned pixheight)
{
return FALSE;
}
void chan_no_request_response(Channel *chan, int success)
{
assert(0 && "this channel type should never send a want-reply request");
@ -387,6 +453,29 @@ static unsigned real_ttymode_opcode(unsigned our_opcode, int ssh_version)
}
}
static unsigned our_ttymode_opcode(unsigned real_opcode, int ssh_version)
{
if (ssh_version == 1) {
switch (real_opcode) {
case TTYMODE_ISPEED_SSH1:
return TTYMODE_ISPEED;
case TTYMODE_OSPEED_SSH1:
return TTYMODE_OSPEED;
default:
return real_opcode;
}
} else {
switch (real_opcode) {
case TTYMODE_ISPEED_SSH2:
return TTYMODE_ISPEED;
case TTYMODE_OSPEED_SSH2:
return TTYMODE_OSPEED;
default:
return real_opcode;
}
}
}
struct ssh_ttymodes get_ttymodes_from_conf(Seat *seat, Conf *conf)
{
struct ssh_ttymodes modes;
@ -492,6 +581,49 @@ struct ssh_ttymodes get_ttymodes_from_conf(Seat *seat, Conf *conf)
return modes;
}
struct ssh_ttymodes read_ttymodes_from_packet(
BinarySource *bs, int ssh_version)
{
struct ssh_ttymodes modes;
memset(&modes, 0, sizeof(modes));
while (1) {
unsigned real_opcode, our_opcode;
real_opcode = get_byte(bs);
if (real_opcode == TTYMODE_END_OF_LIST)
break;
if (real_opcode >= 160) {
/*
* RFC 4254 (and the SSH 1.5 spec): "Opcodes 160 to 255
* are not yet defined, and cause parsing to stop (they
* should only be used after any other data)."
*
* My interpretation of this is that if one of these
* opcodes appears, it's not a parse _error_, but it is
* something that we don't know how to parse even well
* enough to step over it to find the next opcode, so we
* stop parsing now and assume that the rest of the string
* is composed entirely of things we don't understand and
* (as usual for unsupported terminal modes) silently
* ignore.
*/
return modes;
}
our_opcode = our_ttymode_opcode(real_opcode, ssh_version);
assert(our_opcode < TTYMODE_LIMIT);
modes.have_mode[our_opcode] = TRUE;
if (ssh_version == 1 && real_opcode >= 1 && real_opcode <= 127)
modes.mode_val[our_opcode] = get_byte(bs);
else
modes.mode_val[our_opcode] = get_uint32(bs);
}
return modes;
}
void write_ttymodes_to_packet(BinarySink *bs, int ssh_version,
struct ssh_ttymodes modes)
{

View File

@ -127,6 +127,23 @@ int chan_no_exit_signal(Channel *ch, ptrlen s, int c, ptrlen m)
{ return FALSE; }
int chan_no_exit_signal_numeric(Channel *ch, int s, int c, ptrlen m)
{ return FALSE; }
int chan_no_run_shell(Channel *chan) { return FALSE; }
int chan_no_run_command(Channel *chan, ptrlen command) { return FALSE; }
int chan_no_run_subsystem(Channel *chan, ptrlen subsys) { return FALSE; }
int chan_no_enable_x11_forwarding(
Channel *chan, int oneshot, ptrlen authproto, ptrlen authdata,
unsigned screen_number) { return FALSE; }
int chan_no_enable_agent_forwarding(Channel *chan) { return FALSE; }
int chan_no_allocate_pty(
Channel *chan, ptrlen termtype, unsigned width, unsigned height,
unsigned pixwidth, unsigned pixheight, struct ssh_ttymodes modes)
{ return FALSE; }
int chan_no_set_env(Channel *chan, ptrlen var, ptrlen value) { return FALSE; }
int chan_no_send_break(Channel *chan, unsigned length) { return FALSE; }
int chan_no_send_signal(Channel *chan, ptrlen signame) { return FALSE; }
int chan_no_change_window_size(
Channel *chan, unsigned width, unsigned height,
unsigned pixwidth, unsigned pixheight) { return FALSE; }
void chan_no_request_response(Channel *chan, int success) {}
/*

View File

@ -776,6 +776,16 @@ static const struct ChannelVtable X11Connection_channelvt = {
chan_no_exit_status,
chan_no_exit_signal,
chan_no_exit_signal_numeric,
chan_no_run_shell,
chan_no_run_command,
chan_no_run_subsystem,
chan_no_enable_x11_forwarding,
chan_no_enable_agent_forwarding,
chan_no_allocate_pty,
chan_no_set_env,
chan_no_send_break,
chan_no_send_signal,
chan_no_change_window_size,
chan_no_request_response,
};