mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-06-30 19:12:48 -05:00
Move client-specific SSH code into new files.
This is a major code reorganisation in preparation for making this code base into one that can build an SSH server as well as a client. (Mostly for purposes of using the server as a regression test suite for the client, though I have some other possible uses in mind too. However, it's currently no part of my plan to harden the server to the point where it can sensibly be deployed in a hostile environment.) In this preparatory commit, I've broken up the SSH-2 transport and connection layers, and the SSH-1 connection layer, into multiple source files, with each layer having its own header file containing the shared type definitions. In each case, the new source file contains code that's specific to the client side of the protocol, so that a new file can be swapped in in its place when building the server. Mostly this is just a straightforward moving of code without changing it very much, but there are a couple of actual changes in the process: The parsing of SSH-2 global-request and channel open-messages is now done by a new pair of functions in the client module. For channel opens, I've invented a new union data type to be the return value from that function, representing either failure (plus error message), success (plus Channel instance to manage the new channel), or an instruction to hand the channel over to a sharing downstream (plus a pointer to the downstream in question). Also, the tree234 of remote port forwardings in ssh2connection is now initialised on first use by the client-specific code, so that's where its compare function lives. The shared ssh2connection_free() still takes responsibility for freeing it, but now has to check if it's non-null first. The outer shell of the ssh2_lportfwd_open method, for making a local-to-remote port forwarding, is still centralised in ssh2connection.c, but the part of it that actually constructs the outgoing channel-open message has moved into the client code, because that will have to change depending on whether the channel-open has to have type direct-tcpip or forwarded-tcpip. In the SSH-1 connection layer, half the filter_queue method has moved out into the new client-specific code, but not all of it - bidirectional channel maintenance messages are still handled centrally. One exception is SSH_MSG_PORT_OPEN, which can be sent in both directions, but with subtly different semantics - from server to client, it's referring to a previously established remote forwarding (and must be rejected if there isn't one that matches it), but from client to server it's just a "direct-tcpip" request with no prior context. So that one is in the client-specific module, and when I add the server code it will have its own different handler.
This commit is contained in:
648
ssh1connection.c
648
ssh1connection.c
@ -11,61 +11,7 @@
|
||||
#include "sshppl.h"
|
||||
#include "sshchan.h"
|
||||
#include "sshcr.h"
|
||||
|
||||
struct ssh1_channel;
|
||||
|
||||
struct outstanding_succfail;
|
||||
|
||||
struct ssh1_connection_state {
|
||||
int crState;
|
||||
|
||||
Ssh *ssh;
|
||||
|
||||
Conf *conf;
|
||||
int local_protoflags;
|
||||
|
||||
tree234 *channels; /* indexed by local id */
|
||||
|
||||
/* In SSH-1, the main session doesn't take the form of a 'channel'
|
||||
* according to the wire protocol. But we want to use the same API
|
||||
* for it, so we define an SshChannel here - but one that uses a
|
||||
* separate vtable from the usual one, so it doesn't map to a
|
||||
* struct ssh1_channel as all the others do. */
|
||||
SshChannel mainchan_sc;
|
||||
Channel *mainchan_chan; /* the other end of mainchan_sc */
|
||||
mainchan *mainchan; /* and its subtype */
|
||||
|
||||
int got_pty;
|
||||
int ldisc_opts[LD_N_OPTIONS];
|
||||
int stdout_throttling;
|
||||
int want_user_input;
|
||||
int session_terminated;
|
||||
int term_width, term_height, term_width_orig, term_height_orig;
|
||||
|
||||
int X11_fwd_enabled;
|
||||
struct X11Display *x11disp;
|
||||
struct X11FakeAuth *x11auth;
|
||||
tree234 *x11authtree;
|
||||
|
||||
int agent_fwd_enabled;
|
||||
|
||||
tree234 *rportfwds;
|
||||
PortFwdManager *portfwdmgr;
|
||||
int portfwdmgr_configured;
|
||||
|
||||
int finished_setup;
|
||||
|
||||
/*
|
||||
* These store the list of requests that we're waiting for
|
||||
* SSH_SMSG_{SUCCESS,FAILURE} replies to. (Those messages don't
|
||||
* come with any indication of what they're in response to, so we
|
||||
* have to keep track of the queue ourselves.)
|
||||
*/
|
||||
struct outstanding_succfail *succfail_head, *succfail_tail;
|
||||
|
||||
ConnectionLayer cl;
|
||||
PacketProtocolLayer ppl;
|
||||
};
|
||||
#include "ssh1connection.h"
|
||||
|
||||
static int ssh1_rportfwd_cmp(void *av, void *bv)
|
||||
{
|
||||
@ -100,17 +46,11 @@ static const struct PacketProtocolLayerVtable ssh1_connection_vtable = {
|
||||
NULL /* no layer names in SSH-1 */,
|
||||
};
|
||||
|
||||
static struct ssh_rportfwd *ssh1_rportfwd_alloc(
|
||||
ConnectionLayer *cl,
|
||||
const char *shost, int sport, const char *dhost, int dport,
|
||||
int addressfamily, const char *log_description, PortFwdRecord *pfr,
|
||||
ssh_sharing_connstate *share_ctx);
|
||||
static void ssh1_rportfwd_remove(
|
||||
ConnectionLayer *cl, struct ssh_rportfwd *rpf);
|
||||
static SshChannel *ssh1_lportfwd_open(
|
||||
ConnectionLayer *cl, const char *hostname, int port,
|
||||
const char *description, const SocketPeerInfo *pi, Channel *chan);
|
||||
static SshChannel *ssh1_session_open(ConnectionLayer *cl, Channel *chan);
|
||||
static struct X11FakeAuth *ssh1_add_x11_display(
|
||||
ConnectionLayer *cl, int authtype, struct X11Display *disp);
|
||||
static int ssh1_agent_forwarding_permitted(ConnectionLayer *cl);
|
||||
@ -149,50 +89,6 @@ static const struct ConnectionLayerVtable ssh1_connlayer_vtable = {
|
||||
ssh1_set_wants_user_input,
|
||||
};
|
||||
|
||||
struct ssh1_channel {
|
||||
struct ssh1_connection_state *connlayer;
|
||||
|
||||
unsigned remoteid, localid;
|
||||
int type;
|
||||
/* True if we opened this channel but server hasn't confirmed. */
|
||||
int halfopen;
|
||||
|
||||
/* Bitmap of whether we've sent/received CHANNEL_CLOSE and
|
||||
* CHANNEL_CLOSE_CONFIRMATION. */
|
||||
#define CLOSES_SENT_CLOSE 1
|
||||
#define CLOSES_SENT_CLOSECONF 2
|
||||
#define CLOSES_RCVD_CLOSE 4
|
||||
#define CLOSES_RCVD_CLOSECONF 8
|
||||
int closes;
|
||||
|
||||
/*
|
||||
* This flag indicates that an EOF is pending on the outgoing side
|
||||
* of the channel: that is, wherever we're getting the data for
|
||||
* this channel has sent us some data followed by EOF. We can't
|
||||
* actually send the EOF until we've finished sending the data, so
|
||||
* we set this flag instead to remind us to do so once our buffer
|
||||
* is clear.
|
||||
*/
|
||||
int pending_eof;
|
||||
|
||||
/*
|
||||
* True if this channel is causing the underlying connection to be
|
||||
* throttled.
|
||||
*/
|
||||
int throttling_conn;
|
||||
|
||||
/*
|
||||
* True if we currently have backed-up data on the direction of
|
||||
* this channel pointing out of the SSH connection, and therefore
|
||||
* would prefer the 'Channel' implementation not to read further
|
||||
* local input if possible.
|
||||
*/
|
||||
int throttled_by_backlog;
|
||||
|
||||
Channel *chan; /* handle the client side of this channel, if not */
|
||||
SshChannel sc; /* entry point for chan to talk back to */
|
||||
};
|
||||
|
||||
static int ssh1channel_write(SshChannel *c, const void *buf, int len);
|
||||
static void ssh1channel_write_eof(SshChannel *c);
|
||||
static void ssh1channel_initiate_close(SshChannel *c, const char *err);
|
||||
@ -221,120 +117,12 @@ static const struct SshChannelVtable ssh1channel_vtable = {
|
||||
NULL /* hint_channel_is_simple */,
|
||||
};
|
||||
|
||||
static void ssh1mainchan_request_x11_forwarding(
|
||||
SshChannel *c, int want_reply, const char *authproto,
|
||||
const char *authdata, int screen_number, int oneshot);
|
||||
static void ssh1mainchan_request_agent_forwarding(
|
||||
SshChannel *c, int want_reply);
|
||||
static void ssh1mainchan_request_pty(
|
||||
SshChannel *c, int want_reply, Conf *conf, int w, int h);
|
||||
static int ssh1mainchan_send_env_var(
|
||||
SshChannel *c, int want_reply, const char *var, const char *value);
|
||||
static void ssh1mainchan_start_shell(
|
||||
SshChannel *c, int want_reply);
|
||||
static void ssh1mainchan_start_command(
|
||||
SshChannel *c, int want_reply, const char *command);
|
||||
static int ssh1mainchan_start_subsystem(
|
||||
SshChannel *c, int want_reply, const char *subsystem);
|
||||
static int ssh1mainchan_send_env_var(
|
||||
SshChannel *c, int want_reply, const char *var, const char *value);
|
||||
static int ssh1mainchan_send_serial_break(
|
||||
SshChannel *c, int want_reply, int length);
|
||||
static int ssh1mainchan_send_signal(
|
||||
SshChannel *c, int want_reply, const char *signame);
|
||||
static void ssh1mainchan_send_terminal_size_change(
|
||||
SshChannel *c, int w, int h);
|
||||
static void ssh1mainchan_hint_channel_is_simple(SshChannel *c);
|
||||
static int ssh1mainchan_write(SshChannel *sc, const void *data, int len);
|
||||
static void ssh1mainchan_write_eof(SshChannel *sc);
|
||||
|
||||
static const struct SshChannelVtable ssh1mainchan_vtable = {
|
||||
ssh1mainchan_write,
|
||||
ssh1mainchan_write_eof,
|
||||
NULL /* unclean_close */,
|
||||
NULL /* unthrottle */,
|
||||
NULL /* get_conf */,
|
||||
NULL /* window_override_removed is only used by SSH-2 sharing */,
|
||||
NULL /* x11_sharing_handover, likewise */,
|
||||
ssh1mainchan_request_x11_forwarding,
|
||||
ssh1mainchan_request_agent_forwarding,
|
||||
ssh1mainchan_request_pty,
|
||||
ssh1mainchan_send_env_var,
|
||||
ssh1mainchan_start_shell,
|
||||
ssh1mainchan_start_command,
|
||||
ssh1mainchan_start_subsystem,
|
||||
ssh1mainchan_send_serial_break,
|
||||
ssh1mainchan_send_signal,
|
||||
ssh1mainchan_send_terminal_size_change,
|
||||
ssh1mainchan_hint_channel_is_simple,
|
||||
};
|
||||
|
||||
static void ssh1_channel_init(struct ssh1_channel *c);
|
||||
static void ssh1_channel_try_eof(struct ssh1_channel *c);
|
||||
static void ssh1_channel_close_local(struct ssh1_channel *c,
|
||||
const char *reason);
|
||||
static void ssh1_channel_destroy(struct ssh1_channel *c);
|
||||
static void ssh1_channel_check_close(struct ssh1_channel *c);
|
||||
|
||||
static int ssh1_check_termination(struct ssh1_connection_state *s);
|
||||
|
||||
typedef void (*sf_handler_fn_t)(struct ssh1_connection_state *s,
|
||||
int success, void *ctx);
|
||||
struct outstanding_succfail {
|
||||
sf_handler_fn_t handler;
|
||||
void *ctx;
|
||||
struct outstanding_succfail *next;
|
||||
|
||||
/*
|
||||
* The 'trivial' flag is set if this handler is in response to a
|
||||
* request for which the SSH-1 protocol doesn't actually specify a
|
||||
* response packet. The client of this system (mainchan.c) will
|
||||
* expect to get an acknowledgment regardless, so we arrange to
|
||||
* send that ack immediately after the rest of the queue empties.
|
||||
*/
|
||||
int trivial;
|
||||
};
|
||||
|
||||
static void ssh1_connection_process_trivial_succfails(void *vs);
|
||||
|
||||
static void ssh1_queue_succfail_handler(
|
||||
struct ssh1_connection_state *s, sf_handler_fn_t handler, void *ctx,
|
||||
int trivial)
|
||||
{
|
||||
struct outstanding_succfail *osf =
|
||||
snew(struct outstanding_succfail);
|
||||
osf->handler = handler;
|
||||
osf->ctx = ctx;
|
||||
osf->trivial = trivial;
|
||||
if (s->succfail_tail)
|
||||
s->succfail_tail->next = osf;
|
||||
else
|
||||
s->succfail_head = osf;
|
||||
s->succfail_tail = osf;
|
||||
|
||||
/* In case this one was trivial and the queue was already empty,
|
||||
* we should make sure we run the handler promptly, and the
|
||||
* easiest way is to queue it anyway and then run a trivials pass
|
||||
* by callback. */
|
||||
queue_toplevel_callback(ssh1_connection_process_trivial_succfails, s);
|
||||
}
|
||||
|
||||
static void ssh1_connection_process_succfail(
|
||||
struct ssh1_connection_state *s, int success)
|
||||
{
|
||||
struct outstanding_succfail *prevhead = s->succfail_head;
|
||||
s->succfail_head = s->succfail_head->next;
|
||||
prevhead->handler(s, success, prevhead->ctx);
|
||||
sfree(prevhead);
|
||||
}
|
||||
|
||||
static void ssh1_connection_process_trivial_succfails(void *vs)
|
||||
{
|
||||
struct ssh1_connection_state *s = (struct ssh1_connection_state *)vs;
|
||||
while (s->succfail_head && s->succfail_head->trivial)
|
||||
ssh1_connection_process_succfail(s, TRUE);
|
||||
}
|
||||
|
||||
static int ssh1_channelcmp(void *av, void *bv)
|
||||
{
|
||||
const struct ssh1_channel *a = (const struct ssh1_channel *) av;
|
||||
@ -357,7 +145,7 @@ static int ssh1_channelfind(void *av, void *bv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ssh1_channel_free(struct ssh1_channel *c)
|
||||
void ssh1_channel_free(struct ssh1_channel *c)
|
||||
{
|
||||
if (c->chan)
|
||||
chan_free(c->chan);
|
||||
@ -431,17 +219,10 @@ void ssh1_connection_set_local_protoflags(PacketProtocolLayer *ppl, int flags)
|
||||
static int ssh1_connection_filter_queue(struct ssh1_connection_state *s)
|
||||
{
|
||||
PktIn *pktin;
|
||||
PktOut *pktout;
|
||||
ptrlen data, host;
|
||||
ptrlen data;
|
||||
struct ssh1_channel *c;
|
||||
unsigned localid, remid;
|
||||
int port, expect_halfopen;
|
||||
struct ssh_rportfwd pf, *pfp;
|
||||
PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */
|
||||
|
||||
/* Cross-reference to ssh1login.c to handle the common packets
|
||||
* between login and connection: DISCONNECT, DEBUG and IGNORE. */
|
||||
extern int ssh1_common_filter_queue(PacketProtocolLayer *ppl);
|
||||
unsigned localid;
|
||||
int expect_halfopen;
|
||||
|
||||
while (1) {
|
||||
if (ssh1_common_filter_queue(&s->ppl))
|
||||
@ -450,140 +231,6 @@ static int ssh1_connection_filter_queue(struct ssh1_connection_state *s)
|
||||
return FALSE;
|
||||
|
||||
switch (pktin->type) {
|
||||
case SSH1_SMSG_SUCCESS:
|
||||
case SSH1_SMSG_FAILURE:
|
||||
if (!s->finished_setup) {
|
||||
/* During initial setup, these messages are not
|
||||
* filtered out, but go back to the main coroutine. */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!s->succfail_head) {
|
||||
ssh_remote_error(s->ppl.ssh,
|
||||
"Received %s with no outstanding request",
|
||||
ssh1_pkt_type(pktin->type));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ssh1_connection_process_succfail(
|
||||
s, pktin->type == SSH1_SMSG_SUCCESS);
|
||||
queue_toplevel_callback(
|
||||
ssh1_connection_process_trivial_succfails, s);
|
||||
|
||||
pq_pop(s->ppl.in_pq);
|
||||
break;
|
||||
|
||||
case SSH1_SMSG_X11_OPEN:
|
||||
remid = get_uint32(pktin);
|
||||
|
||||
/* Refuse if X11 forwarding is disabled. */
|
||||
if (!s->X11_fwd_enabled) {
|
||||
pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE);
|
||||
put_uint32(pktout, remid);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
ppl_logevent(("Rejected X11 connect request"));
|
||||
} else {
|
||||
c = snew(struct ssh1_channel);
|
||||
c->connlayer = s;
|
||||
ssh1_channel_init(c);
|
||||
c->remoteid = remid;
|
||||
c->chan = x11_new_channel(s->x11authtree, &c->sc,
|
||||
NULL, -1, FALSE);
|
||||
c->remoteid = remid;
|
||||
c->halfopen = FALSE;
|
||||
|
||||
pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION);
|
||||
put_uint32(pktout, c->remoteid);
|
||||
put_uint32(pktout, c->localid);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
ppl_logevent(("Opened X11 forward channel"));
|
||||
}
|
||||
|
||||
pq_pop(s->ppl.in_pq);
|
||||
break;
|
||||
|
||||
case SSH1_SMSG_AGENT_OPEN:
|
||||
remid = get_uint32(pktin);
|
||||
|
||||
/* Refuse if agent forwarding is disabled. */
|
||||
if (!s->agent_fwd_enabled) {
|
||||
pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE);
|
||||
put_uint32(pktout, remid);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
} else {
|
||||
c = snew(struct ssh1_channel);
|
||||
c->connlayer = s;
|
||||
ssh1_channel_init(c);
|
||||
c->remoteid = remid;
|
||||
c->chan = agentf_new(&c->sc);
|
||||
c->halfopen = FALSE;
|
||||
|
||||
pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION);
|
||||
put_uint32(pktout, c->remoteid);
|
||||
put_uint32(pktout, c->localid);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
}
|
||||
|
||||
pq_pop(s->ppl.in_pq);
|
||||
break;
|
||||
|
||||
case SSH1_MSG_PORT_OPEN:
|
||||
remid = get_uint32(pktin);
|
||||
host = get_string(pktin);
|
||||
port = toint(get_uint32(pktin));
|
||||
|
||||
pf.dhost = mkstr(host);
|
||||
pf.dport = port;
|
||||
pfp = find234(s->rportfwds, &pf, NULL);
|
||||
|
||||
if (!pfp) {
|
||||
ppl_logevent(("Rejected remote port open request for %s:%d",
|
||||
pf.dhost, port));
|
||||
pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE);
|
||||
put_uint32(pktout, remid);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
} else {
|
||||
char *err;
|
||||
|
||||
c = snew(struct ssh1_channel);
|
||||
c->connlayer = s;
|
||||
ppl_logevent(("Received remote port open request for %s:%d",
|
||||
pf.dhost, port));
|
||||
err = portfwdmgr_connect(
|
||||
s->portfwdmgr, &c->chan, pf.dhost, port,
|
||||
&c->sc, pfp->addressfamily);
|
||||
|
||||
if (err) {
|
||||
ppl_logevent(("Port open failed: %s", err));
|
||||
sfree(err);
|
||||
ssh1_channel_free(c);
|
||||
pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_FAILURE);
|
||||
put_uint32(pktout, remid);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
} else {
|
||||
ssh1_channel_init(c);
|
||||
c->remoteid = remid;
|
||||
c->halfopen = FALSE;
|
||||
pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION);
|
||||
put_uint32(pktout, c->remoteid);
|
||||
put_uint32(pktout, c->localid);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
ppl_logevent(("Forwarded port opened successfully"));
|
||||
}
|
||||
}
|
||||
|
||||
sfree(pf.dhost);
|
||||
|
||||
pq_pop(s->ppl.in_pq);
|
||||
break;
|
||||
|
||||
case SSH1_MSG_CHANNEL_DATA:
|
||||
case SSH1_MSG_CHANNEL_OPEN_CONFIRMATION:
|
||||
case SSH1_MSG_CHANNEL_OPEN_FAILURE:
|
||||
@ -692,37 +339,14 @@ static int ssh1_connection_filter_queue(struct ssh1_connection_state *s)
|
||||
pq_pop(s->ppl.in_pq);
|
||||
break;
|
||||
|
||||
case SSH1_SMSG_STDOUT_DATA:
|
||||
case SSH1_SMSG_STDERR_DATA:
|
||||
data = get_string(pktin);
|
||||
if (!get_err(pktin)) {
|
||||
int bufsize = seat_output(
|
||||
s->ppl.seat, pktin->type == SSH1_SMSG_STDERR_DATA,
|
||||
data.ptr, data.len);
|
||||
if (!s->stdout_throttling && bufsize > SSH1_BUFFER_LIMIT) {
|
||||
s->stdout_throttling = 1;
|
||||
ssh_throttle_conn(s->ppl.ssh, +1);
|
||||
}
|
||||
}
|
||||
|
||||
pq_pop(s->ppl.in_pq);
|
||||
break;
|
||||
|
||||
case SSH1_SMSG_EXIT_STATUS:
|
||||
{
|
||||
int exitcode = get_uint32(pktin);
|
||||
ppl_logevent(("Server sent command exit status %d", exitcode));
|
||||
ssh_got_exitcode(s->ppl.ssh, exitcode);
|
||||
|
||||
s->session_terminated = TRUE;
|
||||
default:
|
||||
if (ssh1_handle_direction_specific_packet(s, pktin)) {
|
||||
pq_pop(s->ppl.in_pq);
|
||||
if (ssh1_check_termination(s))
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
pq_pop(s->ppl.in_pq);
|
||||
break;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -747,14 +371,10 @@ static void ssh1_connection_process_queue(PacketProtocolLayer *ppl)
|
||||
portfwdmgr_config(s->portfwdmgr, s->conf);
|
||||
s->portfwdmgr_configured = TRUE;
|
||||
|
||||
/*
|
||||
* Start up the main session, by telling mainchan.c to do it all
|
||||
* just as it would in SSH-2, and translating those concepts to
|
||||
* SSH-1's non-channel-shaped idea of the main session.
|
||||
*/
|
||||
s->mainchan = mainchan_new(
|
||||
&s->ppl, &s->cl, s->conf, s->term_width, s->term_height,
|
||||
FALSE /* is_simple */, NULL);
|
||||
while (!s->finished_setup) {
|
||||
ssh1_connection_direction_specific_setup(s);
|
||||
crReturnV;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
|
||||
@ -883,7 +503,7 @@ static void ssh1_channel_destroy(struct ssh1_channel *c)
|
||||
queue_toplevel_callback(ssh1_check_termination_callback, s);
|
||||
}
|
||||
|
||||
static int ssh1_check_termination(struct ssh1_connection_state *s)
|
||||
int ssh1_check_termination(struct ssh1_connection_state *s)
|
||||
{
|
||||
/*
|
||||
* Decide whether we should terminate the SSH connection now.
|
||||
@ -907,7 +527,7 @@ static int ssh1_check_termination(struct ssh1_connection_state *s)
|
||||
* Set up most of a new ssh1_channel. Leaves chan untouched (since it
|
||||
* will sometimes have been filled in before calling this).
|
||||
*/
|
||||
static void ssh1_channel_init(struct ssh1_channel *c)
|
||||
void ssh1_channel_init(struct ssh1_channel *c)
|
||||
{
|
||||
struct ssh1_connection_state *s = c->connlayer;
|
||||
c->closes = 0;
|
||||
@ -993,187 +613,6 @@ static struct X11FakeAuth *ssh1_add_x11_display(
|
||||
return auth;
|
||||
}
|
||||
|
||||
static void ssh1mainchan_succfail_wantreply(struct ssh1_connection_state *s,
|
||||
int success, void *ctx)
|
||||
{
|
||||
chan_request_response(s->mainchan_chan, success);
|
||||
}
|
||||
|
||||
static void ssh1mainchan_succfail_nowantreply(struct ssh1_connection_state *s,
|
||||
int success, void *ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static void ssh1mainchan_queue_response(struct ssh1_connection_state *s,
|
||||
int want_reply, int trivial)
|
||||
{
|
||||
sf_handler_fn_t handler = (want_reply ? ssh1mainchan_succfail_wantreply :
|
||||
ssh1mainchan_succfail_nowantreply);
|
||||
ssh1_queue_succfail_handler(s, handler, NULL, trivial);
|
||||
}
|
||||
|
||||
static void ssh1mainchan_request_x11_forwarding(
|
||||
SshChannel *sc, int want_reply, const char *authproto,
|
||||
const char *authdata, int screen_number, int oneshot)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(sc, struct ssh1_connection_state, mainchan_sc);
|
||||
PktOut *pktout;
|
||||
|
||||
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_X11_REQUEST_FORWARDING);
|
||||
put_stringz(pktout, authproto);
|
||||
put_stringz(pktout, authdata);
|
||||
if (s->local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER)
|
||||
put_uint32(pktout, screen_number);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
|
||||
ssh1mainchan_queue_response(s, want_reply, FALSE);
|
||||
}
|
||||
|
||||
static void ssh1mainchan_request_agent_forwarding(
|
||||
SshChannel *sc, int want_reply)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(sc, struct ssh1_connection_state, mainchan_sc);
|
||||
PktOut *pktout;
|
||||
|
||||
pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_CMSG_AGENT_REQUEST_FORWARDING);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
|
||||
ssh1mainchan_queue_response(s, want_reply, FALSE);
|
||||
}
|
||||
|
||||
static void ssh1mainchan_request_pty(
|
||||
SshChannel *sc, int want_reply, Conf *conf, int w, int h)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(sc, struct ssh1_connection_state, mainchan_sc);
|
||||
PktOut *pktout;
|
||||
|
||||
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_REQUEST_PTY);
|
||||
put_stringz(pktout, conf_get_str(s->conf, CONF_termtype));
|
||||
put_uint32(pktout, h);
|
||||
put_uint32(pktout, w);
|
||||
put_uint32(pktout, 0); /* width in pixels */
|
||||
put_uint32(pktout, 0); /* height in pixels */
|
||||
write_ttymodes_to_packet(
|
||||
BinarySink_UPCAST(pktout), 1,
|
||||
get_ttymodes_from_conf(s->ppl.seat, conf));
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
|
||||
ssh1mainchan_queue_response(s, want_reply, FALSE);
|
||||
}
|
||||
|
||||
static int ssh1mainchan_send_env_var(
|
||||
SshChannel *sc, int want_reply, const char *var, const char *value)
|
||||
{
|
||||
return FALSE; /* SSH-1 doesn't support this at all */
|
||||
}
|
||||
|
||||
static void ssh1mainchan_start_shell(
|
||||
SshChannel *sc, int want_reply)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(sc, struct ssh1_connection_state, mainchan_sc);
|
||||
PktOut *pktout;
|
||||
|
||||
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EXEC_SHELL);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
|
||||
ssh1mainchan_queue_response(s, want_reply, TRUE);
|
||||
}
|
||||
|
||||
static void ssh1mainchan_start_command(
|
||||
SshChannel *sc, int want_reply, const char *command)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(sc, struct ssh1_connection_state, mainchan_sc);
|
||||
PktOut *pktout;
|
||||
|
||||
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EXEC_CMD);
|
||||
put_stringz(pktout, command);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
|
||||
ssh1mainchan_queue_response(s, want_reply, TRUE);
|
||||
}
|
||||
|
||||
static int ssh1mainchan_start_subsystem(
|
||||
SshChannel *sc, int want_reply, const char *subsystem)
|
||||
{
|
||||
return FALSE; /* SSH-1 doesn't support this at all */
|
||||
}
|
||||
|
||||
static int ssh1mainchan_send_serial_break(
|
||||
SshChannel *sc, int want_reply, int length)
|
||||
{
|
||||
return FALSE; /* SSH-1 doesn't support this at all */
|
||||
}
|
||||
|
||||
static int ssh1mainchan_send_signal(
|
||||
SshChannel *sc, int want_reply, const char *signame)
|
||||
{
|
||||
return FALSE; /* SSH-1 doesn't support this at all */
|
||||
}
|
||||
|
||||
static void ssh1mainchan_send_terminal_size_change(SshChannel *sc, int w, int h)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(sc, struct ssh1_connection_state, mainchan_sc);
|
||||
PktOut *pktout;
|
||||
|
||||
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_WINDOW_SIZE);
|
||||
put_uint32(pktout, h);
|
||||
put_uint32(pktout, w);
|
||||
put_uint32(pktout, 0); /* width in pixels */
|
||||
put_uint32(pktout, 0); /* height in pixels */
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
}
|
||||
|
||||
static void ssh1mainchan_hint_channel_is_simple(SshChannel *c)
|
||||
{
|
||||
}
|
||||
|
||||
static int ssh1mainchan_write(SshChannel *sc, const void *data, int len)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(sc, struct ssh1_connection_state, mainchan_sc);
|
||||
PktOut *pktout;
|
||||
|
||||
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_STDIN_DATA);
|
||||
put_string(pktout, data, len);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ssh1mainchan_write_eof(SshChannel *sc)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(sc, struct ssh1_connection_state, mainchan_sc);
|
||||
PktOut *pktout;
|
||||
|
||||
pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_EOF);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
}
|
||||
|
||||
static void ssh1_session_confirm_callback(void *vctx)
|
||||
{
|
||||
struct ssh1_connection_state *s = (struct ssh1_connection_state *)vctx;
|
||||
chan_open_confirmation(s->mainchan_chan);
|
||||
}
|
||||
|
||||
static SshChannel *ssh1_session_open(ConnectionLayer *cl, Channel *chan)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(cl, struct ssh1_connection_state, cl);
|
||||
s->mainchan_sc.cl = &s->cl;
|
||||
s->mainchan_sc.vt = &ssh1mainchan_vtable;
|
||||
s->mainchan_chan = chan;
|
||||
queue_toplevel_callback(ssh1_session_confirm_callback, s);
|
||||
return &s->mainchan_sc;
|
||||
}
|
||||
|
||||
static SshChannel *ssh1_lportfwd_open(
|
||||
ConnectionLayer *cl, const char *hostname, int port,
|
||||
const char *description, const SocketPeerInfo *pi, Channel *chan)
|
||||
@ -1203,61 +642,6 @@ static SshChannel *ssh1_lportfwd_open(
|
||||
return &c->sc;
|
||||
}
|
||||
|
||||
static void ssh1_rportfwd_response(struct ssh1_connection_state *s,
|
||||
int success, void *ctx)
|
||||
{
|
||||
PacketProtocolLayer *ppl = &s->ppl; /* for ppl_logevent */
|
||||
struct ssh_rportfwd *rpf = (struct ssh_rportfwd *)ctx;
|
||||
|
||||
if (success) {
|
||||
ppl_logevent(("Remote port forwarding from %s enabled",
|
||||
rpf->log_description));
|
||||
} else {
|
||||
ppl_logevent(("Remote port forwarding from %s refused",
|
||||
rpf->log_description));
|
||||
|
||||
struct ssh_rportfwd *realpf = del234(s->rportfwds, rpf);
|
||||
assert(realpf == rpf);
|
||||
portfwdmgr_close(s->portfwdmgr, rpf->pfr);
|
||||
free_rportfwd(rpf);
|
||||
}
|
||||
}
|
||||
|
||||
static struct ssh_rportfwd *ssh1_rportfwd_alloc(
|
||||
ConnectionLayer *cl,
|
||||
const char *shost, int sport, const char *dhost, int dport,
|
||||
int addressfamily, const char *log_description, PortFwdRecord *pfr,
|
||||
ssh_sharing_connstate *share_ctx)
|
||||
{
|
||||
struct ssh1_connection_state *s =
|
||||
container_of(cl, struct ssh1_connection_state, cl);
|
||||
struct ssh_rportfwd *rpf = snew(struct ssh_rportfwd);
|
||||
|
||||
rpf->shost = dupstr(shost);
|
||||
rpf->sport = sport;
|
||||
rpf->dhost = dupstr(dhost);
|
||||
rpf->dport = dport;
|
||||
rpf->addressfamily = addressfamily;
|
||||
rpf->log_description = dupstr(log_description);
|
||||
rpf->pfr = pfr;
|
||||
|
||||
if (add234(s->rportfwds, rpf) != rpf) {
|
||||
free_rportfwd(rpf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PktOut *pktout = ssh_bpp_new_pktout(
|
||||
s->ppl.bpp, SSH1_CMSG_PORT_FORWARD_REQUEST);
|
||||
put_uint32(pktout, rpf->sport);
|
||||
put_stringz(pktout, rpf->dhost);
|
||||
put_uint32(pktout, rpf->dport);
|
||||
pq_push(s->ppl.out_pq, pktout);
|
||||
|
||||
ssh1_queue_succfail_handler(s, ssh1_rportfwd_response, rpf, FALSE);
|
||||
|
||||
return rpf;
|
||||
}
|
||||
|
||||
static void ssh1_rportfwd_remove(ConnectionLayer *cl, struct ssh_rportfwd *rpf)
|
||||
{
|
||||
/*
|
||||
|
Reference in New Issue
Block a user