diff --git a/defs.h b/defs.h index 822ee71d..8bd9f13e 100644 --- a/defs.h +++ b/defs.h @@ -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; diff --git a/portfwd.c b/portfwd.c index d200c78b..07210683 100644 --- a/portfwd.c +++ b/portfwd.c @@ -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, diff --git a/ssh.c b/ssh.c index bedfe6af..9ec8553f 100644 --- a/ssh.c +++ b/ssh.c @@ -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; diff --git a/ssh.h b/ssh.h index 4f5fc204..a0085179 100644 --- a/ssh.h +++ b/ssh.h @@ -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 diff --git a/sshshare.c b/sshshare.c index a43ab9c2..7515d117 100644 --- a/sshshare.c +++ b/sshshare.c @@ -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; }