X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=sshshare.c;h=82c4bd31ed8867755fcad1b467356450c3df5410;hb=23841fd85e55f6ca1a915c4a9998c4253d0db515;hp=54d58a6624bfdb9b19b4d32afb37b2943e9e3751;hpb=69d50b2877ea6cb2a23a75e563dbca7548dacd38;p=PuTTY.git diff --git a/sshshare.c b/sshshare.c index 54d58a66..82c4bd31 100644 --- a/sshshare.c +++ b/sshshare.c @@ -133,6 +133,7 @@ #include #include #include +#include #include "putty.h" #include "tree234.h" @@ -502,6 +503,9 @@ static void share_connstate_free(struct ssh_sharing_connstate *cs) sfree(globreq); } + if (cs->sock) + sk_close(cs->sock); + sfree(cs); } @@ -911,8 +915,25 @@ static int share_closing(Plug plug, const char *error_msg, int error_code, int calling_back) { struct ssh_sharing_connstate *cs = (struct ssh_sharing_connstate *)plug; - if (error_msg) - ssh_sharing_logf(cs->parent->ssh, cs->id, "%s", error_msg); + + if (error_msg) { +#ifdef BROKEN_PIPE_ERROR_CODE + /* + * Most of the time, we log what went wrong when a downstream + * disappears with a socket error. One exception, though, is + * receiving EPIPE when we haven't received a protocol version + * string from the downstream, because that can happen as a result + * of plink -shareexists (opening the connection and instantly + * closing it again without bothering to read our version string). + * So that one case is not treated as a log-worthy error. + */ + if (error_code == BROKEN_PIPE_ERROR_CODE && !cs->got_verstring) + /* do nothing */; + else +#endif + ssh_sharing_logf(cs->parent->ssh, cs->id, + "Socket error: %s", error_msg); + } share_begin_cleanup(cs); return 1; } @@ -1807,6 +1828,7 @@ static int share_receive(Plug plug, int urgent, char *data, int len) ssh_sharing_logf(cs->parent->ssh, cs->id, "Downstream version string: %.*s", cs->recvlen, cs->recvbuf); + cs->got_verstring = TRUE; /* * Loop round reading packets. @@ -1924,6 +1946,7 @@ static int share_listen_accepting(Plug plug, struct ssh_sharing_state *sharestate = (struct ssh_sharing_state *)plug; struct ssh_sharing_connstate *cs; const char *err; + char *peerinfo; /* * A new downstream has connected to us. @@ -1966,7 +1989,9 @@ static int share_listen_accepting(Plug plug, cs->forwardings = newtree234(share_forwarding_cmp); cs->globreq_head = cs->globreq_tail = NULL; - ssh_sharing_downstream_connected(sharestate->ssh, cs->id); + peerinfo = sk_peer_info(cs->sock); + ssh_sharing_downstream_connected(sharestate->ssh, cs->id, peerinfo); + sfree(peerinfo); return 0; } @@ -1976,6 +2001,99 @@ static int share_listen_accepting(Plug plug, extern const int share_can_be_downstream; extern const int share_can_be_upstream; +/* + * Decide on the string used to identify the connection point between + * upstream and downstream (be it a Windows named pipe or a + * Unix-domain socket or whatever else). + * + * I wondered about making this a SHA hash of all sorts of pieces of + * the PuTTY configuration - essentially everything PuTTY uses to know + * where and how to make a connection, including all the proxy details + * (or rather, all the _relevant_ ones - only including settings that + * other settings didn't prevent from having any effect), plus the + * username. However, I think it's better to keep it really simple: + * the connection point identifier is derived from the hostname and + * port used to index the host-key cache (not necessarily where we + * _physically_ connected to, in cases involving proxies or + * CONF_loghost), plus the username if one is specified. + * + * The per-platform code will quite likely hash or obfuscate this name + * in turn, for privacy from other users; failing that, it might + * transform it to avoid dangerous filename characters and so on. But + * that doesn't matter to us: for us, the point is that two session + * configurations which return the same string from this function will + * be treated as potentially shareable with each other. + */ +char *ssh_share_sockname(const char *host, int port, Conf *conf) +{ + char *username = get_remote_username(conf); + char *sockname; + + if (port == 22) { + if (username) + sockname = dupprintf("%s@%s", username, host); + else + sockname = dupprintf("%s", host); + } else { + if (username) + sockname = dupprintf("%s@%s:%d", username, host, port); + else + sockname = dupprintf("%s:%d", host, port); + } + + sfree(username); + return sockname; +} + +static void nullplug_socket_log(Plug plug, int type, SockAddr addr, int port, + const char *error_msg, int error_code) {} +static int nullplug_closing(Plug plug, const char *error_msg, int error_code, + int calling_back) { return 0; } +static int nullplug_receive(Plug plug, int urgent, char *data, + int len) { return 0; } +static void nullplug_sent(Plug plug, int bufsize) {} + +int ssh_share_test_for_upstream(const char *host, int port, Conf *conf) +{ + static const struct plug_function_table fn_table = { + nullplug_socket_log, + nullplug_closing, + nullplug_receive, + nullplug_sent, + NULL + }; + struct nullplug { + const struct plug_function_table *fn; + } np; + + char *sockname, *logtext, *ds_err, *us_err; + int result; + Socket sock; + + np.fn = &fn_table; + + sockname = ssh_share_sockname(host, port, conf); + + sock = NULL; + logtext = ds_err = us_err = NULL; + result = platform_ssh_share(sockname, conf, (Plug)&np, (Plug)NULL, &sock, + &logtext, &ds_err, &us_err, FALSE, TRUE); + + sfree(logtext); + sfree(ds_err); + sfree(us_err); + sfree(sockname); + + if (result == SHARE_NONE) { + assert(sock == NULL); + return FALSE; + } else { + assert(result == SHARE_DOWNSTREAM); + sk_close(sock); + return TRUE; + } +} + /* * Init function for connection sharing. We either open a listening * socket and become an upstream, or connect to an existing one and @@ -2012,47 +2130,7 @@ Socket ssh_connection_sharing_init(const char *host, int port, if (!can_upstream && !can_downstream) return NULL; - /* - * Decide on the string used to identify the connection point - * between upstream and downstream (be it a Windows named pipe or - * a Unix-domain socket or whatever else). - * - * I wondered about making this a SHA hash of all sorts of pieces - * of the PuTTY configuration - essentially everything PuTTY uses - * to know where and how to make a connection, including all the - * proxy details (or rather, all the _relevant_ ones - only - * including settings that other settings didn't prevent from - * having any effect), plus the username. However, I think it's - * better to keep it really simple: the connection point - * identifier is derived from the hostname and port used to index - * the host-key cache (not necessarily where we _physically_ - * connected to, in cases involving proxies or CONF_loghost), plus - * the username if one is specified. - */ - { - char *username = get_remote_username(conf); - - if (port == 22) { - if (username) - sockname = dupprintf("%s@%s", username, host); - else - sockname = dupprintf("%s", host); - } else { - if (username) - sockname = dupprintf("%s@%s:%d", username, host, port); - else - sockname = dupprintf("%s:%d", host, port); - } - - sfree(username); - - /* - * The platform-specific code may transform this further in - * order to conform to local namespace conventions (e.g. not - * using slashes in filenames), but that's its job and not - * ours. - */ - } + sockname = ssh_share_sockname(host, port, conf); /* * Create a data structure for the listening plug if we turn out