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

New abstraction 'ConnectionLayer'.

This is a vtable that wraps up all the functionality required from the
SSH connection layer by associated modules like port forwarding and
connection sharing. This extra layer of indirection adds nothing
useful right now, but when I later separate the SSH-1 and SSH-2
connection layer implementations, it will be convenient for each one
to be able to implement this vtable in terms of its own internal data
structures.

To simplify this vtable, I've moved a lot of the logging duties
relating to connection sharing out of ssh.c into sshshare.c: now it
handles nearly all the logging itself relating to setting up
connection sharing in the first place and downstreams connecting and
disconnecting. The only exception is the 'Reusing a shared connection'
announcement in the console window, which is now done in ssh.c by
detecting downstream status immediately after setup.
This commit is contained in:
Simon Tatham 2018-09-17 12:14:00 +01:00
parent 895b09a4c6
commit 8001dd4cbb
5 changed files with 313 additions and 197 deletions

1
defs.h
View File

@ -62,6 +62,7 @@ typedef struct share_channel share_channel;
typedef struct PortFwdManager PortFwdManager;
typedef struct PortFwdRecord PortFwdRecord;
typedef struct ConnectionLayer ConnectionLayer;
typedef struct dlgparam dlgparam;

View File

@ -35,8 +35,8 @@ typedef enum {
} SocksState;
typedef struct PortForwarding {
SshChannel *c; /* channel structure held by SSH backend */
Ssh ssh; /* instance of SSH backend itself */
SshChannel *c; /* channel structure held by SSH connection layer */
ConnectionLayer *cl; /* the connection layer itself */
/* Note that ssh need not be filled in if c is non-NULL */
Socket s;
int input_wanted;
@ -61,7 +61,7 @@ typedef struct PortForwarding {
} PortForwarding;
struct PortListener {
Ssh ssh; /* instance of SSH backend itself */
ConnectionLayer *cl;
Socket s;
int is_dynamic;
/*
@ -160,8 +160,9 @@ static void pfl_closing(Plug plug, const char *error_msg, int error_code,
pfl_terminate(pl);
}
static SshChannel *wrap_send_port_open(
Ssh ssh, const char *hostname, int port, Socket s, Channel *chan)
static SshChannel *wrap_lportfwd_open(
ConnectionLayer *cl, const char *hostname, int port,
Socket s, Channel *chan)
{
char *peerinfo, *description;
SshChannel *toret;
@ -174,7 +175,7 @@ static SshChannel *wrap_send_port_open(
description = dupstr("forwarding");
}
toret = ssh_send_port_open(ssh, hostname, port, description, chan);
toret = ssh_lportfwd_open(cl, hostname, port, description, chan);
sfree(description);
return toret;
@ -419,8 +420,8 @@ static void pfd_receive(Plug plug, int urgent, char *data, int len)
*/
sk_set_frozen(pf->s, 1);
pf->c = wrap_send_port_open(pf->ssh, pf->hostname, pf->port, pf->s,
&pf->chan);
pf->c = wrap_lportfwd_open(pf->cl, pf->hostname, pf->port, pf->s,
&pf->chan);
}
if (pf->ready)
sshfwd_write(pf->c, data, len);
@ -480,7 +481,7 @@ static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx)
pf->input_wanted = TRUE;
pf->c = NULL;
pf->ssh = pl->ssh;
pf->cl = pl->cl;
pf->s = s = constructor(ctx, &pf->plugvt);
if ((err = sk_socket_error(s)) != NULL) {
@ -501,8 +502,8 @@ static int pfl_accepting(Plug p, accept_fn_t constructor, accept_ctx_t ctx)
pf->socks_state = SOCKS_NONE;
pf->hostname = dupstr(pl->hostname);
pf->port = pl->port;
pf->c = wrap_send_port_open(pl->ssh, pf->hostname, pf->port,
s, &pf->chan);
pf->c = wrap_lportfwd_open(pl->cl, pf->hostname, pf->port,
s, &pf->chan);
}
return 0;
@ -525,7 +526,7 @@ static const Plug_vtable PortListener_plugvt = {
* dynamically allocated error message string.
*/
static char *pfl_listen(char *desthost, int destport, char *srcaddr,
int port, Ssh ssh, Conf *conf,
int port, ConnectionLayer *cl, Conf *conf,
struct PortListener **pl_ret, int address_family)
{
const char *err;
@ -542,7 +543,7 @@ static char *pfl_listen(char *desthost, int destport, char *srcaddr,
pl->is_dynamic = FALSE;
} else
pl->is_dynamic = TRUE;
pl->ssh = ssh;
pl->cl = cl;
pl->s = new_listener(srcaddr, port, &pl->plugvt,
!conf_get_int(conf, CONF_lport_acceptall),
@ -637,7 +638,7 @@ static void pfd_open_failure(Channel *chan, const char *errtext)
assert(chan->vt == &PortForwarding_channelvt);
PortForwarding *pf = FROMFIELD(chan, PortForwarding, chan);
logeventf(ssh_get_frontend(pf->ssh),
logeventf(pf->cl->frontend,
"Forwarded connection refused by server%s%s",
errtext ? ": " : "", errtext ? errtext : "");
}
@ -702,18 +703,16 @@ void pfr_free(PortFwdRecord *pfr)
}
struct PortFwdManager {
Ssh ssh;
Frontend *frontend;
ConnectionLayer *cl;
Conf *conf;
tree234 *forwardings;
};
PortFwdManager *portfwdmgr_new(Ssh ssh)
PortFwdManager *portfwdmgr_new(ConnectionLayer *cl)
{
PortFwdManager *mgr = snew(PortFwdManager);
mgr->ssh = ssh;
mgr->frontend = ssh_get_frontend(ssh);
mgr->cl = cl;
mgr->conf = NULL;
mgr->forwardings = newtree234(pfr_cmp);
@ -801,7 +800,7 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf)
sserv = 1;
sport = net_service_lookup(sports);
if (!sport) {
logeventf(mgr->frontend, "Service lookup failed for source"
logeventf(mgr->cl->frontend, "Service lookup failed for source"
" port \"%s\"", sports);
}
}
@ -827,7 +826,7 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf)
dserv = 1;
dport = net_service_lookup(dports);
if (!dport) {
logeventf(mgr->frontend,
logeventf(mgr->cl->frontend,
"Service lookup failed for destination"
" port \"%s\"", dports);
}
@ -897,7 +896,7 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf)
message = msg2;
}
logeventf(mgr->frontend, "Cancelling %s", message);
logeventf(mgr->cl->frontend, "Cancelling %s", message);
sfree(message);
/* pfr->remote or pfr->local may be NULL if setting up a
@ -916,7 +915,7 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf)
* connections the server tries to make on it are
* rejected.
*/
ssh_rportfwd_remove(mgr->ssh, pfr->remote);
ssh_rportfwd_remove(mgr->cl, pfr->remote);
} else if (pfr->local) {
pfl_terminate(pfr->local);
}
@ -954,10 +953,10 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf)
if (pfr->type == 'L') {
char *err = pfl_listen(pfr->daddr, pfr->dport,
pfr->saddr, pfr->sport,
mgr->ssh, conf, &pfr->local,
mgr->cl, conf, &pfr->local,
pfr->addressfamily);
logeventf(mgr->frontend,
logeventf(mgr->cl->frontend,
"Local %sport %s forwarding to %s%s%s",
pfr->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :
pfr->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",
@ -967,10 +966,10 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf)
sfree(err);
} else if (pfr->type == 'D') {
char *err = pfl_listen(NULL, -1, pfr->saddr, pfr->sport,
mgr->ssh, conf, &pfr->local,
mgr->cl, conf, &pfr->local,
pfr->addressfamily);
logeventf(mgr->frontend,
logeventf(mgr->cl->frontend,
"Local %sport %s SOCKS dynamic forwarding%s%s",
pfr->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :
pfr->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",
@ -991,16 +990,16 @@ void portfwdmgr_config(PortFwdManager *mgr, Conf *conf)
}
pfr->remote = ssh_rportfwd_alloc(
mgr->ssh, shost, pfr->sport, pfr->daddr, pfr->dport,
mgr->cl, shost, pfr->sport, pfr->daddr, pfr->dport,
pfr->addressfamily, sportdesc, pfr, NULL);
if (!pfr->remote) {
logeventf(mgr->frontend,
logeventf(mgr->cl->frontend,
"Duplicate remote port forwarding to %s:%d",
pfr->daddr, pfr->dport);
pfr_free(pfr);
} else {
logeventf(mgr->frontend, "Requesting remote port %s"
logeventf(mgr->cl->frontend, "Requesting remote port %s"
" forward to %s", sportdesc, dportdesc);
}
}
@ -1049,7 +1048,7 @@ char *portfwdmgr_connect(PortFwdManager *mgr, Channel **chan_ret,
pf->input_wanted = TRUE;
pf->ready = 1;
pf->c = c;
pf->ssh = mgr->ssh;
pf->cl = mgr->cl;
pf->socks_state = SOCKS_NONE;
pf->s = new_connection(addr, dummy_realhost, port,

179
ssh.c
View File

@ -729,6 +729,8 @@ struct ssh_tag {
tree234 *rportfwds;
PortFwdManager *portfwdmgr;
ConnectionLayer cl;
enum {
SSH_STATE_PREPACKET,
SSH_STATE_BEFORE_SIZE,
@ -2199,39 +2201,6 @@ static void ssh_socket_log(Plug plug, int type, SockAddr addr, int port,
ssh->session_started);
}
void ssh_connshare_log(Ssh ssh, int event, const char *logtext,
const char *ds_err, const char *us_err)
{
if (event == SHARE_NONE) {
/* In this case, 'logtext' is an error message indicating a
* reason why connection sharing couldn't be set up _at all_.
* Failing that, ds_err and us_err indicate why we couldn't be
* a downstream and an upstream respectively. */
if (logtext) {
logeventf(ssh, "Could not set up connection sharing: %s", logtext);
} else {
if (ds_err)
logeventf(ssh, "Could not set up connection sharing"
" as downstream: %s", ds_err);
if (us_err)
logeventf(ssh, "Could not set up connection sharing"
" as upstream: %s", us_err);
}
} else if (event == SHARE_DOWNSTREAM) {
/* In this case, 'logtext' is a local endpoint address */
logeventf(ssh, "Using existing shared connection at %s", logtext);
/* Also we should mention this in the console window to avoid
* confusing users as to why this window doesn't behave the
* usual way. */
if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) {
c_write_str(ssh,"Reusing a shared connection to this server.\r\n");
}
} else if (event == SHARE_UPSTREAM) {
/* In this case, 'logtext' is a local endpoint address too */
logeventf(ssh, "Sharing this connection at %s", logtext);
}
}
static void ssh_closing(Plug plug, const char *error_msg, int error_code,
int calling_back)
{
@ -2363,7 +2332,7 @@ static const char *connect_to_host(Ssh ssh, const char *host, int port,
ssh->connshare = NULL;
ssh->attempting_connshare = TRUE; /* affects socket logging behaviour */
ssh->s = ssh_connection_sharing_init(
ssh->savedhost, ssh->savedport, ssh->conf, ssh, &ssh->plugvt,
ssh->savedhost, ssh->savedport, ssh->conf, &ssh->cl, &ssh->plugvt,
&ssh->connshare);
ssh->attempting_connshare = FALSE;
if (ssh->s != NULL) {
@ -2374,6 +2343,14 @@ static const char *connect_to_host(Ssh ssh, const char *host, int port,
ssh->current_incoming_data_fn = do_ssh_connection_init;
ssh->fullhostname = NULL;
*realhost = dupstr(host); /* best we can do */
if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) {
/* In an interactive session, or in verbose mode, announce
* in the console window that we're a sharing downstream,
* to avoid confusing users as to why this session doesn't
* behave in quite the usual way. */
c_write_str(ssh,"Reusing a shared connection to this server.\r\n");
}
} else {
/*
* We're not a downstream, so open a normal socket.
@ -3758,11 +3735,56 @@ static void ssh_rportfwd_succfail(Ssh ssh, PktIn *pktin, void *ctx)
}
}
struct ssh_rportfwd *ssh_rportfwd_alloc(
Ssh ssh, const char *shost, int sport, const char *dhost, int dport,
/* Many of these vtable methods have the same names as wrapper macros
* in ssh.h, so parenthesise the names to inhibit macro expansion */
static struct ssh_rportfwd *(ssh_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 (ssh_rportfwd_remove)(
ConnectionLayer *cl, struct ssh_rportfwd *rpf);
static SshChannel *(ssh_lportfwd_open)(
ConnectionLayer *cl, const char *hostname, int port,
const char *org, Channel *chan);
static struct X11FakeAuth *(ssh_add_sharing_x11_display)(
ConnectionLayer *cl, int authtype, ssh_sharing_connstate *share_cs,
share_channel *share_chan);
static void (ssh_remove_sharing_x11_display)(ConnectionLayer *cl,
struct X11FakeAuth *auth);
static void (ssh_send_packet_from_downstream)(
ConnectionLayer *cl, unsigned id, int type,
const void *pkt, int pktlen, const char *additional_log_text);
static unsigned (ssh_alloc_sharing_channel)(
ConnectionLayer *cl, ssh_sharing_connstate *connstate);
static void (ssh_delete_sharing_channel)(
ConnectionLayer *cl, unsigned localid);
static void (ssh_sharing_queue_global_request)(
ConnectionLayer *cl, ssh_sharing_connstate *share_ctx);
static int (ssh_agent_forwarding_permitted)(ConnectionLayer *cl);
const struct ConnectionLayerVtable ssh_connlayer_vtable = {
ssh_rportfwd_alloc,
ssh_rportfwd_remove,
ssh_lportfwd_open,
ssh_add_sharing_x11_display,
ssh_remove_sharing_x11_display,
ssh_send_packet_from_downstream,
ssh_alloc_sharing_channel,
ssh_delete_sharing_channel,
ssh_sharing_queue_global_request,
ssh_agent_forwarding_permitted,
};
static struct ssh_rportfwd *(ssh_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)
{
Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl);
/*
* Ensure the remote port forwardings tree exists.
*/
@ -3819,8 +3841,10 @@ struct ssh_rportfwd *ssh_rportfwd_alloc(
return rpf;
}
void ssh_rportfwd_remove(Ssh ssh, struct ssh_rportfwd *rpf)
static void (ssh_rportfwd_remove)(
ConnectionLayer *cl, struct ssh_rportfwd *rpf)
{
Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl);
if (ssh->version == 1) {
/*
* We cannot cancel listening ports on the server side in
@ -3855,9 +3879,10 @@ static void ssh_sharing_global_request_response(Ssh ssh, PktIn *pktin,
BinarySource_UPCAST(pktin)->len);
}
void ssh_sharing_queue_global_request(Ssh ssh,
ssh_sharing_connstate *share_ctx)
static void (ssh_sharing_queue_global_request)(
ConnectionLayer *cl, ssh_sharing_connstate *share_ctx)
{
Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl);
ssh_queue_handler(ssh, SSH2_MSG_REQUEST_SUCCESS, SSH2_MSG_REQUEST_FAILURE,
ssh_sharing_global_request_response, share_ctx);
}
@ -4129,8 +4154,9 @@ static void ssh1_send_ttymode(BinarySink *bs,
}
}
int ssh_agent_forwarding_permitted(Ssh ssh)
static int (ssh_agent_forwarding_permitted)(ConnectionLayer *cl)
{
Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl);
return conf_get_int(ssh->conf, CONF_agentfwd) && agent_exists();
}
@ -4156,7 +4182,7 @@ static void do_ssh1_connection(void *vctx)
ssh->packet_dispatch[SSH1_MSG_CHANNEL_DATA] = ssh1_msg_channel_data;
ssh->packet_dispatch[SSH1_SMSG_EXIT_STATUS] = ssh1_smsg_exit_status;
if (ssh_agent_forwarding_permitted(ssh)) {
if (ssh_agent_forwarding_permitted(&ssh->cl)) {
logevent("Requesting agent forwarding");
pkt = ssh_bpp_new_pktout(ssh->bpp, SSH1_CMSG_AGENT_REQUEST_FORWARDING);
ssh_pkt_write(ssh, pkt);
@ -6945,37 +6971,6 @@ static void ssh_check_termination(Ssh ssh)
}
}
void ssh_sharing_downstream_connected(Ssh ssh, unsigned id,
const char *peerinfo)
{
if (peerinfo)
logeventf(ssh, "Connection sharing downstream #%u connected from %s",
id, peerinfo);
else
logeventf(ssh, "Connection sharing downstream #%u connected", id);
}
void ssh_sharing_downstream_disconnected(Ssh ssh, unsigned id)
{
logeventf(ssh, "Connection sharing downstream #%u disconnected", id);
ssh_check_termination(ssh);
}
void ssh_sharing_logf(Ssh ssh, unsigned id, const char *logfmt, ...)
{
va_list ap;
char *buf;
va_start(ap, logfmt);
buf = dupvprintf(logfmt, ap);
va_end(ap);
if (id)
logeventf(ssh, "Connection sharing downstream #%u: %s", id, buf);
else
logeventf(ssh, "Connection sharing: %s", buf);
sfree(buf);
}
/*
* Close any local socket and free any local resources associated with
* a channel. This converts the channel into a zombie.
@ -7416,10 +7411,11 @@ static void ssh2_msg_global_request(Ssh ssh, PktIn *pktin)
}
}
struct X11FakeAuth *ssh_sharing_add_x11_display(
Ssh ssh, int authtype, ssh_sharing_connstate *share_cs,
static struct X11FakeAuth *(ssh_add_sharing_x11_display)(
ConnectionLayer *cl, int authtype, ssh_sharing_connstate *share_cs,
share_channel *share_chan)
{
Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl);
struct X11FakeAuth *auth;
/*
@ -7434,8 +7430,10 @@ struct X11FakeAuth *ssh_sharing_add_x11_display(
return auth;
}
void ssh_sharing_remove_x11_display(Ssh ssh, struct X11FakeAuth *auth)
static void (ssh_remove_sharing_x11_display)(
ConnectionLayer *cl, struct X11FakeAuth *auth)
{
Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl);
del234(ssh->x11authtree, auth);
x11_free_fake_auth(auth);
}
@ -9477,8 +9475,8 @@ static void do_ssh2_connection(void *vctx)
* Just start a direct-tcpip channel and use it as the main
* channel.
*/
mc->sc = ssh_send_port_open
(ssh, conf_get_str(ssh->conf, CONF_ssh_nc_host),
mc->sc = ssh_lportfwd_open
(&ssh->cl, conf_get_str(ssh->conf, CONF_ssh_nc_host),
conf_get_int(ssh->conf, CONF_ssh_nc_port),
"main channel", &mc->chan);
ssh->mainchan = FROMFIELD(mc->sc, struct ssh_channel, sc);
@ -9603,7 +9601,7 @@ static void do_ssh2_connection(void *vctx)
}
/* Potentially enable agent forwarding. */
if (ssh_agent_forwarding_permitted(ssh))
if (ssh_agent_forwarding_permitted(&ssh->cl))
ssh2_setup_agent(ssh->mainchan, NULL, NULL);
/* Now allocate a pty for the session. */
@ -10351,9 +10349,12 @@ static const char *ssh_init(Frontend *frontend, Backend **backend_handle,
ssh->term_width = conf_get_int(ssh->conf, CONF_width);
ssh->term_height = conf_get_int(ssh->conf, CONF_height);
ssh->cl.vt = &ssh_connlayer_vtable;
ssh->cl.frontend = ssh->frontend;
ssh->channels = NULL;
ssh->rportfwds = NULL;
ssh->portfwdmgr = portfwdmgr_new(ssh);
ssh->portfwdmgr = portfwdmgr_new(&ssh->cl);
ssh->send_ok = 0;
ssh->editing = 0;
@ -10861,8 +10862,10 @@ static void ssh_special(Backend *be, Telnet_Special code)
}
}
unsigned ssh_alloc_sharing_channel(Ssh ssh, ssh_sharing_connstate *connstate)
static unsigned (ssh_alloc_sharing_channel)(
ConnectionLayer *cl, ssh_sharing_connstate *connstate)
{
Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl);
struct ssh_channel *c;
c = snew(struct ssh_channel);
@ -10873,8 +10876,9 @@ unsigned ssh_alloc_sharing_channel(Ssh ssh, ssh_sharing_connstate *connstate)
return c->localid;
}
void ssh_delete_sharing_channel(Ssh ssh, unsigned localid)
static void (ssh_delete_sharing_channel)(ConnectionLayer *cl, unsigned localid)
{
Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl);
struct ssh_channel *c;
c = find234(ssh->channels, &localid, ssh_channelfind);
@ -10882,10 +10886,11 @@ void ssh_delete_sharing_channel(Ssh ssh, unsigned localid)
ssh_channel_destroy(c);
}
void ssh_send_packet_from_downstream(Ssh ssh, unsigned id, int type,
const void *data, int datalen,
const char *additional_log_text)
static void (ssh_send_packet_from_downstream)(
ConnectionLayer *cl, unsigned id, int type,
const void *data, int datalen, const char *additional_log_text)
{
Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl);
PktOut *pkt;
pkt = ssh_bpp_new_pktout(ssh->bpp, type);
@ -10920,9 +10925,11 @@ static void ssh_unthrottle(Backend *be, int bufsize)
queue_idempotent_callback(&ssh->incoming_data_consumer);
}
SshChannel *ssh_send_port_open(Ssh ssh, const char *hostname, int port,
const char *org, Channel *chan)
static SshChannel *(ssh_lportfwd_open)(
ConnectionLayer *cl, const char *hostname, int port,
const char *org, Channel *chan)
{
Ssh ssh = FROMFIELD(cl, struct ssh_tag, cl);
struct ssh_channel *c = snew(struct ssh_channel);
PktOut *pktout;

100
ssh.h
View File

@ -135,8 +135,8 @@ void ssh_unref_packet(PktIn *pkt);
void ssh_free_pktout(PktOut *pkt);
extern Socket ssh_connection_sharing_init(
const char *host, int port, Conf *conf, Ssh ssh, Plug sshplug,
ssh_sharing_state **state);
const char *host, int port, Conf *conf, ConnectionLayer *cl,
Plug sshplug, ssh_sharing_state **state);
int ssh_share_test_for_upstream(const char *host, int port, Conf *conf);
void share_got_pkt_from_server(ssh_sharing_connstate *ctx, int type,
const void *pkt, int pktlen);
@ -147,22 +147,6 @@ int share_ndownstreams(ssh_sharing_state *state);
void ssh_connshare_log(Ssh ssh, int event, const char *logtext,
const char *ds_err, const char *us_err);
unsigned ssh_alloc_sharing_channel(Ssh ssh, ssh_sharing_connstate *connstate);
void ssh_delete_sharing_channel(Ssh ssh, unsigned localid);
void ssh_sharing_queue_global_request(
Ssh ssh, ssh_sharing_connstate *connstate);
struct X11FakeAuth *ssh_sharing_add_x11_display(
Ssh ssh, int authtype, ssh_sharing_connstate *share_cs,
share_channel *share_chan);
void ssh_sharing_remove_x11_display(Ssh ssh, struct X11FakeAuth *auth);
void ssh_send_packet_from_downstream(Ssh ssh, unsigned id, int type,
const void *pkt, int pktlen,
const char *additional_log_text);
void ssh_sharing_downstream_connected(Ssh ssh, unsigned id,
const char *peerinfo);
void ssh_sharing_downstream_disconnected(Ssh ssh, unsigned id);
void ssh_sharing_logf(Ssh ssh, unsigned id, const char *logfmt, ...);
int ssh_agent_forwarding_permitted(Ssh ssh);
void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan,
unsigned upstream_id, unsigned server_id,
unsigned server_currwin, unsigned server_maxpkt,
@ -172,14 +156,78 @@ void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan,
const void *initial_data, int initial_len);
struct ssh_rportfwd;
struct ssh_rportfwd *ssh_rportfwd_alloc(
Ssh ssh, const char *shost, int sport, const char *dhost, int dport,
int addressfamily, const char *log_description, PortFwdRecord *pfr,
ssh_sharing_connstate *share_ctx);
void ssh_rportfwd_remove(Ssh ssh, struct ssh_rportfwd *rpf);
struct ConnectionLayerVtable {
/* Allocate and free remote-to-local port forwardings, called by
* PortFwdManager or by connection sharing */
struct ssh_rportfwd *(*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);
void (*rportfwd_remove)(ConnectionLayer *cl, struct ssh_rportfwd *rpf);
/* Open a local-to-remote port forwarding channel, called by
* PortFwdManager */
SshChannel *(*lportfwd_open)(
ConnectionLayer *cl, const char *hostname, int port,
const char *org, Channel *chan);
/* Add and remove X11 displays for connection sharing downstreams */
struct X11FakeAuth *(*add_sharing_x11_display)(
ConnectionLayer *cl, int authtype, ssh_sharing_connstate *share_cs,
share_channel *share_chan);
void (*remove_sharing_x11_display)(
ConnectionLayer *cl, struct X11FakeAuth *auth);
/* Pass through an outgoing SSH packet from a downstream */
void (*send_packet_from_downstream)(
ConnectionLayer *cl, unsigned id, int type,
const void *pkt, int pktlen, const char *additional_log_text);
/* Allocate/free an upstream channel number associated with a
* sharing downstream */
unsigned (*alloc_sharing_channel)(ConnectionLayer *cl,
ssh_sharing_connstate *connstate);
void (*delete_sharing_channel)(ConnectionLayer *cl, unsigned localid);
/* Indicate that a downstream has sent a global request with the
* want-reply flag, so that when a reply arrives it will be passed
* back to that downstrean */
void (*sharing_queue_global_request)(
ConnectionLayer *cl, ssh_sharing_connstate *connstate);
/* Query whether the connection layer is doing agent forwarding */
int (*agent_forwarding_permitted)(ConnectionLayer *cl);
};
struct ConnectionLayer {
Frontend *frontend;
const struct ConnectionLayerVtable *vt;
};
#define ssh_rportfwd_alloc(cl, sh, sp, dh, dp, af, ld, pfr, share) \
((cl)->vt->rportfwd_alloc(cl, sh, sp, dh, dp, af, ld, pfr, share))
#define ssh_rportfwd_remove(cl, rpf) ((cl)->vt->rportfwd_remove(cl, rpf))
#define ssh_lportfwd_open(cl, h, p, org, chan) \
((cl)->vt->lportfwd_open(cl, h, p, org, chan))
#define ssh_add_sharing_x11_display(cl, auth, cs, ch) \
((cl)->vt->add_sharing_x11_display(cl, auth, cs, ch))
#define ssh_remove_sharing_x11_display(cl, fa) \
((cl)->vt->remove_sharing_x11_display(cl, fa))
#define ssh_send_packet_from_downstream(cl, id, type, pkt, len, log) \
((cl)->vt->send_packet_from_downstream(cl, id, type, pkt, len, log))
#define ssh_alloc_sharing_channel(cl, cs) \
((cl)->vt->alloc_sharing_channel(cl, cs))
#define ssh_delete_sharing_channel(cl, ch) \
((cl)->vt->delete_sharing_channel(cl, ch))
#define ssh_sharing_queue_global_request(cl, cs) \
((cl)->vt->sharing_queue_global_request(cl, cs))
#define ssh_agent_forwarding_permitted(cl) \
((cl)->vt->agent_forwarding_permitted(cl))
/* Exports from portfwd.c */
PortFwdManager *portfwdmgr_new(Ssh ssh);
PortFwdManager *portfwdmgr_new(ConnectionLayer *cl);
void portfwdmgr_free(PortFwdManager *mgr);
void portfwdmgr_config(PortFwdManager *mgr, Conf *conf);
void portfwdmgr_close(PortFwdManager *mgr, PortFwdRecord *pfr);
@ -731,10 +779,6 @@ void random_add_heavynoise(void *noise, int length);
void logevent(Frontend *, const char *);
/* Allocate and register a new channel for port forwarding */
SshChannel *ssh_send_port_open(Ssh ssh, const char *hostname, int port,
const char *org, Channel *chan);
/* Exports from x11fwd.c */
enum {
X11_TRANS_IPV4 = 0, X11_TRANS_IPV6 = 6, X11_TRANS_UNIX = 256

View File

@ -144,7 +144,7 @@ struct ssh_sharing_state {
Socket listensock; /* the master listening Socket */
tree234 *connections; /* holds ssh_sharing_connstates */
unsigned nextid; /* preferred id for next connstate */
Ssh ssh; /* instance of the ssh backend */
ConnectionLayer *cl; /* instance of the ssh connection layer */
char *server_verstring; /* server version string after "SSH-" */
const Plug_vtable *plugvt;
@ -618,7 +618,7 @@ static void share_remove_channel(struct ssh_sharing_connstate *cs,
del234(cs->channels_by_us, chan);
del234(cs->channels_by_server, chan);
if (chan->x11_auth_upstream)
ssh_sharing_remove_x11_display(cs->parent->ssh,
ssh_remove_sharing_x11_display(cs->parent->cl,
chan->x11_auth_upstream);
sfree(chan->x11_auth_data);
sfree(chan);
@ -703,6 +703,45 @@ static void share_remove_forwarding(struct ssh_sharing_connstate *cs,
sfree(fwd);
}
static void logeventf(Frontend *frontend, const char *fmt, ...)
{
va_list ap;
char *buf;
va_start(ap, fmt);
buf = dupvprintf(fmt, ap);
va_end(ap);
logevent(frontend, buf);
sfree(buf);
}
static void log_downstream(struct ssh_sharing_connstate *cs,
const char *logfmt, ...)
{
va_list ap;
char *buf;
va_start(ap, logfmt);
buf = dupvprintf(logfmt, ap);
va_end(ap);
logeventf(cs->parent->cl->frontend,
"Connection sharing downstream #%u: %s", cs->id, buf);
sfree(buf);
}
static void log_general(struct ssh_sharing_state *sharestate,
const char *logfmt, ...)
{
va_list ap;
char *buf;
va_start(ap, logfmt);
buf = dupvprintf(logfmt, ap);
va_end(ap);
logeventf(sharestate->cl->frontend, "Connection sharing: %s", buf);
sfree(buf);
}
static void send_packet_to_downstream(struct ssh_sharing_connstate *cs,
int type, const void *pkt, int pktlen,
struct share_channel *chan)
@ -790,7 +829,7 @@ static void share_try_cleanup(struct ssh_sharing_connstate *cs)
put_stringz(packet, reason);
put_stringz(packet, lang);
ssh_send_packet_from_downstream(
cs->parent->ssh, cs->id, SSH2_MSG_CHANNEL_OPEN_FAILURE,
cs->parent->cl, cs->id, SSH2_MSG_CHANNEL_OPEN_FAILURE,
packet->s, packet->len,
"cleanup after downstream went away");
strbuf_free(packet);
@ -819,7 +858,7 @@ static void share_try_cleanup(struct ssh_sharing_connstate *cs)
packet = strbuf_new();
put_uint32(packet, chan->server_id);
ssh_send_packet_from_downstream(
cs->parent->ssh, cs->id, SSH2_MSG_CHANNEL_CLOSE,
cs->parent->cl, cs->id, SSH2_MSG_CHANNEL_CLOSE,
packet->s, packet->len,
"cleanup after downstream went away");
strbuf_free(packet);
@ -828,7 +867,7 @@ static void share_try_cleanup(struct ssh_sharing_connstate *cs)
chan->state = SENT_CLOSE;
} else {
/* In this case, we _can_ clear up the channel now. */
ssh_delete_sharing_channel(cs->parent->ssh, chan->upstream_id);
ssh_delete_sharing_channel(cs->parent->cl, chan->upstream_id);
share_remove_channel(cs, chan);
i--; /* don't accidentally skip one as a result */
}
@ -852,12 +891,12 @@ static void share_try_cleanup(struct ssh_sharing_connstate *cs)
put_stringz(packet, fwd->host);
put_uint32(packet, fwd->port);
ssh_send_packet_from_downstream(
cs->parent->ssh, cs->id, SSH2_MSG_GLOBAL_REQUEST,
cs->parent->cl, cs->id, SSH2_MSG_GLOBAL_REQUEST,
packet->s, packet->len,
"cleanup after downstream went away");
strbuf_free(packet);
ssh_rportfwd_remove(cs->parent->ssh, fwd->rpf);
ssh_rportfwd_remove(cs->parent->cl, fwd->rpf);
share_remove_forwarding(cs, fwd);
i--; /* don't accidentally skip one as a result */
}
@ -870,7 +909,7 @@ static void share_try_cleanup(struct ssh_sharing_connstate *cs)
* Now we're _really_ done, so we can get rid of cs completely.
*/
del234(cs->parent->connections, cs);
ssh_sharing_downstream_disconnected(cs->parent->ssh, cs->id);
log_downstream(cs, "disconnected");
share_connstate_free(cs);
}
}
@ -919,8 +958,7 @@ static void share_closing(Plug plug, const char *error_msg, int error_code,
/* do nothing */;
else
#endif
ssh_sharing_logf(cs->parent->ssh, cs->id,
"Socket error: %s", error_msg);
log_downstream(cs, "Socket error: %s", error_msg);
}
share_begin_cleanup(cs);
}
@ -979,7 +1017,7 @@ void share_dead_xchannel_respond(struct ssh_sharing_connstate *cs,
strbuf *packet = strbuf_new();
put_uint32(packet, xc->server_id);
ssh_send_packet_from_downstream
(cs->parent->ssh, cs->id, SSH2_MSG_CHANNEL_FAILURE,
(cs->parent->cl, cs->id, SSH2_MSG_CHANNEL_FAILURE,
packet->s, packet->len,
"downstream refused X channel open");
strbuf_free(packet);
@ -995,7 +1033,7 @@ void share_dead_xchannel_respond(struct ssh_sharing_connstate *cs,
}
xc->msgtail = NULL;
if (delete) {
ssh_delete_sharing_channel(cs->parent->ssh, xc->upstream_id);
ssh_delete_sharing_channel(cs->parent->cl, xc->upstream_id);
share_remove_xchannel(cs, xc);
}
}
@ -1031,7 +1069,7 @@ void share_xchannel_confirmation(struct ssh_sharing_connstate *cs,
put_uint32(packet, xc->server_id);
put_uint32(packet, downstream_window - xc->window);
ssh_send_packet_from_downstream(
cs->parent->ssh, cs->id, SSH2_MSG_CHANNEL_WINDOW_ADJUST,
cs->parent->cl, cs->id, SSH2_MSG_CHANNEL_WINDOW_ADJUST,
packet->s, packet->len,
"window adjustment after downstream accepted X channel");
strbuf_free(packet);
@ -1047,7 +1085,7 @@ void share_xchannel_failure(struct ssh_sharing_connstate *cs,
strbuf *packet = strbuf_new();
put_uint32(packet, xc->server_id);
ssh_send_packet_from_downstream(
cs->parent->ssh, cs->id, SSH2_MSG_CHANNEL_CLOSE,
cs->parent->cl, cs->id, SSH2_MSG_CHANNEL_CLOSE,
packet->s, packet->len,
"downstream refused X channel open");
strbuf_free(packet);
@ -1115,7 +1153,7 @@ void share_setup_x11_channel(ssh_sharing_connstate *cs, share_channel *chan,
* If this was a once-only X forwarding, clean it up now.
*/
if (chan->x11_one_shot) {
ssh_sharing_remove_x11_display(cs->parent->ssh,
ssh_remove_sharing_x11_display(cs->parent->cl,
chan->x11_auth_upstream);
chan->x11_auth_upstream = NULL;
sfree(chan->x11_auth_data);
@ -1221,11 +1259,11 @@ void share_got_pkt_from_server(ssh_sharing_connstate *cs, int type,
}
}
} else if (type == SSH2_MSG_CHANNEL_OPEN_FAILURE) {
ssh_delete_sharing_channel(cs->parent->ssh, chan->upstream_id);
ssh_delete_sharing_channel(cs->parent->cl, chan->upstream_id);
share_remove_channel(cs, chan);
} else if (type == SSH2_MSG_CHANNEL_CLOSE) {
if (chan->state == SENT_CLOSE) {
ssh_delete_sharing_channel(cs->parent->ssh,
ssh_delete_sharing_channel(cs->parent->cl,
chan->upstream_id);
share_remove_channel(cs, chan);
if (!cs->sock) {
@ -1330,7 +1368,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
* back to downstream.
*/
rpf = ssh_rportfwd_alloc(
cs->parent->ssh, host, port, NULL, 0, 0, NULL, NULL, cs);
cs->parent->cl, host, port, NULL, 0, 0, NULL, NULL, cs);
if (!rpf) {
if (orig_wantreply) {
send_packet_to_downstream(cs, SSH2_MSG_REQUEST_FAILURE,
@ -1346,10 +1384,10 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
*/
pkt[wantreplypos] = 1;
ssh_send_packet_from_downstream
(cs->parent->ssh, cs->id, type, pkt, pktlen,
(cs->parent->cl, cs->id, type, pkt, pktlen,
orig_wantreply ? NULL : "upstream added want_reply flag");
fwd = share_add_forwarding(cs, host, port);
ssh_sharing_queue_global_request(cs->parent->ssh, cs);
ssh_sharing_queue_global_request(cs->parent->cl, cs);
if (fwd) {
globreq = snew(struct share_globreq);
@ -1399,7 +1437,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
* Tell ssh.c to stop sending us channel-opens for
* this forwarding.
*/
ssh_rportfwd_remove(cs->parent->ssh, fwd->rpf);
ssh_rportfwd_remove(cs->parent->cl, fwd->rpf);
/*
* Pass the cancel request on to the SSH server, but
@ -1409,9 +1447,9 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
*/
pkt[wantreplypos] = 1;
ssh_send_packet_from_downstream
(cs->parent->ssh, cs->id, type, pkt, pktlen,
(cs->parent->cl, cs->id, type, pkt, pktlen,
orig_wantreply ? NULL : "upstream added want_reply flag");
ssh_sharing_queue_global_request(cs->parent->ssh, cs);
ssh_sharing_queue_global_request(cs->parent->cl, cs);
/*
* And queue a globreq so that when the reply comes
@ -1445,7 +1483,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
get_string(src);
id_pos = src->pos;
old_id = get_uint32(src);
new_id = ssh_alloc_sharing_channel(cs->parent->ssh, cs);
new_id = ssh_alloc_sharing_channel(cs->parent->cl, cs);
get_uint32(src); /* skip initial window size */
maxpkt = get_uint32(src);
if (get_err(src)) {
@ -1454,7 +1492,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
}
share_add_channel(cs, old_id, new_id, 0, UNACKNOWLEDGED, maxpkt);
PUT_32BIT(pkt + id_pos, new_id);
ssh_send_packet_from_downstream(cs->parent->ssh, cs->id,
ssh_send_packet_from_downstream(cs->parent->cl, cs->id,
type, pkt, pktlen, NULL);
break;
@ -1477,7 +1515,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
/* This server id may refer to either a halfchannel or an xchannel. */
hc = NULL, xc = NULL; /* placate optimiser */
if ((hc = share_find_halfchannel(cs, server_id)) != NULL) {
new_id = ssh_alloc_sharing_channel(cs->parent->ssh, cs);
new_id = ssh_alloc_sharing_channel(cs->parent->cl, cs);
} else if ((xc = share_find_xchannel_by_server(cs, server_id))
!= NULL) {
new_id = xc->upstream_id;
@ -1491,7 +1529,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
chan = share_add_channel(cs, old_id, new_id, server_id, OPEN, maxpkt);
if (hc) {
ssh_send_packet_from_downstream(cs->parent->ssh, cs->id,
ssh_send_packet_from_downstream(cs->parent->cl, cs->id,
type, pkt, pktlen, NULL);
share_remove_halfchannel(cs, hc);
} else if (xc) {
@ -1515,7 +1553,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
/* This server id may refer to either a halfchannel or an xchannel. */
if ((hc = share_find_halfchannel(cs, server_id)) != NULL) {
ssh_send_packet_from_downstream(cs->parent->ssh, cs->id,
ssh_send_packet_from_downstream(cs->parent->cl, cs->id,
type, pkt, pktlen, NULL);
share_remove_halfchannel(cs, hc);
} else if ((xc = share_find_xchannel_by_server(cs, server_id))
@ -1569,7 +1607,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
* a parent session channel.)
*/
if (ptrlen_eq_string(request_name, "auth-agent-req@openssh.com") &&
!ssh_agent_forwarding_permitted(cs->parent->ssh)) {
!ssh_agent_forwarding_permitted(cs->parent->cl)) {
chan = share_find_channel_by_server(cs, server_id);
if (chan) {
@ -1643,7 +1681,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
chan->x11_auth_data = x11_dehexify(auth_data,
&chan->x11_auth_datalen);
chan->x11_auth_upstream =
ssh_sharing_add_x11_display(cs->parent->ssh, auth_proto,
ssh_add_sharing_x11_display(cs->parent->cl, auth_proto,
cs, chan);
chan->x11_one_shot = single_connection;
@ -1661,7 +1699,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
put_stringz(packet, chan->x11_auth_upstream->datastring);
put_uint32(packet, screen);
ssh_send_packet_from_downstream(
cs->parent->ssh, cs->id, SSH2_MSG_CHANNEL_REQUEST,
cs->parent->cl, cs->id, SSH2_MSG_CHANNEL_REQUEST,
packet->s, packet->len, NULL);
strbuf_free(packet);
@ -1669,13 +1707,13 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
}
}
ssh_send_packet_from_downstream(cs->parent->ssh, cs->id,
ssh_send_packet_from_downstream(cs->parent->cl, cs->id,
type, pkt, pktlen, NULL);
if (type == SSH2_MSG_CHANNEL_CLOSE && pktlen >= 4) {
chan = share_find_channel_by_server(cs, server_id);
if (chan) {
if (chan->state == RCVD_CLOSE) {
ssh_delete_sharing_channel(cs->parent->ssh,
ssh_delete_sharing_channel(cs->parent->cl,
chan->upstream_id);
share_remove_channel(cs, chan);
} else {
@ -1757,9 +1795,8 @@ static void share_receive(Plug plug, int urgent, char *data, int len)
}
if (cs->recvlen > 0 && cs->recvbuf[cs->recvlen-1] == '\015')
cs->recvlen--; /* trim off \r before \n */
ssh_sharing_logf(cs->parent->ssh, cs->id,
"Downstream version string: %.*s",
cs->recvlen, cs->recvbuf);
log_downstream(cs, "Downstream version string: %.*s",
cs->recvlen, cs->recvbuf);
cs->got_verstring = TRUE;
/*
@ -1813,8 +1850,7 @@ static void share_listen_closing(Plug plug, const char *error_msg,
{
ssh_sharing_state *sharestate = FROMFIELD(plug, ssh_sharing_state, plugvt);
if (error_msg)
ssh_sharing_logf(sharestate->ssh, 0,
"listening socket: %s", error_msg);
log_general(sharestate, "listening socket: %s", error_msg);
sk_close(sharestate->listensock);
sharestate->listensock = NULL;
}
@ -1923,7 +1959,9 @@ static int share_listen_accepting(Plug plug,
cs->globreq_head = cs->globreq_tail = NULL;
peerinfo = sk_peer_info(cs->sock);
ssh_sharing_downstream_connected(sharestate->ssh, cs->id, peerinfo);
log_downstream(cs, "connected%s%s",
peerinfo ? " from " : "", peerinfo ? peerinfo : "");
sfree(peerinfo);
return 0;
@ -2024,14 +2062,14 @@ static const Plug_vtable ssh_sharing_listen_plugvt = {
* to the upstream; otherwise (whether or not we have established an
* upstream) we return NULL.
*/
Socket ssh_connection_sharing_init(const char *host, int port,
Conf *conf, Ssh ssh, Plug sshplug,
ssh_sharing_state **state)
Socket ssh_connection_sharing_init(
const char *host, int port, Conf *conf, ConnectionLayer *cl,
Plug sshplug, ssh_sharing_state **state)
{
int result, can_upstream, can_downstream;
char *logtext, *ds_err, *us_err;
char *sockname;
Socket sock;
Socket sock, toret = NULL;
struct ssh_sharing_state *sharestate;
if (!conf_get_int(conf, CONF_ssh_connection_sharing))
@ -2065,10 +2103,6 @@ Socket ssh_connection_sharing_init(const char *host, int port,
result = platform_ssh_share(
sockname, conf, sshplug, &sharestate->plugvt, &sock, &logtext,
&ds_err, &us_err, can_upstream, can_downstream);
ssh_connshare_log(ssh, result, logtext, ds_err, us_err);
sfree(logtext);
sfree(ds_err);
sfree(us_err);
switch (result) {
case SHARE_NONE:
/*
@ -2076,11 +2110,29 @@ Socket ssh_connection_sharing_init(const char *host, int port,
* went wrong setting the socket up). Free the upstream
* structure and return NULL.
*/
if (logtext) {
/* For this result, if 'logtext' is not NULL then it is an
* error message indicating a reason why connection sharing
* couldn't be set up _at all_ */
logeventf(cl->frontend,
"Could not set up connection sharing: %s", logtext);
} else {
/* Failing that, ds_err and us_err indicate why we
* couldn't be a downstream and an upstream respectively */
if (ds_err)
logeventf(cl->frontend, "Could not set up connection sharing"
" as downstream: %s", ds_err);
if (us_err)
logeventf(cl->frontend, "Could not set up connection sharing"
" as upstream: %s", us_err);
}
assert(sock == NULL);
*state = NULL;
sfree(sharestate);
sfree(sockname);
return NULL;
break;
case SHARE_DOWNSTREAM:
/*
@ -2088,10 +2140,16 @@ Socket ssh_connection_sharing_init(const char *host, int port,
* don't need after all, and return the downstream socket as a
* replacement for an ordinary SSH connection.
*/
/* 'logtext' is a local endpoint address */
logeventf(cl->frontend,
"Using existing shared connection at %s", logtext);
*state = NULL;
sfree(sharestate);
sfree(sockname);
return sock;
toret = sock;
break;
case SHARE_UPSTREAM:
/*
@ -2099,15 +2157,22 @@ Socket ssh_connection_sharing_init(const char *host, int port,
* to the caller; return NULL, to tell ssh.c that it has to
* make an ordinary connection after all.
*/
/* 'logtext' is a local endpoint address */
logeventf(cl->frontend, "Sharing this connection at %s", logtext);
*state = sharestate;
sharestate->listensock = sock;
sharestate->connections = newtree234(share_connstate_cmp);
sharestate->ssh = ssh;
sharestate->cl = cl;
sharestate->server_verstring = NULL;
sharestate->sockname = sockname;
sharestate->nextid = 1;
return NULL;
break;
}
return NULL;
sfree(logtext);
sfree(ds_err);
sfree(us_err);
return toret;
}